|
| 1 | +--- |
| 2 | +"@objectstack/spec": minor |
| 3 | +--- |
| 4 | + |
| 5 | +feat(spec)!: a dashboard widget with no dimension declares two or more measures only on a type that renders them — `pie` / `donut` / `funnel` / `scatter` / `radar` / `treemap` / `sankey` are refused at `values` (#20958; objectui#8894 ruling D's principle) |
| 6 | + |
| 7 | +Clause-②: yes (narrowing) — the accept set NARROWS (that is the change), and the published surface GAINS two exports: the one constant the rule reads, `DASHBOARD_WIDGET_MULTI_MEASURE_TYPES`, and the check itself, `checkDashboardWidgetDimensionlessMeasureArity`, exported so objectui's `.shape` mirror can chain it. |
| 8 | + |
| 9 | +<!-- adr-0087: registered dashboard-widget-dimensionless-multi-measure-refused --> |
| 10 | + |
| 11 | +**BREAKING** accept-set narrowing at `dashboard.widgets[].values`, shipped as |
| 12 | +`minor` under this repo's launch-window convention for breaking changes |
| 13 | +(`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-dimensionless-multi-measure-refused`. |
| 17 | + |
| 18 | +**What was wrong.** Outside the metric family, `DashboardWidgetSchema.values` |
| 19 | +(`z.array(z.string()).min(1)`) had no upper bound. Measured on this tree before |
| 20 | +the change: `{ type: 'pie', dataset: 'sales', values: ['a', 'b'] }` with no |
| 21 | +`dimensions` parsed through `DashboardWidgetSchema`, and so did `donut`, |
| 22 | +`funnel`, `scatter`, `radar`, `treemap` and `sankey` — while `bogusProp` on the |
| 23 | +same widget was refused by name, the lit control. After it, the same body is |
| 24 | +refused at `defineStack`, at `os validate` (which loads through `defineStack`), |
| 25 | +and on the metadata save path (`422 INVALID_METADATA`, active and draft). With |
| 26 | +nothing to split by, those seven types draw `values[0]`: every measure after it |
| 27 | +is queried and dropped on the floor by the renderer. The maintainer's ruling D |
| 28 | +(「协议不正确的应该先修改协议」) fixes the protocol where it admits measures a |
| 29 | +widget type cannot render; the metric-family narrowing was its first |
| 30 | +application, and this is the same principle on the chart types. |
| 31 | + |
| 32 | +### Write instead |
| 33 | + |
| 34 | +| wrote | write instead | |
| 35 | +|---|---| |
| 36 | +| `{ id: 'mix', type: 'pie', dataset: 'sales', values: ['amount_sum', 'count'] }` (no `dimensions`) | `{ id: 'mix', type: 'table', dataset: 'sales', values: ['amount_sum', 'count'] }` — a row of measures | |
| 37 | +| the same, wanting a chart | `type: 'bar'` (or `column` / `horizontal-bar`) — one bar per measure | |
| 38 | +| the same, wanting the pie | `{ id: 'mix', type: 'pie', …, values: ['amount_sum'] }` **and** `{ id: 'mix_count', type: 'pie', …, values: ['count'] }` — one widget per measure, each with its own `id` (and `layout`, if you pin positions) | |
| 39 | + |
| 40 | +No conversion does this for you: whether a dimensionless two-measure pie meant a |
| 41 | +table, a bar chart or two pies is an authoring choice. The refusal lands at |
| 42 | +`widgets[N].values` as ONE `custom` issue naming the widget's `id`, the number |
| 43 | +of measures and the authored `type`, and it lists the types that do render |
| 44 | +several measures on a dimensionless widget, read from |
| 45 | +`DASHBOARD_WIDGET_MULTI_MEASURE_TYPES` (`table`, `pivot`, `bar`, `column`, |
| 46 | +`horizontal-bar`, `line`, `area`, `combo`). That constant is the one list — the |
| 47 | +check, the refusal text and the `values` doc string read it, and objectui's |
| 48 | +mirror is to import it rather than restate it. A type that later gains a |
| 49 | +declared multi-measure rendering joins it with no migration. |
| 50 | + |
| 51 | +**Nothing else moves.** The seven types WITH a dimension, and with one measure, |
| 52 | +parse exactly as before; every type in the multi-measure set keeps accepting |
| 53 | +any number of measures with no dimension; the metric family's refusal is |
| 54 | +unchanged and still ONE issue (this check steps aside for `metric` / `kpi` / |
| 55 | +`gauge` / `solid-gauge` / `bullet` and for a typeless widget, which resolves to |
| 56 | +`metric`); an empty `values` keeps its `too_small`; a `type` outside |
| 57 | +`ChartTypeSchema` reports the type refusal alone. Census at the branch point |
| 58 | +(`05be35259`), every tracked `.ts` / `.tsx` / `.js` / `.json` / `.md` / `.mdx`: |
| 59 | +23 widget literals on the seven types, every one with one dimension and one |
| 60 | +measure, and 0 dimensionless multi-measure widgets on them; the same scan over |
| 61 | +an objectui checkout (`1263e40`) reads 0 as well. |
0 commit comments