Repository navigation
Commit cba12d2
fix(app-shell): the permission matrix's field boxes stay reachable while the matrix scrolls sideways (#29744)
<!-- claude-projects-attribution: {"github_login":"zhuangjianguo"} -->
_Requested by **Steedos** · [project
thread](https://claude.ai/code/project/chan_018ETKaNwMZCNRYD7D8Q9Ubb?thread=cmsg_018ETKaNwMZCNRYD7D8Q9Ubb4LsB3BascUZYPdoexzAj3a)_
Fixes #29677
Clause-②: no
Metadata-protocol: none
Claim:
[6593552174](#29677 (comment))
## 维护者速读
-
**改了什么**:权限集矩阵里展开一个对象后,下方的字段面板(筛选、计数、批量按钮和字段表)现在固定在视口内,横向滚动矩阵时不再跟着跑,也不再被“字段名”那一列盖住;Studio
Access 和元数据管理两处的矩阵都改了。
- **为什么改**:矩阵最窄 1304 px,窗口更窄就要横向滚动;原来钉在左边的字段名列宽约 700 px,滚动约 80 px
后就把每个字段的“读 / 编辑”勾选框全部盖住,窄屏上管理员根本点不到,字段权限改不了。
-
**风险与回滚**:只改了一个文件里的样式类(滚动区加容器查询、字段面板改为吸附定位),没有数据、接口或元数据变化;窗口够宽、矩阵不滚动时外观与原来一致。回滚即还原本
PR。
- **先看**:`PermissionMatrixEditor.tsx` 里的 `FIELD_PANEL` / `MATRIX_PANE`
两个常量和 `FieldsSubTable`
根节点;`ui/e2e/permission-field-panel-scroll.spec.ts`(浏览器里逐个滚动位置点中每个勾选框)。
- **两分钟验证**:`cd ui && CI=1 pnpm exec playwright test
e2e/permission-field-panel-scroll.spec.ts --project=chromium`,预期 6 条全绿;在
main 的编辑器上同一命令在 scrollLeft 80 处报“勾选框被字段名单元格盖住”。
- **需要你做的**:无,席位落地。
## What changes
`ui/packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx`
only:
- **The field panel is pinned, not the name column.** The field
sub-table under an expanded object sits in one cell spanning the whole
1304 px matrix, and the table is `w-full`, so its name column (the only
unsized one) took all the leftover width, about 697 px.
objectstack#26846 pinned that column `sticky left-0`, so once the pane
scrolled about 80 px it slid over both boxes. Bounding the column's
width alone would not do: the boxes sit right after the name, so any
scroll past the cell's inset still slides them under a pinned name. Now
`FieldsSubTable`'s root (filter, count, bulk buttons, legend and table)
carries `FIELD_PANEL` = `sticky left-12 max-w-[calc(100cqi-6rem)]`: it
holds its place at the expanded cell's own inset (`pl-12` on Studio's
matrix, `px-12` on the metadata admin's) and is no wider than the pane
shows less both insets. The name header and cells lose their own pin
(`FIELD_NAME_CELL` is gone); the header keeps its top pin from
objectstack#27866 (`FIELD_HEAD_CELL`).
- **The pane is the size container.** Both `MatrixScrollPane` call sites
pass `MATRIX_PANE` = `flex-1 @container`, which sets the container on
the pane's outer box (the same width as its scroll box), so `100cqi` is
the pane's width. `MatrixScrollPane.tsx` is unchanged.
- Where the pane holds the whole matrix, nothing scrolls and the panel
spans the cell as the table did (measured: equal on the metadata admin's
48 + 48 px insets, 24 px narrower on Studio's 48 + 24 px).
The QA item `studio-authoring.permission-matrix-editor-ux` (revision 10)
gains clause acceptance[6], step B5 (steps[8]) and negative[2] for the
field boxes under a sideways scroll, appended so no existing index
moves, and its `automated.ref` names the new spec. One changeset,
`@object-ui/app-shell` patch.
## Why
The card's runner reading on main at `3482f3d8d2`: `elementFromPoint` at
a field box centre answered `perm-field-name-OBJ-FIELD` from scrollLeft
80 up, and below 1304 px of pane width the boxes could not be reached at
all. Re-measured on main at `c76cdebf` before the fix (below).
## Tests
- **New: `ui/e2e/permission-field-panel-scroll.spec.ts`** (Playwright,
picked up by `ui/playwright.config.ts`, `testDir: ./e2e`; CI runs it in
the required `Build & E2E UI` job, `pnpm --dir ui run test:e2e
--project=chromium`). It bundles the real `PermissionMatrixEditPage`
from source with Vite (the metadata client stubbed at bundle time the
way the jsdom tests `vi.mock` it), styles it with the real Tailwind
theme, expands an object of eight fields, and at scroll offsets 0, 40,
57, 80, 120, 200, 320, 480 and the far end reads `elementFromPoint` at
every Read and Edit box centre and at each field name. Six cases: Studio
and metadata-admin renderings at 1000 px and 720 px panes (every box
answers, the panel holds one left offset); a CONTROL at a 1600 px pane
(nothing scrolls, every box answers at scrollLeft 0, green on main too);
and the pin not binding at 1600 px (panel width equals the cell's
content width).
- **Updated jsdom pins** (class contract, guarded in Test UI):
`PermissionMatrixEditor.fieldTableLayout-26846.test.tsx` now pins, on
both renderings, the panel's `sticky left-12 max-w-[calc(100cqi-6rem)]`,
the cell's 48 px inset, `@container` on the pane, the toolbar, header,
names and both boxes inside the panel, and no `sticky` on the name
cells; `PermissionMatrixEditor.gridChrome-27866.test.tsx`'s field-header
pin now expects the name header without `left-0` (it pinned the old
`left-0 z-[3]`).
- **Ablation** (main's `PermissionMatrixEditor.tsx` restored into the
tree under a trap, blob `aa5d4f53` = `origin/main`; restored to HEAD
blob `a0b449fd`, `git status` clean): the spec's four sweep cases go red
with `Read box of amount at scrollLeft 80 (pane 1000/1304) is covered by
td[data-testid=perm-field-name-a_project-amount]` (same at 720 px), the
1600 px CONTROL stays green, the no-bind case is red (no panel); jsdom 4
of 12 red (both panel pins, both field-header pins).
<details><summary>Live Console measure (Vite on source + app-crm
backend, 1000 px window)</summary>
`/studio/~all/metadata/permission/qa_field_scroll` (a writable env-scope
set granting `crm_account`, metadata-admin rendering, pane 1000/1304)
and `/studio/com.example.crm/access?item=crm_sales_user` (Studio Access
rendering, pane 760/1304), `crm_account` expanded, 18 field boxes in
view:
| | scrollLeft 0 | 40 | 57 | 80 | 200 | far end |
|:--|--:|--:|--:|--:|--:|--:|
| main, metadata admin (name cell 705 px) | 18/18 | 18/18 | 18/18 | 9/18
| 0/18 | 0/18 |
| main, Studio Access (name cell 720 px) | 0/18 (off pane) | 9/18 | 9/18
| 0/18 | 0/18 | 0/18 |
| this PR, metadata admin (name cell 506 px) | 18/18 | 18/18 | 18/18 |
18/18 | 18/18 | 18/18 |
| this PR, Studio Access (name cell 350 px) | 18/18 | 18/18 | 18/18 |
18/18 | 18/18 | 18/18 |
Every covered box answered `perm-field-name-crm_account-FIELD`.
Before/after screenshots at scrollLeft 0, 200 and the far end are kept
with the card thread's files.
</details>
<details><summary>Local runs on the final head 9d196c5 (after merging
main)</summary>
- Spec: 6 passed. jsdom: `fieldTableLayout-26846`, `gridChrome-27866`,
`fieldBulk`, `readonly`: 4 files, 26 tests passed.
- Before the merge, at 5799825: the 52 test files under `ui/packages`
naming `PermissionMatrixEditor`, `perm-field-`, `FieldsSubTable` or
`MatrixScrollPane`, 368 tests passed; `pnpm --filter
@object-ui/app-shell run type-check` exit 0; `tsc -p
ui/tsconfig.e2e.json` exit 0; eslint on the four touched ui files 0
errors (19 warnings, all pre-existing lines); `pnpm --dir ui exec vitest
run scripts/` 170 files passed.
- `dispatch-gates --commands` derived 42 families at 5799825; all 42
ran, exit 0, reconciled with `--ran` (42 run, 0 NOT-MEASURED). Re-run on
9d196c5: `check-sdui-manifest`, `check:platform-checklist`,
`check-changeset-no-major --base origin/main`, `check:nul-bytes`, all
exit 0.
- Main's 12 incoming commits touch none of this PR's files.
</details>
## Acceptance notes
- Seen on main and on this branch alike, not changed here: on the Studio
rendering, the object row that is expanded or under the pointer lets the
scrolled object boxes show through its pinned Object cell (the row's
tint is not opaque over them); see the far-end screenshots. Reported to
the seat, not fixed here.
- The panel reserves 6rem (both insets of the metadata admin's cell);
Studio's cell has a 24 px right inset, so there the panel ends 24 px
short of the cell's edge when the pin binds.
## Human Minimum
- [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic.
(not touched)
- [x] 2. Every name I added uses the casing for its kind.
- [x] 3. No formatter ran; `pnpm lint` passes. (eslint on the touched ui
files: 0 errors)
- [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. (not touched)
- [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.
- [x] The *Before Submitting* list in CONTRIBUTING.md is done.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01QsR2jTaAUD6ttuQLjbPsrZ
---
_Generated by [Claude
Code](https://claude.ai/code/session_01QsR2jTaAUD6ttuQLjbPsrZ)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 6d1c659 commit cba12d2
6 files changed
Lines changed: 541 additions & 33 deletions
File tree
- .changeset
- docs/qa/platform-checklist/areas
- ui
- e2e
- 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
906 | 906 | | |
907 | 907 | | |
908 | 908 | | |
909 | | - | |
| 909 | + | |
910 | 910 | | |
911 | 911 | | |
912 | 912 | | |
| |||
930 | 930 | | |
931 | 931 | | |
932 | 932 | | |
933 | | - | |
| 933 | + | |
| 934 | + | |
934 | 935 | | |
935 | 936 | | |
936 | 937 | | |
| |||
968 | 969 | | |
969 | 970 | | |
970 | 971 | | |
| 972 | + | |
| 973 | + | |
| 974 | + | |
| 975 | + | |
| 976 | + | |
| 977 | + | |
971 | 978 | | |
972 | 979 | | |
973 | 980 | | |
974 | 981 | | |
975 | | - | |
| 982 | + | |
| 983 | + | |
976 | 984 | | |
977 | 985 | | |
978 | 986 | | |
979 | 987 | | |
980 | 988 | | |
981 | 989 | | |
982 | 990 | | |
983 | | - | |
| 991 | + | |
984 | 992 | | |
985 | 993 | | |
986 | 994 | | |
| |||
1027 | 1035 | | |
1028 | 1036 | | |
1029 | 1037 | | |
| 1038 | + | |
| 1039 | + | |
| 1040 | + | |
| 1041 | + | |
| 1042 | + | |
| 1043 | + | |
1030 | 1044 | | |
1031 | 1045 | | |
1032 | 1046 | | |
| |||
0 commit comments