Repository navigation
Commit 775a000
fix(plugin-detail): empty related lists fold into one line; record:path terminal stages share the rail (#26414)
Fixes #25895
Clause-②: no
Metadata-protocol: none
## 维护者速读
改了什么:记录页「相关」页签里没有记录的相关列表不再各占一整行,而是在有记录的列表之后合成一行,列出它们的名字,每个保留「新建」;阶段条(record:path)上的终止阶段(已取消
/ 客户未到、成交 / 失败)与其它阶段等宽分配,标签换行而不是挤成一格。
为什么改:HotCRM 客户页「客户 0 · 暂无相关记录」夹在有数据的列表之间;活动页的「× 已取消
客户未到」挤在右端一个窄格里(#25895 两张截图)。
风险与回滚:只改显示,不加不删任何元数据键;全空的栈、单个列表、带「添加」选择器或工具栏动作的列表保持原样;有新记录时折叠的列表自动回到原位。回滚
= revert 本 PR。
先看:`ui/packages/plugin-detail/src/RelatedListEmptyFold.tsx`(规则与折叠行)→
`renderers/record-related-list.tsx`(接入)→
`renderers/record-path.tsx`(等分宽度)。
两分钟验证:`cd ui && pnpm exec vitest run
packages/plugin-detail/src/renderers/__tests__/record-related-list.emptyFold-25895.test.tsx
packages/plugin-detail/src/renderers/__tests__/record-path.terminalWidth-25895.test.tsx`,预期
12 个测试全过。
需要你做的:无,绿了即可落地;新文案的语言包键是后续工作(见下文)。
## What
**Item 1 — empty related lists fold into one line.** On a record's
Related tab, the lists with zero records leave their place once every
list of the stack has answered, and the last list of the stack draws one
line after itself: the empty-state text, then each folded list's title
with its own **New** (same handler, same `createDisabled` verdict). A
folded list stays mounted (hidden), so when it gains a record it answers
"not empty" and returns to its place. Unchanged by design: a stack whose
lists are all empty, a list on its own, and an empty list that offers
more than New (an `add` picker, child toolbar actions, an authoring
notice) draw exactly as before.
**Item 2 — terminal stages get legible width.** On the desktop rail both
stage groups now start from zero and grow by the number of stages they
hold, and every stage fills its share, so a terminal stage is exactly as
wide as any other. A terminal stage's label (the won terminus and the
separated lost group) wraps instead of being truncated or held on one
line. Ordinary forward stages keep their one truncated line; the mobile
row (horizontal scroll) is unchanged.
## Which seam, and why (item 1)
Who stacks the lists: `buildDefaultTabs`
(`synth/buildDefaultPageSchema.ts`) only emits the Related tab's
`record:related_list` children; `page:tabs` (`PageTabsRenderer` in
`@object-ui/components`) draws them as plain siblings through
`renderChildren`; `RecordDetailView` only hands `related` to the
synthesizer. None of the three knows how many rows a list has — each
list learns that from its own read — and an authored page can stack
lists in any container.
So the seam is the block itself: `record:related_list` lists that share
a DOM container coordinate through a small store keyed by that container
(`ui/packages/plugin-detail/src/RelatedListEmptyFold.tsx`).
`RelatedList` gains one optional callback, `onEmptyChange(empty)`,
reporting its settled answer (`null` while a read is in flight); the
block keeps the last answer during a refetch so a write elsewhere does
not unfold and refold the stack. This reaches synthesized and authored
pages alike, adds no node type and no spec key, and leaves the
synthesizer, app-shell and components untouched.
`RelatedList.tsx` and the new `RelatedListEmptyFold.tsx` are outside the
claim's listed file surface (one optional prop plus one effect, and the
new module); both sit in the same package beside the claimed files.
## Strings and locale packs
No new translation key is introduced. The fold line reuses
`detail.noRelatedRecords` and `detail.new`, both already in every pack;
each folded entry is a `role="group"` named by the list's title, so each
**New** is announced inside its list's name. A dedicated phrase such as
「其他 2 个为空:客户、线索」 needs a new key in the locale packs, which this PR does
not touch (that line is busy); it is a follow-up once the i18n line
drains. Note for that follow-up: `check:i18n-keys` refuses a `t()` key
absent from the `en` pack and its baseline is empty, so an inline
`defaultValue` alone would not pass CI — the key has to land in the
packs.
## Tests
-
`ui/packages/plugin-detail/src/renderers/__tests__/record-related-list.emptyFold-25895.test.tsx`
(6 tests) and
`ui/packages/plugin-detail/src/renderers/__tests__/record-path.terminalWidth-25895.test.tsx`
(6 tests), committed red first (`aba3b5ca`).
- Red leg, implementation files restored to the base `f02e6443` in the
tree (markers `onEmptyChange` / `shareOf` counted 0): 9 failed / 3
passed — the three that pass are CONTROL legs that hold before and after
(all-empty stack, single list, ordinary forward stage). Restore proven
by blob hashes equal to HEAD. Green leg: 12/12.
- `pnpm exec vitest run packages/plugin-detail --maxWorkers=2` (from
`ui/`, at `5cf6e03e`): 306 files passed, 1 failed —
`spec-symbol-batch7.test.ts` names every props type in `renderers/` that
is not spelled `…RendererProps`; the fold module was moved out of
`renderers/` to `src/` (beside `EmptySectionsFold.tsx`) in `47121545`,
and the post-merge run below covers that file.
- Consumers of the changed rendering, run as a targeted set (not the
full app-shell suite): 34 files that mention an empty related list or
`record:related_list` under `app-shell`, `apps/console` and
`components`, plus the `RecordDetailView` related-list files: 34/34
files, 293/293 tests.
- `pnpm --filter @object-ui/plugin-detail type-check`: exit 0.
- `sdui.manifest.json`: regenerated under the lock before the merge,
byte-unchanged (106 components, sha256 `1f6e1ccb925a…`); no record is
committed (the sources records were retired on `main`). `node
scripts/check-sdui-manifest.mjs`: exit 0.
After merging `origin/main` (merge `8271adf9`, which retired
`scripts/sdui-manifest.sources/`; no plugin-detail or lockfile overlap),
at head `8271adf9`:
- `pnpm --filter @objectstack/spec build` (main moved spec), then
`spec-symbol-batch7.test.ts` plus every `record-path*`,
`record-related-list*`, `recordComponentAria*` and `RelatedList*` test
in plugin-detail: 59/59 files, 396/396 tests. `pnpm --filter
@object-ui/plugin-detail type-check`: exit 0.
- `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack`: 35 derived families, all run, each exit 0
(`check-sdui-manifest.mjs` among them); `--ran` reconciled 35/35 with
exit codes recorded, 0 NOT-MEASURED.
## Acceptance notes
- A related list whose read FAILS shows today's empty state ("No related
records found") because `RelatedList` only logs the error; with this
change such a list is also folded as empty. That is unchanged behaviour
of the read path, noted, not filed here.
- The stack is the DOM container: lists an authored page wraps in
separate containers never fold together, by design.
- The terminal-stage share is equal up to the alt group's divider gap
and padding.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01SMps7wq7rBTk53e8KTSEup)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 9f16f16 commit 775a000
7 files changed
Lines changed: 680 additions & 11 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 | + | |
| 13 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
275 | 275 | | |
276 | 276 | | |
277 | 277 | | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
278 | 286 | | |
279 | 287 | | |
280 | 288 | | |
| |||
535 | 543 | | |
536 | 544 | | |
537 | 545 | | |
| 546 | + | |
538 | 547 | | |
539 | 548 | | |
540 | 549 | | |
| |||
2274 | 2283 | | |
2275 | 2284 | | |
2276 | 2285 | | |
| 2286 | + | |
| 2287 | + | |
| 2288 | + | |
| 2289 | + | |
| 2290 | + | |
| 2291 | + | |
2277 | 2292 | | |
2278 | 2293 | | |
2279 | 2294 | | |
| |||
| 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 | + | |
| 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 | + | |
0 commit comments