Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
8a9f9ad
refactor(theme): rename chart palette tokens to hue names + unify acr…
elizabetdev May 28, 2026
6e2d26f
fix(theme): resolve legacy chart-1..10 at render time + cover semanti…
elizabetdev May 28, 2026
64f857f
fix(theme): drop ChartPaletteTokenSchema preprocess + heal legacy col…
elizabetdev May 28, 2026
e103ad3
chore(theme): drop dead isChartPaletteToken re-export + minor #2362 c…
alex-fedotyev May 28, 2026
71aefdc
refactor(data viz): unify categorical color palette and streamline co…
elizabetdev May 28, 2026
7eb2b85
docs(changeset): note brand-blue customization, JS source of truth, a…
elizabetdev May 28, 2026
90f0ff3
refactor(theme): extract shared chart categorical SCSS partial
elizabetdev May 28, 2026
ba3d349
fix(theme): heal legacy chart colors at write time + close coverage gaps
elizabetdev May 28, 2026
78cfce7
test(theme): cover fetchDashboards remote-path normalizer + redrop kn…
alex-fedotyev May 29, 2026
131d73e
fix(theme): decouple HyperDX chart-info from success, reuse categoric…
elizabetdev May 29, 2026
3fe3c8c
Merge remote-tracking branch 'origin/main' into agent/rename-chart-pa…
elizabetdev May 29, 2026
1c7a856
Merge branch 'agent/rename-chart-palette-tokens' of github.com:hyperd…
elizabetdev May 29, 2026
f7eaa03
docs(storybook): add per-brand info chart colors to Chart Colors story
elizabetdev May 29, 2026
a134bb6
docs(changeset): align info semantic notes with HyperDX cyan split
elizabetdev May 29, 2026
6edb12b
refactor(theme): unify chart semantic tokens across HyperDX and Click…
elizabetdev May 29, 2026
619e89f
fix(theme): address deep-review findings on chart palette rename
elizabetdev May 29, 2026
9b756d5
fix(theme): address round-2 deep-review findings on chart palette rename
elizabetdev May 29, 2026
b1e5059
fix(api): drop single-GET assertion in legacy-color GET test
elizabetdev May 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions .changeset/rename-chart-palette-tokens.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
---
'@hyperdx/common-utils': minor
'@hyperdx/app': minor
'@hyperdx/api': patch
---

refactor(theme): rename chart palette tokens from chart-1..10 to hue-named
(chart-blue, chart-orange, ...) and unify the categorical palette across HyperDX
and ClickStack

Stored configs from the initial color picker (#2265) keep working.
`ChartPaletteTokenSchema` stays strict (a plain `z.enum`, so its `z.input`
matches `z.output` — wrapping it in `z.preprocess` would poison
`validateRequest`'s `req.body` inference all the way up to
`Dashboard.tiles[i].config.color`). Migration of legacy `chart-1` .. `chart-10`
happens at five complementary points so no entry or wire-format path can slip
through, all composing over a single shared walker
(`walkRawDashboardTileColors` in `common-utils`) so the per-tile traversal
stays in lockstep:

- **Fetch-time / write-time (React)**: `normalizeDashboardTileColors` in
`packages/app/src/dashboard.ts` heals dashboards on read
(`useDashboards` / `fetchLocalDashboards` / `fetchDashboards`) and on write
(`useUpdateDashboard` / `useCreateDashboard`). Unresolvable color strings
(stale hexes, hand-edited values, forward-rolled future tokens) are
preserved so the user's chosen value survives a render pass — the strict
server-side schema surfaces a clear error on next save instead of the
normalizer quietly dropping the field.
- **JSON import**: `DBDashboardImportPage` runs
`normalizeRawDashboardTileColors` on the parsed JSON *before* the strict
`DashboardTemplateSchema.safeParse`, so templates exported from a
pre-rename deploy import cleanly.
- **Server-side GET response healing**: `getDashboards` / `getDashboard` in
`packages/api/src/controllers/dashboard.ts` rewrite legacy tile colors on
the way out. Pre-rename Mongo docs are served on the wire as
hue-named tokens so non-React HTTP clients (CI scripts, stale bundle
tabs during a rolling deploy, the external API) can round-trip
GET → PATCH without ever resurrecting `chart-N` through the strict
schema.
- **Server-side write shim**: the dashboards POST / PATCH routes mount
a request-body preprocessor that rewrites legacy tile colors before
`validateRequest` runs `ChartPaletteTokenSchema`. Catches non-React
HTTP callers (stale-bundle tabs during a rolling deploy, CI scripts,
MCP, the upcoming external-API parity work) for a one-release
deprecation window without weakening the schema's input/output equality.
The dashboard provisioner task applies the same shim before parsing
on-disk template files.
- **Render-time (belt-and-suspenders)**: `DBNumberChart` and
`ColorSwatchInput` also call `resolveChartPaletteToken` for tiles
constructed in memory between fetch and save (`ChartEditor` form
state, unit-test fixtures, hand-rolled `Tile` literals).

The migration preserves the HyperDX slot ordering from #2265 (slot 1 = brand
green, slot 2 = blue, etc.).

**ClickStack legacy color caveat:** Pre-rename ClickStack used a different slot
ordering than HyperDX (`--color-chart-1` was brand blue `#437eef`, not brand
green). The migration map uses HyperDX slot ordering, so any ClickStack
dashboard saved via #2265 with `color: 'chart-1'` will flip from blue to
Observable green after migration. We chose this trade-off deliberately over
branching the legacy map by active theme: `LEGACY_CHART_PALETTE_TOKEN_MAP` lives
in `common-utils` (shared with the API), and migration is one-shot persisted on
next save — theme-branching would couple common-utils to browser DOM state and
still produce wrong results for users whose active theme changed since the
original pick. Affected users can manually re-pick the desired hue via the (now
hue-labeled) color picker.

The categorical palette is based on Observable 10, with `chart-blue` swapped to
`#437eef` to match the brand link color
(`--click-global-color-text-link-default`); all other hues are straight from
Observable 10. The palette resolves identically on both themes — picking
`chart-blue` always renders the brand blue. Brand identity for charts moves
entirely into the semantic layer: `--color-chart-success` and `--color-chart-info`
resolve to categorical `chart-green` (`#3ca951`) and `chart-blue` (`#437eef`) on
both HyperDX and ClickStack, so success fills, info-level logs, and the
matching multi-series slots all read consistently across brands.

Internally, JS (`CATEGORICAL_HEX_BY_TOKEN` in `packages/app/src/utils.ts`) is
the source of truth for categorical hues — `getColorFromCSSVariable` and
`getColorFromCSSToken` skip `getComputedStyle` for categorical tokens since the
palette is unified across themes. The matching `--color-chart-{hue}` CSS vars in
`_tokens.scss` remain as a stylesheet-author affordance (inline `var()` use,
devtools inspection) and a hook for any future per-brand override. Semantic
tokens still resolve through `getComputedStyle` because they genuinely vary per
theme.
Loading
Loading