Skip to content

feat(onboarding): add Storybook components#2564

Draft
elizabetdev wants to merge 11 commits into
mainfrom
elizabet/onboarding-storybook-components
Draft

feat(onboarding): add Storybook components#2564
elizabetdev wants to merge 11 commits into
mainfrom
elizabet/onboarding-storybook-components

Conversation

@elizabetdev

@elizabetdev elizabetdev commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

🚧 WIP / Draft — not ready for review yet. Opening early for visibility.

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-started page 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, optional action/footer slots) 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-shadow design token to both the hyperdx and clickstack themes.
  • Storybook font fix — Mantine renders Drawers/Modals/Tooltips in a portal on document.body, outside the decorator wrapper, so they fell back to the browser default font. The font className is now also applied to <html> (mirroring pages/_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).
  • Adds the react-icons dependency used by the stories and switches the root app:storybook script to yarn 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 stories
  • In the OnboardingAccordion "Send telemetry" stories, click "Browse integration guides" / "Language SDKs" and confirm the real IntegrationsDrawer opens on the right category
  • Open the IntegrationsDrawer story, search + switch category chips, and open an SDK guide (confirm endpoint/key are substituted)
  • Open a Drawer story and confirm the font matches the app (portal font fix)
  • Toggle light/dark theme and confirm LogoBadge shadow renders correctly in both hyperdx and clickstack themes
  • make ci-lint passes

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>
@changeset-bot

changeset-bot Bot commented Jul 1, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 3b36d1f

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel

vercel Bot commented Jul 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hyperdx-oss Ready Ready Preview, Comment Jul 2, 2026 3:18pm
hyperdx-storybook Ready Ready Preview, Comment Jul 2, 2026 3:18pm

Request Review

@greptile-apps

greptile-apps Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This is a presentational-only PR that adds the reusable building blocks for a redesigned onboarding experience, with no changes to app routing or behavior.

  • OnboardingAccordion — a stepper card with 3-state badges, a progress ring, and controlled/uncontrolled expand logic; SummaryRow — compact icon-led status rows for nested setup items.
  • IntegrationsDrawer — a searchable, categorized drawer with inline copy-paste SDK guides backed by integrationGuides.generated.json (regenerated via scripts/generate-integration-guides.mjs); LogoBadge — theme-aware brand tile with a new --logo-badge-shadow design token in both themes.
  • Storybook portal-font fix via <html> class mirroring and a new react-icons dependency.

Confidence Score: 5/5

Safe 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 applyGuideTokens, guide lookup in GuideView) is exercised exclusively in Storybook stories at this stage, so any latent issues have no user-facing impact until the follow-up PR lands.

When the follow-up wiring PR arrives, GuideView.tsx deserves a second look for the unguarded INTEGRATION_GUIDES[guideId] access and integrationsCatalog.tsx for the false-positive dev-mode console warning — both flagged in the previous review cycle and still open.

Important Files Changed

Filename Overview
packages/app/src/components/Integrations/integrationsCatalog.tsx Catalog + token-substitution logic; global-regex used correctly with .replace(); dev-mode warning fires on successful substitutions (pre-existing comment)
packages/app/src/components/Integrations/GuideView.tsx Renders inline SDK guide; guide is accessed without a null guard (flagged in previous review thread)
packages/app/src/components/OnboardingAccordion/OnboardingAccordion.tsx Controlled/uncontrolled accordion with correct state pattern; accordion toggle buttons missing aria-controls / panel id pairing
packages/app/src/components/GettingStarted/SummaryRow.tsx Status circles, badges, and layout card; in-progress uses a background-intent token as foreground color (flagged in previous thread)
packages/app/scripts/generate-integration-guides.mjs Dev-only MDX scraper; section-end boundary detection doesn't track fence state, so ## heading inside a code block could truncate a section prematurely
packages/app/src/components/LogoBadge/LogoBadge.tsx Theme-aware badge tile; dashed path passes empty string '' for border instead of 'none' (flagged in previous thread)
packages/app/.storybook/preview.tsx Portal font fix: applies font className to <html> so Mantine portals inherit the correct font family; cleanup is correct
packages/app/.storybook/main.ts Adds '../public' to staticDirs so integration SVGs (in packages/app/public/) are served by Storybook; the pre-existing './public' entry resolves to .storybook/public/ which doesn't exist and is likely a silent no-op

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
Loading
%%{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
Loading

Reviews (8): Last reviewed commit: "fix(onboarding): restore dismiss link an..." | Re-trigger Greptile

Comment on lines +32 to +36
'in-progress': {
label: 'In progress',
fg: 'var(--color-bg-warning)',
bg: 'color-mix(in srgb, var(--color-bg-warning) 18%, transparent)',
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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.

Suggested change
'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)',
},

Fix in Claude Code Fix in Conductor Fix in Cursor Fix in Codex

Comment thread packages/app/src/components/LogoBadge/LogoBadge.tsx
Comment thread package.json
"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",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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!

Fix in Claude Code Fix in Conductor Fix in Cursor Fix in Codex

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

E2E Test Results

All tests passed • 171 passed • 2 skipped • 1186s

Status Count
✅ Passed 171
❌ Failed 0
⚠️ Flaky 0
⏭️ Skipped 2

Tests ran across 4 shards in parallel.

View full report →

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>
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Knip - Unused Code Analysis

🔴 1 issue found

Unused exported types (1)

  • packages/app/src/components/Integrations/index.ts:IntegrationsDrawerProps

Knip finds unused files, dependencies, and exports in your codebase.
Run yarn knip locally to see full details.

…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>
Comment on lines +90 to +93

return (
<Stack gap={16}>
<UnstyledButton onClick={onBack}>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 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.

Fix in Claude Code Fix in Conductor Fix in Cursor Fix in Codex

…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>
@Blargian

Blargian commented Jul 2, 2026

Copy link
Copy Markdown

@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:

  • Navigate to clickhouse.com/docs?mintlify_preview=1
  • Hard refresh the browser (you should see the new site)
  • Navigate to https://clickhouse.com/docs/integrations/language-clients/js (hard refresh if you get any errors or see the current docs site)
  • Once the page is open, you can append .md to this url -> https://clickhouse.com/docs/integrations/language-clients/js.md and it will serve the markdown directly.

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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants