Repository navigation
Commit 02a891e
fix(app-shell): page block inspector list labels name their group (#27307)
<!-- claude-projects-attribution: {"github_login":"os-warren"} -->
_Requested by **Warren** · [project
thread](https://claude.ai/code/project/chan_01U5RdnAAmkSQmZbqh6FtqZ8?thread=cmsg_01U5RdnAAmkSQmZbqh6FtqZ8L4EbhLan2Y7fLAm2Hf41nK)_
Fixes #27256
Clause-②: no
Metadata-protocol: none
## 维护者速读
- 改了什么:Studio
页面块检查器里的三个列表编辑器(字段列表如「Columns」、字符串列表、数组)现在各自是一个以其标题命名的分组;只带占位提示的文本行输入框按「标题
+ 序号」命名(如「Action names 1」)。
- 为什么改:这三个标题之前不指向任何控件,读屏用户只听到一串无名的行,分不清它们属于哪个属性。
- 风险与回滚:只加 ARIA 属性和一个很小的包装组件,不改数据、写入或布局;回滚即 revert 本 PR。
- 先看:`PageBlockInspector.tsx` 里新增的 `LabelledListGroup` 及三处调用;新测试
`PageBlockInspector.listGroupLabels-27256.test.tsx`。
- 两分钟验证:`pnpm --dir ui exec vitest run
packages/app-shell/src/views/metadata-admin/inspectors/PageBlockInspector.listGroupLabels-27256.test.tsx`,预期
4 passed。
- 需要你做的:无,席位落地。
## What changes
`ui/packages/app-shell/src/views/metadata-admin/inspectors/PageBlockInspector.tsx`,
the three list editors only:
- New `LabelledListGroup` component: the container takes `role="group"`
and `aria-labelledby` pointing at the label's `id`, minted with
`React.useId()` per instance. It is a component (not inline in
`renderField`) because `renderField` is a function run in a loop over
array items and cannot call a hook, and a caller-derived id would repeat
across array rows. This is the same pattern `ColorPropField` already
uses in this file.
- `FieldListField` (Columns, Fields, Card fields …), the `string-list`
case and the `array` case of `renderField` all render through it.
- Row naming (the order asked to check the string-list rows): each
string-list row input had no name but a repeated placeholder, so it now
carries `aria-label` = the list label plus its 1-based position ("Action
names 1"). Chosen over `aria-labelledby` plus an index element because
no visible per-row index exists to point at. The field-list text
fallback rows (shown when the object has no fields) had the same gap and
get the same name. The field-list `Select` trigger rows are left alone:
their name is the selected value's text, and an `aria-label` would hide
it.
`app-shell` is `private: true`, so no changeset (`skip-changeset`).
## Why
Each of the three labels headed a list of rows and named nothing:
`getByLabelText('Columns')` found the label and no control, and a screen
reader heard the rows with no group name. A `for` pairing does not fit,
since one label heads several controls.
## Tests
`PageBlockInspector.listGroupLabels-27256.test.tsx` (4 cases):
- `record:related_list`: `getByRole('group', { name: 'Columns' })`
(field list) and `{ name: 'Sort' }` (array) each resolve; the row
controls (combobox, `#1`, the remove buttons) sit inside their group;
the IDREF resolves to the label element inside the group; the two ids
differ.
- `record:quick_actions`: the `Action names` group holds textboxes named
`Action names 1` and `Action names 2`.
- Field-list text fallback (object with no fields): the `Columns` group
holds a textbox named `Columns 1`.
- `record:details` with two sections: two `Fields` groups inside the
`Sections` group, each named by its own label with distinct ids.
## Acceptance notes
- Ablation (one-off, no file kept): `scripts/ablation-replace.mjs`
swapped the group's `aria-labelledby={labelId}` for an inert attribute →
4 of 4 cases red (`Unable to find an accessible element with the role
"group" and name …`); restore verified blob equal to HEAD and `git diff
HEAD` empty. A first attempt was refused by the tool before running
anything (the replacement text already occurred in the file), so it
measured nothing.
- The remove buttons in each list share one name ("Remove" / "Remove
item") per row; left as is, out of this card's scope.
## Verification
All on head `3402dbdd` (base `5b5cff15`), each exit captured before any
pipe.
- Closure: `pnpm --workspace-concurrency=2 --filter
'@object-ui/app-shell^...' build` under the lock: exit 0.
- New pin: `pnpm --dir ui exec vitest run
packages/app-shell/src/views/metadata-admin/inspectors/PageBlockInspector.listGroupLabels-27256.test.tsx`:
4 passed, exit 0.
- Neighbours: all 14 `PageBlockInspector*.test.tsx` files: 14 files, 90
tests passed, exit 0.
- `pnpm --filter @object-ui/app-shell run type-check` (source and
`tsconfig.test.json`): exit 0.
- `pnpm --dir ui run check:new-line-citations`: 0 new citations, exit 0.
- `node scripts/pm/dispatch-gates.mjs --commands` derived 24 commands;
`--ran` reconciles 24 run, 0 NOT-MEASURED.
<details><summary>Derived gates (24)</summary>
```text
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/check-sdui-manifest.mjs :: exit 0
node scripts/check-sdui-manifest.mjs --self-test :: exit 0
pnpm --dir ui exec vitest run scripts/ :: exit 0
pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0
pnpm check:cross-package-test-inputs :: exit 0
pnpm check:dispatcher-error-vocabulary :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:engine-double-contract :: exit 0
pnpm check:gitlink-declared :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:published-files :: exit 0
pnpm check:query-options-erasure :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:skill-identifier-liveness :: exit 0
pnpm check:test-source-alias :: exit 0
pnpm check:tier-file-adoption :: exit 0
pnpm check:type-check-coverage :: exit 0
pnpm check:type-check-debt :: exit 0
pnpm check:undeclared-dep-imports :: exit 0
pnpm check:watch-hint-literal :: exit 0
pnpm check:where-matcher :: exit 0
```
`pnpm --dir ui exec vitest run scripts/` first exited 1 on an unlocked
run beside the app-shell type-check: two tree-sweep tests
(`check-i18n-dead-keys`, `check-vi-mock-inherit`) hit the 15 s test
timeout. Rerun alone under the lock: 2 files, 229 tests passed; then the
whole suite under the lock: 174 files passed, 2 skipped, exit 0. The
recorded exit is that rerun.
</details>
## 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. (CI runs the repo lint)
- [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. (publishes
nothing: private package)
- [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. (the 维护者速读 section is
the dispatch contract's Chinese summary)
---
_Generated by [Claude
Code](https://claude.ai/code/session_01JQwxbZEzQNxEeTKF7YTgo6)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent ff26bc4 commit 02a891e
2 files changed
Lines changed: 170 additions & 9 deletions
File tree
- ui/packages/app-shell/src/views/metadata-admin/inspectors
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
114 | 114 | | |
115 | 115 | | |
116 | 116 | | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
117 | 139 | | |
118 | 140 | | |
119 | 141 | | |
| |||
122 | 144 | | |
123 | 145 | | |
124 | 146 | | |
125 | | - | |
126 | | - | |
| 147 | + | |
127 | 148 | | |
128 | 149 | | |
129 | 150 | | |
| |||
137 | 158 | | |
138 | 159 | | |
139 | 160 | | |
| 161 | + | |
140 | 162 | | |
141 | 163 | | |
142 | 164 | | |
| |||
151 | 173 | | |
152 | 174 | | |
153 | 175 | | |
154 | | - | |
| 176 | + | |
155 | 177 | | |
156 | 178 | | |
157 | 179 | | |
| |||
625 | 647 | | |
626 | 648 | | |
627 | 649 | | |
| 650 | + | |
| 651 | + | |
| 652 | + | |
628 | 653 | | |
629 | | - | |
630 | | - | |
| 654 | + | |
631 | 655 | | |
632 | 656 | | |
633 | 657 | | |
| 658 | + | |
634 | 659 | | |
635 | 660 | | |
636 | 661 | | |
| |||
644 | 669 | | |
645 | 670 | | |
646 | 671 | | |
647 | | - | |
| 672 | + | |
648 | 673 | | |
649 | 674 | | |
650 | 675 | | |
| |||
654 | 679 | | |
655 | 680 | | |
656 | 681 | | |
657 | | - | |
658 | | - | |
| 682 | + | |
659 | 683 | | |
660 | 684 | | |
661 | 685 | | |
| |||
684 | 708 | | |
685 | 709 | | |
686 | 710 | | |
687 | | - | |
| 711 | + | |
688 | 712 | | |
689 | 713 | | |
690 | 714 | | |
| |||
0 commit comments