|
| 1 | +--- |
| 2 | +'@objectstack/spec': minor |
| 3 | +--- |
| 4 | + |
| 5 | +feat(spec)!: a `pie` / `donut` / `funnel` / `treemap` / `sankey` dashboard widget takes ONE measure with a dimension too — two or more are refused at `values`, and the check export is renamed `checkDashboardWidgetChartMeasureArity` (#21293; extends #20958) |
| 6 | + |
| 7 | +Clause-②: yes (narrowing) — the accept set NARROWS (that is the change), and the published surface swaps one export for another: `checkDashboardWidgetDimensionlessMeasureArity` is removed and `checkDashboardWidgetChartMeasureArity` is added in its place, the same check with a second arm. |
| 8 | + |
| 9 | +<!-- adr-0087: registered dashboard-widget-single-series-multi-measure-refused --> |
| 10 | + |
| 11 | +**BREAKING** accept-set narrowing at `dashboard.widgets[].values`, plus one renamed |
| 12 | +export, shipped as `minor` under this repo's launch-window convention for breaking |
| 13 | +changes (`check-changeset-no-major` refuses `major` while the window is open, so |
| 14 | +breaking-ness is carried by this banner and by the ADR-0087 disposition above, |
| 15 | +never by the bump level). The prescription is registered under protocol major 18 |
| 16 | +as `dashboard-widget-single-series-multi-measure-refused`. |
| 17 | + |
| 18 | +**What was wrong.** The previous release refused two or more measures on a |
| 19 | +dimensionless `pie` / `donut` / `funnel` / `scatter` / `radar` / `treemap` / |
| 20 | +`sankey`, and stepped aside for any widget that declared a dimension. Five of those |
| 21 | +types draw ONE series whatever the dimension: objectui's chart renderer binds the |
| 22 | +first series on its `pie` / `donut`, `funnel`, `treemap` and `sankey` arms and reads |
| 23 | +no other, so `{ type: 'pie', dimensions: ['stage'], values: ['revenue', 'cost'] }` |
| 24 | +drew one slice per stage for `revenue` and no trace of `cost`. Measured on this tree |
| 25 | +before the change: that body parsed through `DashboardWidgetSchema` on all five |
| 26 | +types (and on `scatter` / `radar` / `bar` / `table`), while `bogusProp` on the same |
| 27 | +widget was refused by name, the lit control. After it, the five are refused at |
| 28 | +`widgets[N].values`; `scatter` and `radar` with a dimension are outside the ruling |
| 29 | +and parse as before. |
| 30 | + |
| 31 | +### Write instead |
| 32 | + |
| 33 | +| wrote | write instead | |
| 34 | +|---|---| |
| 35 | +| `{ id: 'mix', type: 'pie', dataset: 'sales', dimensions: ['stage'], values: ['revenue', 'cost'] }` | `{ id: 'mix', type: 'table', dataset: 'sales', dimensions: ['stage'], values: ['revenue', 'cost'] }` — a column per measure | |
| 36 | +| the same, wanting a chart | `type: 'bar'` (or `column` / `horizontal-bar`) — one bar per measure in each stage | |
| 37 | +| the same, wanting the pie | `{ id: 'mix', type: 'pie', …, values: ['revenue'] }` **and** `{ id: 'mix_cost', type: 'pie', …, values: ['cost'] }` — one widget per measure, each with its own `id` (and `layout`, if you pin positions) | |
| 38 | +| `import { checkDashboardWidgetDimensionlessMeasureArity } from '@objectstack/spec/ui'` | `import { checkDashboardWidgetChartMeasureArity } from '@objectstack/spec/ui'` — same `(widget, ctx)` signature; chain it where the old name was chained | |
| 39 | + |
| 40 | +No conversion does this for you: whether a two-measure pie by stage meant a table, a |
| 41 | +grouped bar chart or two pies is an authoring choice. The refusal is ONE `custom` |
| 42 | +issue at `widgets[N].values` naming the widget's `id`, the number of measures and |
| 43 | +the authored `type`, and saying that type draws one series whatever its |
| 44 | +`dimensions`. |
| 45 | + |
| 46 | +**Why the export is renamed.** The dimensionless rule's check now has a second arm |
| 47 | +that judges widgets WITH a dimension, so its old name described a boundary that no |
| 48 | +longer exists. It refuses everything the old name refused, word for word on a |
| 49 | +dimensionless widget. No first-party consumer chained the old name: objectui's |
| 50 | +`DashboardWidgetSchema` mirror chains `checkDashboardWidgetStageOrder` and |
| 51 | +`checkDashboardWidgetMetricMeasureArity` only, measured at the pinned objectui |
| 52 | +commit and on objectui's `main`. |
| 53 | + |
| 54 | +**Nothing else moves.** One measure parses on every type; `scatter` and `radar` |
| 55 | +keep accepting several measures with a dimension; every type in |
| 56 | +`DASHBOARD_WIDGET_MULTI_MEASURE_TYPES` keeps accepting any number of measures with |
| 57 | +or without a dimension; a dimensionless widget of the five keeps the dimensionless |
| 58 | +refusal, word for word and still ONE issue; the metric family's refusal is |
| 59 | +unchanged; an empty `values` keeps its `too_small`; a `type` outside |
| 60 | +`ChartTypeSchema` reports the type refusal alone. Census at the branch point |
| 61 | +(`4b20c8474`), every tracked `.ts` / `.tsx` / `.js` / `.mjs` / `.cjs` / `.json` / |
| 62 | +`.md` / `.mdx` / `.yml`: 496 literals carry `values: [...]`, 33 of them on one of |
| 63 | +the seven types, and the only dimensioned multi-measure one on the five is a spec |
| 64 | +test fixture that pinned the old acceptance (moved to the refusal in this change). |
| 65 | +The same scan over objectui at its pinned commit (`89cad75d5`) finds no authored |
| 66 | +widget of that shape — its one hit is the prose example in a changeset. |
0 commit comments