feat(onboarding): "next quest" cards#7941
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Docker builds report
|
Playwright Test Results (oss - depot-ubuntu-latest-16)Details
Playwright Test Results (oss - depot-ubuntu-latest-arm-16)Details
Playwright Test Results (private-cloud - depot-ubuntu-latest-16)Details
Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)Details
Playwright Test Results (oss - depot-ubuntu-latest-16)Details
Playwright Test Results (oss - depot-ubuntu-latest-arm-16)Details
Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)Details
Playwright Test Results (private-cloud - depot-ubuntu-latest-16)Details
Playwright Test Results (oss - depot-ubuntu-latest-16)Details
Playwright Test Results (oss - depot-ubuntu-latest-arm-16)Details
Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)Details
Playwright Test Results (private-cloud - depot-ubuntu-latest-16)Details
Playwright Test Results (oss - depot-ubuntu-latest-16)Details
Playwright Test Results (oss - depot-ubuntu-latest-arm-16)Details
Playwright Test Results (private-cloud - depot-ubuntu-latest-16)Details
Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)Details
Playwright Test Results (oss - depot-ubuntu-latest-16)Details
Playwright Test Results (oss - depot-ubuntu-latest-arm-16)Details
Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)Details
Playwright Test Results (private-cloud - depot-ubuntu-latest-16)Details
Playwright Test Results (oss - depot-ubuntu-latest-16)Details
Playwright Test Results (oss - depot-ubuntu-latest-arm-16)Details
Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)Details
Playwright Test Results (private-cloud - depot-ubuntu-latest-16)Details
Playwright Test Results (oss - depot-ubuntu-latest-16)Details
Playwright Test Results (oss - depot-ubuntu-latest-arm-16)Details
Failed testsfirefox › tests/onboarding-tests.pw.ts › Onboarding › New user connects via the single-page onboarding flow @oss Details
Playwright Test Results (private-cloud - depot-ubuntu-latest-16)Details
Playwright Test Results (oss - depot-ubuntu-latest-arm-16)Details
|
Visual Regression19 screenshots compared. See report for details. |
f2c4e9f to
eb9646f
Compare
Add an optional content slot (children), make selected optional, and pass through className, so SelectableCard can back a navigational card and not just a selection tile. Additive: existing consumers are unaffected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The three next-quest cards (gradual rollout, experiment, remote config) are built on SelectableCard and each deep-links to the flag's real config: rollout to the segment overrides tab, remote config to the value tab, experiment to the experiments page. The tab param is the slugified tab label. Locked and dimmed (inert) until the app connects. Closes #7739 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the "Flip it once your app connects" lock affordance beside the Your flags heading while the toggle is waiting to connect. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Assert the cards are locked before the first evaluation, and that once connected each one deep-links to the right destination. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
eb9646f to
12e69c9
Compare
Zaimwa9
left a comment
There was a problem hiding this comment.
I have some nits, but I think Kyle's comments are worth addressing, although the last one would be a NIT to me that I let you decide what do with 👍
| ) | ||
|
|
||
| // A value chip: "serve a value, not just on/off". | ||
| const RemoteConfigPreview: FC = () => ( |
There was a problem hiding this comment.
I will handle that on a follow up pr
Review nit: align the classnames import name with SelectableCard's. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Thanks both 🙏 This PR
Follow-up PR (keeping this one focused): the connect step plus the spacing nit.
Shout if you'd rather I fold these into this PR instead. |
📝 WalkthroughWalkthroughAdds a new onboarding next-steps component with three selectable cards and locked-state presentation. Extends selectable cards to support children and custom classes. Integrates connection-aware locking and deep-links to feature configuration or experiments. Adds a lock hint to the flags table, Storybook stories, and Playwright coverage for locked, unlocked, and navigated states. Estimated code review effort: 3 (Moderate) | ~25 minutes Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 47402c70-fb6a-4aa4-8054-15dbf89c81fe
📒 Files selected for processing (11)
frontend/documentation/pages/onboarding/OnboardingNextSteps.stories.tsxfrontend/e2e/tests/onboarding-tests.pw.tsfrontend/web/components/base/SelectableCard/SelectableCard.scssfrontend/web/components/base/SelectableCard/SelectableCard.tsxfrontend/web/components/pages/onboarding/OnboardingFlagsTable/OnboardingFlagsTable.scssfrontend/web/components/pages/onboarding/OnboardingFlagsTable/OnboardingFlagsTable.tsxfrontend/web/components/pages/onboarding/OnboardingFlow/OnboardingFlow.tsxfrontend/web/components/pages/onboarding/OnboardingNextSteps/OnboardingNextSteps.scssfrontend/web/components/pages/onboarding/OnboardingNextSteps/OnboardingNextSteps.tsxfrontend/web/components/pages/onboarding/OnboardingNextSteps/index.tsfrontend/web/components/pages/onboarding/hooks/useOnboardingFlag.ts
| @@ -0,0 +1,30 @@ | |||
| import type { Meta, StoryObj } from 'storybook' | |||
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
Does Storybook 10 export Meta and StoryObj types from the bare 'storybook' package, or only from framework packages like @storybook/react?
💡 Result:
In Storybook 10, the Meta and StoryObj types are exported from your specific framework package (e.g., @storybook/react, @storybook/vue3-vite, @storybook/tanstack-react), not from the bare storybook package [1][2][3]. Official documentation and migration guidance consistently instruct developers to import these utility types from the framework-specific package they are using [4][5][6]. This is necessary because these types are generics that require the framework-aware parameter types (such as React, Vue, or TanStack-specific annotations) to provide correct type safety, autocompletion, and inference for your component's props and arguments [4][5][3]. Using imports like import { Meta, StoryObj } from '@storybook/react' (or your respective framework package) ensures that Storybook can correctly map your component's metadata and args to the framework's internal type definitions [3][6].
Citations:
- 1: https://storybook.js.org/docs/api/csf
- 2: https://storybook.js.org/docs/writing-stories
- 3: https://storybook.js.org/docs/configure/typescript/
- 4: https://github.com/storybookjs/storybook/blob/main/MIGRATION.md
- 5: https://storybook.js.org/docs/writing-stories/typescript.md
- 6: https://storybook.js.org/docs/10.4/writing-stories/typescript.md
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf 'Repository files of interest:\n'
git ls-files | rg '(^|/)(package.json|tsconfig.*|\.storybook/|storybook|OnboardingNextSteps\.stories\.tsx)$'
printf '\nPackage manifests mentioning Storybook:\n'
rg -n '"storybook"|`@storybook`' package.json frontend/package.json .storybook package.json 2>/dev/null || true
printf '\nStorybook-related config files (first 200 lines each if present):\n'
for f in .storybook/main.* .storybook/preview.* frontend/.storybook/main.* frontend/.storybook/preview.*; do
if [ -f "$f" ]; then
echo "--- $f ---"
sed -n '1,200p' "$f"
fi
done
printf '\nTarget file:\n'
sed -n '1,80p' frontend/documentation/pages/onboarding/OnboardingNextSteps.stories.tsxRepository: Flagsmith/flagsmith
Length of output: 2002
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo 'package.json'
sed -n '1,220p' package.json 2>/dev/null || true
echo
echo 'frontend/package.json'
sed -n '1,220p' frontend/package.json 2>/dev/null || true
echo
echo 'Storybook config files'
find . -maxdepth 3 \( -path '*/.storybook/*' -o -name 'main.ts' -o -name 'main.js' -o -name 'preview.ts' -o -name 'preview.js' \) | sort | sed -n '1,50p'
echo
echo 'Search for storybook type imports'
rg -n "from 'storybook'|from \"storybook\"|from '`@storybook/`" frontend --glob '*.stories.*' --glob '*.ts' --glob '*.tsx'Repository: Flagsmith/flagsmith
Length of output: 2002
🌐 Web query:
site:storybook.js.org/docs StoryObj import from 'storybook' Meta StoryObj framework package
💡 Result:
In Storybook, Meta and StoryObj are TypeScript utility types used to type your story files and ensure type safety [1][2]. You should import them from your specific framework's Storybook package, not from a generic 'storybook' package [3][4][5]. Replace 'your-framework' in the import statement with the specific Storybook framework package you are using (e.g., @storybook/react-vite, @storybook/nextjs, @storybook/vue3-vite) [6][1][2]. Example usage in a TypeScript story file: import type { Meta, StoryObj } from '@storybook/your-framework'; import { Button } from './Button'; const meta = { component: Button, } satisfies Meta; export default meta; type Story = StoryObj; export const Primary: Story = { args: { primary: true, }, }; Using these types allows Storybook to infer component metadata and argument types, providing autocompletion and error checking for your stories [1][2]. The satisfies operator is typically used with Meta to associate the component definition with the meta object, which then allows StoryObj to correctly infer the argument types from that meta definition [1][2].
Citations:
- 1: https://storybook.js.org/docs/writing-stories/typescript.md
- 2: https://storybook.js.org/docs/configure/typescript/
- 3: https://storybook.js.org/docs/writing-stories
- 4: https://storybook.js.org/docs/api/new-frameworks
- 5: https://storybook.js.org/docs/get-started/setup
- 6: https://storybook.js.org/docs/api/csf.md
Import Meta/StoryObj from the configured Storybook framework package
storybook does not export these types; use the framework package for this project (for example @storybook/react or @storybook/react-vite) so this story type-checks.
| <div className='onboarding-flags__heading d-flex align-items-center gap-2'> | ||
| <h3 | ||
| className='onboarding-flags__title m-0 fw-bold' | ||
| id='onboarding-flags-title' | ||
| > | ||
| Your flags | ||
| </h3> | ||
| {waiting && ( | ||
| <span className='onboarding-flags__hint d-flex align-items-center gap-1'> | ||
| <Icon name='lock' width={13} /> | ||
| Flip it once your app connects | ||
| </span> | ||
| )} | ||
| </div> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Keep the hint aligned with every disabled state.
The switch is disabled when togglesReady is false, but this hint only renders while waiting is true. If the app connects before the feature-state query resolves, users see a disabled toggle without an explanation. Use the same lock condition or provide a loading-specific message.
| // Each next-step card deep-links to the flag's real config; nothing faked. | ||
| const goToNextStep = (step: OnboardingNextStep) => { | ||
| if (projectId === null) { | ||
| return | ||
| } | ||
| const base = `/project/${projectId}/environment/${environmentKey}` | ||
| if (step === 'experiment') { | ||
| history.push(`${base}/experiments`) | ||
| return | ||
| } | ||
| if (flagId === null) { | ||
| return | ||
| } | ||
| // Tab param is the slugified tab label (see TabMenu/Tabs urlParam). | ||
| const tab = step === 'rollout' ? 'segment-overrides' : 'value' | ||
| history.push(`${base}/features?feature=${flagId}&tab=${tab}`) | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Do not unlock dependent cards before flagId is ready.
The handler returns without navigating when flagId === null, but Lines [203-205] make the cards interactive as soon as the connection is established. During the flag query, rollout and remote-config cards can therefore look clickable while doing nothing. Include flag readiness in the lock condition, or add per-step loading/disabled handling instead of silently returning.
Also applies to: 203-205
| export { default } from './OnboardingNextSteps' | ||
| export type { | ||
| OnboardingNextStep, | ||
| OnboardingNextStepsProps, | ||
| } from './OnboardingNextSteps' |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Use the configured absolute import in this barrel.
Line [1] and the type re-export at Lines [2-5] use a relative path, violating the frontend import-path guideline. Keep consumers importing the component folder, but point this barrel at the implementation through the components/ alias.
Proposed fix
-export { default } from './OnboardingNextSteps'
+export { default } from 'components/pages/onboarding/OnboardingNextSteps/OnboardingNextSteps'
export type {
OnboardingNextStep,
OnboardingNextStepsProps,
-} from './OnboardingNextSteps'
+} from 'components/pages/onboarding/OnboardingNextSteps/OnboardingNextSteps'📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export { default } from './OnboardingNextSteps' | |
| export type { | |
| OnboardingNextStep, | |
| OnboardingNextStepsProps, | |
| } from './OnboardingNextSteps' | |
| export { default } from 'components/pages/onboarding/OnboardingNextSteps/OnboardingNextSteps' | |
| export type { | |
| OnboardingNextStep, | |
| OnboardingNextStepsProps, | |
| } from 'components/pages/onboarding/OnboardingNextSteps/OnboardingNextSteps' |
Source: Coding guidelines






docs/if required so people know about the feature.Changes
Closes #7739
The three "next quest" cards on the onboarding flow (gradual rollout, experiment, remote config) are now actionable. Each one deep-links to the flag's real configuration, nothing faked:
The cards stay locked and dimmed until the app connects, matching the flags table above them.
Also folded in two small fixes for the cards: the rollout deep-link now uses the slugified tab label so it resolves to the right tab, and the cards' secondary text no longer renders gold (a Bootstrap
.text-secondarycollision).Review follow-ups: the
cnimport alignment (Wadii) lands here; the connect-panel, spacing and inline-edit polish (Kyle, Wadii, Matt) is in the stacked #7989.How did you test this code?
Added e2e coverage in
onboarding-tests.pw.ts: it asserts the cards are locked before the first evaluation, and that once connected each card deep-links to the right destination (segment overrides tab, value tab, experiments page).Manually:
onboarding_quickstart_flow, sign up, land on/getting-started./getting-started?connected.