Repository navigation
Commit b4333ab
fix(plugin-dashboard): a dimensionless table renders a row of every measure and a dimensionless chart one mark per measure, as the spec states (objectui#11261) (#11278)
Fixes #11261
Clause-②: no
## What this changes
`DatasetWidget` classified every widget that declares no `dimensions` as
a one-number tile (`isMetric = METRIC_TYPES.has(widgetType) ||
dimensions.length === 0`). So the card's `{ type: 'table', dataset:
'sales', values: ['revenue', 'cost', 'margin'] }` rendered `revenue`
alone. Every door accepts that widget, and the spec's own metric-family
arity refusal sends authors there. Its ADR-0087 entry
`dashboard-widget-metric-family-multi-measure-refused` (`replacement`,
read in the installed `@objectstack/spec` 17.5.0) says: "`type: 'table'`
renders a row of measures, and the chart families (`bar` / `line` /
`area` / `combo`) render one mark per measure".
Per triage `5918660676` (the renderer delivers the stated behaviour; no
spec narrowing):
- **Only a metric-family type is a tile by type.** A widget with no
dimension stays a tile, unless it carries two or more measures on a type
the spec names. Those are `table` / `pivot`, or a widget whose family
(`CHART_TYPE_MAP`) is `bar` / `line` / `area` / `combo`
(`MEASURE_AXIS_CHART_FAMILIES`).
- **table / pivot:** the existing flat-table branch renders the one row
the dimensionless query answers, with every measure as a column. No
totals footer is requested or drawn, because that row already IS the
`[]` grand-total grouping.
- **bar / line / area / combo:** the single row is transposed into one
chart row per declared measure, in declaration order. The category is
the measure's `headerLabel` (the widget's one measure-label channel).
The value sits under one series labelled with the existing
`dashboard.total` key, so no new string is minted. A `compareTo` the
widget asks for draws as one overlay series beside each measure. The
dimensioned overlay path is byte-identical (same data keys and labels).
- **One measure, no dimension:** unchanged. It takes the metric branch
on every type and renders the tile, byte-identical. This is pinned for
`table`, `pivot`, `bar`, `line`, `area` and `combo`.
- **Types the spec's text does not name** (`pie`, `donut`, `funnel`,
`scatter`, `column`, `horizontal-bar`, `radar`, `treemap`, `sankey`):
measured and unchanged. A dimensionless one with two measures is still a
tile. It renders `values[0]`, and objectui#8894's warning still names
the dropped measure. This goes back as an open question in the report,
and no display semantics are invented for these types.
- objectui#8894's warning code is untouched. It follows `isMetric`, so
it no longer fires for the widgets that now render every measure. One
example in `DatasetWidget.unrenderedMeasures-8894.test.tsx` moved. Its
SUBJECT "covers the dimensionless arm" used a dimensionless `bar`, which
is no longer a tile, so it now uses a `pie`, which still is. Its
assertions are unchanged.
## Pins
`DatasetWidget.dimensionlessMeasures-11261.test.tsx` draws real Recharts
marks through the registry, using the
`DatasetWidget.chartConfigMarks-9203` harness.
| Row | Kind |
|---|---|
| the card's `table` (and `pivot`) over revenue, cost, margin renders
one row with all three, no footer, no warning | SUBJECT |
| a two-measure dimensionless `bar` draws two `.recharts-bar-rectangle`,
with category ticks `Revenue`, `Cost` | SUBJECT |
| the same for `combo`; `line` / `area` plot across the two measure
labels | SUBJECT |
| a comparison on a dimensionless `bar` draws 4 marks (2 + 2 overlay) |
SUBJECT |
| a two-measure `metric` tile with no dimension renders the tile markup
and still warns | CONTROL |
| a ONE-measure dimensionless table / pivot / bar / line / area / combo
renders the tile markup | CONTROL |
| a dimensionless `table` / `bar` queries exactly `{ dimensions: [],
measures: values }` (no `totals`) | CONTROL |
| nine unnamed types stay a tile and warn (measured; the open question)
| CONTROL |
PR objectui#8887's two pins stay green: the drop on a metric-type tile,
and the no-sub-caption byte-identity
(`DatasetWidget.subCaption.test.tsx`).
## Ablation (restore the old `isMetric`)
The fix was committed first. `node
../objectstack/scripts/ablation-replace.mjs` then ran in WRAP mode (the
anchor must hit once, the write is verified on disk, and a trap restores
it). It replaced the new `isMetric` line with the old one and ran the
new file, the objectui#8894 file and the sub-caption file.
- The mutation landed: anchor 1 -> 0, blob `9640acd2abcc` ->
`4bf0c16ab58b`.
- **7 failed / 38 passed**: exactly the 7 SUBJECT rows went red. All 18
CONTROL rows, all 8 objectui#8894 rows and all 12 sub-caption rows
stayed green.
- Restored: blob == HEAD `9640acd2abcc`, and `git diff HEAD` is empty
(re-checked independently).
## Gates (at `7d54b7cfb`)
- `pnpm exec vitest run packages/plugin-dashboard/src/`: 155 files
passed, 1420 passed / 6 skipped. At base `f61dab169` it was 154 files,
1395 / 6; the difference is the new file's 25.
- `pnpm --filter @object-ui/plugin-dashboard type-check`, with the
closure built first by turbo: exit 0. `tsc -p tsconfig.test.json
--listFiles` includes both touched test files.
- `pnpm exec eslint` on the 3 changed source and test files: 0 errors.
The 11 warnings in `DatasetWidget.tsx` are the same 11, under the same
rules, as at base. The new file has 0 errors and 0 warnings.
- `node scripts/check-changeset-presence.mjs`: exit 0. `node
scripts/check-control-bytes.mjs`: exit 0. `pnpm
check:new-line-citations`: 0 new citations.
- The changeset is markdown, so `node scripts/markdown-test-inputs.mjs
--audit` ran (exit 0), and so did `pnpm exec vitest run
scripts/__tests__/` (177 files passed, 2 skipped; 5371 passed).
- Consumers: the four app-shell files that render `DatasetWidget`, plus
PR objectui#11257's two door pins (types, app-shell): 6 files, 84
passed.
## Acceptance notes
- Census: every authored multi-measure dashboard widget in objectstack's
examples declares a dimension (`git grep` over its `origin/main` at
`75519e1c0`). objectui's `examples/` and `apps/` author none. So no
shipped example changes rendering.
- Docs: no doc or README stated the old "no dimensions is a tile" rule
(`grep` over `content/docs`, the package README and `skills/`), so none
became false. The changeset carries the user-facing description.
- Observation, not measured through a door, and not filed (no carrier):
`chartType = CHART_TYPE_MAP[widgetType] ?? 'bar'` sends a widget with no
`type` and a dimension to a bar chart, while the spec defaults `type` to
`metric`. A spec-parsed document always carries a type, so this reaches
only an unparsed client draft. This change reads `CHART_TYPE_MAP`
without that default, so it adds no path through it.
---
_Generated by [Claude
Code](https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent e420df3 commit b4333ab
4 files changed
Lines changed: 343 additions & 19 deletions
File tree
- .changeset
- packages/plugin-dashboard/src
- __tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
12 | | - | |
13 | | - | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
14 | 18 | | |
15 | 19 | | |
16 | 20 | | |
| |||
349 | 353 | | |
350 | 354 | | |
351 | 355 | | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
352 | 381 | | |
353 | 382 | | |
354 | 383 | | |
| |||
441 | 470 | | |
442 | 471 | | |
443 | 472 | | |
444 | | - | |
445 | 473 | | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
446 | 495 | | |
447 | 496 | | |
448 | 497 | | |
| |||
524 | 573 | | |
525 | 574 | | |
526 | 575 | | |
| 576 | + | |
| 577 | + | |
| 578 | + | |
| 579 | + | |
527 | 580 | | |
528 | 581 | | |
529 | 582 | | |
| |||
1584 | 1637 | | |
1585 | 1638 | | |
1586 | 1639 | | |
1587 | | - | |
1588 | | - | |
1589 | | - | |
| 1640 | + | |
| 1641 | + | |
| 1642 | + | |
| 1643 | + | |
1590 | 1644 | | |
1591 | 1645 | | |
1592 | 1646 | | |
| |||
1640 | 1694 | | |
1641 | 1695 | | |
1642 | 1696 | | |
1643 | | - | |
1644 | | - | |
1645 | | - | |
1646 | | - | |
| 1697 | + | |
| 1698 | + | |
| 1699 | + | |
| 1700 | + | |
| 1701 | + | |
| 1702 | + | |
| 1703 | + | |
| 1704 | + | |
| 1705 | + | |
| 1706 | + | |
| 1707 | + | |
| 1708 | + | |
| 1709 | + | |
| 1710 | + | |
| 1711 | + | |
| 1712 | + | |
| 1713 | + | |
| 1714 | + | |
| 1715 | + | |
| 1716 | + | |
| 1717 | + | |
| 1718 | + | |
| 1719 | + | |
| 1720 | + | |
| 1721 | + | |
| 1722 | + | |
| 1723 | + | |
| 1724 | + | |
| 1725 | + | |
| 1726 | + | |
| 1727 | + | |
| 1728 | + | |
| 1729 | + | |
| 1730 | + | |
| 1731 | + | |
1647 | 1732 | | |
1648 | 1733 | | |
1649 | 1734 | | |
| |||
1663 | 1748 | | |
1664 | 1749 | | |
1665 | 1750 | | |
| 1751 | + | |
| 1752 | + | |
| 1753 | + | |
| 1754 | + | |
| 1755 | + | |
| 1756 | + | |
1666 | 1757 | | |
1667 | 1758 | | |
1668 | | - | |
| 1759 | + | |
1669 | 1760 | | |
1670 | 1761 | | |
1671 | 1762 | | |
1672 | 1763 | | |
1673 | 1764 | | |
1674 | 1765 | | |
1675 | 1766 | | |
1676 | | - | |
| 1767 | + | |
1677 | 1768 | | |
1678 | | - | |
1679 | | - | |
| 1769 | + | |
| 1770 | + | |
1680 | 1771 | | |
1681 | 1772 | | |
1682 | 1773 | | |
| |||
0 commit comments