Repository navigation
Commit 3461420
fix(plugin-detail): an empty body table of the record page keeps its header instead of folding into one line that reads the empty sentence before its title (#30378)
<!-- claude-projects-attribution: {"github_login":"os-bill"} -->
_Requested by **Bill** · [project
thread](https://claude.ai/code/project/chan_016iMXWSZDzqWRWvWzdNo8wg?thread=cmsg_016iMXWSZDzqWRWvWzdNo8wgJQrw5nPbbXAWPNQRojgu2W)_
domain:ui#2 · os-bill · session_01Utp6Cb5R6JDdfyvtj3dPR2
Fixes #29944
Clause-②: no
Metadata-protocol: none
## 维护者速读
- 改了什么:记录页 v3 详情栏里的正文表格(body
table)不再参与关联列表的「空列表折叠」;空的正文表格保留自己的表头(标题、0、新建),「暂无相关记录」画在表头下方、表格本该在的位置。
- 为什么改:正文表格和兄弟区块同处详情栏一个容器,#25895 的折叠按「同一 DOM
父元素」认栈,把详情栏当成了关联栈,空表被收成一行「暂无相关记录 偏离 + 新建」,空态文字跑到表名前面(hotclm 合同页实测)。
- 风险与回滚:只动 plugin-detail 三个渲染文件与一个测试文件,不动
spec、服务端或元数据;关联页签的折叠与右栏空面板行不变(只按页面的正文表格 id 集合判定)。回滚即 revert 本 PR。
-
先看:`ui/packages/plugin-detail/src/renderers/record-related-list.tsx`(`bodyTable`
判定与 `foldable`)→
`ui/packages/plugin-detail/src/RelatedList.tsx`(空正文表格的表头与表头下空态)→ 测试
`record-related-list.emptyFold-25895.test.tsx` 末尾新 describe。
- 两分钟验证:`pnpm --dir ui exec vitest run
packages/plugin-detail/src/renderers/__tests__/record-related-list.emptyFold-25895.test.tsx`,预期
8/8 通过(在 main 源码上新用例失败:折叠行出现)。
- 需要你做的:无,席位落地。
## What changes
On the record page v3 (`RecordPageColumns`, and the tab-strip page whose
Details tab carries the body tables), the record's body tables are drawn
as siblings of the details sections in one container. The related-list
empty fold (`RelatedListEmptyFold.tsx`, #25895) keys a stack by the DOM
parent of each `record:related_list` root, so it took the details column
for a Related tab stack: once one body table had rows, an empty one left
its place and was drawn as one line after the last table, reading the
empty sentence first (「暂无相关记录 偏离 + 新建」).
- **A body table never folds.** `record-related-list.tsx` reads
`RecordBodyTablesContext` (the page's body-table relationship ids,
already provided by the record page host) and, outside the related
column's panels, a list whose `object.field` id is in the set answers
`foldable: false` to its stack. The body tables and the Related tab are
a partition of the page's relationships (`buildDefaultPageSchema`:
`related.filter(isBody)` vs the rest), so no Related tab list is in the
set, and the fold rule itself (`decideEmptyFold`) is untouched.
- **An empty body table keeps its siblings' shape.** In `RelatedList`'s
card face, a body table no longer writes 「暂无相关记录」 inline in its header
row; while expanded and empty it draws the sentence in the card body
under the header (a dashed box where the table would be,
`data-body-table-empty`). The header keeps title, count 0, ⤢ and New.
Lists that are not body tables keep the inline sentence. The card header
gains a `data-related-list-head` attribute (the panel face already has
`data-related-panel-head`).
- `RelatedListEmptyFold.tsx`: the file header names the body-table
exception; no code change there.
No new authoring key, no spec change, no change to the Related tab or
the related column.
## Tests
- New top-level describe in
`ui/packages/plugin-detail/src/renderers/__tests__/record-related-list.emptyFold-25895.test.tsx`
(the fold's shared harness; it now takes an optional body-table set):
- an empty body table beside tables with records: no fold line, its card
visible, its header carries count 0 and a New that creates its own
object, the empty sentence is not in the header and follows it in
document order;
- CONTROL: the Related tab stack (the existing `ACCOUNT_STACK`) under a
body-table context that lists another relationship folds exactly as
before.
- Red on main's sources (the three source files restored to `13c0c5ba`,
test file from this branch): `Tests 1 failed | 7 passed (8)`, the new
case failing on `expect(fold()).toBeNull()`: the fold line (a div with
two children) was drawn.
- Green: the 116 plugin-detail test files that name `RelatedList`,
`record:related_list`, `related-list`, `RecordPageColumns` or the empty
sentence, plus three app-shell files that assert on the empty sentence
or the New button: `Test Files 118 passed | 1 skipped (119)`, `Tests
1016 passed | 8 skipped (1024)`.
- Ablation, three legs through `scripts/ablation-replace.mjs`, each
landing verified and restored to the HEAD blob (tests import `src`, no
build involved):
1. `!bodyTable &&` dropped from `foldable` → new case red (fold line
drawn);
2. the inline sentence drawn for body tables again → new case red
(sentence inside the header);
3. the under-header block disabled → new case red (no sentence found).
A first attempt at leg 1 was refused by the tool before any run (its
replacement text already occurred in the file), then re-run with a
distinct replacement.
- `pnpm exec turbo run type-check --filter=@object-ui/plugin-detail
--concurrency=2`: 52/52 tasks.
- `pnpm lint` in `ui/packages/plugin-detail`: 0 errors; per-file warning
counts on the three source files equal main's (102 / 17 / 1), the test
file 0.
## Acceptance notes
- The card's Expected says the empty state goes under the header, "the
shape the non-empty tables and the pre-18.3 `record:related_list` both
draw". Measured on the published `@object-ui/plugin-detail@18.2.0`: the
pre-18.3 empty card wrote the sentence inline in its header row (title,
0, sentence, New), not under it. This PR follows the first half of the
Expected (under the header, as the non-empty tables place their table)
and keeps the inline sentence for every list that is not a body table.
The second symptom on the card, 「合同 0 暂无相关记录」, is that inline header
line on a body table; it is covered by the same change.
## Verification
<details><summary>Derived gates (dispatch-gates --commands, final
tree)</summary>
Head `4b04fd97` (after merging `origin/main` at `8589756a`). Every
command's exit code was captured before any pipe.
```text
node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0
node scripts/check-adr-0087-registration.mjs --self-test :: exit 0
node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0
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-empty-changeset.mjs --base origin/main :: exit 0
node scripts/check-empty-changeset.mjs --self-test :: exit 0
node scripts/check-sdui-manifest.mjs :: exit 0
node scripts/check-sdui-manifest.mjs --self-test :: exit 0
node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0
node scripts/release-pending-publish.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:changeset-gate-self-tests :: exit 0
pnpm check:closed-ceremony-text :: 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:registry-log-declared :: exit 0
pnpm check:rest-log-spy-declared :: 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
```
`dispatch-gates --ran`: `Run reconciliation — 35 derived, 35 run, 0
NOT-MEASURED, 0 UNRUN` (a derived zero: all 35 recorded an exit code).
`check-sdui-manifest`: `sdui.manifest.json is present and intact (… 106
components)`.
</details>
<details><summary>Standing ui gates</summary>
- `pnpm --dir ui check:new-line-citations`: `VERDICT
new-cross-file-line-citations: 0 new citation(s), enforcement
report-only -> exit 0`.
</details>
---
_Generated by [Claude
Code](https://claude.ai/code/session_01Utp6CXft9FMzbd2ggz2oyp)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 677ac3b commit 3461420
5 files changed
Lines changed: 108 additions & 10 deletions
File tree
- .changeset
- ui/packages/plugin-detail/src
- renderers
- __tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3629 | 3629 | | |
3630 | 3630 | | |
3631 | 3631 | | |
| 3632 | + | |
3632 | 3633 | | |
3633 | 3634 | | |
3634 | 3635 | | |
| |||
3656 | 3657 | | |
3657 | 3658 | | |
3658 | 3659 | | |
3659 | | - | |
| 3660 | + | |
| 3661 | + | |
| 3662 | + | |
3660 | 3663 | | |
3661 | 3664 | | |
3662 | 3665 | | |
| |||
3756 | 3759 | | |
3757 | 3760 | | |
3758 | 3761 | | |
| 3762 | + | |
| 3763 | + | |
| 3764 | + | |
| 3765 | + | |
| 3766 | + | |
| 3767 | + | |
| 3768 | + | |
| 3769 | + | |
| 3770 | + | |
| 3771 | + | |
| 3772 | + | |
| 3773 | + | |
| 3774 | + | |
3759 | 3775 | | |
3760 | 3776 | | |
3761 | 3777 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
25 | | - | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
26 | 29 | | |
27 | 30 | | |
28 | 31 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
37 | 37 | | |
38 | 38 | | |
39 | 39 | | |
| 40 | + | |
40 | 41 | | |
41 | 42 | | |
42 | 43 | | |
| |||
79 | 80 | | |
80 | 81 | | |
81 | 82 | | |
82 | | - | |
| 83 | + | |
83 | 84 | | |
84 | 85 | | |
85 | 86 | | |
| |||
89 | 90 | | |
90 | 91 | | |
91 | 92 | | |
92 | | - | |
93 | | - | |
94 | | - | |
95 | | - | |
96 | | - | |
97 | | - | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
98 | 101 | | |
99 | 102 | | |
100 | 103 | | |
| |||
200 | 203 | | |
201 | 204 | | |
202 | 205 | | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
36 | 36 | | |
37 | 37 | | |
38 | 38 | | |
39 | | - | |
| 39 | + | |
| 40 | + | |
40 | 41 | | |
41 | 42 | | |
42 | 43 | | |
| |||
226 | 227 | | |
227 | 228 | | |
228 | 229 | | |
| 230 | + | |
| 231 | + | |
229 | 232 | | |
230 | 233 | | |
231 | 234 | | |
| |||
612 | 615 | | |
613 | 616 | | |
614 | 617 | | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
615 | 621 | | |
| 622 | + | |
| 623 | + | |
| 624 | + | |
| 625 | + | |
616 | 626 | | |
| 627 | + | |
617 | 628 | | |
618 | 629 | | |
619 | 630 | | |
| |||
0 commit comments