diff --git a/.changeset/11880-element-datasource-only.md b/.changeset/11880-element-datasource-only.md index 8321a1e5fe..525bb8153e 100644 --- a/.changeset/11880-element-datasource-only.md +++ b/.changeset/11880-element-datasource-only.md @@ -6,7 +6,7 @@ `element:record_picker` and `element:number` bind data through the node-level `dataSource` only (objectui#11880, part of the objectui half of objectstack#11509, ruled A-narrow). -- Neither element reads the flat `properties.object` / `filter` / `sort` / `limit` beside the binding any more: the `composed?.x ?? props.x` fallbacks are gone, and `element:number`'s filter is the binding's alone (the AND with `properties.filter` is gone). An element whose node names no `dataSource.object` issues no query. The flat keys stay published until `@objectstack/spec` retires them in v18; each input's description now says it is not read and names the binding member that is. +- Neither element reads the flat `properties.object` / `filter` / `sort` / `limit` beside the binding any more: the `composed?.x ?? props.x` fallbacks are gone, and `element:number`'s filter is the binding's alone (the AND with `properties.filter` is gone). An element whose node names no `dataSource.object` issues no query. The flat keys stayed published, each input's description saying it is not read and naming the binding member that is, until `@objectstack/spec` retired them in 18: the record picker's four inputs left with that retirement (objectui#12030), and `element:number`'s two with objectui#12085. - The Studio page designer writes `element:number`'s object to `dataSource.object` at node level, and its measure picker reads the object from there. A stored `properties.object` stays visible in the inspector's Advanced section. - `element.number.noObject` now names only `dataSource.object`, in all ten language packs. diff --git a/.changeset/11880-grid-filter-handoff.md b/.changeset/11880-grid-filter-handoff.md index 9f4678247c..729e2ce4ba 100644 --- a/.changeset/11880-grid-filter-handoff.md +++ b/.changeset/11880-grid-filter-handoff.md @@ -4,11 +4,11 @@ An `object-view` grid now exports the filter it shows, and returns to page 1 when that filter changes (objectui#11880, item 5). -`ObjectView` hands the grid it draws one filter slot, `filter`, carrying the whole chain: the active named view's filter, else `table.filter` unless it lowers to nothing (absent, `[]` or `{}`), else the deprecated `table.defaultFilters`. It no longer writes `defaultFilters` on that grid node, which `@objectstack/spec` retires on `object-grid` (objectstack#11509). +`ObjectView` hands the grid it draws one filter slot, `filter`, carrying the whole chain: the active named view's filter, else `table.filter` unless it lowers to nothing (absent, `[]` or `{}`), else the deprecated `table.defaultFilters` (a rung retired in 18, see objectui#12030: `ObjectView` no longer reads it). It no longer writes `defaultFilters` on that grid node, which `@objectstack/spec` retires on `object-grid` (objectstack#11509). Two user-visible corrections, both on an `object-view` rendered by the registered renderer (a page node, the Studio's stored-view preview; a host that supplies `renderListView` already behaved this way): - **The export carries the view's filter.** A named view's filter and an authored `table.defaultFilters` narrowed the rows on screen, but the server-streamed export (CSV, XLSX, JSON) was handed no filter and downloaded every record of the object. It now downloads the rows the view shows, as it already did for `table.filter`. - **Changing the filter returns the grid to page 1.** When a named view's filter or `table.defaultFilters` changed while the grid stayed mounted, the next query kept the old page index, which could ask for a page the new result does not have. It now returns to page 1, as `table.filter` already did. -What did not change: which filter applies (each rung and each pair sends the same query and draws the same rows), and a refused filter still draws the grid's malformed-filter panel and queries nothing. Nothing is added to or removed from any published type, schema or export. +What did not change: which filter applies (each rung and each pair sends the same query and draws the same rows; in 18 the `table.defaultFilters` rung is retired, see objectui#12030), and a refused filter still draws the grid's malformed-filter panel and queries nothing. Nothing is added to or removed from any published type, schema or export. diff --git a/.changeset/11880-repeater-datasource.md b/.changeset/11880-repeater-datasource.md index c2d1fa3e0d..d5c6c3c46b 100644 --- a/.changeset/11880-repeater-datasource.md +++ b/.changeset/11880-repeater-datasource.md @@ -5,5 +5,5 @@ `element:repeater` reads the node-level `dataSource` binding first (objectui#11880, the repeater half of the objectui step of objectstack#11509, ruled A-narrow). -- **Renderer (`@object-ui/components`).** A repeater bound only through `dataSource` now lists the records it names; it showed "No records" before. Its flat `properties.object` / `filter` / `sort` / `limit` stay read, as the fallback, until `@objectstack/spec` retires them in v18, so a repeater that carries only the flat keys reads exactly as before. Where a node carries both, the precedence is the one `ElementDataSourceGate` applies to every object-bound block: the binding's `object`; the flat `filter` AND-combined with the binding's (and its saved view's), so neither is dropped; the binding's own `sort` and `limit`, else the flat key, else the saved view's. An unresolvable `view`, or a filter the merge refuses, shows the configuration-error panel and reads nothing. The registration now publishes the injected `dataSource` input; `object` stays required. -- **Schema (`@object-ui/types`).** `ElementRepeaterBlockSchema` declares `dataSource` as `@objectstack/spec`'s `ElementDataSourceSchema`, by reference, and its bag's `object` stays required. Clause-②: the strict authoring face (`StrictAnyComponentSchema`) now ACCEPTS a repeater carrying `properties.object` plus a well-formed `dataSource`, which it refused as an unrecognized key; and the tolerant face (`safeValidateSchema`) now JUDGES the binding, so a repeater whose `dataSource` the spec's own node schema refuses (a string, a non-string `object`, an undeclared member, a record-form `filter`) is refused at `dataSource` where it was passed through unjudged. The TypeScript node type derived from the arm types the binding. A repeater whose bag omits `object` is refused at `properties.object` on both faces, as before. +- **Renderer (`@object-ui/components`).** A repeater bound only through `dataSource` now lists the records it names; it showed "No records" before. Its flat `properties.object` / `filter` / `sort` / `limit` stay read, as the fallback (spec 18 retires them as authored keys, see objectui#12030, and the renderer keeps this read for metadata written before), so a repeater that carries only the flat keys reads exactly as before. Where a node carries both, the precedence is the one `ElementDataSourceGate` applies to every object-bound block: the binding's `object`; the flat `filter` AND-combined with the binding's (and its saved view's), so neither is dropped; the binding's own `sort` and `limit`, else the flat key, else the saved view's. An unresolvable `view`, or a filter the merge refuses, shows the configuration-error panel and reads nothing. The registration now publishes the injected `dataSource` input; `object` stays required (until objectui#12085 dropped the flat query inputs). +- **Schema (`@object-ui/types`).** `ElementRepeaterBlockSchema` declares `dataSource` as `@objectstack/spec`'s `ElementDataSourceSchema`, by reference, and its bag's `object` stays required (until objectui#12056's waiver, and retired in 18, see objectui#12030). Clause-②: the strict authoring face (`StrictAnyComponentSchema`) now ACCEPTS a repeater carrying `properties.object` plus a well-formed `dataSource`, which it refused as an unrecognized key (since 18 it refuses `properties.object` by name, so the accepted node carries the binding alone); and the tolerant face (`safeValidateSchema`) now JUDGES the binding, so a repeater whose `dataSource` the spec's own node schema refuses (a string, a non-string `object`, an undeclared member, a record-form `filter`) is refused at `dataSource` where it was passed through unjudged. The TypeScript node type derived from the arm types the binding. A repeater whose bag omits `object` is refused at `properties.object` on both faces, as before; retired in 18, see objectui#12030: such a repeater is accepted. diff --git a/.changeset/12030-console-bundles-spec-18.md b/.changeset/12030-console-bundles-spec-18.md new file mode 100644 index 0000000000..a2b0df40cf --- /dev/null +++ b/.changeset/12030-console-bundles-spec-18.md @@ -0,0 +1,6 @@ +--- +"@object-ui/console": minor +"@object-ui/runner": minor +--- + +The console and the runner bundles are built against `@objectstack/*` 18.0.0-next.0 (objectui#12030). In both, the `@objectstack/*` ranges are `devDependencies`, but each package is an app build whose published `dist` bundles them, together with the `@object-ui/*` packages it compiles from source. So the shipped console and runner now carry the 18 prerelease line and the `@object-ui/*` changes that follow it. diff --git a/.changeset/12030-i18n-capability-labels.md b/.changeset/12030-i18n-capability-labels.md new file mode 100644 index 0000000000..6a36844994 --- /dev/null +++ b/.changeset/12030-i18n-capability-labels.md @@ -0,0 +1,7 @@ +--- +"@object-ui/i18n": minor +--- + +The ten locale packs follow `@objectstack/spec` 18's platform capability set (objectui#12030): the key `capability.label.manage_org_presentation` is replaced by `capability.label.manage_mailboxes`, as spec 18 retires `manage_org_presentation` from `PLATFORM_CAPABILITIES` and adds `manage_mailboxes`. + +**For consumers:** a reader of `capability.label.manage_org_presentation` now gets no translation, and the exported `TranslationKeys` type loses that key and gains the new one. Scored `minor`, not `patch`, because a key a consumer could read is replaced; objectui's own breaking changes ship as `minor` (AGENTS.md §版本号策略). diff --git a/.changeset/12030-objectstack-next-18.md b/.changeset/12030-objectstack-next-18.md new file mode 100644 index 0000000000..94e36325c7 --- /dev/null +++ b/.changeset/12030-objectstack-next-18.md @@ -0,0 +1,38 @@ +--- +"@object-ui/app-shell": minor +"@object-ui/auth": minor +"@object-ui/cli": minor +"@object-ui/components": minor +"@object-ui/core": minor +"@object-ui/data-objectstack": minor +"@object-ui/fields": minor +"@object-ui/layout": minor +"@object-ui/permissions": minor +"@object-ui/plugin-chatbot": minor +"@object-ui/plugin-dashboard": minor +"@object-ui/plugin-designer": minor +"@object-ui/plugin-detail": minor +"@object-ui/plugin-form": minor +"@object-ui/plugin-gantt": minor +"@object-ui/plugin-grid": minor +"@object-ui/plugin-list": minor +"@object-ui/plugin-timeline": minor +"@object-ui/plugin-tree": minor +"@object-ui/plugin-view": minor +"@object-ui/react": minor +"@object-ui/types": minor +--- + +Depend on the `@objectstack/*` 18 prerelease line (objectui#12030). + +Every `@objectstack/*` range these packages declare in `dependencies` or `peerDependencies` moves from `^17.x` to `^18.0.0-next.0`, the `next` prerelease of `@objectstack/*` 18. + +**Breaking for consumers:** an install that resolves `@objectstack/spec` (or `@objectstack/client`, `@objectstack/formula`, `@objectstack/lint`) 17.x no longer satisfies these ranges. A consumer must move its own `@objectstack/*` packages to the 18 line, starting with `18.0.0-next.0`, at the same time as it takes this release. + +**objectui's own surface moves with it:** + +- `element:record_picker`'s registration stops publishing the `object`, `filter`, `sort` and `limit` inputs, which spec 18 retires; a JSX page that writes one now gets `unknown-prop`. +- The `CapabilityMultiSelectField` widget's curated capability set (`@object-ui/fields`) follows spec 18: `manage_mailboxes` in, `manage_org_presentation` out. +- `element:number` and `element:repeater` nodes that bind no object are accepted, as spec 18's row and `PageComponentSchema` accept them; the two `ELEMENT_*_OBJECT_REQUIRED` refusals are gone. + +**Retired with the spec:** `@objectstack/spec` 18 tombstones `object-grid`'s `defaultFilters` and refuses it by name, and `ObjectGrid` and `ObjectView` stop reading it (`table.defaultFilters` on an `object-view` included). A view that still carries it renders unfiltered: rename the key to `filter`, whose value is the same rule array. diff --git a/.changeset/12056-repeater-datasource.md b/.changeset/12056-repeater-datasource.md index 64aac80132..75d2ed9f36 100644 --- a/.changeset/12056-repeater-datasource.md +++ b/.changeset/12056-repeater-datasource.md @@ -4,7 +4,7 @@ The page designer writes a repeater's query into its node-level `dataSource` binding, as it already does for `element:number` (objectui#12056, the repeater half of objectui#11880). -In the page-block inspector, an `element:repeater`'s Object picker now writes `dataSource.object` and its Limit box writes `dataSource.limit`. They used to write `properties.object` and `properties.limit`, the flat keys `@objectstack/spec` retires in v18 (objectstack#11509). The repeater's Title field and Fields pickers now list the fields of the object in `dataSource.object`. The Empty text and Dividers between rows controls still write `properties`. The repeater's renderer already reads the binding first (objectui#11880), and `objectui validate` accepts the node the designer now writes, because `@object-ui/types` takes the spec gate's `object` waiver for this element in the same change. +In the page-block inspector, an `element:repeater`'s Object picker now writes `dataSource.object` and its Limit box writes `dataSource.limit`. They used to write `properties.object` and `properties.limit`, the flat keys `@objectstack/spec` retires in v18 (objectstack#11509). The repeater's Title field and Fields pickers now list the fields of the object in `dataSource.object`. The Empty text and Dividers between rows controls still write `properties`. The repeater's renderer already reads the binding first (objectui#11880), and `objectui validate` accepts the node the designer now writes: `@object-ui/types` took the spec gate's `object` waiver for this element in the same change, and since 18 (objectui#12030) the row has no flat `object` left to require. A repeater already stored with a flat `properties.object` or `properties.limit` is not migrated. The inspector shows the binding's values in the curated controls, and a stored flat key stays visible and editable under Advanced. diff --git a/.changeset/12056-repeater-object-waiver.md b/.changeset/12056-repeater-object-waiver.md index e96d074753..1a77afb296 100644 --- a/.changeset/12056-repeater-object-waiver.md +++ b/.changeset/12056-repeater-object-waiver.md @@ -2,12 +2,12 @@ '@object-ui/types': minor --- -An `element:repeater` node may omit `properties.object` when its `dataSource.object` names the object. The zod arm `ElementRepeaterBlockSchema` now applies the same `object` waiver as the spec's props gate (objectui#12056). +An `element:repeater` node may omit `properties.object` when its `dataSource.object` names the object. The zod arm `ElementRepeaterBlockSchema` now applies the same `object` waiver as the spec's props gate (objectui#12056); superseded in 18, see objectui#12030: spec 18 retires the flat `object`, so the arm is the row by reference, a node may omit `properties.object` whether or not it binds one, and a `properties.object` is refused by name. -`ComponentPropsMap['element:repeater']` requires `object`. The spec's props gate in `@objectstack/lint` (`suppliedByDataSource`) does not report a missing `object` on any component whose `dataSource.object` is a non-empty name. `ElementNumberBlockSchema` already applies that waiver. The repeater arm did not, so it refused the node the Studio page designer now writes: `properties: {}` beside `dataSource: { object: … }`. The arm now applies the waiver the same way `element:number`'s does. The bag is the spec row with `object` alone made optional, and a node refinement puts the requirement back wherever no binding names the object. +`ComponentPropsMap['element:repeater']` required `object` through 17.x. The spec's props gate in `@objectstack/lint` (`suppliedByDataSource`) does not report a missing `object` on any component whose `dataSource.object` is a non-empty name. `ElementNumberBlockSchema` already applies that waiver. The repeater arm did not, so it refused the node the Studio page designer now writes: `properties: {}` beside `dataSource: { object: … }`. The arm now applies the waiver the same way `element:number`'s does. The bag is the spec row with `object` alone made optional, and a node refinement puts the requirement back wherever no binding names the object. Both waivers and both refinements are gone in 18 (objectui#12030): the row has no flat `object` left to waive. - **WIDENS, both zod faces.** The strict face (`StrictAnyComponentSchema`, which `objectui validate` and `objectui check` run) and the tolerant face (`safeValidateSchema`) used to refuse such a repeater at `properties.object`, whatever its `dataSource` said. Both now accept it when `dataSource.object` is a non-empty string. -- **Still refused at `properties.object`.** A bag with no `object` is refused when the node has no binding that names one: no `dataSource`, or a `dataSource.object` that is empty or not a string. The refusal is a `custom` issue with `params.code` `ELEMENT_REPEATER_OBJECT_REQUIRED`, and its message names both remedies. A `properties.object` of the wrong type is still refused by the row itself. -- **TypeScript.** The inferred `ElementRepeaterBlockSchema` type now types `properties.object` as optional, and so does the authoring type `PublicBlockNodeOf<'element:repeater'>` derived from it. +- **Still refused at `properties.object` through 17.x.** A bag with no `object` was refused when the node had no binding that names one: no `dataSource`, or a `dataSource.object` that is empty or not a string. The refusal was a `custom` issue with `params.code` `ELEMENT_REPEATER_OBJECT_REQUIRED`, and its message named both remedies; retired in 18, see objectui#12030: the refinement and its code are deleted, so such a bag is accepted. A `properties.object` of the wrong type is still refused by the row itself, and since 18 so is any `properties.object`, by name. +- **TypeScript.** The inferred `ElementRepeaterBlockSchema` type typed `properties.object` as optional through 17.x, and so did the authoring type `PublicBlockNodeOf<'element:repeater'>` derived from it; since 18 (objectui#12030) both follow the row, which retires `object`, so a typed `properties.object: string` no longer type-checks. **Clause-② yes (widening):** a strict face widens to the spec gate's rule. No export is added or removed. diff --git a/.changeset/12093-spec-main-compile.md b/.changeset/12093-spec-main-compile.md index 960a6c41a4..f1d0c25024 100644 --- a/.changeset/12093-spec-main-compile.md +++ b/.changeset/12093-spec-main-compile.md @@ -1,4 +1,4 @@ --- --- -No release. objectui#12093 makes objectui compile against `@objectstack/spec` built from objectstack `main` (the Spec Main Shape Gate) while it keeps compiling, unchanged, against the installed release. The edits are tests, plus two type-only source edits with no runtime effect: `@object-ui/plugin-view`'s `ObjectView` reads the deprecated `table.defaultFilters` through a typed legacy read (the same value, read the same way, now typed by the rule-array shape legacy metadata carries rather than by the row's declaration, a retired-key tombstone on objectstack `main`), and `@object-ui/app-shell`'s zh-CN overlay-scope label table keys `org` beside the spec's union (objectstack `main` narrows that union to `env`). +No release. objectui#12093 makes objectui compile against `@objectstack/spec` built from objectstack `main` (the Spec Main Shape Gate) while it keeps compiling, unchanged, against the installed release. The edits are tests, plus two type-only source edits with no runtime effect: `@object-ui/plugin-view`'s `ObjectView` reads the deprecated `table.defaultFilters` through a typed legacy read (the same value, read the same way, now typed by the rule-array shape legacy metadata carries rather than by the row's declaration, a retired-key tombstone on objectstack `main`; the read itself is retired in 18, see objectui#12030), and `@object-ui/app-shell`'s zh-CN overlay-scope label table keys `org` beside the spec's union (objectstack `main` narrows that union to `env`; the `org` label is dropped in 18, see objectui#12030). diff --git a/.changeset/6152-grid-default-filters-gantt-map-filter.md b/.changeset/6152-grid-default-filters-gantt-map-filter.md index 3f8d70f130..692f321632 100644 --- a/.changeset/6152-grid-default-filters-gantt-map-filter.md +++ b/.changeset/6152-grid-default-filters-gantt-map-filter.md @@ -10,39 +10,44 @@ feat(types)!: `ObjectGridSchema.defaultFilters` and the flat `ObjectGanttSchema` Clause-②: yes -`@objectstack/spec` has typed `ComponentPropsMap['object-grid'].defaultFilters` as the same -`ViewFilterRule` array as `filter`, `[{ field, operator, value }, ...]`, since 17.6.0: the legacy -fallback `ObjectGrid` reads only when `filter` is absent, refusing the MongoDB-style record, a bare -string and the AST tuple array. The `object-gantt` and `object-map` rows type `filter` the same +`@objectstack/spec` typed `ComponentPropsMap['object-grid'].defaultFilters` as the same +`ViewFilterRule` array as `filter`, `[{ field, operator, value }, ...]`, from 17.6.0 until 18 +retired it (see objectui#12030): the legacy fallback `ObjectGrid` read only when `filter` was +absent, refusing the MongoDB-style record, a bare string and the AST tuple array. The `object-gantt` and `object-map` rows type `filter` the same way. `@object-ui/types` now takes each row's own member by reference, on the TypeScript interface and on the zod mirror, with no alias window. **Widened.** `ObjectGridSchema.defaultFilters` was `Record` and `z.record(z.string(), z.any())`, so the zod mirror REFUSED the rule array the row declares. The flat grid mirror is the source of an `object-view`'s `table` slot, so -`table: { defaultFilters: [{ field: 'status', operator: 'equals', value: 'open' }] }` now parses -there, on the tolerant and the strict face and through `safeValidateSchema`. +`table: { defaultFilters: [{ field: 'status', operator: 'equals', value: 'open' }] }` parsed +there through 17.x, on the tolerant and the strict face and through `safeValidateSchema`; retired +in 18, see objectui#12030: the row's tombstone refuses `defaultFilters` by name, so every value, +the rule array included, is refused there now. **Narrowed (breaking).** - The record form of `defaultFilters` is refused: on the interface (a compile error, in an `object-view`'s `table` too) and on the zod mirror, at `defaultFilters` (`table.defaultFilters` - in an `object-view`), with the protocol's own message, which computes the rule array from the - record's keys. Respell + in an `object-view`), with the protocol's own message, which computed the rule array from the + record's keys through 17.x (since 18, see objectui#12030, it is the retired-key message, which + names `filter`). Respell `defaultFilters: { status: 'open' }` as - `defaultFilters: [{ field: 'status', operator: 'equals', value: 'open' }]`, or, better, move it - to `filter`, which takes the same array and wins when both are written. + `filter: [{ field: 'status', operator: 'equals', value: 'open' }]`; the rule-array + `defaultFilters` spelling this entry first offered is retired in 18 too. - `ObjectGanttSchema.filter` and `ObjectMapSchema.filter` were `any[]` and `z.array(z.any())`, so `filter: [['status', '=', 'open']]` type-checked and parsed. Both are the row's rule array now; respell the tuple as `[{ field: 'status', operator: 'equals', value: 'open' }]`. These two flat types describe the node as the renderers read it: an authored `object-gantt` / `object-map` node's `properties` bag is the row itself, which refused the tuple array already. -What did not move: the renderers' reads. `ObjectGrid` lowers `defaultFilters` through the same -`toFilterNode` sink as `filter`, so a rule array there sends the same `$filter` and draws the same -rows as the same array written as `filter`; the sink still lowers a record or an AST that reaches -the slot at runtime, and `ObjectGantt` / `ObjectMap` still forward an AST a host composes. The +What did not move: the renderers' reads. `ObjectGrid` lowered `defaultFilters` through the same +`toFilterNode` sink as `filter`, so a rule array there sent the same `$filter` and drew the same +rows as the same array written as `filter` (retired in 18, see objectui#12030: `ObjectGrid` and +`ObjectView` no longer read `defaultFilters`, so a view that still carries it renders unfiltered); +the sink still lowers a record or an AST that reaches `filter` at runtime, and `ObjectGantt` / `ObjectMap` still forward an AST a host composes. The `@object-ui/core`, `@object-ui/plugin-grid` and `@object-ui/plugin-view` entries are comment repairs to sentences that called the key `Record`. `@object-ui/plugin-grid`, `@object-ui/plugin-view` and `@object-ui/plugin-map` also carry typed test fixtures re-spelled to -the rule array, and `@object-ui/plugin-grid` a pin of the above through the real renderer. +the rule array, and `@object-ui/plugin-grid` a pin of the above through the real renderer (since +18 it pins that `defaultFilters` is not read). diff --git a/.changeset/7611-approver-registry-read.md b/.changeset/7611-approver-registry-read.md index 653baa0253..0b296c06c8 100644 --- a/.changeset/7611-approver-registry-read.md +++ b/.changeset/7611-approver-registry-read.md @@ -6,4 +6,4 @@ A position approver is read through the spec's registry binding, `{ source: 'reg - **The approval panel and the override dialog.** When the bundled spec binds `position` to the registry (the console objectstack ships injects that spec), a pending `position:` approver now reads as the position's label, read through the console's metadata store (`ensureType('position')`), else as the prettified name. It used to fall through to the opaque-id truncation and read `positi…ager`. Who holds the seat is still read from `sys_user_position`. - **The flow designer's approver Value cell.** A `registry` entry in the approval node's published `xRef.sources` is no longer dropped. A kind bound that way renders a select over that metadata type's items (`GET /api/v1/meta/`) and commits the item's name, with a manual-entry toggle; a stored name the registry does not list shows flagged `(not found)`, and an empty registry leaves the text box. It used to fall back to a lookup over `sys_position` rows, or to a plain text box on the console objectstack ships. -- **Unchanged.** A `data` binding (`user`, `team`, `department`, and `position` under the installed spec 17.7.0) still renders the record lookup and still resolves its label from its directory object. No authoring surface changes, so `objectui validate` and the strict faces are unchanged. The type that admits the registry member before the installed spec declares it is marked for removal when objectui moves to spec 18. +- **Unchanged.** A `data` binding (`user`, `team`, `department`, and `position` under spec 17.7.0; spec 18, which objectui installs from objectui#12030, binds `position` to the registry) still renders the record lookup and still resolves its label from its directory object. No authoring surface changes, so `objectui validate` and the strict faces are unchanged. The type that admitted the registry member before the installed spec declared it was marked for removal when objectui moves to spec 18; removed in 18, see objectui#12030. diff --git a/QUICK_REFERENCE.md b/QUICK_REFERENCE.md index f03ff44a53..181eafc2db 100644 --- a/QUICK_REFERENCE.md +++ b/QUICK_REFERENCE.md @@ -126,9 +126,9 @@ behind (objectui#5394 — that had happened once per release, three times). - **Version:** 17.7.0 (the version every `@object-ui/*` manifest carries — they are one `fixed` group in `.changeset/config.json`, so a release moves all of them together) -- **Spec:** `@objectstack/spec` ^17.0.0 (declared by the root `package.json` and by +- **Spec:** `@objectstack/spec` ^18.0.0-next.0 (declared by the root `package.json` and by `apps/console/package.json`) -- **Client:** `@objectstack/client` ^17.3.0 (declared by `apps/console/package.json` +- **Client:** `@objectstack/client` ^18.0.0-next.0 (declared by `apps/console/package.json` and `packages/data-objectstack/package.json`) - **Node.js:** ≥ 22.13 (see root `engines.node`) - **pnpm:** ≥ 10 (the workspace pins `pnpm@10.31.0` via `packageManager`) diff --git a/apps/console/package.json b/apps/console/package.json index 23993d7e9c..f81889ba13 100644 --- a/apps/console/package.json +++ b/apps/console/package.json @@ -91,9 +91,9 @@ "@object-ui/react": "workspace:*", "@object-ui/test-support": "workspace:*", "@object-ui/types": "workspace:*", - "@objectstack/client": "^17.3.0", - "@objectstack/lint": "^17.0.0", - "@objectstack/spec": "^17.0.0", + "@objectstack/client": "^18.0.0-next.0", + "@objectstack/lint": "^18.0.0-next.0", + "@objectstack/spec": "^18.0.0-next.0", "@tailwindcss/postcss": "^4.3.3", "@tailwindcss/typography": "^0.5.20", "@testing-library/jest-dom": "^7.0.1", diff --git a/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts b/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts index 1e2b465485..f2f81f3dd5 100644 --- a/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts +++ b/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts @@ -976,6 +976,12 @@ const UNJUDGED_SPEC_BLOCKS: Record = { 'EMPTY SPEC SHAPE. New in `@objectstack/spec` 17.3.0, which declares it with no top-level key at all. Registered propless by `@object-ui/app-shell` (`src/console/marketplace/InstalledListWidget.tsx`), outside this file\'s import graph; the empty shape is the load-bearing half either way. objectui#7122, ledger objectui#8176.', 'mcp:connect-agent': 'EMPTY SPEC SHAPE. New in `@objectstack/spec` 17.3.0, which declares it with no top-level key at all. Registered propless by `@object-ui/app-shell` (`src/console/connect/ConnectAgentWidget.tsx`), outside this file\'s import graph; the empty shape is the load-bearing half either way. objectui#7122, ledger objectui#8176.', + 'record:approval_decision': + 'EMPTY SPEC SHAPE. New in `@objectstack/spec` 18 (objectui#12030), which declares it with no top-level key at all, so neither direction has a question to ask. `ApprovalDecisionRenderer` (`@object-ui/app-shell` `src/views/approval-decision/ApprovalDecisionPanel.tsx`) is written, and no registration mounts it yet; the empty shape is the load-bearing half either way. objectui#12030, ledger objectui#8176.', + 'record:approvals': + 'EMPTY SPEC SHAPE. New in `@objectstack/spec` 18 (objectui#12030), which declares it with no top-level key at all. Registered by `@object-ui/app-shell` (`src/views/record-approvals-renderer.tsx`), outside this file\'s import graph; the empty shape is the load-bearing half either way, exactly as for `app:launcher` above. objectui#12030, ledger objectui#8176.', + 'record:attachments': + 'EMPTY SPEC SHAPE. New in `@objectstack/spec` 18 (objectui#12030), which declares it with no top-level key at all. Registered by `@object-ui/app-shell` (`src/views/record-attachments-renderer.tsx`), outside this file\'s import graph; the empty shape is the load-bearing half either way, exactly as for `app:launcher` above. objectui#12030, ledger objectui#8176.', // The fourth class, and the only one that is not mechanically "unjudgeable": // OWED. The 17.5.0 bump booked four blocks here — new in that spec, registered // with `registerLazy` by the console (`register-plugins.ts`) and not loaded by @@ -1274,7 +1280,7 @@ const UNPUBLISHED_EXEMPTIONS: Record = { // five extra (`showPagination`, `defaultSort`, `defaultFilters`, // `resizableColumns`, `title`) are the same class by the same test, so they are // carved out with it. `defaultSort` has since been harvested — spec 17.3.0 - // tombstoned it (see the note below), and `resizableColumns` followed at 17.7.0, leaving eight. Trimming back to exactly five is a one-line reversal + // tombstoned it (see the note below), `resizableColumns` followed at 17.7.0 and `defaultFilters` at 18 (objectui#12030), leaving seven. Trimming back to exactly five is a one-line reversal // (delete the entry, declare the input); publishing first and withdrawing later // is not, which is why the exemption is the direction taken while the card is // open. @@ -1311,8 +1317,14 @@ const UNPUBLISHED_EXEMPTIONS: Record = { * declared already, and publishing a key the contract rejects by name is the * one resolution the test below forbids in so many words. */ - 'object-grid.defaultFilters': - '@deprecated in ObjectGridSchema ("Use filter instead"); GA describes it as the "Legacy base-filter fallback, read only when `filter` is absent. Prefer `filter`". Read as back-compat, deliberately not published — the canonical `filter` IS declared. Same ruled carve-out class as the five the ruling enumerated, measured on this branch — objectui#4648 (maintainer 2026-08-16).', + /* + * `object-grid.defaultFilters` WAS THE ELEVENTH TOMBSTONE HARVESTED HERE — + * `@objectstack/spec` 18 (objectstack#11509, objectui#12030), the way + * `defaultSort` above was at 17.3.0 and `resizableColumns` below at 17.7.0. + * The row now refuses the key by name (`invalid_type`, `expected: 'never'`), + * so the entry went dangling and stale and was deleted, and the key left + * `GA_PENDING_UNPUBLISHED_KEYS` and the ruled carve-out list with it. + */ /* * `object-grid.resizableColumns` WAS THE TENTH TOMBSTONE HARVESTED HERE — * `@objectstack/spec` 17.7.0 (objectstack#21445, PR objectstack#21463), the way @@ -1557,21 +1569,13 @@ const UNPUBLISHED_EXEMPTIONS: Record = { // `carries no stale unpublished-key exemption` would refuse it. // ── objectui#12085: the element-layer flat binding keys objectstack#11509 retires ── - // The repeater still READS its four as a fallback for metadata written - // before the retirement; the metric reads neither of its two. Each entry - // dies on its own at the pin that carries the tombstones. - 'element:repeater.object': - 'objectui#12085: NOT published, and publishing it would be WRONG, not premature. `@objectstack/spec` retires the repeater\'s flat `object` as a tombstone (objectstack#11509, objectstack PR #22421), and the manifest this registration feeds is read by objectstack\'s `os validate` against that spec: a published `object` made the html tier accept the retired spelling, and its `required: true` refused a repeater bound through `dataSource` alone. The binding\'s `dataSource.object` is the published door (the injected `dataSource` input). The renderer still READS the flat key as the binding\'s fallback, for metadata written before the retirement; a back-compat read is not an authoring surface (the split `page:card.body` records above). The installed pin predates the retirement, which is why the reverse direction still asks for the key here; at the pin that carries objectstack#11509\'s tombstone the key leaves the accepted set, and `carries no stale unpublished-key exemption` deletes this entry there.', - 'element:repeater.filter': - 'objectui#12085: NOT published, and publishing it would be WRONG, not premature. `@objectstack/spec` retires the repeater\'s flat `filter` as a tombstone (objectstack#11509, objectstack PR #22421), and the manifest this registration feeds is read by objectstack\'s `os validate` against that spec: a published `filter` made the html tier accept the retired spelling. The binding\'s `dataSource.filter` is the published door (the injected `dataSource` input). The renderer still READS the flat key as the binding\'s fallback, for metadata written before the retirement; a back-compat read is not an authoring surface (the split `page:card.body` records above). The installed pin predates the retirement, which is why the reverse direction still asks for the key here; at the pin that carries objectstack#11509\'s tombstone the key leaves the accepted set, and `carries no stale unpublished-key exemption` deletes this entry there.', - 'element:repeater.sort': - 'objectui#12085: NOT published, and publishing it would be WRONG, not premature. `@objectstack/spec` retires the repeater\'s flat `sort` as a tombstone (objectstack#11509, objectstack PR #22421), and the manifest this registration feeds is read by objectstack\'s `os validate` against that spec: a published `sort` made the html tier accept the retired spelling. The binding\'s `dataSource.sort` is the published door (the injected `dataSource` input). The renderer still READS the flat key as the binding\'s fallback, for metadata written before the retirement; a back-compat read is not an authoring surface (the split `page:card.body` records above). The installed pin predates the retirement, which is why the reverse direction still asks for the key here; at the pin that carries objectstack#11509\'s tombstone the key leaves the accepted set, and `carries no stale unpublished-key exemption` deletes this entry there.', - 'element:repeater.limit': - 'objectui#12085: NOT published, and publishing it would be WRONG, not premature. `@objectstack/spec` retires the repeater\'s flat `limit` as a tombstone (objectstack#11509, objectstack PR #22421), and the manifest this registration feeds is read by objectstack\'s `os validate` against that spec: a published `limit` made the html tier accept the retired spelling. The binding\'s `dataSource.limit` is the published door (the injected `dataSource` input). The renderer still READS the flat key as the binding\'s fallback, for metadata written before the retirement; a back-compat read is not an authoring surface (the split `page:card.body` records above). The installed pin predates the retirement, which is why the reverse direction still asks for the key here; at the pin that carries objectstack#11509\'s tombstone the key leaves the accepted set, and `carries no stale unpublished-key exemption` deletes this entry there.', - 'element:number.object': - 'objectui#12085: NOT published, and publishing it would be WRONG, not premature. The renderer does not read the flat `object` (since objectui#11880 the metric\'s query is the node-level `dataSource` only), and `@objectstack/spec` retires it as a tombstone (objectstack#11509, objectstack PR #22421), so a published `object` advertised configuration the platform drops and its own spec refuses. The binding\'s `dataSource.object` is the published door (the injected `dataSource` input). The installed pin predates the retirement, which is why the reverse direction still asks for the key here; at the pin that carries objectstack#11509\'s tombstone the key leaves the accepted set, and `carries no stale unpublished-key exemption` deletes this entry there.', - 'element:number.filter': - 'objectui#12085: NOT published, and publishing it would be WRONG, not premature. The renderer does not read the flat `filter` (since objectui#11880 the metric\'s query is the node-level `dataSource` only), and `@objectstack/spec` retires it as a tombstone (objectstack#11509, objectstack PR #22421), so a published `filter` advertised configuration the platform drops and its own spec refuses. The binding\'s `dataSource.filter` is the published door (the injected `dataSource` input). The installed pin predates the retirement, which is why the reverse direction still asks for the key here; at the pin that carries objectstack#11509\'s tombstone the key leaves the accepted set, and `carries no stale unpublished-key exemption` deletes this entry there.', + // Six entries stood here — `element:repeater.object` / `.filter` / `.sort` / + // `.limit` and `element:number.object` / `.filter` — each "dies on its own at + // the pin that carries the tombstones". `@objectstack/spec` 18 is that pin + // (objectui#12030): every one of the six is a tombstone now, so each entry + // went dangling and stale and was deleted. The repeater still READS its four + // as a fallback for metadata written before the retirement; that read is the + // renderer's, and nothing here publishes the keys. }; /** @@ -1690,7 +1694,6 @@ const GA_PENDING_UNPUBLISHED_KEYS = [ 'object-grid.pageSize', 'object-grid.showSearch', 'object-grid.showPagination', - 'object-grid.defaultFilters', 'object-grid.title', ]; @@ -2803,10 +2806,11 @@ const MEMBER_PINS: Record = { file: 'apps/console/src/__tests__/component-input-union-specimens.test.ts', pins: 'The `object` arm is the inline translation map, asserted at the render site that actually resolves one, with the non-matching controls (`42`, `["No records"]`) still reported (objectui#3832).', }, - 'element:record_picker.filter': { - file: 'packages/components/src/__tests__/record-picker-inputs-spec-parity.test.ts', - pins: 'The `array` arm is `ViewFilterRuleSchema[]` — the one filter orthography this map\'s array-declared `filter` doors share — with the MongoDB-style RECORD spelling (`{ status }`, `{ $and }`) refused by kind at `filter` and a bare tuple refused at `filter.0`, and the description pinned to say the key is NOT READ and to name `dataSource.filter`, the one filter the renderer reads since objectui#11880 (`composed?.filter`). objectui#3830 declared the key; objectstack#14406 converged it off the record form and objectui#7663 moved this side onto the array arm; it stays published until the spec\'s v18 retirement (objectstack#11509).', - }, + // `element:record_picker.filter` and `.sort` stood here until the `@objectstack/spec` + // 18 bump retired both as tombstones and the registration stopped publishing them + // (objectui#12030): a member pin names a key still array/object-armed on a covered + // block, and neither is. The binding's `dataSource.sort` reach is still pinned by + // `record-picker-sort-members.test.tsx`, and the binding itself by `.dataSource` below. 'element:record_picker.label': { file: 'packages/components/src/renderers/basic/__tests__/record-picker-label-placeholder-i18n.test.tsx', pins: 'The I18nLabel object arm, resolved at ITS OWN read site rather than through the row-value helper `toText` it used to share: the map resolves to the active language rather than always to its `en` entry (the pre-fix harm rendered ENGLISH to a zh-CN viewer), a region tag falls back to the base language an author actually wrote, and — the quiet failure — a legal map that simply omits `en` used to delete the `