| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
feat(webapp): polish the audit event drawer and export dialog (#7417) ## Problem A function deploy can name hundreds of targets — 365 in production today. The event drawer listed every one, pushing the fields below Targets and the thousand-line JSON far below the fold. Design review then found the export dialog out of step with its Figma component, and it had no stories. ## Solution - Targets past the tenth and JSON past forty lines collapse behind a toggle that expands **and** collapses again. The Targets label carries the count (`TARGETS · 249`) so the scale shows without expanding. - Thresholds come from production data, so an ordinary event never collapses: nothing but a function deploy exceeds ten targets. - Export dialog: labels move to the label ramp, row spacing 10 → 8px, every vertical gap in the body at 16px, and the info alert gets the icon every other alert already passes. - Three export dialog stories, one per event-count outcome. Follow-up to [NAN-6672](https://linear.app/nango/issue/NAN-6672), which made the table row single-line but moved the problem into the drawer. ## Stories - [Under cap](https://pr-7417-storybook.app-development.nango.dev/?path=/story/features-audit-trail-auditexportdialog--under-cap) - [Capped](https://pr-7417-storybook.app-development.nango.dev/?path=/story/features-audit-trail-auditexportdialog--capped) - [Count unavailable](https://pr-7417-storybook.app-development.nango.dev/?path=/story/features-audit-trail-auditexportdialog--count-unavailable) ## Testing Locally against a seeded 249-target event: both toggles expand and collapse independently and every field is back above the fold. Export dialog checked in light and dark against Figma in both states. Worth eyeballing on the preview deploy against account 11885 (Replo) or 1908 (Beam AI), which holds the 365-target deploy. | 5 天前 | |
feat(audit): publish audit events to pub/sub, consume in metering (NAN-6271) (#6783) - Replaces the server's direct ClickHouse write with a pub/sub publish, consumed by a new `AuditProcessor` in metering that writes to `audit_trail_events`. Registers `audit` as a pub/sub subject and allows it in `NANGO_PUBSUB_SNS_SQS_CONFIG`. - Splits `AuditStore` into `AuditWriter` (record) and `AuditReader` (list), so the server can publish writes while still reading from ClickHouse. `ClickhouseAuditStore` implements both; `PubSubAuditWriter` implements only the writer. - Stamps the event `id` and `version` at the emit boundary rather than at storage, so a redelivered message keeps one identity and `ReplacingMergeTree` can collapse the duplicate (NAN-6285). - Adds `NANGO_AUDIT_TRANSPORT` (`direct` | `pubsub`, default `direct`) so each environment cuts over independently. This PR changes no behaviour on deploy — dev is flipped separately in nango-environments. - Counts successful publishes in `nango.pubsub.publish`, which previously only counted failures. Paired with `nango.audit.clickhouse.ingest.result` on the consumer side, this gives an emitted-vs-stored signal for detecting loss. ### The wire payload is the serialized event, not the typed object `SerializedAuditEvent` (`{ event: string }`) carries the canonical JSON, serialized once at the emit boundary and stored verbatim. `@nangohq/types` cannot import from `@nangohq/audit`, so a typed payload would have meant relocating `AuditEvent` and converting its whole tree to type aliases to satisfy the pub/sub `Serializable` constraint. Keeping the blob on the wire also makes it byte-identical to the stored `event` column, so nothing re-serializes between emit and storage. ### Deploy order The env schema rejects unknown subjects, so config referencing `audit` before this code is deployed fails startup for every pod mounting `nango-pubsub-sns-sqs`, not just audit. 1. This PR 2. NangoHQ/nango-infra#172 — topic, queue and DLQ 3. NangoHQ/nango-environments#155 — topic ARN, queue URL, and `NANGO_AUDIT_TRANSPORT=pubsub` on dev 4. Same variable on staging, then production ## Follow-ups - **Production-ready consumer, separate PR.** The consumer currently logs and acknowledges on a failed write, matching the direct-write path — so a ClickHouse failure drops the event. Redelivery, DLQ handling and publish-side batching land with the hardened consumer; the SNS/SQS transport already supports commit-after-write when it does. - **Audit event types and names, once this and #6917 are merged.** Move the event model into `@nangohq/types`, fold `id`/`version` into `AuditEvent` and construct them at the single emit site (which needs the `as AuditEvent` cast in the middleware removed first, otherwise the required fields are not enforced), drop `StoredAuditEvent`, and derive `ApiAuditTrailEvent` from the model instead of restating it. Both files this touches are rewritten by #6917, so it has to follow it. - Dedicated `audit` ClickHouse database, replacing the current colocation in `usage`. - `nango.pubsub.publish` now emits successes, so the "Usage metrics publish failures" widget on the Data Transfer dashboard needs `success:false` added to its query. The `[PubSub] High failure rate` monitor already filters correctly. ## Test plan - [x] `npm run ts-build` clean across the monorepo - [x] Unit: `packages/audit` (14), `packages/pubsub` (35, including new `Publisher` coverage), `packages/metering` (3), `packages/utils` (345) - [x] Integration: `packages/audit` store (5), `getAuditTrail` + audit middleware private/public (13) - [x] Verified by deliberate regression that the id-stamping, publish-metric, consumer-ack and Publisher tests fail when the behaviour they guard is removed - [x] prettier + oxlint clean on changed files - [ ] Deploy to dev, flip `NANGO_AUDIT_TRANSPORT=pubsub`, confirm events reach `audit_trail_events` via the consumer and appear in the dashboard - [ ] Confirm the queue drains and the DLQ stays empty - [ ] Staging, then production --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> | 1 个月前 | |
feat(webapp): let customers add and remove the Growth add-on (#7402) ## Problem The Pay-as-you-go card names the Growth add-on as a feature bullet and nothing more. Nothing shows whether an account has one, and buying or dropping it is a support conversation. ## Solution - The add-on block on the Pay-as-you-go card, in its three states: not on the plan, active, deactivating on a date. - Add and remove dialogs, plus a checkbox and live monthly total in the upgrade dialog. Add-on and plan move in one `POST /plans/change`, which takes an end state. - Both actions are locked while a plan change is already scheduled, and for members without `account:plan:update`. - An `addonState` override in the dev panel, so all three states preview without Orb. - Solid `sm` buttons drop to 12px, matching Figma, and the dialog's add-on block gets its `surface/inputMuted` fill. Fixes [NAN-6834](https://linear.app/nango/issue/NAN-6834) ## Testing Full round trip against Orb test mode on `test+orb@nango.dev`, checked in the DB and against Orb's API: upgrading with the add-on added `Growth Add-on / Ytp8wFpTKfVjiY8r` to the subscription, and removing scheduled that interval to end at the period boundary. ## Follow-ups - `Keep add-on` stays hidden until [NAN-6816](https://linear.app/nango/issue/NAN-6816) lets a scheduled removal be cancelled. - The dialog shows a $500 monthly total while a mid-month first invoice is prorated — Orb prorates both the minimum and the add-on. Three copy variants are mocked in Figma; this ships the one explaining proration in prose. | 9 天前 | |
feat(webapp): polish the audit event drawer and export dialog (#7417) ## Problem A function deploy can name hundreds of targets — 365 in production today. The event drawer listed every one, pushing the fields below Targets and the thousand-line JSON far below the fold. Design review then found the export dialog out of step with its Figma component, and it had no stories. ## Solution - Targets past the tenth and JSON past forty lines collapse behind a toggle that expands **and** collapses again. The Targets label carries the count (`TARGETS · 249`) so the scale shows without expanding. - Thresholds come from production data, so an ordinary event never collapses: nothing but a function deploy exceeds ten targets. - Export dialog: labels move to the label ramp, row spacing 10 → 8px, every vertical gap in the body at 16px, and the info alert gets the icon every other alert already passes. - Three export dialog stories, one per event-count outcome. Follow-up to [NAN-6672](https://linear.app/nango/issue/NAN-6672), which made the table row single-line but moved the problem into the drawer. ## Stories - [Under cap](https://pr-7417-storybook.app-development.nango.dev/?path=/story/features-audit-trail-auditexportdialog--under-cap) - [Capped](https://pr-7417-storybook.app-development.nango.dev/?path=/story/features-audit-trail-auditexportdialog--capped) - [Count unavailable](https://pr-7417-storybook.app-development.nango.dev/?path=/story/features-audit-trail-auditexportdialog--count-unavailable) ## Testing Locally against a seeded 249-target event: both toggles expand and collapse independently and every field is back above the fold. Export dialog checked in light and dark against Figma in both states. Worth eyeballing on the preview deploy against account 11885 (Replo) or 1908 (Beam AI), which holds the 365-target deploy. | 5 天前 | |
feat(design-system): lift Alert into design system (#7122) ## Problem `Alert` lived in `packages/webapp/src/components/ui/Alert.tsx`, so it couldn't be consumed from `@nangohq/design-system`. Its typography and focus classes (`text-body-*`, `focus-default`) are webapp-only utilities, and its layout had drifted from the Dharma source — call sites were hand-approximating Figma's sizes with `className` (`px-3 py-2`, `w-[350px]`, `text-body-small-regular`). ## Solution - Adds `Alert` to the design system with full parity against the Figma source: Status × Size × Title, hairline status border, 13px title in the status colour, 12px description in `text/default`, icon and close X in `status/{s}/icon`. - `size` (`wide` | `compact` | `toast`) replaces the `actionsBelow` boolean and absorbs the ad-hoc padding/width/type overrides. - `error` → `danger`, matching Figma, the `status-danger-*` tokens and `Badge`. - The root publishes `--alert-link` and `--alert-icon` per status, so `AlertButton` and the close X inherit their colours instead of taking a `variant`. That collapses the old 10-variant pill scale into Figma's single link treatment, and removes the footgun of keeping a child's variant in sync with its parent's (`variant={`${variant}-secondary`}` in `Toast`). - `AlertButton` follows Figma's state matrix: undecorated at rest, underlined on hover/focus/active, `text/disabled` when disabled. - `onDismiss` renders the close affordance, replacing hand-rolled dismiss buttons. - Migrates all 32 call sites and deletes the webapp component. `AlertButtonLink` stays in the webapp over the exported `alertButtonVariants` (mirroring `ButtonLink`) so the design system keeps no react-router dependency. - With the overrides gone, the `Alert` family joins the `react/forbid-component-props` lockdown. Fixes [NAN-6590](https://linear.app/nango/issue/NAN-6590/lift-alert-into-the-design-system) ## Also in here - **Tokens.** Cherry-picks the 12 `text.link{Status}` tokens `AlertButton` needs, the `linkNeutral`/`linkNeutralActive` pair, and the two `status.neutral.bg` values design re-pointed for the neutral alert (white in light, one stop darker in dark). Additions and those two values only — the rest of the `design/tokens` branch is blocked on [NAN-6642](https://linear.app/nango/issue/NAN-6642). - **`Button` link variants.** Per design's note on the Button frame, only hover, focus and active carry an underline: `link-accent`, `link-danger` and `link-neutral` drop it when disabled and gain it on focus. `link-neutral`'s active state moves onto `text/linkNeutralActive` instead of borrowing the accent link's blue. ## Testing **Visual QA checklist: [🗂️ NAN-6590 — Alert in the design system](https://app.notion.com/p/3bcce298312181aeabe0e24f0e96ee8f)** — per-route, per-component sweep. Previews: [app](https://pr-7122.app-development.nango.dev) · [Storybook](https://pr-7122-storybook.app-development.nango.dev). - `ts-build`, `lint`, `format:check`, `tokens:check` and `build-storybook` all clean. - Storybook: every size and status checked against the Figma frame in light and dark, with the trailing-slot offsets and disabled link states measured in the DOM. - App: `danger` alert verified on `/signin`. - The rest of the checklist is unticked — the conditional error-state surfaces still need a pass. ## Storybook New stories under `Design System/Components/Alert`, on the [preview deploy](https://pr-7122-storybook.app-development.nango.dev). Each one walks the same shape groups (titled, titled + action, non-dismissible, description-only, description-only + action, bare), running all five statuses in the first group only: - [Wide](https://pr-7122-storybook.app-development.nango.dev/?path=/story/design-system-components-alert--wide) — action link and close centred across the two text rows - [Compact](https://pr-7122-storybook.app-development.nango.dev/?path=/story/design-system-components-alert--compact) — action link on its own row, close top-right, wrapping at 320px - [Toast](https://pr-7122-storybook.app-development.nango.dev/?path=/story/design-system-components-alert--toast) — single line, plus the titled and titled + action shapes the webapp's `Toast` needs Removes the old `Components/UI/Alert` story. ## Follow-ups - `AlertButton` has no `loading` state, which Figma models — call sites pass their own spinner today. Unticketed. - `Alert` defaults to `role="alert"` (assertive), carried over unchanged from the webapp component. Persistent banners with focusable actions would be better as `status` — a call site can already override it, but the default deserves its own a11y pass. Unticketed. - Remaining visual QA across the ~20 conditional alert surfaces (auth pages, Integrations forms, Playground, toasts) — several need specific error states to reach. - Renaming `Toast`'s public `variant` prop `error` → `danger` (83 call sites, no parity stake) — unticketed, optional. - A full `tokens:fetch` to take the danger-palette changes and the `border.interactive` / `text.linkHover` removals — [NAN-6642](https://linear.app/nango/issue/NAN-6642). | 26 天前 | |
feat(design-system): add basic Storybook setup with a11y and MCP addons (#6204) ## Problem No component development environment existed for the design system. There was no way to view tokens in isolation, verify that CSS custom properties resolve correctly, or confirm dark/light theme switching without running the full app. ## Solution Adds Storybook 10 to `packages/design-system` as the living style guide, with stories driven directly from `tokens.json` so they stay in sync with Figma automatically. **Storybook setup** - `@storybook/react-vite` with `@tailwindcss/vite` injected via `viteFinal` so `@theme {}` in `tokens.generated.css` is processed correctly - Theme toolbar toggle sets `data-theme="dark"` on `<html>` via `@storybook/addon-themes` — same mechanism as the app - Geist / Geist Mono loaded via `preview-head.html`; React pre-bundled via `optimizeDeps` for Vite 7 CJS compat - `@storybook/addon-a11y` and `@storybook/addon-mcp` included - MCP server will be useful after the design system grows and matures - `packages/design-system` added to `tsconfig.build.json` so CI typechecks it **Token pipeline** - `tokens-fetch.mjs` extended to process the `Typography` group from `tokens.json` and emit `.type-{name}` CSS classes (e.g. `.type-heading-lg`, `.type-code-medium-sm`) for all 21 composite text-style tokens **Stories** (`Design System/Tokens/`) - `Typography` — type scale using generated `.type-*` classes; sections for Heading, Text·Regular, Text·Medium, Label, Code·Regular, Code·Medium; plus Font Families specimen - `Color Palette / Primitives` — all color ramps derived programmatically from `Primitives.color` in `tokens.json` (neutral, brand, info, success, warning, danger, mono, alpha, accent) - `Color Palette / Semantic` — all 118 semantic tokens derived programmatically from `Semantic/Light` in `tokens.json`, grouped by category; no manual token lists to maintain Closes [NAN-5665](https://linear.app/nangohq/issue/NAN-5665) ## Testing - `npm run storybook` from `packages/design-system` → opens at `http://localhost:6006` - Typography story renders all type scale rows using the generated `.type-*` CSS classes with correct sizes, weights, and font families - Color Palette / Primitives shows all 10 color ramps including alpha and accent groups - Color Palette / Semantic shows all 118 semantic tokens grouped by category with correct colors - Theme toolbar toggle switches light ↔ dark — semantic token values flip correctly - `npm run build-storybook` builds without errors - `npm run test` passes (token pipeline unit tests) ## Screenshots ### Tokens overview <img width="1066" height="936" alt="image" src="https://github.com/user-attachments/assets/359e9a51-8c1d-4703-8332-5002b4efc6a2" /> <img width="1220" height="959" alt="image" src="https://github.com/user-attachments/assets/2e0ec14c-f85f-4eac-aba1-0e7f21764c50" /> <img width="935" height="914" alt="image" src="https://github.com/user-attachments/assets/e19134da-1d53-4425-b0d0-cecaac7cd581" /> ### Dark theme <img width="872" height="898" alt="image" src="https://github.com/user-attachments/assets/2c8d3254-d0d2-4071-a888-40d1628e2f46" /> ### Accessibility addon <img width="984" height="525" alt="image" src="https://github.com/user-attachments/assets/c3ce0138-eaea-48d2-beec-f6272c8e16eb" /> ### Storybook MCP server <img width="787" height="324" alt="image" src="https://github.com/user-attachments/assets/03ff28c3-b71a-4a76-b3dc-da9e29b3e49f" /> --------- Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> | 3 个月前 | |
feat(webapp): add a primary action to the billing page header (#7111) ## Problem The Billing & usage page header had nothing on the right. The only action a paid account had — "View invoice details" — was a small text link buried under the usage table, and free accounts had no upgrade entry point above the fold. ## Solution - Free plan: primary **Upgrade** button in the page header that scrolls to the Plans section. - Paid plans: primary **All invoices** button that opens the billing portal in a new tab, replacing the "View invoice details" link under the usage table. Reuses the existing `ButtonLink`, same as the other external-link buttons in the app. - New optional `actions` slot on `SectionHeader` (`titleActions` on `DashboardLayout`), plus a `centered` prop that caps and centers the header row and the page content at one shared width, so the title and its action line up with the content between them. Billing opts in — it was left-aligned before and is now centered; every other page is untouched. - A skeleton holds the button's place while the plan and (for paid) the portal URL load, so the header doesn't sit empty and pop the button in. If those requests fail it falls back to no action rather than a placeholder that pulses forever. - Adds the `web:usage:upgrade_clicked` event. The invoices button keeps `web:usage:invoice_details_clicked` so the before/after series stays comparable. - Separate commit: fixes the design-system `AGENTS.md`, which told contributors to put stories in the top-level `stories/` dir while the structure diagram right below showed them co-located. Co-location is what every component actually does. Fixes [NAN-6582](https://linear.app/nango/issue/NAN-6582/give-the-billing-and-usage-page-a-primary-action-in-its-header) ## Testing Against `REMOTE_API=dev`: on Free (`matej+dev`) the header shows Upgrade and clicking it scrolls to Plans; on a paid account (`matej+dev-paid`) it shows All invoices pointing at the Orb portal with `target="_blank"`, in light and dark mode. At 1920px the title's left edge and the button's right edge match the content's own edges (318px and 1826px). Connections and Integrations are unchanged, header and content alike. <img width="3238" height="2006" alt="image" src="https://github.com/user-attachments/assets/494eebb0-5f23-4265-adee-c08112baac0a" /> <img width="3254" height="2006" alt="image" src="https://github.com/user-attachments/assets/7f024e58-3755-437c-845d-5d45d253061b" /> | 1 个月前 | |
feat(design-system): component foundations (#6246) ## Problem The `@nangohq/design-system` package had the token pipeline and Storybook in place, but no established pattern for building components on top of them. ## Solution Establishes the component foundations: - **Components** — `Button` and `IconButton` as the reference set, built with the shadcn/ui pattern (`cva` + `forwardRef` + `Slot` + `cn()`). They share one `cva` config, auto-size inline icons, and expose a `2xs`–`lg` size scale (plus a deprecated `xl` kept only for migrating legacy webapp buttons). An internal `Spinner` (not exported) powers the loading state. - **Token-backed Tailwind utilities** — the token pipeline emits a `@theme` block mapping primitives to named utilities (`rounded-ds-xs`, `text-ds-md`, `border-ds-hairline`, …) so components use plain classes instead of `[var(--ds-*)]` arbitrary values. - **`cn()` helper** — registers the DS token groups with `extendTailwindMerge` so `className` conflicts resolve correctly. - **`AGENTS.md`** — a step-by-step guide for adding components with the Figma variable → CSS → Tailwind mapping. All six button variants were validated against the Figma design system (variants compose from the `interactive/*`, `surface/*`, `text/*`, `border/*` semantic tokens — there are no component-level `button-*` tokens by design). > **Note:** the new `Button` has minor contrast-ratio shortfalls in a few variants. These will be addressed in a follow-up by updating the underlying design tokens, not by overriding the components. Migrating the webapp to these components is done in a follow-up PR: #6503. Fixes [NAN-5667](https://linear.app/nango/issue/NAN-5667) ## Testing `cd packages/design-system && npm run storybook` — review the `Button` and `IconButton` stories across variants and sizes in light and dark themes. Deployed Storybook (this branch): https://storybook.nango.dev | 2 个月前 | |
feat(design-system): component foundations (#6246) ## Problem The `@nangohq/design-system` package had the token pipeline and Storybook in place, but no established pattern for building components on top of them. ## Solution Establishes the component foundations: - **Components** — `Button` and `IconButton` as the reference set, built with the shadcn/ui pattern (`cva` + `forwardRef` + `Slot` + `cn()`). They share one `cva` config, auto-size inline icons, and expose a `2xs`–`lg` size scale (plus a deprecated `xl` kept only for migrating legacy webapp buttons). An internal `Spinner` (not exported) powers the loading state. - **Token-backed Tailwind utilities** — the token pipeline emits a `@theme` block mapping primitives to named utilities (`rounded-ds-xs`, `text-ds-md`, `border-ds-hairline`, …) so components use plain classes instead of `[var(--ds-*)]` arbitrary values. - **`cn()` helper** — registers the DS token groups with `extendTailwindMerge` so `className` conflicts resolve correctly. - **`AGENTS.md`** — a step-by-step guide for adding components with the Figma variable → CSS → Tailwind mapping. All six button variants were validated against the Figma design system (variants compose from the `interactive/*`, `surface/*`, `text/*`, `border/*` semantic tokens — there are no component-level `button-*` tokens by design). > **Note:** the new `Button` has minor contrast-ratio shortfalls in a few variants. These will be addressed in a follow-up by updating the underlying design tokens, not by overriding the components. Migrating the webapp to these components is done in a follow-up PR: #6503. Fixes [NAN-5667](https://linear.app/nango/issue/NAN-5667) ## Testing `cd packages/design-system && npm run storybook` — review the `Button` and `IconButton` stories across variants and sizes in light and dark themes. Deployed Storybook (this branch): https://storybook.nango.dev | 2 个月前 | |
feat(design-system): lift Tooltip into design system (#7176) ## Problem `Tooltip` lived in `packages/webapp/src/components/ui/Tooltip.tsx` and couldn't be consumed from `@nangohq/design-system` — the last high-traffic overlay primitive still in the webapp after `Dialog`, `Card`, `Badge` and `Alert`. It had also drifted from its [Dharma source](https://www.figma.com/design/T8aoiWC73uCiM5eucb0syk/Nango-%E2%80%94-Design-System--Dharma-?node-id=3-134595), which models an inverse chip. We rendered a light-grey panel on webapp-only utilities (`text-s`, `shadow-md`). Current shadcn ships the inverse look too, so the drift is ours. ## Solution - New `packages/design-system/src/components/ui/tooltip.tsx` at Figma parity — inverse chip, `rounded-ds-xs`, `px-1.5 py-1`, `type-label-sm`, `max-w-96`, `shadow-container-panel`. Every value maps to an existing token, so no `tokens:fetch`. - Dropped the `primary`/`secondary` pair — Figma ships one look, and `secondary`'s single call-site went pure black in dark mode. No variant axis left, so the component drops `cva`. - `Tooltip` no longer self-wraps in a `TooltipProvider`, which shadowed anything a consumer configured. The root provider in `providers.tsx` already defaults `delayDuration` to 0, so hover timing is unchanged. - Links inside a tooltip take the chip's own foreground with an underline, by redefining the link colour tokens in scope so every state follows. The accent tokens are tuned for the page surface and collapse on the inverted chip — down to 1.64:1 when pressed. A deliberate stopgap for the 12 links across 5 files; [NAN-5464](https://linear.app/nango/issue/NAN-5464/solve-issue-with-inaccessible-upgrade-link-in-tooltips) removes the links and these overrides together. - Moved `@radix-ui/react-tooltip` to the design system, migrated all 16 call-sites, deleted the webapp component. `InfoTooltip`, `ConditionalTooltip` and `PermissionGate` stay in the webapp — no Dharma source. - Dropped the Team members tooltip — its copy described the table directly beneath it, so the help icon earned nothing. - Locked `className`/`style` on `TooltipContent`. Four overrides that fought the new spec are deleted; the two keeping tooltip content hoverable carry a justified disable. Fixes [NAN-6676](https://linear.app/nango/issue/NAN-6676/lift-tooltip-into-the-design-system) ## Testing `ts-build`, `lint`, `format:check` and `build-storybook` clean. **[Visual QA checklist](https://app.notion.com/p/3c2ce2983121819ca9a4ccc6fa1a85bc)** — 8 surfaces on the [app preview](https://pr-7176.app-development.nango.dev), each in both themes. Four are ticked; the rest are open. New stories, replacing the deleted `App Components/UI/Tooltip`: [Sides](https://pr-7176-storybook.app-development.nango.dev/?path=/story/design-system-components-tooltip--sides) · [Alignment](https://pr-7176-storybook.app-development.nango.dev/?path=/story/design-system-components-tooltip--alignment) · [Long Content](https://pr-7176-storybook.app-development.nango.dev/?path=/story/design-system-components-tooltip--long-content) · [On Hover](https://pr-7176-storybook.app-development.nango.dev/?path=/story/design-system-components-tooltip--on-hover) ## Follow-ups - [NAN-6679](https://linear.app/nango/issue/NAN-6679/make-per-model-sync-breakdowns-discoverable-in-the-syncs-table) — `SyncsTab`'s two `SimpleCodeBlock` tooltips read as a frame around a code panel; they should be a popover behind a real trigger. - [NAN-5464](https://linear.app/nango/issue/NAN-5464/solve-issue-with-inaccessible-upgrade-link-in-tooltips) — now carries the full inventory of all 12 links in tooltips. Removing them retires both `pointer-events-auto` disables and the inverse-link rule added here. - The Figma Tooltip's optional `KbdGroup` comes from the old `CURRENT 🐺` library, not Dharma — skipped, worth cleaning up in the Figma file. - Ad-hoc hover hints (native `title=`) adopting the DS `Tooltip` — separate ticket under Component consolidation. | 21 天前 | |
feat(design-system): add basic Storybook setup with a11y and MCP addons (#6204) ## Problem No component development environment existed for the design system. There was no way to view tokens in isolation, verify that CSS custom properties resolve correctly, or confirm dark/light theme switching without running the full app. ## Solution Adds Storybook 10 to `packages/design-system` as the living style guide, with stories driven directly from `tokens.json` so they stay in sync with Figma automatically. **Storybook setup** - `@storybook/react-vite` with `@tailwindcss/vite` injected via `viteFinal` so `@theme {}` in `tokens.generated.css` is processed correctly - Theme toolbar toggle sets `data-theme="dark"` on `<html>` via `@storybook/addon-themes` — same mechanism as the app - Geist / Geist Mono loaded via `preview-head.html`; React pre-bundled via `optimizeDeps` for Vite 7 CJS compat - `@storybook/addon-a11y` and `@storybook/addon-mcp` included - MCP server will be useful after the design system grows and matures - `packages/design-system` added to `tsconfig.build.json` so CI typechecks it **Token pipeline** - `tokens-fetch.mjs` extended to process the `Typography` group from `tokens.json` and emit `.type-{name}` CSS classes (e.g. `.type-heading-lg`, `.type-code-medium-sm`) for all 21 composite text-style tokens **Stories** (`Design System/Tokens/`) - `Typography` — type scale using generated `.type-*` classes; sections for Heading, Text·Regular, Text·Medium, Label, Code·Regular, Code·Medium; plus Font Families specimen - `Color Palette / Primitives` — all color ramps derived programmatically from `Primitives.color` in `tokens.json` (neutral, brand, info, success, warning, danger, mono, alpha, accent) - `Color Palette / Semantic` — all 118 semantic tokens derived programmatically from `Semantic/Light` in `tokens.json`, grouped by category; no manual token lists to maintain Closes [NAN-5665](https://linear.app/nangohq/issue/NAN-5665) ## Testing - `npm run storybook` from `packages/design-system` → opens at `http://localhost:6006` - Typography story renders all type scale rows using the generated `.type-*` CSS classes with correct sizes, weights, and font families - Color Palette / Primitives shows all 10 color ramps including alpha and accent groups - Color Palette / Semantic shows all 118 semantic tokens grouped by category with correct colors - Theme toolbar toggle switches light ↔ dark — semantic token values flip correctly - `npm run build-storybook` builds without errors - `npm run test` passes (token pipeline unit tests) ## Screenshots ### Tokens overview <img width="1066" height="936" alt="image" src="https://github.com/user-attachments/assets/359e9a51-8c1d-4703-8332-5002b4efc6a2" /> <img width="1220" height="959" alt="image" src="https://github.com/user-attachments/assets/2e0ec14c-f85f-4eac-aba1-0e7f21764c50" /> <img width="935" height="914" alt="image" src="https://github.com/user-attachments/assets/e19134da-1d53-4425-b0d0-cecaac7cd581" /> ### Dark theme <img width="872" height="898" alt="image" src="https://github.com/user-attachments/assets/2c8d3254-d0d2-4071-a888-40d1628e2f46" /> ### Accessibility addon <img width="984" height="525" alt="image" src="https://github.com/user-attachments/assets/c3ce0138-eaea-48d2-beec-f6272c8e16eb" /> ### Storybook MCP server <img width="787" height="324" alt="image" src="https://github.com/user-attachments/assets/03ff28c3-b71a-4a76-b3dc-da9e29b3e49f" /> --------- Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> | 3 个月前 | |
feat(webapp): Add design system tokens sync (#6201) ## Problem The webapp redesign requires a new design system with tokens authored in Figma via Tokens Studio. There was no pipeline to get those tokens into code, and no way for the designer to share tokens across multiple Figma files. ## Solution Adds a `packages/design-system` package with a token sync workflow: - **Designer** edits tokens in Figma (Tokens Studio plugin) → pushes to the `design/tokens` branch via Figma plugin - **Developer** runs `npm run tokens:fetch` → fetches `tokens.json` from that branch → regenerates CSS → commits both files No env vars or Figma API credentials required — the repo is public and tokens are fetched via a plain GitHub raw URL. **`packages/design-system` contains:** - `tokens/tokens.json` — Tokens Studio export (committed to git) - `tokens/tokens.generated.css` — generated CSS: primitives (`:root`, `--ds-` prefix), semantic light/dark (`:root` / `[data-theme="dark"]`), and a Tailwind v4 `@theme` block for utility class generation (`bg-surface-canvas`, `text-text-strong`, etc.) - `scripts/tokens-fetch.mjs` — token pipeline using Style Dictionary v5 + sd-transforms - Unit tests for all pipeline functions (`tokens-fetch.unit.test.mjs`) The CSS is imported in `packages/webapp/src/index.css` and picked up by Vite's HMR — token changes in `tokens.generated.css` propagate to the browser instantly without a page reload. The new tokens are additive — legacy `--color-*` vars in `index.css` are untouched. Primitives use `--ds-` prefix to avoid collisions. Dark mode via `[data-theme="dark"]`. High level Notion doc describing the integration at https://www.notion.so/nangohq/Figma-Design-Tokens-integration-367ce298312180d2a563f5b43c5a16ce **New tokens are not yet used for any UI, that will happen in follow ups.** Fixes [NAN-5664](https://linear.app/nango/issue/NAN-5664) ## Testing - `cd packages/design-system && npm run tokens:fetch` — fetches tokens from GitHub `design/tokens` branch, writes `tokens.json` and `tokens.generated.css` - `npm run tokens:build` — rebuilds CSS from local `tokens.json` (no network) - `npm test` — runs unit tests for the pipeline script - Verified in local dev: token changes in `tokens.generated.css` hot-reload in the browser via Vite HMR; the full pipeline (`tokens.json` → `tokens:build` → CSS → HMR) works end-to-end <!-- start telescope-canary-packages --> <!-- end telescope-canary-packages --> | 3 个月前 |
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 5 天前 | ||
| 1 个月前 | ||
| 9 天前 | ||
| 5 天前 | ||
| 26 天前 | ||
| 3 个月前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 21 天前 | ||
| 3 个月前 | ||
| 3 个月前 |