Repository navigation
Commit ad2c286
fix(plugin-grid): inline cells read the record-grained update verdict the row kebab reads (#27384)
<!-- claude-projects-attribution: {"github_login":"os-warren"} -->
_Requested by **Warren** · [project
thread](https://claude.ai/code/project/chan_01U5RdnAAmkSQmZbqh6FtqZ8?thread=cmsg_01U5RdnAAmkSQmZbqh6FtqZ88z34ttNLNf2N8f3PHSjhj7)_
Fixes #27365
Clause-②: no
Metadata-protocol: none
## 维护者速读
- 改了什么:列表行内编辑现在按「这一行」的服务端写权限判定;服务端拒绝的行点不开单元格编辑器,和该行的 ⋮ 菜单给出同一个答案。
- 为什么改:对象级有编辑权、但共享/归属/RLS 拒绝某行时,⋮ 菜单已隐藏「编辑」,单元格却仍可编辑,保存时被服务端整单拒绝。
- 风险与回滚:只收窄不放宽;没拿到行级答案(未返回、请求失败、行无 id)时保持原行为。回滚即 revert 本 PR。
- 先看:`ui/packages/plugin-grid/src/ObjectGrid.tsx`(`isRowEditable` 与
`update: canEdit ||
inlineEditable`)、`ui/packages/components/src/renderers/complex/data-table.tsx`(`rowMayEdit`)、`ui/packages/types/src/data-display.ts`(新运行时槽位)。
- 两分钟验证:`pnpm --dir ui exec vitest run
packages/plugin-grid/src/__tests__/inlineEditRecordVerdict-27365.test.tsx`,预期
8 个用例全绿。
- 需要你做的:无,席位落地。
## What changes
An inline-editable grid gated its cells on the object-level affordance
only (`inlineEditable`), while the row kebab on the same rows also read
the server's record-grained `update` verdict (`useRecordCrudVerdicts`).
A row refused by sharing, ownership or RLS lost Edit from its kebab but
still opened a cell editor, and the save was refused whole. Now the
cells read the same verdict.
- `@object-ui/types`: `DataTableSchema` declares a new runtime slot,
`isRowEditable?: (row: any) => boolean`. The zod mirror refuses it by
name (`handlerKeyRefusal`, `runtime-slot`), like `renderCellEditor` and
`rowGroups`. The ledgers move with it: the `KnownDrift` entry for
`data-display.zod.ts#DataTableSchema` gains the key (51 entries, 88
keys), and the read lists in the `body`/`children` tombstones name it.
- `@object-ui/components`: `data-table` reads `isRowEditable` through
one `rowMayEdit(row)` check in `startEdit` (the door click, double-click
and Enter all pass through), in the Enter key path, and in the per-cell
`isEditable`. A refused row reads like a row of a read-only table: no
editor, no edit cursor, and a click reaches the row's own click handler.
With the slot absent, every row behaves as before.
- `@object-ui/plugin-grid`: `ObjectGrid` supplies `isRowEditable` as
`resolveRowRecordCrudAffordance(inlineEditable,
recordVerdict(rowRecordId(row), 'update'))`, the exact accessor the
kebab reads. It asks the batched probe whenever the grid is
inline-editable (`update: canEdit || inlineEditable`), so an editable
grid whose kebab offers no Edit is narrowed too. That is still one
probe, read by both affordances, with no second evaluator (ruling
6457467702 B).
- ListView reaches the cells through `ObjectGrid` (`type:
'object-grid'`, `editable: inlineEdit && inlineEditOffered`), so it has
no separate door and needs no plugin-list change.
- Test doubles: editable-grid suites now get the explain probe. Nine
plugin-grid suites and one app-shell suite
(`ListView.gridRowColorSelect-12393`) answer it from an explain double
instead of reaching the network. This is test-only, per claim amendment
6487558539. The assertions are unchanged.
## Why
The card: one grid gave two answers for one row. Fail-open is preserved
exactly as the `useRecordCrudVerdicts` docblock requires: an unknown
verdict keeps the object-level behaviour.
## Tests
- `plugin-grid/src/__tests__/inlineEditRecordVerdict-27365.test.tsx`
(8): a refused row opens no editor on click or Enter and shows no edit
cursor. CONTROLs: an allowed row stays editable; a non-OK response, a
network failure, a response with no `records[]`, and the pre-answer
window all keep the row editable. The kebab and the cells agree on both
rows from ONE `update` probe. An editable grid with no kebab Edit still
asks and still narrows.
- `components/src/__tests__/data-table-row-editable-27365.test.tsx` (7):
the seam on its own covers click, double-click and Enter, a click that
reaches `onRowClick`, an allowed-row control, the no-predicate control,
and narrows-only.
- `types/src/__tests__/data-table-declared-keys-6882.test.ts`: the
declared exact shape, a widened-return control (`@ts-expect-error`), and
the zod mirror refusing an authored `isRowEditable` by name.
## Acceptance notes
- Ablation 1, ObjectGrid's per-row read replaced by `(_row: any) =>
true` via `scripts/ablation-replace.mjs`: 4 of 8 tests in the new grid
suite red (the repro, agreement, no-kebab and pre-answer legs). Restored
blob equals HEAD and `git diff HEAD` is empty.
- Ablation 2, data-table's `rowMayEdit` replaced by `() => true`: 3 of 7
tests in the seam suite red (click, double-click, Enter). Restored blob
equals HEAD.
- `ui/apps/site` was retired on main. After merging main, an ignored
leftover directory (node_modules) in the worktree reddened
`quick-reference-commands-4149` locally. That was a local-state artifact
only: the test is green once the leftover is removed, and nothing in the
tree changed.
## Verification
All readings were taken on head `3b46f5a1` (origin/main `c4c515ad`
merged in), with the `@object-ui/console^...` closure built under the
lock.
<details><summary>Tests</summary>
- `pnpm --dir ui exec vitest run` over the two new suites,
`packages/types/`, the ten double-carrying suites,
`inlineEditPermissionGate` and `rowRecordCrudVerdict`: Test Files 398
passed (398), Tests 10521 passed (10521).
- Before the merge, at `e77abe74` plus the doubles:
`packages/plugin-grid/`, `packages/types/` and the data-table suites
went 934/935 files green with one skipped; the 9 red files were the
network-escape suites that now carry the double (46/46). Across 59 ui
consumer suites that render an editable grid, 58 were green and the
app-shell one was fixed (2/2).
- `pnpm --dir ui exec vitest run scripts/`: 168 passed, 2 skipped, 1 red
on a stale ignored `ui/apps/site` leftover. That test is green (10/10)
once the leftover is removed.
- `pnpm --filter @object-ui/types|components|plugin-grid run
type-check`: exit 0, all three.
</details>
<details><summary>Gates</summary>
- `node scripts/pm/dispatch-gates.mjs --commands`: 35 families, all run
on `3b46f5a1`, every exit code 0, including `node
scripts/check-sdui-manifest.mjs`.
- `dispatch-gates --ran`: 35 derived, 35 run, 0 NOT-MEASURED, 0 UNRUN.
- `pnpm --dir ui run check:new-line-citations`: 0 new citations.
- Repo-wide lint and the full ui battery are CI's (`Lint UI`, `Type
Check UI`, `Test UI`).
</details>
## Human Minimum
- [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic.
- [x] 2. Every name I added uses the casing for its kind.
- [ ] 3. No formatter ran; `pnpm lint` was not run locally (CI `Lint UI`
and `Lint & Repo Gates` own it).
- [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: n/a, 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 维护者速读 block is the
dispatch's required Chinese summary).
- [x] The *Before Submitting* list in CONTRIBUTING.md is done.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---
_Generated by [Claude
Code](https://claude.ai/code/session_01JQwxba6qJDidRrN2u71o5N)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 7e200b4 commit ad2c286
19 files changed
Lines changed: 655 additions & 28 deletions
File tree
- .changeset
- ui/packages
- app-shell/src/__tests__
- components/src
- __tests__
- renderers/complex
- plugin-grid/src
- __tests__
- types/src
- __tests__
- zod
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
209 | 209 | | |
210 | 210 | | |
211 | 211 | | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
212 | 234 | | |
213 | | - | |
214 | 235 | | |
215 | 236 | | |
216 | 237 | | |
| |||
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1206 | 1206 | | |
1207 | 1207 | | |
1208 | 1208 | | |
| 1209 | + | |
1209 | 1210 | | |
1210 | 1211 | | |
1211 | 1212 | | |
| |||
2262 | 2263 | | |
2263 | 2264 | | |
2264 | 2265 | | |
| 2266 | + | |
| 2267 | + | |
| 2268 | + | |
| 2269 | + | |
| 2270 | + | |
2265 | 2271 | | |
2266 | 2272 | | |
2267 | | - | |
| 2273 | + | |
2268 | 2274 | | |
2269 | 2275 | | |
2270 | 2276 | | |
| |||
2798 | 2804 | | |
2799 | 2805 | | |
2800 | 2806 | | |
2801 | | - | |
| 2807 | + | |
2802 | 2808 | | |
2803 | 2809 | | |
2804 | 2810 | | |
| |||
3654 | 3660 | | |
3655 | 3661 | | |
3656 | 3662 | | |
3657 | | - | |
3658 | | - | |
| 3663 | + | |
| 3664 | + | |
| 3665 | + | |
3659 | 3666 | | |
3660 | 3667 | | |
3661 | 3668 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
70 | 70 | | |
71 | 71 | | |
72 | 72 | | |
73 | | - | |
| 73 | + | |
74 | 74 | | |
75 | 75 | | |
76 | 76 | | |
| |||
1007 | 1007 | | |
1008 | 1008 | | |
1009 | 1009 | | |
| 1010 | + | |
| 1011 | + | |
| 1012 | + | |
1010 | 1013 | | |
1011 | 1014 | | |
1012 | 1015 | | |
1013 | | - | |
| 1016 | + | |
1014 | 1017 | | |
1015 | 1018 | | |
1016 | 1019 | | |
| |||
2546 | 2549 | | |
2547 | 2550 | | |
2548 | 2551 | | |
| 2552 | + | |
| 2553 | + | |
| 2554 | + | |
| 2555 | + | |
| 2556 | + | |
| 2557 | + | |
| 2558 | + | |
| 2559 | + | |
| 2560 | + | |
2549 | 2561 | | |
2550 | 2562 | | |
2551 | 2563 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
27 | 27 | | |
28 | 28 | | |
29 | 29 | | |
30 | | - | |
| 30 | + | |
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
| |||
54 | 54 | | |
55 | 55 | | |
56 | 56 | | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
57 | 71 | | |
58 | 72 | | |
59 | 73 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
55 | 55 | | |
56 | 56 | | |
57 | 57 | | |
58 | | - | |
59 | | - | |
| 58 | + | |
| 59 | + | |
60 | 60 | | |
61 | 61 | | |
62 | 62 | | |
63 | 63 | | |
64 | 64 | | |
65 | 65 | | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
66 | 80 | | |
67 | 81 | | |
68 | 82 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
25 | | - | |
26 | | - | |
| 25 | + | |
| 26 | + | |
27 | 27 | | |
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
34 | 48 | | |
35 | 49 | | |
36 | 50 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
14 | | - | |
15 | | - | |
| 14 | + | |
| 15 | + | |
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
22 | 36 | | |
23 | 37 | | |
24 | 38 | | |
| |||
0 commit comments