Repository navigation
fix(app-shell): the Setup position page previews each permission set it names, read-only (#26187) - #26360
Conversation
…views (#26187) Red first: the Setup position page names its permission sets but shows nothing of what they grant. Claude-Session: https://claude.ai/code/session_01SMps7wq7rBTk53e8KTSEup Co-authored-by: Claude <noreply@anthropic.com>
…it names, read-only (#26187) One PermissionPreview per named set, in declared order, under the set's name and a link to its page. No client-side union, no editing. A set the server does not serve shows one not-found line; a refused read says so. Claude-Session: https://claude.ai/code/session_01SMps7wq7rBTk53e8KTSEup Co-authored-by: Claude <noreply@anthropic.com>
…set previews (#26187) Claude-Session: https://claude.ai/code/session_01SMps7wq7rBTk53e8KTSEup Co-authored-by: Claude <noreply@anthropic.com>
…#26187) A path-relative link resolves against the matched route's pathname, so the href pin needs the route the console mounts the page under. Claude-Session: https://claude.ai/code/session_01SMps7wq7rBTk53e8KTSEup Co-authored-by: Claude <noreply@anthropic.com>
维护者速读改了什么:Setup → 岗位页面上,岗位列出的每个权限集各显示一个只读的权限预览(对象 × 增删改查、读写记录范围、字段、行级策略),按岗位列出的顺序排列,标题是权限集名并链接到该权限集页面;找不到的权限集只显示一行「未找到」,岗位没列权限集时显示空状态。 席位核对seat 2 · 2026-10-26T23:45Z · head
|
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.
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 onePermissionPreviewper permission set the position names inpermissionSets:h3with 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;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 noonPatch; the section holds no control);getanswersnullon 404) shows one line,Permission set "NAME" was not found., for that set only; the other previews still render;Permission set "NAME" could not be read.plus the server's sentence, not "not found": a refused read is not an absent set;This position names no permission sets.and reads nothing.PositionPreviewabove 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_SECTIONSmaps a type to an ordered list of sections, each handed{ name, draft };positionis[PositionHoldersSection, PositionPermissionSetsSection].PositionHoldersSectionis unchanged and still reads onlyname.i18n.ts: 7 newengine.position.sets.*keys, en and zh, beside the existingengine.position.*block. No existing key changes.PermissionPreview.tsx: unchanged. WithoutonPatchit is already read-only, so no prop was needed..changeset/26187-position-permission-preview.md,@object-ui/app-shellpatch.Tests
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 nopermissionSetskey, give the empty state and no read.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.Acceptance notes
main(.changeset/24757-retire-position-name-fold.md), so the declared list is the whole grant; the list page's served_grantedPermissionSetscolumn remains the server's own answer.permissionSetspreviews the edited list. The Setup position page renders read-only for a caller withoutmanage_metadata, where the draft equals the stored definition.max-h-[35vh], scrolling), so several previews scroll inside it rather than squeezing the canvas.Verification
Red first — the two new files against `origin/main` 46255b1's implementation (tree only), then restored
ResourceEditPage.tsxandi18n.tsrestored to46255b19in the working tree only (blob equal to themainblob; 0engine.position.setskeys) and the new component removed, underscripts/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 onmain).HEADblob,git diff HEADempty.Ablation, once — a refused read reported as missing
node scripts/ablation-replace.mjsreplaced the failed-read arm(err: unknown): SetRead => ({ state: 'failed', ... })with(): SetRead => ({ state: 'missing' })(anchor x1 -> x0, blob83ca6312->60eba45d).PositionPermissionSetsSection.test.tsx:Tests 1 failed | 5 passed (6), the failing test beinga refused read is said as a refusal, not as "not found". Restored: blob == HEAD (83ca6312),git diff HEADempty. Nodistis involved: app-shell tests importsrc.Green on the final head 771f48f (after merging `main` with #26340), each under the verify lock
pnpm exec turbo run build --filter='@object-ui/app-shell^...' --concurrency=2: exit 0.Test Files 2 passed (2)/Tests 9 passed (9).ResourceEditPage,PermissionPreview,PositionHoldersSection, the new section ormetadata-admin/i18n(resolved by real import path, 291 files), plus Setup permission set, Delegated Admin Scope: no hint or one-click grant for the companion grants a delegate needs to enter Setup and pick people #26191'sPermissionAdvancedFacets.companionGrants-26191.test.tsx, which sharesi18n.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.jsonincluded): exit 0.Derived gates — `dispatch-gates --commands --repo objectstack-ai/objectstack` at 771f48f: 35 commands, all exit 0; `--ran`: 35 derived, 35 run, 0 NOT-MEASURED
Derivation header:
gate list derived from the tree of 'objectstack-ai/objectstack' at commit 771f48f4; change set 6 paths, 495 changed lines (+489 / -6), under the 3000 human-merge threshold. Each command viabash -c, exit code captured before any pipe.node scripts/check-adr-0087-registration.mjs --base origin/mainnode scripts/check-adr-0087-registration.mjs --self-testnode scripts/check-changeset-no-major.mjs --base origin/mainnode scripts/check-changeset-no-major.mjs --self-testnode scripts/check-closing-keyword-parity.mjsnode scripts/check-closing-keyword-parity.mjs --self-testnode scripts/check-comment-mask-corpus.mjsnode scripts/check-empty-changeset.mjs --base origin/mainnode scripts/check-empty-changeset.mjs --self-testnode scripts/check-sdui-manifest.mjsnode scripts/check-sdui-manifest.mjs --self-testnode scripts/check-undeclared-dep-imports.mjsnode scripts/check-undeclared-dep-imports.mjs --self-testnode scripts/pm/release-rehearsal-clone.mjs --self-testnode scripts/release-pending-publish.mjs --self-testpnpm --filter @objectstack/spec run check:duration-unit-keyspnpm check:changeset-gate-self-testspnpm check:closed-ceremony-textpnpm check:cross-package-test-inputspnpm check:dispatcher-error-vocabularypnpm check:driver-memory-censuspnpm check:engine-double-contractpnpm check:gitlink-declaredpnpm check:nul-bytespnpm check:pm-changeset-deadline-censuspnpm check:published-filespnpm check:query-options-erasurepnpm check:refd-timer-probepnpm check:skill-identifier-livenesspnpm check:test-source-aliaspnpm check:tier-file-adoptionpnpm check:type-check-coveragepnpm check:watch-hint-literalpnpm check:where-matcherpnpm check:type-check-debt(run under the verify lock)check-sdui-manifest:sdui.manifest.json is present, intact (sha256 1f6e1ccb925a…, 106 components); app-shell has no sdui record andscripts/sdui-manifest.*is untouched.Generated by Claude Code