feat(onboarding): add Storybook components#2564
Conversation
Add the presentational building blocks for the redesigned onboarding experience, showcased in Storybook (no app behavior change yet): - OnboardingAccordion: stepper card with status badges/circles and a progress ring - SummaryRow: compact status row (check circle + status badge) for nested setup items - LogoBadge: theme-aware brand logo badge (adds --logo-badge-shadow token) Also fixes Storybook so Drawer/Modal portals inherit the app font (applied to <html>, matching pages/_app.tsx), and adds the react-icons dependency used by the stories. These components are presentational only; the /getting-started page that wires them into the app follows in a separate PR. Co-authored-by: Cursor <cursoragent@cursor.com>
|
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThis is a presentational-only PR that adds the reusable building blocks for a redesigned onboarding experience, with no changes to app routing or behavior.
Confidence Score: 5/5Safe to merge — purely presentational, no routing or data-path changes; all new code is Storybook-only or behind a not-yet-wired UI component. All new components are presentational and not yet wired into any app page or route. The only runtime-visible logic (token substitution in When the follow-up wiring PR arrives, Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant U as User
participant OA as OnboardingAccordion
participant ID as IntegrationsDrawer
participant DC as DrawerContent
participant IT as ItemTile
participant GV as GuideView
U->>OA: Click step header (toggle)
OA->>OA: handleToggle(id) → update open state
OA->>OA: StepCard renders Collapse(expanded)
U->>ID: Click "Browse integration guides"
ID->>DC: Mount DrawerContent(initialCategory)
DC->>DC: useState(initialCategory) → activeChip
DC->>IT: Render CategorySection tiles
U->>IT: "Click SDK tile (hasGuide = true)"
IT->>DC: onOpenGuide(id) → setGuideId(id)
DC->>GV: Render GuideView(guideId, endpoint, apiKey)
GV->>GV: INTEGRATION_GUIDES[guideId] lookup
GV->>GV: applyGuideTokens(code, endpoint, apiKey)
GV-->>U: Copy-paste ready code snippet
U->>IT: "Click infra tile (hasGuide = false)"
IT-->>U: Opens docs URL in new tab
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant U as User
participant OA as OnboardingAccordion
participant ID as IntegrationsDrawer
participant DC as DrawerContent
participant IT as ItemTile
participant GV as GuideView
U->>OA: Click step header (toggle)
OA->>OA: handleToggle(id) → update open state
OA->>OA: StepCard renders Collapse(expanded)
U->>ID: Click "Browse integration guides"
ID->>DC: Mount DrawerContent(initialCategory)
DC->>DC: useState(initialCategory) → activeChip
DC->>IT: Render CategorySection tiles
U->>IT: "Click SDK tile (hasGuide = true)"
IT->>DC: onOpenGuide(id) → setGuideId(id)
DC->>GV: Render GuideView(guideId, endpoint, apiKey)
GV->>GV: INTEGRATION_GUIDES[guideId] lookup
GV->>GV: applyGuideTokens(code, endpoint, apiKey)
GV-->>U: Copy-paste ready code snippet
U->>IT: "Click infra tile (hasGuide = false)"
IT-->>U: Opens docs URL in new tab
Reviews (8): Last reviewed commit: "fix(onboarding): restore dismiss link an..." | Re-trigger Greptile |
| 'in-progress': { | ||
| label: 'In progress', | ||
| fg: 'var(--color-bg-warning)', | ||
| bg: 'color-mix(in srgb, var(--color-bg-warning) 18%, transparent)', | ||
| }, |
There was a problem hiding this comment.
The
in-progress entry uses --color-bg-warning (a background-intent token) as the text/foreground color. This works today but is semantically incorrect — if the warning background token is ever adjusted to a color that's only safe on dark surfaces, the badge text will lose contrast. There is no --color-text-warning token defined in either theme, so the closest correct substitute is the amber value expressed directly, or a dedicated text token added alongside the other --color-text-* tokens.
| 'in-progress': { | |
| label: 'In progress', | |
| fg: 'var(--color-bg-warning)', | |
| bg: 'color-mix(in srgb, var(--color-bg-warning) 18%, transparent)', | |
| }, | |
| 'in-progress': { | |
| label: 'In progress', | |
| // TODO: replace with --color-text-warning once that token is added to each theme. | |
| fg: 'var(--color-bg-warning)', | |
| bg: 'color-mix(in srgb, var(--color-bg-warning) 18%, transparent)', | |
| }, |
| "app:dev:local": "sh -c '. ./scripts/dev-env.sh && yarn build:common-utils && concurrently -k -n \"APP,COMMON-UTILS\" -c \"blue.bold,magenta\" \"nx run @hyperdx/app:dev:local 2>&1 | tee ${HDX_DEV_LOGS_DIR:+\\\"$HDX_DEV_LOGS_DIR/app.log\\\"}\" \"nx run @hyperdx/common-utils:dev 2>&1 | tee ${HDX_DEV_LOGS_DIR:+\\\"$HDX_DEV_LOGS_DIR/common-utils.log\\\"}\"'", | ||
| "app:lint": "nx run @hyperdx/app:ci:lint", | ||
| "app:storybook": "nx run @hyperdx/app:storybook", | ||
| "app:storybook": "yarn workspace @hyperdx/app storybook", |
There was a problem hiding this comment.
app:storybook bypasses Nx task pipeline
The script was changed from nx run @hyperdx/app:storybook to yarn workspace @hyperdx/app storybook, which skips the Nx cache and any dependent tasks (e.g., building @hyperdx/common-utils) that the Nx project graph would have triggered first. If any story imports from packages that need a prior build step, this will silently use stale or missing build artifacts. Could you confirm there are no upstream dependsOn tasks in the Nx config that need to run before Storybook starts?
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
E2E Test Results✅ All tests passed • 171 passed • 2 skipped • 1186s
Tests ran across 4 shards in parallel. |
Add the presentational IntegrationsDrawer used by the "Send telemetry" step, plus a Storybook story: - IntegrationsDrawer: right-side drawer with searchable, categorized integration tiles (languages, frameworks, infrastructure, cloud, collectors) - SDK/framework tiles open inline copy-paste setup guides with the team's endpoint + ingestion key substituted in; other tiles deep-link to docs - integrationsCatalog + integrationGuides.generated.json back the tiles/guides The drawer is fully prop-driven (opened/onClose/endpoint/apiKey); the getting-started page wiring and the guide generator script land in a follow-up PR. Co-authored-by: Cursor <cursoragent@cursor.com>
Knip - Unused Code Analysis🔴 1 issue found Unused exported types (1)
Knip finds unused files, dependencies, and exports in your codebase. |
…stories The integrations drawer isn't onboarding-specific, so move it out of the GettingStarted folder to a shared components/IntegrationsDrawer/ module (carrying its integrationsCatalog + generated guides, re-exported via index.ts so other surfaces can reuse it). Wire the OnboardingAccordion "Browse integration guides" / "Language SDKs" links to the real IntegrationsDrawer instead of the previous mock docs drawer, opening the languages category from the SDKs link. Removes the now-unused mock (IntegrationsDocsDrawer/DocRow and its static lists). Co-authored-by: Cursor <cursoragent@cursor.com>
Use the broader components/Integrations/ name (was IntegrationsDrawer/) so the module can house more integration-related surfaces beyond the drawer. Co-authored-by: Cursor <cursoragent@cursor.com>
Add the generator that produces components/Integrations/ integrationGuides.generated.json from the ClickStack SDK MDX (yarn generate:integration-guides), pointed at the new Integrations module path, plus the package.json script entry. Include the "machine-readable Quickstart contract" proposal that motivates making the docs structured so the generator can drop its heuristics; adapted to reference this PR's Integrations module and to note it's non-blocking. Co-authored-by: Cursor <cursoragent@cursor.com>
Add an optional `logo` field to catalog items that points to a brand SVG in public/integrations/ and takes precedence over the react-icons glyph/monogram, for logos react-icons doesn't carry. Ship the Vector logo as the first one and switch Vector from its "Vec" monogram to the SVG. Co-authored-by: Cursor <cursoragent@cursor.com>
Add the brand SVGs under public/integrations/ and point every catalog item at its <id>.svg, replacing the react-icons glyphs and text monograms. Render logos on a white tile in both themes since several brand SVGs use near-black marks meant for a light background. Co-authored-by: Cursor <cursoragent@cursor.com>
|
|
||
| return ( | ||
| <Stack gap={16}> | ||
| <UnstyledButton onClick={onBack}> |
There was a problem hiding this comment.
Unguarded access on
guide crashes for unknown guideId
INTEGRATION_GUIDES[guideId] returns undefined when the id isn't in the generated JSON. Every subsequent access — guide.title, guide.steps.length, guide.steps.map(...), guide.docUrl — throws a TypeError. item has an explicit null guard (item ? ... : null) but guide does not. The current call site in DrawerContent guards via hasGuide before calling setGuideId, but GuideView is a publicly exported component; any future caller (or a Storybook story) that passes a stale/invalid id will get a white-screen crash instead of a graceful fallback.
…rows Replace the two plain endpoint/ingestion-key copy rows at the top of the integrations drawer with a ConnectionSnippet card that mirrors the send-telemetry connection panel (monospace endpoint/api-key block, reveal-key toggle, copy) — scoped to just the URL view, since the collector/env-var/AI-agent tabs aren't relevant when picking an integration. Co-authored-by: Cursor <cursoragent@cursor.com>
…tiles - Add a signals map (logs/traces/metrics) per integration and show a "This guide integrates: [chips]" row in the setup guide. - Mark tiles that deep-link out with a corner external-link icon and an "Opens the docs in a new tab" tooltip, so it's clear which open externally vs. show an inline guide. Co-authored-by: Cursor <cursoragent@cursor.com>
Mantine's Drawer body shrinks its right padding to reserve scrollbar space, which reads as missing right padding on overlay-scrollbar systems. Override paddingInlineEnd so left/right padding match. Co-authored-by: Cursor <cursoragent@cursor.com>
|
@elizabetdev you mentioned it in the call, but I suspect trying to extract the structure from the docs will be a big challenge - especially in the present state where there isn't a strong structure across files. I would suggest we find a way to render the markdown in the product directly from the .md page that the Mintlify docs site serves. For example:
We could give you pages with the structure you need, and it would then be a case of figuring out how we render this markdown within the product. It doesn't look like the page front-matter is served. Compare: https://github.com/ClickHouse/mintlify-docs-dev/blob/main/integrations/language-clients/js.mdx |
… stories Re-wire onDismiss into the story flows so the "Remove from sidebar" footer link renders again, and override paddingInlineEnd on the collector-setup, connection, and data-source drawers so their body padding is symmetric (Mantine reserves scrollbar space on the right). Co-authored-by: Cursor <cursoragent@cursor.com>
Summary
First of two PRs for the redesigned onboarding experience. This PR is presentational only — it adds the reusable building blocks and their Storybook stories, with no changes to app behavior or routing. The
/getting-startedpage that wires these into the app (plus the OSS/self-managed/fully-managed flows) will follow in a separate PR, once this one merges.What's included
OnboardingAccordion— stepper card with 3-state status badges/circles (Completed/In progress/Not started), a compact header progress ring, and a "remove from sidebar" footer affordance. Stories cover the OSS, self-managed, and fully-managed flows.SummaryRow— compact, icon-led status row (check circle + status badge, optionalaction/footerslots) used for nested setup items like connect / data sources / collector setup.components/Integrations/— reusable integrations module (not onboarding-specific):IntegrationsDrawer— right-side drawer with searchable, categorized integration tiles (languages, frameworks, infrastructure, cloud, collectors). SDK/framework tiles open inline copy-paste setup guides with the team's endpoint + ingestion key substituted in; others deep-link to docs. Fully prop-driven (opened/onClose/endpoint/apiKey/initialCategory), showcased in Storybook and used by the OnboardingAccordion stories.integrationsCatalog+integrationGuides.generated.json— the catalog + committed guide data backing the tiles.scripts/generate-integration-guides.mjs(yarn generate:integration-guides) — regenerates the guide JSON from the ClickStack SDK MDX.LogoBadge— theme-aware brand logo badge; adds a--logo-badge-shadowdesign token to both thehyperdxandclickstackthemes.document.body, outside the decorator wrapper, so they fell back to the browser default font. The fontclassNameis now also applied to<html>(mirroringpages/_app.tsx) so portal content inherits it.docs/clickstack-docs-quickstart-proposal.md— proposal to make the ClickStack SDK docs expose a machine-readable "quickstart" contract so the generator can drop its heuristics (non-blocking; the committed JSON ships as-is).react-iconsdependency used by the stories and switches the rootapp:storybookscript toyarn workspace @hyperdx/app storybook.Why split this out
Keeping the pure presentational components + Storybook separate from the app wiring/migration makes both PRs smaller and easier to review. There is no user-facing behavior change here.
Test plan
yarn workspace @hyperdx/app storybook— review the OnboardingAccordion, SummaryRow, IntegrationsDrawer, and LogoBadge storieshyperdxandclickstackthemesmake ci-lintpasses