fix(onboarding): don't seed a demo flag into a project that has flags - #8217
fix(onboarding): don't seed a demo flag into a project that has flags#8217talissoncosta wants to merge 3 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedNo new commits to review since the last review. ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThe change adds shared onboarding-flag constants, lookup logic, and seeding rules. Bootstrap reuses existing flags, creates flags only for empty projects, and reports whether an onboarding flag exists. The resource hook exposes this state to Estimated code review effort: 3 (Moderate) | ~25 minutes Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
e165808 to
3f8c70c
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 687db188-e702-4cea-8a87-bdf2abececc2
📒 Files selected for processing (7)
frontend/web/components/pages/onboarding/OnboardingFlow/OnboardingFlow.tsxfrontend/web/components/pages/onboarding/hooks/__tests__/demoFlag.test.tsfrontend/web/components/pages/onboarding/hooks/bootstrapOnboarding.tsfrontend/web/components/pages/onboarding/hooks/demoFlag.tsfrontend/web/components/pages/onboarding/hooks/useEnsureOnboardingResources.tsfrontend/web/components/pages/onboarding/onboarding-already-set-up/OnboardingAlreadySetUp.tsxfrontend/web/components/pages/onboarding/onboarding-already-set-up/index.ts
3f8c70c to
e66002b
Compare
e66002b to
1b1d836
Compare
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
There was a problem hiding this comment.
Actionable comments posted: 2
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: f2bc4afd-cc1d-4693-947a-0bd91c472a61
📒 Files selected for processing (5)
frontend/web/components/pages/onboarding/OnboardingFlow/OnboardingFlow.tsxfrontend/web/components/pages/onboarding/hooks/__tests__/demoFlag.test.tsfrontend/web/components/pages/onboarding/hooks/bootstrapOnboarding.tsfrontend/web/components/pages/onboarding/hooks/demoFlag.tsfrontend/web/components/pages/onboarding/hooks/useEnsureOnboardingResources.ts
1b1d836 to
44b9d75
Compare
Visiting /getting-started created show_demo_button in whichever project came back first, whether or not the customer had ever onboarded. Features are project-level, so it appeared in every environment of that project, including production, alongside a new Onboarding tag. The Getting Started nav link is ungated, so any customer could trigger this by clicking it. ensureFlag already computed isFirstFeature for analytics; it now also decides whether to create anything. An empty project still gets the demo flag, an established one gets nothing. That leaves the tour with no flag to teach with, so the page says so and points at the project's own flags instead of walking someone through connecting a project that is already connected. Copy and treatment of that state are provisional. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
bootstrapOnboarding and createOrganisationViaAccountStore are plain functions, so hooks/ described three of its nine files wrongly. Both belong to the provisioning that runs before the tour, which is what the new bootstrap/ folder holds. Paths and one comment only; no logic changes.
44b9d75 to
8c41def
Compare
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 4bbc3d97-5922-410b-b554-ee151a4fab97
📒 Files selected for processing (6)
frontend/web/components/pages/onboarding/OnboardingFlow/OnboardingFlow.tsxfrontend/web/components/pages/onboarding/bootstrap/__tests__/demoFlag.test.tsfrontend/web/components/pages/onboarding/bootstrap/bootstrapOnboarding.tsfrontend/web/components/pages/onboarding/bootstrap/createOrganisationViaAccountStore.tsfrontend/web/components/pages/onboarding/bootstrap/demoFlag.tsfrontend/web/components/pages/onboarding/hooks/useEnsureOnboardingResources.ts
There was a problem hiding this comment.
Caution
Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 4bbc3d97-5922-410b-b554-ee151a4fab97
📒 Files selected for processing (6)
frontend/web/components/pages/onboarding/OnboardingFlow/OnboardingFlow.tsxfrontend/web/components/pages/onboarding/bootstrap/__tests__/demoFlag.test.tsfrontend/web/components/pages/onboarding/bootstrap/bootstrapOnboarding.tsfrontend/web/components/pages/onboarding/bootstrap/createOrganisationViaAccountStore.tsfrontend/web/components/pages/onboarding/bootstrap/demoFlag.tsfrontend/web/components/pages/onboarding/hooks/useEnsureOnboardingResources.ts
🛑 Comments failed to post (1)
frontend/web/components/pages/onboarding/bootstrap/createOrganisationViaAccountStore.ts (1)
15-40: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash set -euo pipefail store_file="$(fd -t f 'account-store\.(ts|tsx|js|jsx)$' frontend | head -n 1)" test -n "$store_file" echo "== AccountStore event declarations and emissions ==" rg -n -C 5 "['\"](saved|problem)['\"]|\.emit\(|\.trigger\(" "$store_file" echo "== AccountStore consumers and emitters ==" rg -n -C 4 "AccountStore\.(on|off|emit|trigger)\(['\"](saved|problem)['\"]" frontendRepository: Flagsmith/flagsmith
Length of output: 3897
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "== candidate files ==" fd -t f 'account-store\.(ts|tsx|js|jsx)$|app-actions\.(ts|tsx|js|jsx)$|accountActions\.(ts|tsx|js|jsx)$|actions' frontend | head -n 50 echo "== AccountStore source outline and relevant sections ==" store_file="$(fd -t f 'account-store\.(ts|tsx|js|jsx)$' frontend | head -n 1)" test -n "$store_file" wc -l "$store_file" sed -n '1,220p' "$store_file" | cat -n sed -n '350,430p' "$store_file" | cat -n echo "== createOrganisation references ==" rg -n -C 6 "createOrganisation|savedId|Problem|problem|saving|API\.|fetch\(|request" frontend -g '*.ts' -g '*.tsx' -g '*.js' -g '*.jsx'Repository: Flagsmith/flagsmith
Length of output: 50376
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "== AccountStore files ==" fd -t f 'account-store\.(ts|tsx|js|jsx)$' frontend echo "== createOrganisation event consumers ==" rg -n -C 8 "createOrganisation|saved|savedId|problem|AccountStore\.on\(['\"](saved|problem)" frontend/web/components/pages/frontend/web/components/pages/onboarding/bootstrap frontend/web/components/pages/CreateOrganisationPage.tsx frontend/web/components/pages/onboarding/bootstrap/createOrganisationViaAccountStore.ts 2>/dev/null || true api_file="$(fd -t f 'API\.(ts|js)$' frontend/common frontend | head -n 1)" if [ -n "$api_file" ]; then echo "== API file: $api_file ==" wc -l "$api_file" sed -n '1,240p' "$api_file" | cat -n fi echo "== AppActions likely files ==" fd -t f '.*actions.*\.(ts|js)$' frontend | rg -i 'app|action' | head -n 50Repository: Flagsmith/flagsmith
Length of output: 9869
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "== account-store.js outline/sections ==" wc -l frontend/common/stores/account-store.js sed -n '1,220p' frontend/common/stores/account-store.js | cat -n sed -n '220,360p' frontend/common/stores/account-store.js | cat -n echo "== app-actions.js and related sections ==" for f in frontend/common/dispatcher/app-actions.js frontend/common/dispatcher/base/_app-actions.js; do [ -f "$f" ] || continue echo "--- $f ($(wc -l < "$f") lines) ---" rg -n -C 10 "createOrganisation|fetch|API|isSaving|savedId|trigger|emit|saved|problem" "$f" done echo "== precise AccountStore saved/problem references ==" rg -n -C 4 "savedId|'saved'|\"saved\"|'problem'|\"problem\"|trigger\(['\"](saved|problem)" frontend/common/stores/account-store.js frontend/common/dispatcher/app-actions.js frontend/common/dispatcher/base/_app-actions.js frontend 2>/dev/null | head -n 220Repository: Flagsmith/flagsmith
Length of output: 14785
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "== dispatchers ==" fd -t f 'dispatcher\.(js|ts)$|_dispatcher\.(js|ts)$' frontend/common/dispatcher frontend for f in frontend/common/dispatcher/dispatcher.js frontend/common/dispatcher/base/_dispatcher.js frontend/common/dispatcher/app-actions.js frontend/common/dispatcher/base/_app-actions.js frontend/common/dispatcher/account-actions.js frontend/common/dispatcher/base/account-actions.js frontend/common/stores/account-store.js; do [ -f "$f" ] || continue echo "--- $f ($(wc -l < "$f") lines) ---" rg -n -C 8 "CREATE_ORGANISATION|CREATE.*ORG|saved|problem|save|trigger|isSaving|error" "$f" || true done echo "== store helper methods around saved/problem ==" rg -n -C 6 "saved\(|problem\(|issue\(|changing\(|savedId|isSaving|trigger\(" frontend/common/stores/account-store.js frontend/common/stores/base/_store.js frontend/common/dispatcher/account-actions.js | head -n 240 echo "== all AccountStore saved/event consumers by file ==" rg -n "AccountStore\.(on|off)\(['\"](saved|problem|change)" frontend/web -g '*.tsx' -g '*.ts' <(printf "frontend/web/components/pages/CreateOrganisationPage.tsx\nfrontend/web/components/pages/onboarding/bootstrap/createOrganisationViaAccountStore.ts\n")Repository: Flagsmith/flagsmith
Length of output: 23457
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "== _store.js full contents ==" cat -n frontend/common/stores/base/_store.js echo "== dispatcher and store event binding sections ==" cat -n frontend/common/dispatcher/dispatcher.js | sed -n '1,80p' rg -n -C 5 "_emit|DEFAULT_SAVED_EVENT|DEFAULT_ERROR_EVENT|registerWith|saved|problem\(|error" frontend/common/stores/account-store.js frontend/common/stores/base/_store.js frontend/common/dispatcher/dispatcher.js echo "== precise consumers ==" python3 - <<'PY' from pathlib import Path import re paths=[Path("frontend/web/components/pages/CreateOrganisationPage.tsx"),Path("frontend/web/components/pages/onboarding/bootstrap/createOrganisationViaAccountStore.ts")] for p in paths: print(f"\n--- {p} ---") text=p.read_text() for i,line in enumerate(text.splitlines(),1): if re.search(r"AccountStore\.(on|off)\(['\"](saved|problem|change)", line): print(f"{i}: {line.strip()}") PYRepository: Flagsmith/flagsmith
Length of output: 14284
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "== account store registration ==" rg -n -C 8 "AccountStore|registerWith|emit|trigger|saved\(|problem\(|goneABitWest" frontend/common/stores/account-store.js | sed -n '1,180p' echo "== account store exports and event constants ==" sed -n '560,620p' frontend/common/stores/account-store.js | cat -n rg -n -C 3 "DEFAULT_SAVED_EVENT|DEFAULT_ERROR_EVENT|constants|Actions\." frontend/common/stores/account-store.js frontend/common/dispatcher baseline 2>/dev/null || trueRepository: Flagsmith/flagsmith
Length of output: 33828
Use a request-scoped AccountStore completion callback.
This helper waits on the generic
savedandproblemevents, butAccountStoreemits the same events from other operations such as 2FA and password reset. Pass a callback fromcreateOrganisationViaAccountStoreintoAppActions.createOrganisationso only the organisation creation result resolves/rejects the flow.
The flag is found by its Onboarding tag, falling back to the name only because renaming a flag is a delete and recreate, so "onboarding flag" is what the lookup actually means. "Demo" also read as throwaway, which is the opposite of the problem being fixed here: this flag lands in a real project and shows up in every environment, production included. The flag's own name stays show_demo_button, since the tour's snippet references it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
docs/if required so people know about the feature.Changes
Visiting
/getting-startedcreatedshow_demo_buttonin whichever project came back first, whether or not the customer had onboarded. Features are project-level, so it appeared in every environment of that project including production, next to a newOnboardingtag. The nav link is shown to everyone, so any customer could trigger it.onboardingFlag.tsas two pure functions with tests. It was inline in an async orchestrator that nothing could test.The helpers are named after onboarding rather than "demo", because the lookup matches on the
Onboardingtag, and because this flag lands in a real project rather than a throwaway one. The flag's own name staysshow_demo_button, which the tour's snippet references.Copy of the already-set-up state is provisional, and still calls it a demo flag.
Still open: creation happens on page load rather than on an explicit action, and there's no persisted "has onboarded" state (
isGettingStartedis set at register, in memory, lost on refresh).How did you test this code?
7 unit tests on the seeding rule, checked by mutation: forcing
shouldSeedOnboardingFlagto true fails the suitetest:unit(395) andlintclean, and no typecheck errors in the touched filesNew account: seeds the flag, tags it, tour works end to end
Project with flags: nothing created, no
Onboardingtag, already-set-up state shownProject that already has the onboarding flag: reused, not duplicated
Empty project on an established account: still seeded