Repository navigation
Commit 9d7419b
spec(types,plugin-dashboard,app-shell,plugin-designer): widgets[] entries read by the slot's element type, a typeless widget draws as
Fixes #11514
Clause-②: no (narrowing)
objectui#11514 is rescoped by the seat's answers (comment 5964120765) to
three things, all in this PR: objectui#11483's closure
(`DashboardWidgetSchema['type']` drops the component type, and every
reader of a `widgets[]` entry reads it by the slot's element type), both
`object-chart` producers named `ObjectChartSchema` with no cast, and Q2
A (what a widget with no `type`, or with a `type` that names nothing,
draws). The `object-metric` producer moved to objectui#11525 and is
untouched here. The class-a finding this PR's first report raised (a
rule-list `filter` with a structured `groupBy` draws an error) is filed
as objectui#11526.
## What changed — before and after
| | before (`fc7db059f`) | after |
|---|---|---|
| `DashboardWidgetSchema['type']` (TS face) | `DashboardWidgetTypeName
\| DashboardComponentWidgetType` | `DashboardWidgetTypeName`, the zod
twin's set |
| `{ type: 'metric-card', title }` directly in `widgets[]` | compiles
(the MEASURED LIMIT pin); both zod faces refuse | `tsc` refuses it too;
zod faces unchanged |
| read type of a `widgets[]` entry in `DashboardRenderer`,
`DashboardGridLayout`, `DashboardWithConfig`, `isLegacyRetiredWidget`
and the designer's `DashboardEditor` | `DashboardWidgetSchema` |
`DashboardComponentSchema['widgets'][number]` |
| `DashboardRendererProps['onWidgetsReorder']` parameter, and app-shell
`DashboardPreview`'s handler | `DashboardWidgetSchema[]` |
`DashboardComponentSchema['widgets']` |
| `WidgetDispatch['chartType']` | `string` | `SeriesChartFamily`: the 12
series families, each a member of `ObjectChartSchema['chartType']` |
| both `object-chart` producers | untyped literal, `chartType` typed
`string` | `satisfies ObjectChartSchema`, no cast |
| a widget with no `type`, both surfaces | the slot-component
passthrough: the red "Unknown component type" (OBJUI-001) panel;
dataset-bound with a dimension: a bar chart | draws exactly what the
same widget with `type: 'metric'` draws: inline, dataset-bound, and in
`DashboardRenderer`'s mobile metric row |
| a `type` that names no family and no component type, both surfaces |
the passthrough: the OBJUI-001 panel | the labelled placeholder
"「type」chart type is not supported yet", as `heatmap` draws |
| the slot-component passthrough | every entry no family matched | the
component arm (`metric-card`) alone, drawn as before |
| the legacy `component` envelope | its node, handed to `SchemaRenderer`
bare | the same node; a typeless envelope keeps its card heading (the
spec default is not applied to it); a number or `true` in it goes
through `toRenderableSchema`, which draws the same text |
What renders differently is exactly the two cases Q2 A lifts: a typeless
widget and an unknown-type widget. Every widget that names a known
family draws as before, and so does every legacy envelope (control
below).
## Q2 A: the ruling and how it lands
「协议为基准」: `@objectstack/spec` 17.5.0's `DashboardWidgetSchema.type`
defaults to `metric`. objectui's validator accepts a typeless widget and
does not write the default in, so the surfaces are where it resolves.
- `specDefaultWidgetType()` reads the default from the spec
(`DashboardWidgetSchema.shape.type.parse(undefined)`), not a literal; a
row pins it to `metric` at the installed spec.
- `resolveWidgetType(entry)` is the authored `type`, or that default
when the entry names none. Every read of an entry's `type` on both
surfaces goes through it: the dispatch, the metric span and
self-contained chrome, the mobile metric row. `DatasetWidget` takes the
same default.
- The legacy `component` envelope (`{ id, component, layout }`,
objectui's own format, no member on the spec's widget) is not given the
default: `resolveWidgetType` keeps `undefined` for an entry whose
`component` is truthy, the same test both surfaces use to take the
envelope branch.
- `isSlotComponentEntry(entry)` gates the passthrough to the component
arm; anything else that reaches it draws `unsupportedWidgetSchema`, the
placeholder an unsupported family already drew, now declared once for
both surfaces.
- `entryComponent(entry)` reads the envelope's `component` typed as the
widget arm declares it. A bare `entry.component` read through
`BaseSchema`'s index signature and made both `getComponentSchema`s
return `any`, which is what had let an earlier cast removal look clean.
## The `object-metric` producer
Not touched, and no type added for it: it moved to objectui#11525. The
premise measurement (branch B: the broadcast's `$and` carries the
widget's MongoDB-style `filter`, and the bar's rule list makes the
spec-shape aggregate branch draw an error) is in this card's first
`os-dev-report` (comment 5964044891). It stays red under V1, as
expected.
## V1 census
Probe: PR #11512's branch (`ff7f748e`) merged with this branch at
`2fb1b92b` through `git merge-tree` in a throwaway worktree (the one
known conflict, `zod-mirror-parity.test.ts`'s comment opener, restored
by hand). Nothing was committed or pushed from it; the worktree and its
ref are removed.
- **Cast sites:** 8 lines, the card's 4 sites in plugin-dashboard's src
and test programs: `DashboardGridLayout.tsx` 648 and 701,
`DashboardRenderer.tsx` 1077 and 1118, each in both programs. 0 new
lines. The types test program: 1 line, `node-recursion-point-8344`'s
drift ratchet, objectui#11515's (unchanged from the first report).
- **What holds them, per branch** (a probe-only annotation typing both
`getComponentSchema`s as the renderer's prop, `DeclaredNode | string |
null | undefined`): the `object-metric` branch (`DashboardGridLayout`
381, 383; `DashboardRenderer` 876, 878, 879), objectui#11525;
`plugin-dashboard:metric` (`DASHBOARD_NODE_TYPES.metric` typed `string`;
396 and 894), objectui#11466's registry entry; `DashboardGridLayout`'s
static `pivot` (472), objectui#11466. The passthrough and the
unknown-type branch: 0. The envelope branch: 0. Before the
`toRenderableSchema` bridge it was 2 (`string | number | true |
DeclaredNode`).
- The two `SchemaRenderer` casts stay: the branches they cover are
objectui#11525's and objectui#11466's.
- **Not re-probed:** the merge of `main` `9ed8d0f1` (objectui#11517)
that followed. NOT MEASURED, because rebuilding the probe means a fresh
install and closure build on a shared box. What was checked instead:
none of objectui#11517's 15 files is among V1's own 74 changed files;
`git merge-tree` of the new head with `ff7f748e` shows only the same one
conflict; and `main`'s type-check at the new head is green.
## Pins, controls, reverse verification, ablation
- `widget-type-default-and-unknown-11514.test.tsx` (12 tests). On both
surfaces: a typeless widget draws byte-for-byte what `type: 'metric'`
draws, inline and dataset-bound (the control is the explicit `metric`),
and in the mobile layout (non-vacuity: its 2-column metric row is
drawn). An unknown `type` (`gauge2`) draws the placeholder and no
OBJUI-001 panel. Controls: `heatmap` draws the same placeholder; a
`metric-card` still draws through the component arm. Plus one row: the
spec default is `metric`.
- **Reverse verification:** the three surface files at `b92e80dc`
(before Q2 A): 7 failed, 5 passed (the 5 are the controls and the
spec-default row). Restored from `HEAD`, blob-matched.
- `dashboard-producer-node-types-11514.test.tsx` (32 tests): round one's
28, plus a number and `true` in a legacy `component` envelope, on both
surfaces, drawn under the widget's heading.
- **Envelope control:** those 4 rows against the surfaces at `b92e80dc`
pass (4 passed, 28 skipped), so the envelope draws as it did.
**Ablation:** the envelope exemption removed from `resolveWidgetType`
(`ablation-replace.mjs`, anchor 1 to 0, blob `7f60e1c6` to `da48a7f9`):
all 4 rows fail. Restored: blob equal to `HEAD`, `git diff HEAD` empty.
- Round one's: the `SERIES_CHART_FAMILIES` ablation (`'gauge'` planted:
2 `tsc` errors at both `satisfies ObjectChartSchema` sites, 2 vitest
rows red), the `DashboardPreview` reverse verification (TS2322 at its
`onWidgetsReorder` prop), and the objectui#11483 `@ts-expect-error` row.
## Readers of the narrowed type
Needed an edit: plugin-dashboard's `DashboardRenderer`,
`DashboardGridLayout`, `DashboardWithConfig`, `isLegacyRetiredWidget`,
`DatasetWidget` (the default `type`), and two test readers; app-shell's
`DashboardPreview` (type-only); plugin-designer's `DashboardEditor` and
three test readers (its build went red on 3 lines once the component
type left the widget arm); the types pins for objectui#11483 and
objectui#7952 and `zod-mirror-parity`'s `KnownDrift` row; the plugin
page and the plugin-dashboard README, which taught `const widgets:
DashboardWidgetSchema[] = dashboard.widgets` and now narrow on `type`
and say what a typeless or unknown-type widget draws.
Needed nothing: core's `buildWidgetScopedFilter`, `useWidgetSubCaption`,
app-shell's `DashboardWidgetInspector`, and `apps/*`. Render suites
outside the package that mount a dashboard (app-shell's `DashboardView`
and previews, `StudioDesignSurface`, the widget DOM-leak sweep, the
schema-catalog galleries, the console's drill-down and chart-stub
suites) pass unchanged.
## Changeset sweep
- **This PR's entries:** `11514-types-widget-arm-type`
(`@object-ui/types` minor), `11514-dashboard-slot-entry-types`
(`@object-ui/plugin-dashboard` minor; now also states the typeless and
unknown-type renders, the passthrough serving the component arm, and the
envelope exemption), `11514-designer-dashboard-entry-type` and
`11514-app-shell-dashboard-preview-reorder` (patch, type-only).
- **Dated notes (2026-10-03), from round one:**
`11483-metric-card-needs-value`, `7952-dashboard-widgets-component-arm`,
`11348-dashboard-widget-reads`, `dashboard-widget-type-closed-enum`.
- **Swept again for Q2 A, no new note needed:**
`dashboard-widget-type-closed-enum` (its OBJUI-001 sentence describes
the hatch before that change, still true of it),
`8760-unfulfilled-chart-stubs` (its OBJUI-001 sentence is about a
document node, not a `widgets[]` entry),
`7952-dashboard-widgets-component-arm` ("What still refuses" is about
validation), `10859-dashboard-node-keys` and
`11483-metric-card-needs-value` (unchanged), and objectui#11517's three
entries (drill-down only).
## Acceptance notes
- **Filed by the seat:** the class-a finding (an authored
`object-metric` with a rule-list `properties.filter` and a structured
`aggregate.groupBy` draws `UnloweredAggregateWhereError` instead of its
number), as objectui#11526.
- **File surface beyond the claim's list:** plugin-designer's
`DashboardEditor` and its three tests, `DatasetWidget`, the two docs
pages, the objectui#7952 pin, the two plugin-dashboard test readers,
`isLegacyRetiredWidget`, and the static `chart` producer's `chartType`.
Each is the same retype or the Q2 A ruling, and is named above.
- **Merges of `main`:** `b92e80dc` (`8366accd1`), `9b0ec494`
(`6903eafbc`, objectui#11484's docs) and `7939c9a0` (`9ed8d0f1`,
objectui#11517). All three merged cleanly.
- The title drops "part 1": the card is rescoped to what this PR holds.
## Tests and gates, at `7939c9a0`
- `type-check` for `@object-ui/types`, `@object-ui/plugin-dashboard`,
`@object-ui/plugin-designer` and `@object-ui/app-shell` (each script
echoed, after rebuilding the designer and app-shell closures): exit 0.
- vitest, `pnpm exec vitest run packages/plugin-dashboard/`: 164 files
passed; 1591 tests passed, 6 skipped. Readers: the types pins and
objectui#11517's drill-down suites, the schema-catalog, console and
script suites (24 files, 1136 tests), and the designer and app-shell
dashboard suites (212 files, 2140 tests): all passed.
- `check:doc-snippets`: 777 of 777 blocks judged, 0 failed.
`check:doc-examples`, `check:doc-types`, `check:doc-fences`,
`check:doc-example-ids`, `check:doc-example-readers`,
`check:readme-exports`, `check:changeset-claims`,
`check:pending-changeset-literals`, `check:new-line-citations` (0 new),
`check:control-bytes`, `check:handler-key-reads`, `check:spec-symbols`,
`check:test-path-roots`, `check:component-surface-parity`,
`check:phantom-deps`, `check:esm-specifiers`,
`check:installed-pin-claims`, `check-changeset-no-major`,
`check-changeset-presence`: exit 0. Governed-surface guard over the 29
paths: NOT GOVERNED.
- `check:eager-closure` and `check:sdui-registration-pins`: NOT
MEASURED, reason: both read a built console bundle (exit 2,
precondition). The one new runtime import, `@objectstack/spec/ui` in
`widgetDispatch.ts`, is a module app-shell already imports eagerly
(`UnifiedSidebar`, `MetadataProvider`), and no registration input moved.
- eslint, narrowed to the 19 changed TS files (`eslint.config.js` lints
`**/*.{ts,tsx}` with no parser project, so it is not type-aware and this
diff cannot move an untouched file's verdict): 0 errors, 66 warnings.
The 17 files that exist at the merge base: 58 warnings there, 58 now,
file for file; the new producer pin carries 8 `no-explicit-any`, the
recorder and fixture casts. Repo-wide lint is CI's.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC)_
---------
Co-authored-by: Claude <noreply@anthropic.com>metric and an unknown type the placeholder, the object-chart producers name ObjectChartSchema (objectui#11514) (#11524)1 parent 06634af commit 9d7419b
29 files changed
Lines changed: 806 additions & 228 deletions
File tree
- .changeset
- content/docs/plugins
- packages
- app-shell/src/views/metadata-admin/previews
- plugin-dashboard
- src
- __tests__
- plugin-designer/src
- __tests__
- types/src
- __tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
| 33 | + | |
| 34 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| 15 | + | |
| 16 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
| 14 | + | |
| 15 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
| 16 | + | |
| 17 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
390 | 390 | | |
391 | 391 | | |
392 | 392 | | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
393 | 413 | | |
394 | 414 | | |
395 | 415 | | |
| |||
537 | 557 | | |
538 | 558 | | |
539 | 559 | | |
540 | | - | |
541 | | - | |
542 | | - | |
543 | | - | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
544 | 567 | | |
545 | 568 | | |
546 | | - | |
| 569 | + | |
547 | 570 | | |
548 | 571 | | |
549 | 572 | | |
550 | | - | |
551 | | - | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
552 | 576 | | |
553 | 577 | | |
554 | 578 | | |
| |||
Lines changed: 4 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
20 | | - | |
| 20 | + | |
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
| |||
76 | 76 | | |
77 | 77 | | |
78 | 78 | | |
| 79 | + | |
| 80 | + | |
79 | 81 | | |
80 | | - | |
| 82 | + | |
81 | 83 | | |
82 | 84 | | |
83 | 85 | | |
| |||
0 commit comments