Repository navigation
fix(console): the record header reads placedActions, so a packaged sys_user header action draws again (#29951) - #30097
Conversation
…s_user header action draws again (#29951) Ruling A on #29951 (record 6624172200), ui half of #30018's spec key. - PageHeaderActions (@object-ui/components) reads page:header's placedActions: true and draws every action of the page's object placed at record_header / record_more, read live, through placedHeaderActions (@object-ui/types), the one placed-header reader RecordDetailView's synthesized header now reads too. Omitted or false, an authored actions list is still the whole set (#11592). A true beside a list draws none of the object's actions and is reported once. The page:header registration publishes the input. - sys_user_detail, sys_organization_detail and sys_approval_request_detail set placedActions: true in place of the id lists #27219 froze. Tab strips unchanged. - Drop the "not drawn yet" qualifiers: the describe marker (reference regenerated), the page liveness PLANNED record (re-graded live), the registry-inputs parity exemption, pages.mdx and layout-dsl.mdx. The skills/objectstack-ui/rules/pages.md qualifier goes in a separate PR (Tier H). Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzh8VRbTbBnqwnrXsSL
📓 Docs Drift CheckThis PR changes 3 package(s): 5 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 2 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 170 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin cd9f7e2ba7b51d8d3d87c0ba137c8359244c3809 && git checkout cd9f7e2ba7b51d8d3d87c0ba137c8359244c3809
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin f68b47cacede768ec0b4b54aae8656f8a7f88bb2 6d81dac28c962ac76b435e04d3879154023df545 && git checkout -B drift-repro f68b47cacede768ec0b4b54aae8656f8a7f88bb2 && git merge --no-ff 6d81dac28c962ac76b435e04d3879154023df545
node scripts/docs-audit/affected-docs.mjs --json f68b47cacede768ec0b4b54aae8656f8a7f88bb2
|
…ions The unconsumed #30018 changeset rides the same release as this reader, so its "declared ahead of its reader" bullet now says the console's page:header renderer reads the key and the PLANNED marker is gone. The @objectstack/skills bullet stays until the skills follow-up. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzh8VRbTbBnqwnrXsSL
|
domain:ui#1 · os-support-ai · session_01WGufzjDyeFwq6AuFu3vwTd 维护者速读(席位终稿)
席位核对 · ACCEPT · head
|
Check Changeset refuses an edit to a changeset already on the merge base (the foreign-changeset rule, #17712), so the reworded bullet goes back. This PR's own changeset says the console reads placedActions; the stale sentence in 30018's entry is left to the release-time notes. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzh8VRbTbBnqwnrXsSL
|
domain:ui#1 · os-support-ai · session_01WGufzjDyeFwq6AuFu3vwTd 席位核对 · ACCEPT carried to head
|
PR #30097 made the header renderer read placedActions, so the objectui page-builder guide names it beside actions and the objectstack-ui pages catalogue drops "not drawn yet". Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J8VVAjSbVpQUeFNuTTm3me
Requested by Yibo Wang · project thread
Fixes #29951
维护者速读
page:header的placedActions: true(spec(page:header): an explicit opt-in to draw every action placed at record_header / record_more, read live (#29951 ruling A, spec half) #30018 落地的新键),画出该对象所有放在record_header/record_more的动作,实时读取。用户、组织、审批请求三个平台记录页改用这个开关,去掉了 feat(spec,ui)!: retire the record page's slots.tabs; a page that needs its own strip is kind: 'full' #27219 冻结的 id 列表。sys_user加的页头动作(比如type: 'url'的链接)在设置里的用户抽屉和整页都不显示了,因为平台页面只列了自己的 id,而手写列表就是全部。placedActions: true的页头,也就是这三个平台页面;原来列表里的动作都放在页头位置,所以照样显示,只是多了别的包加的。不写这个键的页面行为不变。回滚 = revert 本 PR。按你的修订,18.3.x 不发、不写发版说明。ui/packages/components/src/renderers/layout/containers.tsx(PageHeaderActions读这个键)、ui/packages/types/src/ui-action.ts(共用的placedHeaderActions,合成页头也用它)、三个页面文件。pnpm --dir ui exec vitest run packages/app-shell/src/views/RecordDetailView.placedHeaderActions-29951.test.tsx,预期 7 个用例全绿:抽屉和整页都画出别的包加的 url 动作,旧的冻结列表画不出来。skills/objectstack-ui/rules/pages.md的那条限定语是受管文件,另开一个小 PR(Refs #29951)给你合并。Clause-②: no
Metadata-protocol: none
What changes
placedActions: true(ui/packages/components/src/renderers/layout/containers.tsx).PageHeaderRendererhands the key toPageHeaderActions.truedraws every action of the page's object whoselocationsincluderecord_headerorrecord_more, in declaration order, read from the object's metadata through the sameuseMetadataItem('object', …)lookup an id list uses, and through the same predicate, capability and switched-off chain after it. Omitted orfalse, an authoredactionslist is still the whole set (PageHeaderProps.actionsdeclaresz.array(z.string())but objectui's canonicalpage:headerrenderer consumes ActionDef objects — satisfying the schema deletes every header button #11592). Only the booleantrueopts in. Atruebeside an authored list, which the spec refuses at parse, draws none of the object's actions and is reported once withconsole.error, the same fail-closed answer a refused id array gets.placedHeaderActions(ui/packages/types/src/ui-action.ts, exported from@object-ui/types) is the rule: every actionactionRendersAtplaces atrecord_headerorrecord_more, the first of a name.RecordDetailView's synthesized header (recordHeaderActions) now reads it instead of its inline filter, so the synthesized default page and aplacedActions: trueheader draw the same set. No second reader.page:headerregistration declaresplacedActions(boolean), andsdui.manifest.jsonis regenerated (node scripts/gen-sdui-manifest-node.mjs, in-tree; the only component change is that input), withscripts/sdui-manifest.record.jsonand the component reference pages it renders (content/docs/ui/components/page.mdxandindex.mdx,node scripts/gen-sdui-reference.mjs).sys_user_detailandsys_organization_detail(@objectstack/platform-objects) andsys_approval_request_detail(@objectstack/plugin-approvals) set{ type: 'page:header', properties: { placedActions: true } }in place of the id lists feat(spec,ui)!: retire the record page's slots.tabs; a page that needs its own strip is kind: 'full' #27219 froze (11 ids onsys_user, 4 onsys_organization, none on the approval request). The tab strips feat(spec,ui)!: retire the record page's slots.tabs; a page that needs its own strip is kind: 'full' #27219 introduced are unchanged. Every action the old lists named was placed atrecord_header/record_more(the old pin held each list equal to exactly that set), so nothing the pages drew is dropped.sys_approval_requestplaces no header action of its own (its decision actions arerecord_section), so its header now draws only what an installed package places there.packages/spec/src/ui/component.zod.ts: theplacedActionsdescribe drops its[PLANNED — not yet rendered]marker and the docblock says the reader is live;content/docs/references/ui/component.mdxregenerated (gen:schema+gen:docs).packages/spec/liveness/page.json: the_note's PLANNED RECORD sentence is rewritten as a LIVE RECORD that namesPageHeaderActions,placedHeaderActionsand the three producer pages.ui/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts:UNPUBLISHED_EXEMPTIONS['page:header.placedActions']struck (a strike note in its place, as the file does forparentDataSource).content/docs/ui/pages.mdxandcontent/docs/protocol/objectui/layout-dsl.mdx: the qualifier is gone..changeset/29951-page-header-placed-actions-reader.md: patch for the six touched packages.Why
Ruling A on #29951 (record 6624172200). #27219 rebuilt the platform record pages as
kind: 'full'pages with their own tab strips and copied the platform's header action ids intopage:header.actions. Under #11592 an authored list is the whole set, so a header action any other package places onsys_user(orsys_organization,sys_approval_request) stopped drawing: the 18.2 slotted page's synthesized header had read the object's placed actions live. #30018 (PR #30028) declaredplacedActions: truespec first; this is its reader and its producers. The tab strips #27219 was for stay. Nothing ships in 18.3.x.Tests
ui/packages/app-shell/src/views/RecordDetailView.placedHeaderActions-29951.test.tsx, through the realRecordDetailView→page:header→PageHeaderActions, on the full page (route) and the drawer (embedded, asObjectViewmounts it). Asys_userdef carries the platform'sban_user(record_header) andimpersonate_user(record_more), two actions placed elsewhere, and two packagedtype: 'url'actions (record_headerandrecord_more,_packageId: 'com.qa.hdr').placedActions: true): the packagedrecord_headeraction draws inline and therecord_moreone in the ⋯ menu, beside the platform's own; thelist_toolbar/record_sectionactions do not draw. Page and drawer.placedActions: truedraws exactly the four placed actions in declaration order; an authored['ban_user']without the key draws exactlyBan User(PageHeaderProps.actionsdeclaresz.array(z.string())but objectui's canonicalpage:headerrenderer consumes ActionDef objects — satisfying the schema deletes every header button #11592).packages/platform-objects/src/pages/record-page-header-actions.test.tsrewritten: per page, the object places header actions (non-vacuous), the header node is exactly{ placedActions: true }, andComponentPropsMap['page:header']accepts it.sys-approval-request-page.test.tspins the new node.packages/spec/src/ui/component.test.ts: the marker test now asserts the describe carries no[PLANNEDmarker.const placedOptIn = false && rawPlacedActions === true;) turns 4 of the 7 pin cases red (Unable to find role="button" and name "Ban User": shipped page, shipped drawer, CONTROL placed, refused pair) and leaves the 3 list cases green. File restored byte-identical (cmp).Acceptance notes
@objectstack/platform-objectsis not a dependency of the ui tree. The platform-objects and plugin-approvals pins hold the shipped node equal to it..changeset/30018-page-header-placed-actions.md(PR feat(spec): page:header placedActions draws every placed header action, refused beside an actions list (#30018) #30028, unconsumed) still says the renderer does not read the key yet. Both changesets ride the same next release, so its CHANGELOG entry will carry that sentence beside this one. Not edited here (it is spec(page:header): an explicit opt-in to draw every action placed at record_header / record_more, read live (#29951 ruling A, spec half) #30018's record); flagging it for the seat.Verification
pnpm buildunderos-verify-lock, 119/119; showcase backendpnpm dev -- --fresh -p 4317; Console fromui/src via vite withDEV_PROXY_TARGET). A writable packagecom.qa.hdrstoreshdr_user_profile(type: 'url',record_header, onsys_user) and the CONTROLhdr_account_profileonshowcase_account. Served:GET /api/v1/meta/page/sys_user_detail,sys_organization_detailandsys_approval_request_detaileach answerkind: 'full'with{"type":"page:header","properties":{"placedActions":true}};/meta/object/sys_userserveshdr_user_profile. Playwright readings:6a4737ab), both readings were the same lists without QA User Profile. CONTROLshowcase_account, full page and drawer: QA Account Profile · Edit · ⋯, as before.ui/root: the new pin 7/7;packages/components/src/__tests__/page-header*,packages/app-shell/src/views/RecordDetailView.*,packages/types/src/__tests__and the console parity test: 518 files, 11620 tests green;registry-inputs-spec-parity.test.tsalone: 261 green with the exemption struck.@objectstack/platform-objectssrc/pages46,@objectstack/plugin-approvalssys-approval-request-page.test.ts20,@objectstack/specsrc/ui/component.test.ts361, all green.@object-ui/types,@object-ui/components,@object-ui/app-shell(type-check, from the ui root),@objectstack/platform-objects,@objectstack/plugin-approvals(typecheck),@objectstack/spectsc --noEmit: clean.gen:schema+gen:docs(reference),node scripts/gen-sdui-manifest-node.mjs(manifest + record),node scripts/gen-sdui-reference.mjs(content/docs/ui/components/);node scripts/check-sdui-manifest.mjsandpnpm check:sdui-referencegreen.node scripts/pm/dispatch-gates.mjs --commandson the final diff (119), then--ran: 119 derived, 119 run, 0 NOT-MEASURED, 0 UNRUN. 118 exit 0.pnpm check:platform-checklistexits 1 on an absentassertProtocolCompatanchor inpackages/metadata-protocol/src/protocol.ts(areas/platform-core.json); it is red the same way on merge based79eecfe5band onorigin/mainf35b361997, outside this diff. Three first-pass reds were re-run:pnpm check:sdui-referencewas this diff's own (component pages regenerated and committed, then green);pnpm --dir ui exec vitest run scripts/(one 15 s timeout under load) andpnpm --filter @objectstack/spec run check:generated(check:test-typecheck's tsc ran out of heap because this container'sNODE_OPTIONScarries no heap flag) were green re-run alone under the lock, the second with--max-old-space-size=4096appended.Human Minimum
packages/specholds no runtime logic.pnpm lintpasses. (The changed TypeScript files pass eslint with 0 errors: the seven underpackages/with the root config and--no-inline-config, the six underui/from the ui root. CI'spnpm lintcovers the full tree.)main, one pull request.packages/spectouched: its generated artifacts are regenerated and committed.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.## 维护者速读block, which is written in Chinese for the maintainer.🤖 Generated with Claude Code
https://claude.ai/code/session_01WGufzh8VRbTbBnqwnrXsSL