Repository navigation
Commit 8eeb3b3
feat(spec,types,plugin-list,app-shell)!: retire the list view's
<!-- claude-projects-attribution: {"github_login":"os-support-ai"} -->
_Requested by **Yibo Wang** · [project
thread](https://claude.ai/code/project/chan_01BVUyyPie8gHwoPM18iABwB?thread=cmsg_01BVUyyPie8gHwoPM18iABwBFijSMgUXzsRVhP3BchJpt1)_
Part of #25923
Clause-②: no (narrowing)
Metadata-protocol: narrowed
Skills-docs: skills/objectstack-ui/references/react-blocks.md
regenerated by `pnpm gen:react-blocks`; the `list-view` table drops its
`options` prop row. No other `skills/**` file teaches the bag:
skills/objectstack-ui/rules/list-views.md and
skills/objectui/guides/page-builder.md already write the top-level
blocks only.
ADR-0087: registered list-view-options-bag-folded,
ui-list-view-options-bag-folded
## 维护者速读
- 改了什么:列表视图的旧 `options` 配置包退役。规范的视图写入口按名拒收 `options` 并提示改写为顶层 `kanban` /
`calendar` 等配置块;已存储的配置包由 ADR-0087 D2 转换在下发前折叠到顶层配置块;objectui
的类型镜像直接引用规范的墓碑,`ListView`、对象页中继、界面页、Studio 预览和检查器都只读写顶层配置块。
- 为什么改:同一个配置块有两种写法,每个渲染器各自实现一遍合并(#12);普查在所有可达元数据里找到 0 行存储的配置包,席位裁定走 A
方案一个 PR 落地(claim amendment 6460225523)。
- 风险与回滚:直接写 `options` 的 PUT 请求、页面 `list-view` 节点或 `ListView`
宿主会被拒收或不再生效;已存储的行由服务端折叠,渲染不变。回滚即还原本 PR;D2 转换只在读取时折叠,不改写存储数据。
-
先看:`packages/spec/src/ui/view.zod.ts`(墓碑)、`packages/spec/src/conversions/registry.ts`(`list-view-options-bag-folded`)、`ui/packages/app-shell/src/views/objectViewListRenderer.tsx`(顶层中继)、`ui/packages/plugin-list/src/ListView.tsx`。
- 两分钟验证:`cd ui && pnpm exec vitest run
packages/types/src/__tests__/list-view-options-bag-6152.test.ts
packages/plugin-list/src/__tests__/ListView.readersRetired-6152.test.tsx
packages/app-shell/src/views/ObjectView.storedRowParity-10380.test.tsx`,预期全绿:配置包在每个入口被拒收并给出规范原文,源码普查没有
`schema.options` 读取,存储的配置包折叠后两页渲染一致。
- 需要你做的:无,席位落地
## What changes
- `@objectstack/spec`: the flattened list overlay's `options` is a
`retiredKey()` tombstone that refuses a bag by name with the
move-each-`options.KIND`-to-`KIND` prescription. The D2 conversion
`list-view-options-bag-folded` folds a stored or source bag onto the
top-level blocks before a row is served (top-level wins per key; for
`chart`, whose block replaced the bag whole, the top-level block wins
whole). It leaves `options.grid`, a non-object block and a bag on a form
view in place with a TODO. The D3 entry
`ui-list-view-options-bag-folded` names what the fold cannot decide (a
folded block can still miss a required key). The page `list-view`
component row shares the tombstone, and `react-blocks.ts` drops the
`options` prop row.
- `@object-ui/types`: `ListViewSchema.options` is the spec's tombstone
by reference, so the mirror, the tolerant and strict faces and
`safeValidateSchema` refuse a bag at `options` with the spec's text,
unreworded. `NamedListView.options` is a `?: never` tombstone naming the
top-level blocks, moved from held to retired in the
`object-view-unmirrored-keys-7779` census (22 tombstones, was 21). The
dataset-chart filter refusal reads the `chart` block alone. A page
node's flat `options` is refused with the bag text rather than pointed
at `properties.options`.
- `@object-ui/plugin-list`: `ListView` reads every kind from its
top-level block alone (render branches, capability gate, projection and
expand collectors, fetch effect dependencies). The `list-view`
registration publishes no `options` input.
- `@object-ui/app-shell`: the object page relays each per-kind block at
the top level of the list schema, each held by value through
`isSameOptionsValue` so an equal rebuild keeps its identity, and
forwards no stored bag (`storedLegacyOptions` removed). The interface
page sends one `map` block (its derivation with the authored keys laid
over) and no bag. `ViewPreview` and the list-view inspector fold
nothing; the server does.
- `@object-ui/plugin-view`: the host list schema carries the active
view's blocks at the top level instead of under `options`.
`@object-ui/plugin-map`: two development warnings name the `map` block.
- `@object-ui/console`, `@objectstack/rest`,
`@objectstack/metadata-protocol`, `@objectstack/lint`: test pins only.
## Tests
- Refusal on the authoring face: `list-view-options-bag-6152` pins the
mirror IS the spec tombstone, and every door refuses five bag shapes at
`options` with the spec's text, beside a CONTROL that the same blocks
written top-level parse. The named alias refusals the bag carried are
pinned at the top-level block.
- No read left: `ListView.readersRetired-6152` gains a SOURCE census
(TypeScript AST over every non-test plugin-list file) that finds no
`schema.options` read, with a firing control on `schema.kanban` and a
probe of each retired shape. The same scanner finds 39 reads in
`ListView.tsx` on `origin/main`. The object page relay census
(`ObjectView.relayRungCensus-7559`) declares `options` unread and every
block relayed; the interface page census
(`InterfaceListPage.relayCensus-11572`) writes `map` and not `options`.
- Stored rows convert: the spec and metadata-protocol pins replay
`list-view-options-bag-folded` on stored rows; in ui,
`ObjectView.storedRowParity-10380` and `ViewPreview.foldedOnRead-25923`
render rows folded with `applyConversionsToStoredItem` and pin that an
unfolded bag renders nothing.
- The test fixtures that mounted a bag (79 by the seat's count in the
ruling) moved to the top-level KIND form, not loosened. Tests that
pinned bag behaviour now pin that the bag is refused or reaches nothing,
each beside a CONTROL with the block.
## Census
TypeScript AST + JSON + YAML walk of every object literal: views
carrying a top-level `options` bag with a kind key.
| | sites | where |
|:--|--:|:--|
| `origin/main` 4b8f8cd (19,856 files) | 158 | 157 tests + 1 the object
page composer, `objectViewListRenderer.tsx` |
| this branch (21,425 files) | 109 | 106 tests that pin the refusal, the
fold or the inversion + 3 in `packages/spec/src/conversions/registry.ts`
(the fold's own doc and fixtures) |
| stored (examples, apps, the console's shipped metadata, ui/examples,
seeds, platform-objects, fixtures) | 0 | before and after |
Not reachable, so not counted as zero: hotcrm metadata, tenant
`sys_metadata` rows, cloud.
## Acceptance notes
- `chart` folds whole: the top-level `chart` block replaced the bag
outright before this change, so a bag beside a block is dropped, not
merged.
- Kanban title floor: after the fold the object page and the interface
page still differ on a kanban card title with no `titleField`. The
object page floors `titleField: 'name'` in `kanbanViewOptions` (pinned
by `kanbanLane-8193`); the interface page sends none. This is
pre-existing and `ObjectView.storedRowParity-10380` pins it as observed.
- The D3 entries `18.view-item-options-bag-refused.ts` and
`18.view-overlay-options-bag-judged.ts` are left unedited. They describe
the earlier view-item refusal and the earlier judged overlay; this PR
adds `18.ui-list-view-options-bag-folded.ts` beside them.
- Overlap, rechecked at push time: #27031 and #27013 (both merged)
touched `ListView.tsx`, `ListView.test.tsx` and
`objectViewListRenderer.tsx`; both are in this head's main merge, which
was clean, and plugin-list, types, spec and metadata-protocol were rerun
after it. #26966 (open) adds its own conversion to `registry.ts`; this
PR's fold is registered at order 78, so the one that lands second takes
the next free order.
- Size: `dispatch-gates` counts 5,341 changed lines over 88 files
(+2,704 / -2,637), over the 3,000-line human-merge threshold. Most of it
is test fixtures moving from the bag to the block.
- Test-only package entries (`patch`): console, rest, metadata-protocol,
lint.
- Left on #25923 after this PR (both checked on this head): work item 2
landed in #26019 except dropping `FormField`'s `[key: string]: any`
index signature (`ui/packages/types/src/form.ts`), which ruling
6412606977 deferred because it breaks components `form.tsx`, plugin-form
and plugin-grid; and the `immutable` follow-up from 6448239783:
plugin-form's `normalizeSectionField` (`sectionFields.ts:417`) copies
`immutable`, but no form renderer reads it, so an edit-mode form leaves
an immutable field editable. Work item 3 is complete with #27026 and
this PR.
## Verification
Head `3f56e4cfe` (main `b322b5da6` merged in). Every run below was under
os-verify-lock.
<details><summary>ui tests</summary>
- Full ui suite on the branch before the last main merge, in three
batches with `--maxWorkers=3` (a single `vitest run` hit the container's
memory limit at 1h49m and was killed, so it measured nothing): app-shell
`Test Files 1826 passed | 1 skipped` · `Tests 16795 passed | 9 skipped`;
components, plugin-list, plugin-view, plugin-map, types, core, react,
plugin-grid, plugin-detail `Test Files 2041 passed | 2 skipped` · `Tests
28433 passed | 69 skipped`; the other packages, apps, scripts,
eslint-rules and examples `Test Files 1843 passed | 4 skipped` · `Tests
25842 passed | 291 skipped`. Each batch exit 0.
- After merging main `b322b5da6` (#27013 touched `ListView.tsx` and
`ListView.test.tsx`): plugin-list + types `Test Files 560 passed (560)`
· `Tests 12306 passed`, exit 0.
</details>
<details><summary>spec and server packages</summary>
- `pnpm --filter @objectstack/spec test` after the last merge: `Test
Files 741 passed (741)` · `Tests 22244 passed | 1 todo`, exit 0.
`typecheck`: exit 0.
- `pnpm --filter @objectstack/spec check:generated` after the spec
closure build: all 14 generated artifacts up to date, exit 0.
- `@objectstack/metadata-protocol` after the last merge and its closure
build: `Test Files 277 passed | 4 skipped` · `Tests 21752 passed | 26
skipped`, exit 0. (Run before the closure build, one test from #26937,
`runtime-authoring-gate.email-template-writes`, failed on a stale
`@objectstack/lint` dist; it passes once that dist is built.)
- `@objectstack/rest` `Test Files 332 passed` · `Tests 6552 passed | 326
skipped`; `@objectstack/lint` `Test Files 170 passed` · `Tests 7516
passed`. Both exit 0.
</details>
<details><summary>type-check and lint</summary>
- `type-check` for types, plugin-list, plugin-view, plugin-map,
app-shell and console: exit 0, after building the app-shell and console
dependency closures (stale dists from main's #26681 had red them first).
plugin-list type-check rerun after the last merge: exit 0.
- `lint` for the same six packages: 0 errors.
</details>
<details><summary>changeset checks</summary>
- `check-changeset-no-major.mjs --base origin/main` with this body as
the event: exit 0; it reads `Clause-②: no (narrowing)` and
`Metadata-protocol: narrowed` against the `minor` grade on
`@objectstack/spec`.
- `check-adr-0087-registration` (registers
`list-view-options-bag-folded`, `ui-list-view-options-bag-folded`),
`check-empty-changeset`, `check:changeset-fixed`, `check:nul-bytes`:
exit 0.
</details>
<details><summary>dispatch gates</summary>
- `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack`: 100 commands, each run with its exit code
recorded.
- `--ran`: 100 derived, 99 run, 1 NOT-MEASURED, 0 UNRUN. All 99 measured
exit 0.
- NOT-MEASURED: `pnpm check:dual-build-cjs-loads` exit 3 (its
prerequisite is a full `pnpm build`). CI runs it.
- `node scripts/check-platform-checklist.mjs --changed-from
origin/main`: OK, exit 0.
</details>
<details><summary>dogfood battery</summary>
- Head `3f56e4cfe` (after the `b322b5da6` merge and the round-1 fixes):
closure `pnpm --filter '@objectstack/dogfood^...' build` exit 0, then
`pnpm --filter @objectstack/dogfood test`: `Test Files 348 passed | 3
skipped (351)` · `Tests 2804 passed | 20 skipped (2824)`, exit 0.
- Earlier reading, on the `07d18e692` merge: `Test Files 348 passed | 3
skipped (351)` · `Tests 2803 passed | 20 skipped (2823)`, exit 0.
</details>
<details><summary>review round 1 (contract review 6467465885 on
ef9b178)</summary>
- Build & E2E UI: `sdui.manifest.json` still listed the `list-view`
`options` input. `node scripts/gen-sdui-manifest-node.mjs` drops that
row (5 lines, the same diff CI printed) and re-records
`scripts/sdui-manifest.record.json`; `node
scripts/check-sdui-manifest.mjs` exit 0.
- Test Core 2/8: `scripts/conversions-major18-merge.test.ts` rule 2
wants a conversion added after the rule defined directly above the next
entry's definition. Reproduced locally (3 failed of 12, naming
`listViewOptionsBagFolded` and `listViewSortStringClauseToArray`). The
fold and its `LIST_VIEW_OPTIONS_BAG_KINDS` constant now sit directly
above `listViewSortStringClauseToArray`: 12 passed. Spec repo project
`Test Files 81 passed` · `Tests 1324 passed`; spec local conversions,
migrations and ui `Test Files 167 passed` · `Tests 6308 passed`.
- Test Core 6/8: the D3 entry's printed `reason` cited `objectui#10380`
and `#25923`. Reproduced locally with the old text and a spec build:
`migrate-meta-engine-guidance.test.ts` fails with
"ui-list-view-options-bag-folded: the printed guidance cites a tracker
id: expected '#10380' to be undefined". Rephrased without ids: 3 passed.
Full `@objectstack/cli` test `Test Files 521 passed | 1 skipped` ·
`Tests 6484 passed | 9 skipped`, exit 0; `check:generated` exit 0.
- Changeset: the "renders as before" sentence is qualified. A stored bag
folds onto the top-level blocks, which on the object page pass through
the relay's defaults (the kanban `titleField: 'name'` floor, for one),
so a folded row can draw differently where its bag left such a key
unset; 0 reachable rows, pinned by `ObjectView.storedRowParity-10380`.
</details>
---
_Generated by [Claude
Code](https://claude.ai/code/session_01WGufzevL8Q6rTfGz2XHXGT)_
---------
Co-authored-by: Claude <noreply@anthropic.com>options bag; stored bags fold onto the top-level blocks, and the renderers read the blocks alone (#27206)1 parent ebfadb0 commit 8eeb3b3
87 files changed
Lines changed: 1877 additions & 1816 deletions
File tree
- .changeset
- content/docs/ui/components
- docs/audits/2026-07-unknown-key-strictness-ledger.counts
- packages
- lint/src
- metadata-protocol/src
- rest/src
- spec/src
- conversions
- migrations/entries/semantic
- ui
- scripts
- skills/objectstack-ui/references
- ui
- apps/console/src/__tests__
- packages
- app-shell/src
- __tests__
- views
- metadata-admin/previews
- studio-design
- plugin-list/src
- __tests__
- plugin-map/src
- plugin-view/src
- __tests__
- types/src
- __tests__
- zod
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| 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 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
87 | 87 | | |
88 | 88 | | |
89 | 89 | | |
90 | | - | |
| 90 | + | |
91 | 91 | | |
92 | 92 | | |
93 | 93 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
313 | 313 | | |
314 | 314 | | |
315 | 315 | | |
316 | | - | |
317 | 316 | | |
318 | 317 | | |
319 | 318 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
24 | | - | |
| 24 | + | |
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
| |||
44 | 44 | | |
45 | 45 | | |
46 | 46 | | |
47 | | - | |
| 47 | + | |
48 | 48 | | |
49 | | - | |
| 49 | + | |
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
53 | 53 | | |
54 | 54 | | |
55 | 55 | | |
56 | 56 | | |
57 | | - | |
| 57 | + | |
58 | 58 | | |
59 | 59 | | |
60 | 60 | | |
61 | 61 | | |
62 | 62 | | |
63 | | - | |
| 63 | + | |
64 | 64 | | |
65 | | - | |
| 65 | + | |
66 | 66 | | |
67 | 67 | | |
68 | 68 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
11 | | - | |
12 | | - | |
13 | | - | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
14 | 16 | | |
15 | 17 | | |
16 | 18 | | |
| |||
21 | 23 | | |
22 | 24 | | |
23 | 25 | | |
24 | | - | |
| 26 | + | |
25 | 27 | | |
26 | 28 | | |
27 | 29 | | |
| |||
45 | 47 | | |
46 | 48 | | |
47 | 49 | | |
48 | | - | |
| 50 | + | |
49 | 51 | | |
50 | | - | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
51 | 55 | | |
52 | 56 | | |
53 | 57 | | |
| |||
75 | 79 | | |
76 | 80 | | |
77 | 81 | | |
78 | | - | |
| 82 | + | |
79 | 83 | | |
80 | 84 | | |
81 | 85 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
383 | 383 | | |
384 | 384 | | |
385 | 385 | | |
386 | | - | |
387 | | - | |
388 | | - | |
389 | | - | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
390 | 390 | | |
391 | | - | |
392 | | - | |
393 | | - | |
394 | | - | |
395 | | - | |
396 | | - | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
397 | 396 | | |
398 | 397 | | |
399 | 398 | | |
400 | | - | |
401 | | - | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
402 | 402 | | |
403 | 403 | | |
404 | 404 | | |
| |||
418 | 418 | | |
419 | 419 | | |
420 | 420 | | |
421 | | - | |
422 | | - | |
423 | | - | |
424 | | - | |
425 | | - | |
426 | | - | |
427 | | - | |
428 | | - | |
429 | | - | |
430 | | - | |
431 | | - | |
432 | | - | |
433 | | - | |
434 | | - | |
435 | | - | |
436 | | - | |
437 | | - | |
438 | | - | |
439 | | - | |
440 | | - | |
441 | | - | |
442 | | - | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
443 | 427 | | |
444 | 428 | | |
445 | 429 | | |
446 | | - | |
447 | | - | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
448 | 434 | | |
449 | 435 | | |
450 | | - | |
451 | | - | |
452 | | - | |
453 | | - | |
454 | | - | |
455 | | - | |
456 | | - | |
457 | | - | |
458 | | - | |
459 | | - | |
460 | | - | |
461 | | - | |
462 | | - | |
463 | | - | |
464 | | - | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
465 | 440 | | |
466 | 441 | | |
467 | 442 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
239 | 239 | | |
240 | 240 | | |
241 | 241 | | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
242 | 277 | | |
243 | 278 | | |
244 | 279 | | |
| |||
0 commit comments