Repository navigation
Commit 0d6d406
fix(studio): explain each control the field inspector locks in display-patch mode (#29081)
<!-- claude-projects-attribution: {"github_login":"zhuangjianguo"} -->
_Requested by **Steedos** · [project
thread](https://claude.ai/code/project/chan_018ETKaNwMZCNRYD7D8Q9Ubb?thread=cmsg_018ETKaNwMZCNRYD7D8Q9UbbSoAeFWE57GxG3dEVs9Yx86)_
Fixes #28986
Clause-②: no
Metadata-protocol: none
## 维护者速读
- **改了什么**:Studio 字段检查器在「只能改显示属性」模式(只读基础包的字段,经配对的 `.custom`
包定制)下,每个被锁住的控件(API
名、类型、必填/唯一、默认值、选项值与颜色、跟踪历史、三个条件规则编辑器、上移/下移、删除等)外面多了一层可 Tab
聚焦的包装:悬停或键盘聚焦时弹出提示,读屏通过 aria-describedby
读到顶部那句「此字段属于已安装的包:你只能修改它的……」。可编辑的标签、描述、帮助文本、占位符、选项标签不加包装、不带原因。
- **为什么改**:#28860
让基础包字段可以写显示补丁后,整栏的只读原因包装(objectui#12303)不再绘制,被锁控件变成灰着却说不出原因,`ux-conventions.disabled-control-reason`
的回归行由 PASS 变 FAIL;这是 18.3.0 发版前的回归。
- **风险与回滚**:低。只改检查器的渲染:新增的包装只在显示补丁模式下出现,普通可写字段和整栏只读两种情形 DOM
不变(各有对照测试钉住);不新增文案、不碰保存逻辑。代价是该模式下 Tab 序列里多了若干个停靠点(每个被锁控件或一行一组一个)。回滚即还原本
PR。
-
**先看**:`ui/packages/app-shell/src/views/metadata-admin/inspectors/ObjectFieldInspector.tsx`
的 `DisplayPatchLock` 与 `DisplayPatchReasonContext`,然后同文件 `OptionsEditor`
里选项值与选项工具条的包装;测试
`ObjectFieldInspector.displayPatchReason-28986.test.tsx`。
- **两分钟验证**:`pnpm --dir ui exec vitest run
packages/app-shell/src/views/metadata-admin/inspectors/ObjectFieldInspector.displayPatchReason-28986.test.tsx`,预期
1 个文件、16 个测试全绿。
- **需要你做的**:无,席位落地。
## What changes
- **One lock, one reason.** `ObjectFieldInspector` gains a
module-private `DisplayPatchLock`. In display-patch mode
(`BaseFieldDisplayPatchContext` on, `readOnly` off) it wraps a locked
control, or one row of them, in a `role="group"` tab stop with
`data-disabled-reason`. `aria-describedby` on that wrapper points at the
existing whitelist sentence at the top of BASIC
(`field-base-patch-only`, which now carries an id), and a Radix tooltip
shows the same sentence on hover and on focus. This is the shape
`DeclaredActionsBar` (objectui#11811) and the read-only rail
(objectui#12303) already use. In any other mode the lock renders its
children unchanged.
- **What is wrapped:** API name, Type, the Required/Unique row, Default
value, the picklist source, the related object and the lookup and
related-list blocks, the formula editor, the summary block, the numeric
and text-length grids, currency, value domain, the
Read-only/Hidden/Track history row, the conditional-rules block, Field
group, the header's Move up/down pair and the footer's Remove. Inside
the options editor, each option's value input and its
colour/kind/reorder/remove strip are wrapped, and a malformed row's
controls too. Each option's label input is not.
- **The reason is provided above the shell.** `InspectorShell` draws the
header and footer itself, so the inspector hands the reason through a
context provided around the shell, and the options editor reads it from
there too.
- **No new text.** The reason is the sentence the inspector already
shows ("This field belongs to the installed package: you can change only
its …"), which names the condition, so the checklist's specificity
clause reads it as specific.
- **`StudioDesignSurface.tsx`:** a comment only, at `fieldRailReadOnly`,
saying where the reason for a base field's locked controls now lives.
The rail's read-only wrapper is unchanged.
## Tests
- New `ObjectFieldInspector.displayPatchReason-28986.test.tsx` mounts
the real inspector under the display-patch context, over six fields
(text, select with options, lookup, number, formula, currency):
- every control rendered disabled (attribute, `aria-disabled` or Radix
`data-disabled`) sits in a `[data-disabled-reason]` wrapper with
`tabindex="0"` whose `aria-describedby` resolves to the whitelist
sentence;
- every wrapper contains at least one disabled control (no empty tab
stop), and Label, Description, Help text, Placeholder and each option
label are enabled with no wrapper and no reason;
- the card's named controls (API name, Required, Track history, a rule
editor, every Move up, Remove, an option value) are each described by
the sentence's id;
- Tab reaches the API name lock and its tooltip shows the sentence;
hovering the Required lock shows it too;
- CONTROL: a writable field draws no lock and nothing disabled; a
read-only rail (patch context on or off) draws no inner lock, since the
host describes the whole rail.
- `DataPillar.baseObjectExtension-28575.test.tsx` (the real Data
pillar): the `required` case now also asserts the Required box's wrapper
is a tab stop described by the sentence, and that the Label input has no
wrapper.
## Acceptance notes
- **Live browser not measured.** The checklist row's oracle is the
showcase boot in a real browser. This PR is verified in jsdom only. The
wrapper is the same tab-stop-plus-tooltip shape the read-only rail uses,
which the checklist's QA run measured PASS for hover and keyboard in
Chromium; the next QA pass of `ux-conventions.disabled-control-reason`
re-measures it here.
- **Tab stops.** One stop per locked control or row, and per option two
(value, then the strip). That is the cost of keeping the editable
controls undescribed between them.
- **Scope.** The external-object locks (`ddlLocked` from an external
binding) keep their own badge and are unchanged.
## Verification
<details><summary>New pin · 16/16, and 15 red against main's
inspector</summary>
`pnpm --dir ui exec vitest run --maxWorkers=2
packages/app-shell/src/views/metadata-admin/inspectors/ObjectFieldInspector.displayPatchReason-28986.test.tsx`
under `os-verify-lock`: Test Files 1 passed (1), Tests 16 passed (16).
Reverse check at `97144b76`: `ObjectFieldInspector.tsx` restored from
`origin/main` (`ab085a04`, `DisplayPatchLock` count 0 on disk), the new
file plus `DataPillar.baseObjectExtension-28575.test.tsx` run: Tests 15
failed, 11 passed. The 14 display-patch cases and the 28575 `required`
case failed; both CONTROL cases and the rest of 28575 passed. Restored
with `git checkout HEAD --`, blob hash back to `4509f157`, `git diff
HEAD` empty.
</details>
<details><summary>Every test file naming the field inspector · 61
files</summary>
`git grep -l -E
"ObjectFieldInspector|field-base-patch|BaseFieldDisplayPatchContext|fieldRailReadOnly|data-field-inspector"`
over ui test files: 61 files in two locked batches at `--maxWorkers=2`.
Test Files 31 passed, Tests 215 passed; Test Files 30 passed, Tests 400
passed. This is a declared narrowing; CI's Test UI runs the rest of
app-shell.
</details>
<details><summary>Type check and lint</summary>
- `turbo run type-check --filter=@object-ui/app-shell` (65 tasks,
includes `tsc -p tsconfig.test.json`): exit 0.
- `eslint` on the three changed `.tsx` files: 0 errors, 15 warnings, all
on lines that predate this diff (re-indented `any` casts in the rule
editors, and two existing hook warnings).
- `pnpm --dir ui run check:new-line-citations`: 0 new citations.
</details>
<details><summary>Derived gates</summary>
`node scripts/pm/dispatch-gates.mjs --commands` derived 34 commands
against merge base `ab085a048` at head `97144b76`. All 34 ran and exited
0, including `check-sdui-manifest.mjs` and its `--self-test`,
`check:type-check-debt`, `check:nul-bytes`,
`check:cross-package-test-inputs`, `check:test-source-alias` and `pnpm
--dir ui exec vitest run scripts/` (Test Files 169 passed, 2 skipped;
Tests 4900 passed, 2 skipped). `dispatch-gates --ran` reconciled 34
derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. `origin/main` moved 9 commits
since the base, none touching the three changed source files.
</details>
---
_Generated by [Claude
Code](https://claude.ai/code/session_01QsR2jVM5iRVAwVwYSkX5u7)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent c503b95 commit 0d6d406
5 files changed
Lines changed: 672 additions & 335 deletions
File tree
- .changeset
- ui/packages/app-shell/src/views
- metadata-admin/inspectors
- studio-design
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 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 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
0 commit comments