Repository navigation
Commit 77a52cf
Fixes #26187
Clause-②: no
Metadata-protocol: none
## 维护者速读
改了什么:Setup → 岗位页面上,岗位列出的每个权限集各显示一个只读的权限预览(对象 ×
增删改查、读写记录范围、字段、行级策略),按岗位列出的顺序排列,标题是权限集名并链接到该权限集页面;找不到的权限集只显示一行「未找到」,岗位没列权限集时显示空状态。
为什么改:#26187
的裁决(Q1)要求岗位页能看到权限集授予的范围;之前岗位页只列权限集名字,管理员必须逐个打开权限集才知道岗位到底给了什么。权限集页面本身已由
PR 1(#26284)的矩阵选择器显示范围,席位裁定不再加第二份只读副本。
风险与回滚:只改 app-shell 的岗位页面(新增一个只读区块 + 环境区块从单个改为列表)和 i18n
新键,不改任何写入、规范或接口;最坏情况是岗位页多出一个显示不对的区块,不影响保存。回滚 = revert 本 PR。
先看:`ui/packages/app-shell/src/views/metadata-admin/PositionPermissionSetsSection.tsx`(风险
hunk:按名读取权限集的 effect,404 → 未找到、其它错误 → 拒绝原文)→
`ResourceEditPage.tsx`(`ENVIRONMENT_SECTIONS` 改为数组并把页面草稿传入)→
`i18n.ts`(en + zh 各 7 个新键)。
两分钟验证:在 `ui/` 下跑 `pnpm exec vitest run
packages/app-shell/src/views/metadata-admin/PositionPermissionSetsSection.test.tsx
packages/app-shell/src/views/metadata-admin/ResourceEditPage.positionPermissionSets-26187.test.tsx
--maxWorkers=2`,预期 `Test Files 2 passed (2)` / `Tests 9 passed (9)`;或打开
`/apps/setup/metadata/position/POSITION_NAME?scope=environment`,持有人区块下方出现「Permission
sets」区块。
需要你做的:无,席位落地
## What changes
PR 2 of 2 (PR 1, the matrix scope pickers, merged as #26284). This PR
touches the position page only: the seat ruled that the permission-set
page needs no second, read-only preview, because its matrix already
shows each object's read and write scope since PR 1.
- **New `PositionPermissionSetsSection`**
(`metadata-admin/PositionPermissionSetsSection.tsx`). On the Setup
position page (environment scope, not create mode, not embedded), under
the definition and after the holders, it renders one `PermissionPreview`
per permission set the position names in `permissionSets`:
- in declared order, each under an `h3` with the set's name, linking to
`../../permission/NAME` (path-relative, keeping `?scope=environment`),
so the link lands on the set's own page in the same catalog scope;
- each preview is the set's own body, read with
`client.get('permission', name)` through the console metadata client the
page already uses. No union of sets is computed and nothing is editable
(the preview gets no `onPatch`; the section holds no control);
- a named set the server does not serve (`get` answers `null` on 404)
shows one line, `Permission set "NAME" was not found.`, for that set
only; the other previews still render;
- a refused or failed read shows `Permission set "NAME" could not be
read.` plus the server's sentence, not "not found": a refused read is
not an absent set;
- a position that names no sets shows `This position names no permission
sets.` and reads nothing.
- The names come from the page's draft (as `PositionPreview` above it
reads them), and the read effect keys on the list's content, so editing
another field does not re-read the sets.
- **`ResourceEditPage.tsx`**: `ENVIRONMENT_SECTIONS` maps a type to an
ordered list of sections, each handed `{ name, draft }`; `position` is
`[PositionHoldersSection, PositionPermissionSetsSection]`.
`PositionHoldersSection` is unchanged and still reads only `name`.
- **`i18n.ts`**: 7 new `engine.position.sets.*` keys, en and zh, beside
the existing `engine.position.*` block. No existing key changes.
- **`PermissionPreview.tsx`**: unchanged. Without `onPatch` it is
already read-only, so no prop was needed.
- Changeset: `.changeset/26187-position-permission-preview.md`,
`@object-ui/app-shell` patch.
## Tests
- New `PositionPermissionSetsSection.test.tsx` (6 tests): two named sets
give two previews in declared order, each with its own objects and
scopes (no union), each headed by the set name with the right href;
read-only (no checkbox, combobox or button); a missing set gives one
not-found line only for that set; a refused read is said as a refusal,
not "not found"; no sets, and no `permissionSets` key, give the empty
state and no read.
- New `ResourceEditPage.positionPermissionSets-26187.test.tsx` (3
tests): the Setup position page mounts the previews in order beside the
holders; Studio (no scope) and another type in the Setup scope do not.
- Red first, ablation, green, the importer suite and the type-check are
in Verification below.
## Acceptance notes
- **Declared sets only.** The section shows exactly the sets the
definition names. The position-name fold (a set sharing the position's
name) is retired on `main`
(`.changeset/24757-retire-position-name-fold.md`), so the declared list
is the whole grant; the list page's served `_grantedPermissionSets`
column remains the server's own answer.
- **Draft, not saved state.** The names are read from the definition on
screen, so an unsaved edit to `permissionSets` previews the edited list.
The Setup position page renders read-only for a caller without
`manage_metadata`, where the draft equals the stored definition.
- **Layout.** Under the designer, the environment sections share the
existing bounded strip (`max-h-[35vh]`, scrolling), so several previews
scroll inside it rather than squeezing the canvas.
- Card relation is declared once, in this body.
## Verification
<details><summary>Red first — the two new files against `origin/main`
46255b1's implementation (tree only), then restored</summary>
`ResourceEditPage.tsx` and `i18n.ts` restored to `46255b19` in the
working tree only (blob equal to the `main` blob; 0
`engine.position.sets` keys) and the new component removed, under
`scripts/pm/os-verify-lock.sh`:
- `ResourceEditPage.positionPermissionSets-26187.test.tsx`: `Tests 1
failed | 2 passed (3)`. The failing test is the positive pin (`renders
one preview per named set, in declared order, beside the holders`); the
two passing ones are its absence controls (Studio, another type).
- `PositionPermissionSetsSection.test.tsx`: fails to resolve
`./PositionPermissionSetsSection` (the module does not exist on `main`).
- Restore proven: every restored blob equals its `HEAD` blob, `git diff
HEAD` empty.
</details>
<details><summary>Ablation, once — a refused read reported as
missing</summary>
`node scripts/ablation-replace.mjs` replaced the failed-read arm `(err:
unknown): SetRead => ({ state: 'failed', ... })` with `(): SetRead => ({
state: 'missing' })` (anchor x1 -> x0, blob `83ca6312` -> `60eba45d`).
`PositionPermissionSetsSection.test.tsx`: `Tests 1 failed | 5 passed
(6)`, the failing test being `a refused read is said as a refusal, not
as "not found"`. Restored: blob == HEAD (`83ca6312`), `git diff HEAD`
empty. No `dist` is involved: app-shell tests import `src`.
</details>
<details><summary>Green on the final head 771f48f (after merging `main`
with #26340), each under the verify lock</summary>
- Closure `pnpm exec turbo run build --filter='@object-ui/app-shell^...'
--concurrency=2`: exit 0.
- The two new files: `Test Files 2 passed (2)` / `Tests 9 passed (9)`.
- Every app-shell test file that imports `ResourceEditPage`,
`PermissionPreview`, `PositionHoldersSection`, the new section or
`metadata-admin/i18n` (resolved by real import path, 291 files), plus
#26191's `PermissionAdvancedFacets.companionGrants-26191.test.tsx`,
which shares `i18n.ts`: `Test Files 292 passed (292)` / `Tests 2726
passed (2726)`, exit 0.
- `pnpm --filter @object-ui/app-shell type-check` (both tsc programs,
`tsconfig.test.json` included): exit 0.
- The full app-shell suite was not run locally (it holds the shared lock
for 50+ minutes); CI's Test UI shards run it.
</details>
<details><summary>Derived gates — `dispatch-gates --commands --repo
objectstack-ai/objectstack` at 771f48f: 35 commands, all exit 0;
`--ran`: 35 derived, 35 run, 0 NOT-MEASURED</summary>
Derivation header: `gate list derived from the tree of
'objectstack-ai/objectstack' at commit 771f48f`; change set 6 paths,
495 changed lines (+489 / -6), under the 3000 human-merge threshold.
Each command via `bash -c`, exit code captured before any pipe.
| command | exit | wall |
|:--|:--|:--|
| `node scripts/check-adr-0087-registration.mjs --base origin/main` | 0
| 4s |
| `node scripts/check-adr-0087-registration.mjs --self-test` | 0 | 48s |
| `node scripts/check-changeset-no-major.mjs --base origin/main` | 0 |
0s |
| `node scripts/check-changeset-no-major.mjs --self-test` | 0 | 8s |
| `node scripts/check-closing-keyword-parity.mjs` | 0 | 2s |
| `node scripts/check-closing-keyword-parity.mjs --self-test` | 0 | 4s |
| `node scripts/check-comment-mask-corpus.mjs` | 0 | 190s |
| `node scripts/check-empty-changeset.mjs --base origin/main` | 0 | 0s |
| `node scripts/check-empty-changeset.mjs --self-test` | 0 | 2s |
| `node scripts/check-sdui-manifest.mjs` | 0 | 0s |
| `node scripts/check-sdui-manifest.mjs --self-test` | 0 | 3s |
| `node scripts/check-undeclared-dep-imports.mjs` | 0 | 5s |
| `node scripts/check-undeclared-dep-imports.mjs --self-test` | 0 | 5s |
| `node scripts/pm/release-rehearsal-clone.mjs --self-test` | 0 | 2s |
| `node scripts/release-pending-publish.mjs --self-test` | 0 | 5s |
| `pnpm --filter @objectstack/spec run check:duration-unit-keys` | 0 |
8s |
| `pnpm check:changeset-gate-self-tests` | 0 | 61s |
| `pnpm check:closed-ceremony-text` | 0 | 3s |
| `pnpm check:cross-package-test-inputs` | 0 | 28s |
| `pnpm check:dispatcher-error-vocabulary` | 0 | 6s |
| `pnpm check:driver-memory-census` | 0 | 5s |
| `pnpm check:engine-double-contract` | 0 | 53s |
| `pnpm check:gitlink-declared` | 0 | 1s |
| `pnpm check:nul-bytes` | 0 | 3s |
| `pnpm check:pm-changeset-deadline-census` | 0 | 1s |
| `pnpm check:published-files` | 0 | 1s |
| `pnpm check:query-options-erasure` | 0 | 299s |
| `pnpm check:refd-timer-probe` | 0 | 19s |
| `pnpm check:skill-identifier-liveness` | 0 | 9s |
| `pnpm check:test-source-alias` | 0 | 26s |
| `pnpm check:tier-file-adoption` | 0 | 0s |
| `pnpm check:type-check-coverage` | 0 | 5s |
| `pnpm check:watch-hint-literal` | 0 | 6s |
| `pnpm check:where-matcher` | 0 | 11s |
| `pnpm check:type-check-debt` (run under the verify lock) | 0 | 110s
re-measure |
`check-sdui-manifest`: `sdui.manifest.json is present, intact (sha256
1f6e1ccb925a…, 106 components)`; app-shell has no sdui record and
`scripts/sdui-manifest.*` is untouched.
</details>
---
_Generated by [Claude
Code](https://claude.ai/code/session_01SMps7wq7rBTk53e8KTSEup)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 4ddf6df commit 77a52cf
6 files changed
Lines changed: 489 additions & 6 deletions
File tree
- .changeset
- ui/packages/app-shell/src/views/metadata-admin
| 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 | + | |
| 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 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 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 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
0 commit comments