From a96d58defbcfc7e13b745a452a0e9cb5529b13d2 Mon Sep 17 00:00:00 2001 From: os-zhuang Date: Wed, 10 Jun 2026 20:25:04 +0500 Subject: [PATCH 1/2] chore: bump objectui to ec530a92ba2c Merge pull request #1626 from objectstack-ai/fix-flowrunner-terminal-failure-reset objectui@ec530a92ba2cdb6dbb0a1f5ee3b800503296e2f1 --- .objectui-sha | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.objectui-sha b/.objectui-sha index bbab823b0f..868180fbb1 100644 --- a/.objectui-sha +++ b/.objectui-sha @@ -1 +1 @@ -76094e0d4ed79b8732ba9879c75aa5ab8283180d +ec530a92ba2cdb6dbb0a1f5ee3b800503296e2f1 From 1c83ee8d8fcbbcfada328378e39f37cb087057d9 Mon Sep 17 00:00:00 2001 From: os-zhuang Date: Wed, 10 Jun 2026 20:29:06 +0500 Subject: [PATCH 2/2] feat(spec)!: trim ChartTypeSchema to distinctly-renderable families MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drops 8 variant types that only rendered as their base chart, so the taxonomy no longer advertises a type that renders as something else: grouped-bar / stacked-bar / bi-polar-bar (→bar), stacked-area (→area), step-line / spline (→line), pyramid (→funnel), bubble (→scatter). 0 downstream usages (the showcase gallery was already trimmed; hotcrm/templates use none of them). Kept: the rendered families + the single-value performance group (metric / kpi / gauge / solid-gauge / bullet) — honest values today, a dial when a gauge renderer lands; `gauge` is used downstream (hotcrm SLA widget). - chart.zod: enum trimmed + taxonomy NOTE documents both exclusion groups. - chart.test: removed types moved to the reject list (+ a dedicated case). - showcase coverage.test: FALLBACK_ONLY simplified to the 4 metric-synonyms now that the 8 variants are gone from the enum. spec 6527/6527, turbo build 72/72, test 123/123. Co-Authored-By: Claude Opus 4.8 --- .changeset/trim-charttype-schema.md | 21 +++++++++++ content/docs/references/ui/chart.mdx | 12 +----- examples/app-showcase/test/coverage.test.ts | 22 ++++------- packages/spec/src/ui/chart.test.ts | 23 ++++++++--- packages/spec/src/ui/chart.zod.ts | 42 +++++++++++---------- 5 files changed, 70 insertions(+), 50 deletions(-) create mode 100644 .changeset/trim-charttype-schema.md diff --git a/.changeset/trim-charttype-schema.md b/.changeset/trim-charttype-schema.md new file mode 100644 index 0000000000..78c52063a9 --- /dev/null +++ b/.changeset/trim-charttype-schema.md @@ -0,0 +1,21 @@ +--- +"@objectstack/spec": major +--- + +BREAKING: `ChartTypeSchema` drops 8 variant types that only rendered as their +base chart, so the taxonomy now advertises only families the renderer draws +distinctly. + +Removed: `grouped-bar`, `stacked-bar`, `bi-polar-bar` (→ bar — no multi-series +grouping/stacking), `stacked-area` (→ area), `step-line`, `spline` (→ line), +`pyramid` (→ funnel), `bubble` (→ scatter — no size encoding). + +Kept: bar / horizontal-bar / column, line / area, pie / donut / funnel, scatter, +treemap / sankey, radar, table / pivot, and the single-value performance family +(metric / kpi / gauge / solid-gauge / bullet — these render an honest value +today and gain a dial when a gauge renderer lands). + +Migration: a widget/series using a removed type should switch to its base +(`stacked-bar`→`bar`, `spline`→`line`, `pyramid`→`funnel`, `bubble`→`scatter`, +etc.). These can return via an opt-in renderer once a real renderer + data model +backs them. diff --git a/content/docs/references/ui/chart.mdx b/content/docs/references/ui/chart.mdx index fef917664a..fa86df49ba 100644 --- a/content/docs/references/ui/chart.mdx +++ b/content/docs/references/ui/chart.mdx @@ -69,7 +69,7 @@ const result = ChartAnnotation.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **type** | `Enum<'bar' \| 'horizontal-bar' \| 'column' \| 'grouped-bar' \| 'stacked-bar' \| 'bi-polar-bar' \| 'line' \| 'area' \| 'stacked-area' \| 'step-line' \| 'spline' \| 'pie' \| 'donut' \| 'funnel' \| 'pyramid' \| 'scatter' \| 'bubble' \| 'treemap' \| 'sankey' \| 'gauge' \| 'solid-gauge' \| 'metric' \| 'kpi' \| 'bullet' \| 'radar' \| 'table' \| 'pivot'>` | ✅ | | +| **type** | `Enum<'bar' \| 'horizontal-bar' \| 'column' \| 'line' \| 'area' \| 'pie' \| 'donut' \| 'funnel' \| 'scatter' \| 'treemap' \| 'sankey' \| 'gauge' \| 'solid-gauge' \| 'metric' \| 'kpi' \| 'bullet' \| 'radar' \| 'table' \| 'pivot'>` | ✅ | | | **title** | `string` | optional | Chart title | | **subtitle** | `string` | optional | Chart subtitle | | **description** | `string` | optional | Accessibility description | @@ -109,7 +109,7 @@ const result = ChartAnnotation.parse(data); | :--- | :--- | :--- | :--- | | **name** | `string` | ✅ | Field name or series identifier | | **label** | `string` | optional | Series display label | -| **type** | `Enum<'bar' \| 'horizontal-bar' \| 'column' \| 'grouped-bar' \| 'stacked-bar' \| 'bi-polar-bar' \| 'line' \| 'area' \| 'stacked-area' \| 'step-line' \| 'spline' \| 'pie' \| 'donut' \| 'funnel' \| 'pyramid' \| 'scatter' \| 'bubble' \| 'treemap' \| 'sankey' \| 'gauge' \| 'solid-gauge' \| 'metric' \| 'kpi' \| 'bullet' \| 'radar' \| 'table' \| 'pivot'>` | optional | Override chart type for this series | +| **type** | `Enum<'bar' \| 'horizontal-bar' \| 'column' \| 'line' \| 'area' \| 'pie' \| 'donut' \| 'funnel' \| 'scatter' \| 'treemap' \| 'sankey' \| 'gauge' \| 'solid-gauge' \| 'metric' \| 'kpi' \| 'bullet' \| 'radar' \| 'table' \| 'pivot'>` | optional | Override chart type for this series | | **color** | `string` | optional | Series color (hex/rgb/token) | | **stack** | `string` | optional | Stack identifier to group series | | **yAxis** | `Enum<'left' \| 'right'>` | ✅ | Bind to specific Y-Axis | @@ -127,20 +127,12 @@ const result = ChartAnnotation.parse(data); * `bar` * `horizontal-bar` * `column` -* `grouped-bar` -* `stacked-bar` -* `bi-polar-bar` * `line` * `area` -* `stacked-area` -* `step-line` -* `spline` * `pie` * `donut` * `funnel` -* `pyramid` * `scatter` -* `bubble` * `treemap` * `sankey` * `gauge` diff --git a/examples/app-showcase/test/coverage.test.ts b/examples/app-showcase/test/coverage.test.ts index dc0b3751d8..e55d5cd010 100644 --- a/examples/app-showcase/test/coverage.test.ts +++ b/examples/app-showcase/test/coverage.test.ts @@ -49,20 +49,14 @@ describe('showcase coverage (introspected against the spec)', () => { }); it('covers every distinctly-renderable ChartType', () => { - // The Chart Gallery demonstrates only chart families the renderer draws - // DISTINCTLY — advertising a type that renders as something else (a "sankey" - // that draws bars) is worse than not offering it. The families below have no - // distinct renderer yet and fall back to a near-relative, so the showcase - // intentionally does not duplicate them: grouped/stacked/bi-polar bars (→bar), - // stacked-area (→area), step-line/spline (→line), pyramid (→funnel), bubble - // (→scatter), and the dial-less performance variants kpi/gauge/solid-gauge/ - // bullet (→ the same KPI value as `metric`). Follow-up: trim these from - // `ChartTypeSchema` so spec ↔ renderer ↔ showcase stay in lockstep. - const FALLBACK_ONLY = new Set([ - 'grouped-bar', 'stacked-bar', 'bi-polar-bar', 'stacked-area', 'step-line', - 'spline', 'pyramid', 'bubble', 'kpi', 'gauge', 'solid-gauge', 'bullet', - ]); - const expected = enumValues(ui.ChartTypeSchema).filter((t) => !FALLBACK_ONLY.has(t)); + // The fallback-only VARIANTS (grouped/stacked/bi-polar bar, stacked-area, + // step-line, spline, pyramid, bubble) were removed from `ChartTypeSchema`, so + // the enum now lists only families that render. The remaining exception is + // the performance group: `metric` represents the single-value KPI, and + // `kpi`/`gauge`/`solid-gauge`/`bullet` render the SAME value today (no dial), + // so the gallery demonstrates `metric` once rather than duplicating them. + const SAME_AS_METRIC = new Set(['kpi', 'gauge', 'solid-gauge', 'bullet']); + const expected = enumValues(ui.ChartTypeSchema).filter((t) => !SAME_AS_METRIC.has(t)); const used = new Set(); for (const w of ChartGalleryDashboard.widgets ?? []) if (w.type) used.add(w.type); expectFullCoverage('ChartType', expected, used); diff --git a/packages/spec/src/ui/chart.test.ts b/packages/spec/src/ui/chart.test.ts index ea4044ec0e..1bbfb0b143 100644 --- a/packages/spec/src/ui/chart.test.ts +++ b/packages/spec/src/ui/chart.test.ts @@ -8,16 +8,16 @@ import { describe('ChartTypeSchema', () => { it('should accept all comparison chart types', () => { - const types = ['bar', 'horizontal-bar', 'column', 'grouped-bar', 'stacked-bar'] as const; - + const types = ['bar', 'horizontal-bar', 'column'] as const; + types.forEach(type => { expect(() => ChartTypeSchema.parse(type)).not.toThrow(); }); }); it('should accept all trend chart types', () => { - const types = ['line', 'area', 'stacked-area', 'step-line'] as const; - + const types = ['line', 'area'] as const; + types.forEach(type => { expect(() => ChartTypeSchema.parse(type)).not.toThrow(); }); @@ -32,8 +32,8 @@ describe('ChartTypeSchema', () => { }); it('should accept all relationship chart types', () => { - const types = ['scatter', 'bubble'] as const; - + const types = ['scatter'] as const; + types.forEach(type => { expect(() => ChartTypeSchema.parse(type)).not.toThrow(); }); @@ -72,6 +72,17 @@ describe('ChartTypeSchema', () => { }); }); + it('should reject variant types that only render as their base chart', () => { + // Removed: each fell back to a base family the renderer already draws, so + // advertising them lied about the output (see the taxonomy NOTE in chart.zod). + const fallbackOnly = ['grouped-bar', 'stacked-bar', 'bi-polar-bar', 'stacked-area', + 'step-line', 'spline', 'pyramid', 'bubble'] as const; + + fallbackOnly.forEach(type => { + expect(() => ChartTypeSchema.parse(type)).toThrow(); + }); + }); + it('should accept all tabular chart types', () => { const types = ['table', 'pivot'] as const; diff --git a/packages/spec/src/ui/chart.zod.ts b/packages/spec/src/ui/chart.zod.ts index 580be20b5e..09f1281956 100644 --- a/packages/spec/src/ui/chart.zod.ts +++ b/packages/spec/src/ui/chart.zod.ts @@ -20,32 +20,25 @@ export const ChartTypeSchema = lazySchema(() => z.enum([ 'bar', 'horizontal-bar', 'column', - 'grouped-bar', - 'stacked-bar', - 'bi-polar-bar', - + // Trend 'line', 'area', - 'stacked-area', - 'step-line', - 'spline', - + // Distribution 'pie', 'donut', 'funnel', - 'pyramid', - + // Relationship 'scatter', - 'bubble', - + // Composition 'treemap', 'sankey', - // Performance + // Performance (single value — metric/kpi render a number; gauge/solid-gauge/ + // bullet are honest single-value variants pending a real dial/target renderer) 'gauge', 'solid-gauge', 'metric', @@ -60,13 +53,22 @@ export const ChartTypeSchema = lazySchema(() => z.enum([ 'pivot', ])); -// NOTE: chart families that require data shapes the platform does not model -// (OHLC for candlestick/stock, per-record distributions for box-plot/violin), -// geographic data (choropleth/bubble-map/gl-map), or dependencies the default -// Recharts renderer lacks (sunburst, heatmap, word-cloud, waterfall) were -// removed from this taxonomy: advertising a chart type the renderer can't draw -// is worse than not offering it. They can return via an opt-in renderer plugin -// once there is real demand and a data model to back them. +// NOTE: the taxonomy lists only chart families the default Recharts renderer +// draws DISTINCTLY. Two groups are intentionally absent: +// +// 1. Families requiring data/dependencies the platform does not model — OHLC +// (candlestick/stock), per-record distributions (box-plot/violin), geo +// (choropleth/bubble-map/gl-map), or extra renderers (sunburst, heatmap, +// word-cloud, waterfall). +// 2. VARIANTS that only render as their base chart, so advertising them lies +// about the output: grouped-bar / stacked-bar / bi-polar-bar (→ bar, no +// multi-series grouping/stacking), stacked-area (→ area), step-line / spline +// (→ line), pyramid (→ funnel), bubble (→ scatter, no size encoding). +// +// Both can return via an opt-in renderer once there is a real renderer and a +// data model to back them. (`metric`/`kpi` are kept as honest single-value +// synonyms; `gauge`/`solid-gauge`/`bullet` render a value today and gain a dial +// when a gauge renderer lands.) export type ChartType = z.infer;