Skip to content

feat(app-shell): the permission-set editor shows the Export column, and Assigned Users no longer covers the grid - #26955

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/project-thread-4s2d7m
Oct 28, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/project-thread-4s2d7m

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Steedos · project thread

Fixes #26885

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:权限集编辑器(Setup 页与 Studio「访问」的对象页)增加「导出」列(E,allowExport),位置在删除与转移之间,和岗位页摘要的顺序一致,可以看到并勾选。Setup 页的「已分配用户」面板从网格下方固定的 35% 高条带,移到网格自己的滚动区里、排在网格和高级设置之后;手机宽度下整页一起滚动。
  • 为什么改:原来授予导出的权限集和不授予的看起来一样,管理员无法在授予它的权限集上看到导出权限;笔记本上「已分配用户」面板挤得网格只剩约 5 行,手机上一行都看不到。
  • 风险与回滚:低。只改前端编辑器的列表与布局,服务端、spec 不动,存储的数据不变。批量按钮 R / CRUD / All 都不碰导出(导出是需要单独授予的高权限项,All 的提示里写明),None 仍清空整行。回滚即还原本 PR。
  • 先看:ui/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx 的 getObjectActions(新增 optIn 的 Export 行)、bulkSetObject(bulkKeys 排除导出)、页面主体(perm-assignments 移进网格滚动区,外层 md:h-full md:overflow-hidden);PermissionMatrixEditor.exportColumn-26885.test.tsx。
  • 两分钟验证:pnpm --dir ui exec vitest run packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.exportColumn-26885.test.tsx,预期 9 个测试全绿。
  • 需要你做的:无,席位落地。

What changes

  • Export is a matrix column. getObjectActions lists allowExport (E, "Export records"; zh 导出记录) between Delete and Transfer, the order previews/PermissionPreview's CAPS uses for the position summary. Both renderings read that list, so the routed Setup page's table and the Studio Access pillar's Objects tab both gain the header, the per-row checkbox (toggled through updateObjectPerm, like Transfer) and the legend entry (engine.studio.access.legend.export). ObjectPerm in permission-slice.ts declares the key (one line), so ObjectPermFlag covers it.
  • The bulk buttons leave Export as it is. The entry carries optIn: true; bulkSetObject resets and grants only the other columns (bulkKeys). So R, CRUD and All neither set nor clear Export, which is what they did before this change too, when the key rode through unmodelled. "All" gets a tooltip saying so (perm.bulk.allTip). "None" still replaces the row with {}, unchanged. Reason for the choice: allowExport is the opt-in, high-privilege export axis (packages/spec/src/security/high-privilege.ts, the ADR-0090 D5 list), whose point is that export is granted deliberately; a button labelled "All" quietly granting bulk egress would undo that. The bulk-arm pins in PermissionMatrixEditor.bulkMergeKeys.test.tsx hold unchanged; only their comments are updated.
  • Assigned Users scrolls with the grid. The Setup page's perm-assignments panel moves from a shrink-0 max-h-[35vh] strip under the matrix into the matrix's own scroll box, after the grid and the advanced facets.
  • On a phone the page scrolls as one. Below md the editor's column takes its content's height (md:h-full md:overflow-hidden), so PageShell's body scrolls the chrome and the grid together. From md up nothing changes. The filter bar wraps (flex-wrap, input w-full sm:w-72).
  • The grid's minimum width grows by the one column (1248px to 1304px) on both renderings.
  • Four new studio namespace rows in @object-ui/i18n, en and zh. One root changeset: @object-ui/app-shell patch, @object-ui/i18n patch.
  • No packages/spec/**, no server change, no new metadata key.

Tests

PermissionMatrixEditor.exportColumn-26885.test.tsx, nine cases on the real PermissionMatrixEditPage, asserting the saved payload:

  • the E header sits between D and Tr, titled "Export records";
  • a stored grant shows ticked, and unticking saves allowExport: false; ticking saves allowExport: true and nothing else;
  • the Studio Objects tab has the column and its legend entry, and its checkbox saves the grant;
  • "All" grants the seven other columns and not Export, and its tooltip says so; "R", "CRUD" and "All" each keep a granted Export ticked and saved;
  • in the Setup scope, Assigned Users is inside the grid's scroll box and after the table.

PermissionMatrixEditor.retiredLifecycleKeys.test.tsx: the live column set now includes E (the pin's purpose is the exact set).

Acceptance notes

  • Measured in a browser (Chromium, pnpm dev:crm -- --fresh, Setup → Permission Sets → crm_sales_user, 83 objects, the built Console from this branch). At 1440×900: the grid's scroll box is 441px tall with 9 object rows fully on screen, the panel sits after the grid at the end of that scroll, no horizontal page overflow. At 390×844: once the page is scrolled to the grid, 12 rows are on screen (before the phone change, the grid's own box was 121px tall with 2 rows). "Only granted" is fully in view at both widths. The before reading (about 5 rows at 1440×900, none at 390×844) is the filer's, from the card's screenshots; I did not rebuild main to re-measure it. Screenshots are in the project files under issue-26885/.
  • crm_sales_user is a code-package set, so it is read-only in the browser; toggling Export is covered by the tests above, not the browser pass.
  • On a phone the table header is not sticky while the page scrolls (it is sticky inside the grid's own box from md up).
  • At 1440×900 the grid is still wider than the content area with the Setup sidebar open (minimum 1304px), so Bulk and the scope pickers sit behind the grid's horizontal scroll, as before.

Verification

All at head dafbeddd, in a worktree off origin/main 8074feb6, unless a line names another head.

New tests, ablations, type-check and nearby suites
  • pnpm --dir ui exec vitest run on PermissionMatrixEditor.exportColumn-26885, .bulkMergeKeys, .retiredLifecycleKeys and .setupCatalog-7611 under scripts/pm/os-verify-lock.sh: Test Files 4 passed (4), Tests 26 passed (26).
  • Ablation 1 (node scripts/ablation-replace.mjs, anchor const bulkKeys = OBJECT_ACTIONS.filter((a) => !a.optIn).map((a) => a.key); replaced by const bulkKeys = OBJECT_ACTIONS.map((a) => a.key);, anchor x1 to x0): Tests 3 failed | 6 passed (9), the three bulk cases ("All" grants every other column but not Export, "R" and "CRUD" keep a granted Export). Restored, blob equal to HEAD (b1f94509ca8b). The tests import the editor from source, so no build sits between mutation and run.
  • Pre-fix leg for the layout case: the new test file run against origin/main's PermissionMatrixEditor.tsx (written to disk, restored from HEAD under a trap, blob checked): "renders in the matrix's own scroll, after the grid" fails (expected false to be true).
  • pnpm --filter @object-ui/app-shell run type-check && pnpm --filter @object-ui/i18n run type-check under the lock: VERDICT command-exit 0 (app-shell's covers the test files).
  • Narrowed suite at 3c942530 (the later commit touches only ui/scripts/): every app-shell test file naming PermissionMatrixEdit, permission-slice, a perm.action / perm.bulk / engine.studio.access key or AccessPillar (52 files), plus all of packages/i18n/: Test Files 141 passed (141), Tests 1756 passed | 13 skipped (1769). CI's Test UI runs the rest of app-shell.
  • pnpm run check:i18n-designer-parity (from ui/): "Every en row has a zh row, and every shared row carries the same placeholders." pnpm check:new-line-citations (from ui/): 0 new citation(s).
Browser measurement

Chromium (Playwright), pnpm dev:crm -- --fresh on a private port, the Console built from this branch (turbo run build then pnpm console:build), signed in as the seeded admin, /_console/apps/setup/metadata/permission/crm_sales_user?scope=environment:

  • 1440×900: headers Object C R U D E Tr VA MA Read scope Write scope Bulk; the grid's scroll box is 441px tall from y=459, 9 object rows fully on screen; perm-assignments inside that box, after the grid; "Only granted" in view; no horizontal page overflow.
  • 390×844: same headers; the column is page-height and the page body scrolls it; with the grid scrolled to the top of the body (661px), 12 object rows fully on screen; "Only granted" in view (x 76–148); no horizontal page overflow. Before the phone change, at 9ee0f570, the grid's own box was 121px tall with 2 rows.
Derived dispatch gates (34/34)
  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 34 commands at dafbeddd; every one exited 0, the PR-body gates (check-closing-keyword-parity, check-adr-0087-registration, check-changeset-no-major) against this body.
  • pnpm --dir ui exec vitest run scripts/ under the lock: Test Files 178 passed | 2 skipped (180), Tests 5065 passed | 2 skipped (5067). Its first run at 3c942530 was red in one case: check-designer-field-key-parity.test.ts "stays EMIT-SIDE" named allowExport as the key ObjectPerm omits. That is no longer true, so the case now names allowRestore (still accepted by the spec, still omitted), and the gate's header comment lists the current omissions.
  • pnpm check:type-check-debt under the lock: 0 raw tsc error(s) total, none above its recorded number.
  • dispatch-gates --ran: 34 derived famil(ies) accounted for — 34 run, 0 NOT-MEASURED.
  • pnpm check:nul-bytes: OK.

Dogfood battery: not run, no ! in the title and no (narrowing) arm.


Generated by Claude Code

…nd Assigned Users scrolls under the grid

The matrix lists Export (allowExport) between Delete and Transfer, as the
position summary does, on the routed page and the Studio Objects tab. It is
an opt-in grant: the R, CRUD and All buttons leave it as it is, and All says
so on its tooltip. The Setup page's Assigned Users panel moves into the
matrix's own scroll, after the grid, instead of a 35vh strip pinned under it,
and the filter bar wraps on a phone.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsR2jURizai1Jspt8sbMXk
Below md the chrome above the matrix is taller than the screen, so the
grid's own scroll box was about 120px tall at 390x844. There the column now
takes its content's height and PageShell's body scrolls it; from md up the
matrix keeps its own scroll.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsR2jURizai1Jspt8sbMXk
…cle pair

ObjectPerm now declares allowExport (the matrix's Export column), so the
EMIT-SIDE case's example of a key the shape omits moves to allowRestore,
which the spec still accepts. The gate header's list of omissions is
corrected to match.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsR2jURizai1Jspt8sbMXk
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface labels Oct 27, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对

ACCEPT · seat domain:ui#4 · session_01QsR2jTfvjNTaR29ehLk26T · 2026-10-27T23:18Z · head dafbeddd52caf1727f190aa1779cbb282a4aece2

  1. Shape: draft, base main, Fixes #26885. Clause-②: no and Metadata-protocol: none are in the body and the changeset, and they match the claim (6454597659). Ten files: PermissionMatrixEditor.tsx (+50/−24), the studio namespace en.ts/zh.ts (+3 each), one new test file and two updated pins beside, one root changeset (@object-ui/app-shell and @object-ui/i18n, both patch), plus the two accepted deviations below. No packages/spec/**, no server package, no metadata key.
  2. Premise, measured: the seat read the diff.
    • getObjectActions gains allowExport (E, "Export records") between D and Tr, marked optIn. It shows on the Setup page and in Studio's Access Objects tab, through STUDIO_LEGEND_KEYS.
    • The granting bulk arms reset and grant only the non-optIn columns, so R, CRUD and All neither set nor clear Export, and All's tooltip says so. None still empties the row.
    • Assigned Users moves into the matrix scroll after the grid, out of the shrink-0 max-h-[35vh] strip. Below md the page scrolls as one, and the filter bar wraps.
    • The new file has its cases, the ablation reddens 3, and the layout case is red against main. The thread measured 9 rows at 1440×900 and 12 rows at 390×844 once the grid scrolls up.
  3. Gates, pinned to the head: check-runs?filter=latest 43 success, 9 skipped, 0 failing or pending · check-governed-merges --pr 26955: NOT governed, +284/−32. mergeable_state: clean. origin/main b1b153a3 has no allowExport column, so nothing here is already landed.
  4. Accepted deviations:
    • permission-slice.ts +2. ObjectPerm declares allowExport, so the column's key type-checks. This is the editor's own payload shape, and the spec already declares the key.
    • ui/scripts/check-designer-field-key-parity test and header comment. Its emit-side case named allowExport as the key ObjectPerm omits, which is now false by design. It is repointed to the retired allowRestore, so the case still proves a non-empty omission. Not a weakened assertion.
    • Open question, answered A by the seat (shipped): All does not grant Export. It is an opt-in, high-privilege axis (security/high-privilege.ts ~106), so a button labelled All should not silently widen export.
  5. Out of scope: the thread notes that the phone header is not sticky while the page scrolls. That note is in the PR's Acceptance notes, and no card is filed. No skip, quarantine or raised timeout. Skills-docs: is not owed.
  6. Prose face, checked against the diff: the changeset's four bullets match the code (column order, bulk behaviour, the panel's new place, phone scroll). The code comments cite Setup permission-set editor: no Export column, so allowExport cannot be seen on the set, and the Assigned Users panel covers the object grid (at 390 px no object row is visible) #26885.

Landing: no contract review is owed (no published schema, no governed text, Clause-②: no). The seat marks the PR ready and arms auto-merge. On MERGED, Fixes #26885 closes the card.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Projects

None yet

2 participants