feat: implement onboard walkthrough for new user - #2712
Conversation
There was a problem hiding this comment.
Pull request overview
Implements an onboarding walkthrough for first-time dashboard users, guiding them through creating a feature flag, creating an API key, and then showing SDK connection starter snippets. This is enabled/disabled via a new WALKTHROUGH_ENABLED config flag and relies on backend lastSeen behavior to detect first login.
Changes:
- Add a Driver.js-based walkthrough hook, storage flag, UI tour targets, and “Get started” navigation entry.
- Add “Connect SDK” modal with multi-language install/init snippets and i18n strings.
- Add
WALKTHROUGH_ENABLEDconfiguration across Vite env,window.env, Helm values, and docker-compose; updateGetMeto return pre-updatelastSeento detect first login.
Reviewed changes
Copilot reviewed 26 out of 29 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| ui/dashboard/package.json | Adds driver.js dependency for the walkthrough UI. |
| ui/dashboard/yarn.lock | Locks driver.js@1.8.0. |
| ui/dashboard/src/storage/walkthrough.ts | Adds localStorage helpers to mark walkthrough pending on first login. |
| ui/dashboard/src/hooks/use-walkthrough.tsx | New walkthrough orchestrator hook (Driver.js steps, polling for API key creation, SDK modal trigger). |
| ui/dashboard/src/hooks/index.ts | Re-exports use-walkthrough from the hooks barrel. |
| ui/dashboard/src/components/navigation/menu-item.tsx | Adds optional tourId to attach data-tour attributes to nav items. |
| ui/dashboard/src/components/navigation/index.tsx | Adds “Get started” entry, wires useWalkthrough, and renders ConnectSdkModal. |
| ui/dashboard/src/pages/feature-flags/page-content.tsx | Adds data-tour target to “Create flag” button. |
| ui/dashboard/src/pages/create-flag/flag-form/index.tsx | Adds data-tour target to “Create flag” submit button. |
| ui/dashboard/src/pages/create-flag/flag-form/general-info.tsx | Adds data-tour target to general info section container. |
| ui/dashboard/src/pages/create-flag/flag-form/flag-variations/index.tsx | Adds data-tour target to variations section container. |
| ui/dashboard/src/pages/api-keys/page-content.tsx | Adds data-tour target to “New API key” button. |
| ui/dashboard/src/pages/api-keys/api-key-modal/api-key-create-update-modal/index.tsx | Adds data-tour targets to API key form + submit button. |
| ui/dashboard/src/index.css | Adds Driver.js-related z-index/pointer-event overrides. |
| ui/dashboard/src/elements/connect-sdk-modal/index.tsx | Adds new modal UI showing SDK snippets and copy actions. |
| ui/dashboard/src/elements/connect-sdk-modal/snippets.ts | Adds SDK snippet definitions used by the modal. |
| ui/dashboard/src/env.d.ts | Adds VITE_WALKTHROUGH_ENABLED env typing. |
| ui/dashboard/src/configs/index.ts | Adds WALKTHROUGH_ENABLED config resolution (Vite env vs window.env). |
| ui/dashboard/src/auth/auth-context.tsx | Sets walkthrough pending flag on first login. |
| ui/dashboard/src/@locales/en/common.json | Adds walkthrough strings + “Get started” label. |
| ui/dashboard/src/@locales/ja/common.json | Adds walkthrough strings + “Get started” label (JP). |
| ui/dashboard/src/@icons/sidebar-icons/rocket.svg | Adds rocket icon for the “Get started” menu item. |
| ui/dashboard/src/@icons/index.tsx | Exports new rocket icon. |
| ui/dashboard/.env.example | Adds VITE_WALKTHROUGH_ENABLED example value. |
| pkg/account/api/admin_account.go | Returns pre-update lastSeen to let clients detect first login while still updating storage. |
| pkg/account/api/admin_account_test.go | Updates test fixture to account for lastSeen behavior change. |
| manifests/bucketeer/charts/web/values.yaml | Adds Helm value walkthroughEnabled (default true). |
| manifests/bucketeer/charts/web/templates/env-js-configmap.yaml | Exposes WALKTHROUGH_ENABLED via window.env. |
| docker-compose/static-files/js/env.js | Enables walkthrough in docker-compose env defaults. |
Comments suppressed due to low confidence (2)
ui/dashboard/src/hooks/use-walkthrough.tsx:233
- This polling effect also uses
consoleAccount!. If auth state is not ready,getCurrentEnvironment(consoleAccount!)can throw. Guard onconsoleAccountand avoid the non-null assertion.
useEffect(() => {
if (stage !== 'await-apikey-created') return;
const currentEnvironment = getCurrentEnvironment(consoleAccount!);
const startedAt = Date.now();
ui/dashboard/src/hooks/use-walkthrough.tsx:260
startWalkthroughalso relies onconsoleAccount!. Add a guard so clicking "Get started" (or auto-start) can't crash during initial auth loading.
const startWalkthrough = useCallback(() => {
const currentEnvironment = getCurrentEnvironment(consoleAccount!);
navigate(`/${currentEnvironment.urlCode}${PAGE_PATH_FEATURES}`);
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Address review comments on PR #2712: - Move WALKTHROUGH_TARGETS to side-effect-free constants/walkthrough.ts so pages don't pull driver.js via the hooks barrel - Guard consoleAccount instead of non-null assertions in use-walkthrough - Remove blockEnterSubmit listener in onDestroyed as a safety net - Add missing stdlib imports to the Go SDK snippet Also show a welcome dialog before the auto-started walkthrough for first-time users. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Address review comments on PR #2712: - Move the walkthrough entry from the sidebar to Settings as a "Replay tutorial" action (walkthrough state now lives in a shared WalkthroughProvider so any page can start it) - Sync the sliding settings panel with navigation so starting the tour from the settings area highlights the right elements - Guide users to enable the created flag: add a note to the SDK modal and land on the flag's targeting page when closing it Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Inherit the console font (Sofia Pro / Noto Sans JP) in driver.js popovers instead of its bundled font stack - Replace emoji in walkthrough titles with the sidebar SVG icons Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Address review comments on PR #2712: - Start the tour only after the flag list page is reached, so the unsaved-changes dialog no longer leaves a stray tour running when replaying from Settings - Refresh the spotlight when panels/modals finish animating in Also keep highlighted scrollable containers scrollable (refreshing the spotlight on nested scrolls) and enlarge the welcome dialog. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Replace the Settings page tutorial card with a "Tutorial" item in the sliding settings menu so it is visible without scrolling, including for system admins - Skip spotlight refreshes while the step transition tween is running, which made the animation replay and feel laggy, and shorten the tween to match the console's animation timing
- Move the tutorial entry into the user menu, under the language choice - Ignore navigation attempts and block Escape during the walkthrough so the API key panel cannot be closed and the leave-page confirm never interrupts a tour - Show the SDK snippet immediately after the key-created dialog closes and keep the snippet modal open on outside clicks Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Cancelling the leave-page dialog now drops the pending tour request, and any navigation consumes the request, so the tour can no longer start unexpectedly when the user later returns to the flag list. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
| overlayClickBehavior: () => undefined, | ||
| allowKeyboardControl: false, | ||
| nextBtnText: t('walkthrough.next'), | ||
| doneBtnText: t('walkthrough.done'), |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 40 out of 43 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (3)
ui/dashboard/src/components/navigation/user-menu.tsx:124
- The PR description says there is a “Get Started” button pinned at the bottom of the sidebar to start the walkthrough at any time, but the only entry point added in the UI code here is a “Tutorial” item in the user menu (no sidebar-pinned entry). Either add the promised sidebar entry point (likely in the main navigation) or adjust the PR description so it matches the implemented UI.
WALKTHROUGH_ENABLED && {
label: t(`walkthrough.tutorial`),
icon: IconRocket,
onClick: () => {
popoverCloseRef?.current?.click();
startWalkthrough();
}
},
ui/dashboard/src/components/navigation/index.tsx:149
- The effect uses
settingPaths,onOpenSetting, andonCloseSettingbut they are not included in the dependency array. This can lead to stale values being captured (and will typically tripreact-hooks/exhaustive-deps). Include the referenced values in the dependency list or otherwise ensure they are stable/memoized.
useEffect(() => {
if (settingPaths.some(path => pathname.startsWith(path))) {
onOpenSetting();
} else {
onCloseSetting();
}
}, [pathname]);
ui/dashboard/src/elements/connect-sdk-modal/index.tsx:79
getCurrentEnvironment(consoleAccount!)relies on a non-null assertion. IfconsoleAccountis temporarily undefined (auth still loading, or during logout/unmount races) this will throw and break the modal. Add a guard and bail out (or render a loading state) whenconsoleAccountis not available.
const ConnectSdkModal = ({ isOpen, flagId, onClose }: ConnectSdkModalProps) => {
const { t } = useTranslation(['common', 'message']);
const { notify } = useToast();
const navigate = useNavigate();
const { consoleAccount } = useAuth();
const currentEnvironment = getCurrentEnvironment(consoleAccount!);

Resolves #2514
What this PR does
Adds an animated, in-console onboarding walkthrough that guides new users through the core journey — create a feature flag → create an API key → connect an SDK — using spotlight overlays on the real UI (powered by driver.js, ~5 kB, MIT).
Entry points
account.lastSeen == 0fromGetMe.Walkthrough flow
advanceOnClick), not a "Next" button — users learn by doing in their own console.YOUR_API_KEYplaceholder — the real secret is only displayed in the dedicated secret dialog.UX guardrails
Configuration
web.env.walkthroughEnabled(defaulttrue) → rendered intowindow.env.WALKTHROUGH_ENABLED, hides the Get Started entry whenfalse.env.js) and Vite (VITE_WALKTHROUGH_ENABLED) equivalents included.Backend change
GetMenow returns the pre-updatelastSeen(while still bumping it), restoring the first-login signal that #2185 unintentionally removed — previouslylastSeenalways read as "just now", so clients could never detect a first login (this had also broken the existing first-login profile form).How to test
last_seento0in the DB (requires a rebuilt backend), then sign in.web.env.walkthroughEnabled: false(orWALKTHROUGH_ENABLED: falseinenv.js) and confirm the Get Started entry disappears.demo
Screen.Recording.2026-07-28.at.17.21.11.mov