Repository navigation
Commit f68b47c
fix(plugin-detail): lead the derived related table with the record name (#30090)
<!-- claude-projects-attribution: {"github_login":"os-support-ai"} -->
_Requested by **Yibo Wang** · [project
thread](https://claude.ai/code/project/chan_01BVUyyPie8gHwoPM18iABwB?thread=cmsg_01BVUyyPie8gHwoPM18iABwBMmajhVvgaZ1CHUdWTUXtVx)_
Fixes #30033
Clause-②: no
Metadata-protocol: none
## 维护者速读
- **改了什么:** 关联列表在关系上没有声明列时,列取自子对象的 `highlightFields`,而它按设计从不含记录名称。现在用
`@object-ui/core` 现成的
`leadWithNameField`(ADR-0079:`nameField`,否则平台推导的名称字段)把名称放到第一列,高亮字段跟在后面;高亮里本来就有名称时只出现一次。没有
`highlightFields` 时的字段遍历同样让声明的名称领头。
- **为什么改:**
客户页的「商机」页签只看到金额、日期、概率,五行金额分不清是哪一单;唯一的链接是金额。「联系人」只剩邮箱,「活动」只剩类型。
- **风险与回滚:** 只改 `RelatedList.tsx` 的派生列;作者在关系上声明的列原样不动,`highlightFields`
含义、高亮条和概览紧凑面板都没碰。名称列照样过 FLS、脱敏、外键剔除与全空剔除。`@object-ui/plugin-detail`
patch。回滚 = revert 本 PR。
- **先看:** `ui/packages/plugin-detail/src/RelatedList.tsx` 中
`effectiveColumns` 的 `declaredHighlights` 分支与字段遍历排序后的
`leadWithNameField` 三行;测试 `RelatedList.enlargedListGrid-28865.test.tsx`
末尾的 `objectstack#30033` describe。
- **两分钟验证:** `pnpm --dir ui exec vitest run
packages/plugin-detail/src/__tests__/RelatedList.enlargedListGrid-28865.test.tsx`,预期
`18 passed`;或在 example CRM 打开 Acme Corp 的「商机」页签,第一列是「商机名称」且可点开记录。
- **需要你做的:** 无,席位落地。
## What changes
`ui/packages/plugin-detail/src/RelatedList.tsx`, `effectiveColumns`, the
two paths taken when the relation declares no columns:
- **`highlightFields` path.** The declared highlights now go through
`leadWithNameField(objectSchema, declaredHighlights)` before the
existing normalize, redaction, parent-key, FLS and empty gates. That
helper is the one `@object-ui/core` already exports for exactly this (a
synthesized list led by the record's name; the console's object list
tabs and `InterfaceListPage` call it): the declared `nameField`
(ADR-0079), else the type-aware derivation, moved to the front and
listed once. It adds nothing when the name has no field definition, is
`hidden`, or the derivation lands on a system-managed field. Because it
runs before the gates, a name the reader may not read, a redacted one,
or one that is the key back to the parent record is still dropped.
- **Field walk** (child declares no `highlightFields`). After the
existing priority sort, the declared or derived name is moved to the
front only if it is already among the surviving entries, so a field the
walk filtered out never comes back. The name-ish ranking stays as the
fallback order.
- **Authored columns** (`columns` on the relation) take the first
branch, which is untouched: drawn exactly as declared.
- **Who reads this set.** The enlarged tab hands `object-grid` these
keys, and the grid auto-links its first column to the record (pinned by
`the auto-linked primary field gets the same anchor` in `plugin-grid`'s
`ObjectGrid.linkCellAnchor.test.tsx`), so the name is now the row's
link. The non-enlarged table (`data-table`, through `sortableColumns` /
`tableColumns`) reads the same `effectiveColumns`, so it gets the same
lead. Two more readers of `effectiveColumns[0]` and the key list move
with it: the phone card gallery's `titleField` (now the name) and the
CSV export's field list (now includes the name). The compact panels on
概览 return before any of these and are unchanged.
- **`titleFormat`.** `leadWithNameField` answers in field space: a
legacy `titleFormat` is a render-only template with no column behind it,
so a `titleFormat`-only object leads with the field the platform derives
(pinned below), not the formatted title.
- **No spec key.** `Metadata-protocol: none`, `Clause-②: no`: no export,
key or accepted value changes. Changeset: `@object-ui/plugin-detail`
patch.
## Tests
New top-level `describe` in
`RelatedList.enlargedListGrid-28865.test.tsx` (the enlarged face's
shared harness), 7 cases:
- `highlightFields` that omit the name (`['account', 'amount',
'close_date', 'probability']`, as `crm_opportunity` declares): the
grid's columns are `['name', 'amount', 'close_date', 'probability']`
(the parent key `account` is dropped as before).
- A declared `nameField` that is not name-ish (`deal_title`) leads the
same way.
- The name listed in `highlightFields` too: shown once, first.
- CONTROL: columns declared on the relation are drawn exactly as
declared, no name added.
- The non-enlarged table reads the same set: `data-table` columns lead
with `name`.
- No `highlightFields`: a declared name leads the field walk.
- `titleFormat` with no `nameField`: the column is the derived field
(`code`), not the formatted title.
<details><summary>Runs</summary>
- New file, fix in place: `Test Files 1 passed (1)`, `Tests 18 passed
(18)`.
- Ablation 1, `scripts/ablation-replace.mjs` replacing
`leadWithNameField(objectSchema,
declaredHighlights).map(normalizeColumn)` with
`declaredHighlights.map(normalizeColumn)` (anchor 1 to 0, blob
`edff8db6` to `eed0f11d`): 5 failed, 13 passed. Red: the highlight case
(`expected [ 'amount', 'close_date', …(1) ]`), the non-name-ish
`nameField`, the name-once case, the non-enlarged table, the
`titleFormat` case. Restored: blob equals HEAD, `git diff HEAD` empty.
- Ablation 2, deleting the walk's
`entries.unshift(...entries.splice(leadAt, 1))` line: 1 failed (`no
highlightFields: a declared name leads the field walk too`), 17 passed.
Restored the same way.
- The tests import `../RelatedList` from source, so no dist rebuild sits
between the mutation and the run.
- Whole `@object-ui/plugin-detail` suite under the lock, before the
`main` merge: `Test Files 369 passed | 1 skipped (370)`, `Tests 3260
passed | 18 skipped (3278)`.
</details>
## Acceptance notes
- **Browser check**, `examples/app-crm` dev boot (`pnpm dev:crm --
--fresh`), Console from `ui/` source through vite, zh-CN, dev admin,
Acme Corp. Before = `RelatedList.tsx` at `origin/main` `c23501b2b`,
after = this branch; vite restarted between the legs and the served
module checked for the change each time. Headers read off the page:
| Tab | Before | After | Row link after |
|:--|:--|:--|:--|
| 商机 on Acme Corp | #, 金额, 预计成交日期, 赢单概率 (%), 操作 | #, 商机名称, 金额, 预计成交日期,
赢单概率 (%), 操作 | `Acme — Year-Ago Renewal` → the opportunity record |
| 联系人 on Acme Corp | #, 邮箱, 操作 | #, 姓名, 邮箱, 操作 | `Ada Lovelace` → the
contact record |
| 活动 on an opportunity | #, 活动类型, 截止日期, 联系人, 客户, 操作 | #, 主题, 活动类型, 截止日期,
联系人, 客户, 操作 | `Product Demo — Globex New CRM` → the activity record |
Before, the row link text was `75,000.00`, `ada@acme.example` and `会议`.
联系人 resolves through its declared `nameField: 'full_name'` (a formula);
商机 and 活动 declare none and lead with the derived `name` / `subject`.
Screenshots (`before-*.png`, `after-*.png`, plus `*-readings.json`) are
in the project's `ui-orders/30033-shots/` folder.
- **The non-enlarged face.** Measured in code: it reads the same
`effectiveColumns`, so it is fixed in the same place and pinned above.
Measured in the browser: on the example CRM's account and opportunity
record pages the 概览 tab draws only the compact panels (zero tables on
either page), so there is no body table there to photograph.
- **`maxColumns`.** The derived set is still capped at `maxColumns`
(default 6), and the name now takes one of those slots, so a child with
six or more highlights shows one highlight fewer.
## Verification
All on head `8408edf6` (this branch merged with `origin/main`
`d79eecfe5`; the merge brought no change under
`ui/packages/plugin-detail/` or core's `record-title.ts`), after a full
`turbo run build` of the merged tree (119/119), under
`scripts/pm/os-verify-lock.sh`:
- `pnpm --dir ui --filter @object-ui/plugin-detail run type-check` (both
programs; the test file is in `tsconfig.test.json`'s file list): exit 0.
- `npx eslint src/RelatedList.tsx
src/__tests__/RelatedList.enlargedListGrid-28865.test.tsx` from the
package: 0 errors.
- `node scripts/check-sdui-manifest.mjs`: exit 0, manifest intact (106
components).
- `node scripts/pm/dispatch-gates.mjs --commands` derived 35 gates over
the 3 changed paths; all 35 ran, all `exit 0`; `--ran` reconciles `35
derived, 35 run, 0 NOT-MEASURED, 0 UNRUN`.
- The `@object-ui/plugin-detail` vitest suite ran before the merge
(above); the merge touched nothing it reads from source. The other
families are this PR's CI check-runs.
## Human Minimum
- [x] 1. No `packages/spec` change.
- [x] 2. No new names.
- [x] 3. No formatter ran; eslint reports 0 errors on the touched files.
- [x] 4. One issue, one branch, one pull request.
- [x] 5. Changeset `@object-ui/plugin-detail` patch, both declaration
lines in it and here.
- [x] 6. n/a, `packages/spec` untouched.
- [x] 7. No hand edits to generated or release-owned docs.
- [x] 8. Title, body and comments are in English, except the Chinese
maintainer brief above, which the dispatch contract asks for.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01WGufzewdXHDkMAKTyWjGh5)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent f6f663a commit f68b47c
3 files changed
Lines changed: 169 additions & 1 deletion
File tree
- .changeset
- ui/packages/plugin-detail/src
- __tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
72 | 72 | | |
73 | 73 | | |
74 | 74 | | |
| 75 | + | |
75 | 76 | | |
76 | 77 | | |
77 | 78 | | |
| |||
2377 | 2378 | | |
2378 | 2379 | | |
2379 | 2380 | | |
| 2381 | + | |
| 2382 | + | |
| 2383 | + | |
| 2384 | + | |
| 2385 | + | |
| 2386 | + | |
2380 | 2387 | | |
2381 | | - | |
| 2388 | + | |
| 2389 | + | |
| 2390 | + | |
2382 | 2391 | | |
2383 | 2392 | | |
2384 | 2393 | | |
| |||
2461 | 2470 | | |
2462 | 2471 | | |
2463 | 2472 | | |
| 2473 | + | |
| 2474 | + | |
| 2475 | + | |
| 2476 | + | |
| 2477 | + | |
| 2478 | + | |
| 2479 | + | |
2464 | 2480 | | |
2465 | 2481 | | |
2466 | 2482 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
238 | 238 | | |
239 | 239 | | |
240 | 240 | | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
0 commit comments