Skip to content
Merged
7 changes: 7 additions & 0 deletions .changeset/10685-drilldown-per-block.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,10 @@ TSX code now fails to compile in two places. The first is a refused member insid
`ObjectDataTableSchema.drillDown`, or inside `ObjectPivotTable`'s `schema.drillDown`. The
second is a value typed as the shared `DrillDownConfig` handed to either. Delete the key.
Runtime rendering is unchanged.

⚠️ **Dated note, 2026-09-28 — the plain `pivot` node has a mirror now — objectui#10859.**
Later in this same release `PivotTableSchema` (the `pivot` node, not `object-pivot`) gains a
zod mirror whose `drillDown` is the shared `DrillDownConfigSchema`, so a validator does read
the members of a `pivot` node's `drillDown`, and accepts `mode` there, as `DrillDownConfig`
declares it. `object-pivot` still has no mirror, so what the paragraph above says of a stored
`object-pivot` config stands. The rest of this entry is kept as the reading of this change.
15 changes: 15 additions & 0 deletions .changeset/10859-pivot-object-block-zod-arms.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
'@object-ui/types': minor
---

`safeValidateSchema` — and so `objectui validate` — accepts three more registered node types: `pivot`, `object-metric` and `object-master-detail-form` (objectui#10859, batch 2).

**Clause-②: yes** — the accept set of `AnyComponentSchema` widens by three `type` literals, and `@object-ui/types/zod` exports four new schemas. Nothing that parsed before is refused now: every document naming one of these types was refused at `type`, at the root and at every child slot.

**What it was.** `pivot` is registered by `@object-ui/plugin-dashboard` and declared on the published TypeScript face (`PivotTableSchema`); `object-metric` and `object-master-detail-form` are ADR-0080 public blocks, registered by `@object-ui/plugin-dashboard` and `@object-ui/plugin-form`, whose props `@objectstack/spec` declares as `ComponentPropsMap` rows. `AnyComponentSchema` carried no arm for any of them, so every document naming one was refused with `invalid_union` at `type` — the objectstack showcase's own `object-metric` KPIs and its master-detail form page included.

**What changed, in observable terms.**

- `@object-ui/types/zod` exports `PivotTableSchema`, a member for member restatement of the TypeScript `PivotTableSchema`: `rowField`, `columnField`, `valueField` and `data` are required, as they are there; `aggregation` is one of `sum`, `count`, `avg`, `min`, `max`; `drillDown` is the shared `DrillDownConfigSchema`; `body` and `children` are refused by name, as the declaration's `?: never` members refuse them (objectui#9256). `DataDisplaySchema` lists it.
- `@object-ui/types/zod` exports `ObjectMetricBlockSchema` and `ObjectMasterDetailFormBlockSchema`, built the way the objectui#10872 public-block arms are: `BaseSchema`, the `type` literal, and `properties`, which is the block's `ComponentPropsMap` row by reference, so the spec's members, value types and strictness apply to the bag unchanged. `ObjectMasterDetailFormBlockSchema` also refuses `onSuccess`, `onError` and `onCancel` by name: they are runtime slots a React host fills (objectui#6124). Both reach `AnyComponentSchema` through a new union, `ObjectQLPublicBlockComponentSchema`.
- The strict authoring face (`StrictAnyComponentSchema`) derives from `AnyComponentSchema` and accepts the same three types, closed to undeclared keys like every other arm. As on the public blocks, a prop written flat on an `object-metric` or `object-master-detail-form` node instead of inside `properties` is not judged against the spec row. A key `BaseSchema` does not declare passes the tolerant face unjudged and is refused by name on the strict face; a key it does declare (`label` and `description`, both also members of the `object-metric` row) is judged by `BaseSchema`'s own type on both faces.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
---

Test-only, no package released: `RelatedList.unmaterializedSort.test.tsx`'s case "keeps that button in
client mode" now awaits the object schema before it reads the `Total` sort button. Since
objectui#10728 the sort-button row reads the masked stamp, which covers every column until
`getObjectSchema` resolves, and the case gated only on the view type, which client mode reaches on the
first commit. So whether the button existed when it was read depended on scheduling; on one merge-queue
build it did not (objectui#10895). No source file changes.
5 changes: 5 additions & 0 deletions .changeset/7352-drill-down-config-mirror.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,8 @@ The blocks now take per-block drill shapes. `mode` is read only by
(`ObjectMetricDrillDownConfig`, objectui#9002), whose click points are always
aggregates. `report` is read by `object-pivot` and `object-metric`, through the
drawer they open. The rest of this entry is kept as the reading of this change.

⚠️ **Dated note, 2026-09-28 — `PivotTableSchema` has a mirror now — objectui#10859.**
Later in this same release `PivotTableSchema` gains a zod mirror, and its `drillDown`
is this entry's `DrillDownConfigSchema`, so the opening paragraph's two referencing declarations are three for the release, and the first half of the second "Unchanged" bullet above (`PivotTableSchema.drillDown` has no zod mirror at all) is this change's reading, not the release's. The rest of this entry is kept as
the reading of this change.
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,11 @@ import { validate } from '../commands/validate.js';

/**
* The head's refused count (objectui#10859 batch 1: 79 on `main` before it,
* minus the three `@object-ui/plugin-ai` arms). LOWER it when a batch arms more
* keys; never raise it.
* minus the three `@object-ui/plugin-ai` arms; batch 2: minus `pivot`,
* `object-metric` and `object-master-detail-form`). LOWER it when a batch arms
* more keys; never raise it.
*/
const REFUSED_AT_TYPE = 76;
const REFUSED_AT_TYPE = 73;

/**
* The head's refused count over the NAMESPACED keys (objectui#10872 batch 1:
Expand Down Expand Up @@ -144,6 +145,13 @@ describe('registered component types refused at `type` — a ratchet (objectui#1
expect(refusedAtType(key), key).toBe(false);
}
});

it('counts the three keys batch 2 armed (objectui#10859 batch 2)', () => {
for (const key of ['pivot', 'object-metric', 'object-master-detail-form']) {
expect(BARE_KEYS, key).toContain(key);
expect(refusedAtType(key), key).toBe(false);
}
});
});

describe('registered NAMESPACED component types refused at `type` — a ratchet (objectui#10872)', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,11 @@ describe('RelatedList — the sort-button row for a `list` card (#3950)', () =>
});

it('keeps that button in client mode', async () => {
renderList({ type: 'list', data: items });
const dataSource = renderList({ type: 'list', data: items });
await waitFor(() => expect(h.schema?.type).toBe('data-list'));
// Since objectui#10728 the sort-button row reads the masked stamp, which
// covers every column until the object schema lands (#7007).
await settleObjectSchema(dataSource);

expect(screen.getByRole('button', { name: /Total/ })).toBeTruthy();
});
Expand Down
9 changes: 9 additions & 0 deletions packages/types/src/__tests__/imported-defaults-8317.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ import {
ChartDrillDownSchema as SpecChartDrillDownSchema,
UserFilterFieldSchema as SpecUserFilterFieldSchema,
ViewFilterRuleSchema as SpecViewFilterRuleSchema,
// objectui#10859 batch 2 — the `ComponentPropsMap` rows of the two public
// blocks `objectql.zod.ts` arms.
ObjectMetricPropsSchema as SpecObjectMetricPropsSchema,
ObjectMasterDetailFormPropsSchema as SpecObjectMasterDetailFormPropsSchema,
// objectui#10872 — the `ComponentPropsMap` rows the public-block arms read.
PageHeaderProps as SpecPageHeaderProps,
PageTabsProps as SpecPageTabsProps,
Expand Down Expand Up @@ -228,6 +232,11 @@ const IMPORTED: Array<readonly [string, z.ZodType]> = [
// `listViews` record, crossed through this boundary, so the container is
// measured here like every other crossing.
['ViewSchema', SpecViewSchema],
// objectui#10859 batch 2: the `object-metric` and `object-master-detail-form`
// arms' `properties` are their `ComponentPropsMap` rows, crossed through this
// boundary, so both rows are measured here like every other crossing.
['ObjectMetricPropsSchema', SpecObjectMetricPropsSchema],
['ObjectMasterDetailFormPropsSchema', SpecObjectMasterDetailFormPropsSchema],
// objectui#10872: each ADR-0080 public-block arm's `properties` is the
// block's `ComponentPropsMap` row, crossed through this boundary, so every
// row is measured here like every other crossing (`page:section`,
Expand Down
Loading
Loading