Repository navigation
Commit a52761f
<!-- claude-projects-attribution: {"github_login":"os-support-ai"} -->
_Requested by **Yibo Wang** · [project
thread](https://claude.ai/code/project/chan_01BVUyyPie8gHwoPM18iABwB?thread=cmsg_01BVUyyPie8gHwoPM18iABwB4xjiquevJqfBXiUoqfQwa1)_
Fixes #29951
## 维护者速读
- 改了什么:控制台的记录页头现在会读 `page:header` 的 `placedActions: true`(#30018
落地的新键),画出该对象所有放在 `record_header` / `record_more`
的动作,实时读取。用户、组织、审批请求三个平台记录页改用这个开关,去掉了 #27219 冻结的 id 列表。
- 为什么改:按你对 #29951 的裁决 A(记录 6624172200)。18.3 里别的包给 `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 动作,旧的冻结列表画不出来。
- 需要你做的:本 PR 不需要你操作,席位复核后走队列落地。`skills/objectstack-ui/rules/pages.md`
的那条限定语是受管文件,另开一个小 PR(`Refs #29951`)给你合并。
Clause-②: no
Metadata-protocol: none
## What changes
- **The header reads `placedActions: true`**
(`ui/packages/components/src/renderers/layout/containers.tsx`).
`PageHeaderRenderer` hands the key to `PageHeaderActions`. `true` draws
every action of the page's object whose `locations` include
`record_header` or `record_more`, in declaration order, read from the
object's metadata through the same `useMetadataItem('object', …)` lookup
an id list uses, and through the same predicate, capability and
switched-off chain after it. Omitted or `false`, an authored `actions`
list is still the whole set (#11592). Only the boolean `true` opts in. A
`true` beside an authored list, which the spec refuses at parse, draws
none of the object's actions and is reported once with `console.error`,
the same fail-closed answer a refused id array gets.
- **One placed-header reader.** `placedHeaderActions`
(`ui/packages/types/src/ui-action.ts`, exported from `@object-ui/types`)
is the rule: every action `actionRendersAt` places at `record_header` or
`record_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 a `placedActions: true`
header draw the same set. No second reader.
- **Registration input.** The `page:header` registration declares
`placedActions` (`boolean`), and `sdui.manifest.json` is regenerated
(`node scripts/gen-sdui-manifest-node.mjs`, in-tree; the only component
change is that input), with `scripts/sdui-manifest.record.json` and the
component reference pages it renders
(`content/docs/ui/components/page.mdx` and `index.mdx`, `node
scripts/gen-sdui-reference.mjs`).
- **The three platform pages opt in.** `sys_user_detail` and
`sys_organization_detail` (`@objectstack/platform-objects`) and
`sys_approval_request_detail` (`@objectstack/plugin-approvals`) set `{
type: 'page:header', properties: { placedActions: true } }` in place of
the id lists #27219 froze (11 ids on `sys_user`, 4 on
`sys_organization`, none on the approval request). The tab strips #27219
introduced are unchanged. Every action the old lists named was placed at
`record_header` / `record_more` (the old pin held each list equal to
exactly that set), so nothing the pages drew is dropped.
`sys_approval_request` places no header action of its own (its decision
actions are `record_section`), so its header now draws only what an
installed package places there.
- **The "not drawn yet" qualifiers PR #30028 listed** (five of six; the
sixth is in the skills PR):
- `packages/spec/src/ui/component.zod.ts`: the `placedActions` describe
drops its `[PLANNED — not yet rendered]` marker and the docblock says
the reader is live; `content/docs/references/ui/component.mdx`
regenerated (`gen:schema` + `gen:docs`).
- `packages/spec/liveness/page.json`: the `_note`'s PLANNED RECORD
sentence is rewritten as a LIVE RECORD that names `PageHeaderActions`,
`placedHeaderActions` and 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 for `parentDataSource`).
- `content/docs/ui/pages.mdx` and
`content/docs/protocol/objectui/layout-dsl.mdx`: the qualifier is gone.
- Changeset `.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 into `page:header.actions`.
Under #11592 an authored list is the whole set, so a header action any
other package places on `sys_user` (or `sys_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) declared `placedActions: true` spec first; this is its reader
and its producers. The tab strips #27219 was for stay. Nothing ships in
18.3.x.
## Tests
- **Card pin**
`ui/packages/app-shell/src/views/RecordDetailView.placedHeaderActions-29951.test.tsx`,
through the real `RecordDetailView` → `page:header` →
`PageHeaderActions`, on the full page (route) and the drawer
(`embedded`, as `ObjectView` mounts it). A `sys_user` def carries the
platform's `ban_user` (`record_header`) and `impersonate_user`
(`record_more`), two actions placed elsewhere, and two packaged `type:
'url'` actions (`record_header` and `record_more`, `_packageId:
'com.qa.hdr'`).
- Shipped header node (`placedActions: true`): the packaged
`record_header` action draws inline and the `record_more` one in the ⋯
menu, beside the platform's own; the `list_toolbar` / `record_section`
actions do not draw. Page and drawer.
- Frozen #27219 header (an id list, no opt-in): neither packaged action
draws. Page and drawer.
- CONTROL on a non-platform object: `placedActions: true` draws exactly
the four placed actions in declaration order; an authored `['ban_user']`
without the key draws exactly `Ban User` (#11592).
- The refused pair draws none of the object's actions and reports once.
-
`packages/platform-objects/src/pages/record-page-header-actions.test.ts`
rewritten: per page, the object places header actions (non-vacuous), the
header node is exactly `{ placedActions: true }`, and
`ComponentPropsMap['page:header']` accepts it.
`sys-approval-request-page.test.ts` pins the new node.
- `packages/spec/src/ui/component.test.ts`: the marker test now asserts
the describe carries no `[PLANNED` marker.
- **Ablation**: the reader made to ignore the key (`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
- The ui pin mirrors the shipped header node rather than importing the
page: `@objectstack/platform-objects` is 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 #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 #30018's record);
flagging it for the seat.
- No 18.3.x release-notes line, per the maintainer's amendment to ruling
A.
## Verification
- **Live, on a dev boot** (`pnpm build` under `os-verify-lock`, 119/119;
showcase backend `pnpm dev -- --fresh -p 4317`; Console from `ui/` src
via vite with `DEV_PROXY_TARGET`). A writable package `com.qa.hdr`
stores `hdr_user_profile` (`type: 'url'`, `record_header`, on
`sys_user`) and the CONTROL `hdr_account_profile` on `showcase_account`.
Served: `GET /api/v1/meta/page/sys_user_detail`,
`sys_organization_detail` and `sys_approval_request_detail` each answer
`kind: 'full'` with
`{"type":"page:header","properties":{"placedActions":true}}`;
`/meta/object/sys_user` serves `hdr_user_profile`. Playwright readings:
- Setup → Users, full page: row Update Profile · Ban User · Set Password
· Edit · ⋯; ⋯ = Refresh · Impersonate User · Set Manager · Change
Password · Change Email · **QA User Profile** · Add to favorites · Share
· Delete My Account.
- Setup → Users, drawer: the same row; ⋯ = Impersonate User · Set
Manager · Change Password · Change Email · **QA User Profile** · Add to
favorites · Share · Open as full page · Delete My Account. The tab strip
(Details · Positions · Permission Sets · Business Units · Sessions …) is
unchanged.
- Before the fix (round 1, main `6a4737ab`), both readings were the same
lists without QA User Profile. CONTROL `showcase_account`, full page and
drawer: QA Account Profile · Edit · ⋯, as before.
- **ui suites** from the `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.ts` alone: 261
green with the exemption struck.
- **Package suites**: `@objectstack/platform-objects` `src/pages` 46,
`@objectstack/plugin-approvals` `sys-approval-request-page.test.ts` 20,
`@objectstack/spec` `src/ui/component.test.ts` 361, all green.
- **Type-check**: `@object-ui/types`, `@object-ui/components`,
`@object-ui/app-shell` (`type-check`, from the ui root),
`@objectstack/platform-objects`, `@objectstack/plugin-approvals`
(`typecheck`), `@objectstack/spec` `tsc --noEmit`: clean.
- **Generated**: `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.mjs` and `pnpm check:sdui-reference` green.
- **Gates**: every line of `node scripts/pm/dispatch-gates.mjs
--commands` on the final diff (119), then `--ran`: 119 derived, 119 run,
0 NOT-MEASURED, 0 UNRUN. 118 exit 0. `pnpm check:platform-checklist`
exits 1 on an absent `assertProtocolCompat` anchor in
`packages/metadata-protocol/src/protocol.ts`
(`areas/platform-core.json`); it is red the same way on merge base
`d79eecfe5b` and on `origin/main` `f35b361997`, outside this diff. Three
first-pass reds were re-run: `pnpm check:sdui-reference` was this diff's
own (component pages regenerated and committed, then green); `pnpm --dir
ui exec vitest run scripts/` (one 15 s timeout under load) and `pnpm
--filter @objectstack/spec run check:generated`
(`check:test-typecheck`'s tsc ran out of heap because this container's
`NODE_OPTIONS` carries no heap flag) were green re-run alone under the
lock, the second with `--max-old-space-size=4096` appended.
## Human Minimum
- [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic.
- [x] 2. Every name I added uses the casing for its kind.
- [x] 3. No formatter ran; `pnpm lint` passes. (The changed TypeScript
files pass eslint with 0 errors: the seven under `packages/` with the
root config and `--no-inline-config`, the six under `ui/` from the ui
root. CI's `pnpm lint` covers the full tree.)
- [x] 4. One issue, one branch off an up-to-date `main`, one pull
request.
- [x] 5. A change that publishes carries a changeset, and both
declaration lines are filled in here and in the changeset.
- [x] 6. `packages/spec` touched: its generated artifacts are
regenerated and committed.
- [x] 7. No hand edits to `content/docs/references/`,
`packages/*/CHANGELOG.md` or `content/docs/releases/`.
- [x] 8. Title, body and comments are in English, except the `## 维护者速读`
block, which is written in Chinese for the maintainer.
- [x] The *Before Submitting* list in CONTRIBUTING.md is done.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01WGufzh8VRbTbBnqwnrXsSL
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 987ff33 commit a52761f
22 files changed
Lines changed: 500 additions & 92 deletions
File tree
- .changeset
- content/docs
- protocol/objectui
- references/ui
- ui
- components
- packages
- platform-objects/src/pages
- plugins/plugin-approvals/src
- spec
- liveness
- src/ui
- scripts
- ui
- apps/console/src/__tests__
- packages
- app-shell/src/views
- components/src/renderers/layout
- types/src
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
93 | 93 | | |
94 | 94 | | |
95 | 95 | | |
96 | | - | |
97 | | - | |
98 | | - | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
99 | 99 | | |
100 | 100 | | |
101 | 101 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1575 | 1575 | | |
1576 | 1576 | | |
1577 | 1577 | | |
1578 | | - | |
| 1578 | + | |
1579 | 1579 | | |
1580 | 1580 | | |
1581 | 1581 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
109 | 109 | | |
110 | 110 | | |
111 | 111 | | |
112 | | - | |
| 112 | + | |
113 | 113 | | |
114 | 114 | | |
115 | 115 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
52 | 52 | | |
53 | 53 | | |
54 | 54 | | |
| 55 | + | |
55 | 56 | | |
56 | 57 | | |
57 | 58 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
296 | 296 | | |
297 | 297 | | |
298 | 298 | | |
299 | | - | |
| 299 | + | |
300 | 300 | | |
301 | 301 | | |
302 | 302 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
5 | | - | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
6 | 7 | | |
7 | | - | |
8 | | - | |
9 | | - | |
10 | | - | |
11 | | - | |
12 | | - | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
13 | 17 | | |
14 | | - | |
| 18 | + | |
| 19 | + | |
15 | 20 | | |
16 | 21 | | |
17 | 22 | | |
| 23 | + | |
18 | 24 | | |
19 | 25 | | |
20 | 26 | | |
21 | 27 | | |
22 | 28 | | |
23 | 29 | | |
24 | 30 | | |
25 | | - | |
26 | | - | |
| 31 | + | |
| 32 | + | |
27 | 33 | | |
28 | 34 | | |
29 | 35 | | |
| |||
34 | 40 | | |
35 | 41 | | |
36 | 42 | | |
37 | | - | |
38 | | - | |
| 43 | + | |
| 44 | + | |
39 | 45 | | |
40 | 46 | | |
41 | | - | |
| 47 | + | |
42 | 48 | | |
43 | 49 | | |
44 | 50 | | |
45 | 51 | | |
46 | 52 | | |
47 | | - | |
48 | | - | |
49 | | - | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
50 | 56 | | |
51 | 57 | | |
52 | | - | |
53 | | - | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
54 | 65 | | |
55 | 66 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
20 | | - | |
21 | | - | |
22 | | - | |
23 | | - | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
24 | 26 | | |
25 | 27 | | |
26 | 28 | | |
| |||
56 | 58 | | |
57 | 59 | | |
58 | 60 | | |
59 | | - | |
60 | | - | |
61 | | - | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
62 | 66 | | |
63 | 67 | | |
64 | 68 | | |
65 | | - | |
| 69 | + | |
66 | 70 | | |
67 | 71 | | |
68 | 72 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
40 | 40 | | |
41 | 41 | | |
42 | 42 | | |
43 | | - | |
44 | | - | |
45 | | - | |
46 | | - | |
47 | | - | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
48 | 50 | | |
49 | 51 | | |
50 | 52 | | |
| |||
84 | 86 | | |
85 | 87 | | |
86 | 88 | | |
87 | | - | |
88 | | - | |
89 | | - | |
90 | | - | |
91 | | - | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
92 | 94 | | |
93 | 95 | | |
94 | 96 | | |
95 | | - | |
96 | | - | |
97 | | - | |
98 | | - | |
99 | | - | |
100 | | - | |
101 | | - | |
102 | | - | |
103 | | - | |
104 | | - | |
105 | | - | |
106 | | - | |
107 | | - | |
| 97 | + | |
108 | 98 | | |
109 | 99 | | |
110 | 100 | | |
| |||
0 commit comments