Repository navigation
Commit 8bb2417
fix(plugin-detail): the record strip is the declared highlights only; the path's stage and the owner show once (#28907)
<!-- claude-projects-attribution: {"github_login":"zhuangjianguo"} -->
_Requested by **Steedos** · [project
thread](https://claude.ai/code/project/chan_018ETKaNwMZCNRYD7D8Q9Ubb?thread=cmsg_018ETKaNwMZCNRYD7D8Q9Ubb6wxbsWyHo3SfTcNubseV95)_
Fixes #28868
Clause-②: no
Metadata-protocol: none
## 维护者速读
- **改了什么**:记录页的要点条(highlight strip)只画对象声明的 `highlightFields`(去掉标题字段,最多 6
个)。没声明就不画:默认记录页、手机记录头、记录悬停卡三处都一样,字段全部留在正文。路径条(`record:path`)画了阶段字段时,正文不再重复画这个字段。要点条里有
`owner_id` 时,正文下方的元信息行不再重复写负责人。系统字段 `owner_id` 的中文平台标签从「所有者」改为「负责人」,和 ui
的 `detail.owner` 统一。
- **为什么改**:维护者裁决 A1「没声明就不挑」(#28868)。以前没声明时按字段名猜 6 个(owner
打头)并从正文隐藏,小对象的正文因此被掏空;阶段在路径条和正文各出现一次;负责人在要点条和元信息行各出现一次,还用了「所有者」「负责人」两个词。
- **风险与回滚**:低到中。没声明 `highlightFields` 的对象(含 `examples/app-crm`)会失去要点条,直到
#28870 给 app-crm 补声明;HotCRM 已声明。没有新的元数据键,没有新门禁。回滚即还原本 PR。
-
**先看**:`ui/packages/plugin-detail/src/synth/buildDefaultPageSchema.ts`(`deriveHighlightFields`、`headerDrawnFields`、`drawnPathField`)、`ui/packages/plugin-detail/src/RecordMetaFooter.tsx`(负责人只出现一次)、`synth/__tests__/highlights-declaredOnly-28868.test.ts`。
- **两分钟验证**:`pnpm --dir ui exec vitest run
packages/plugin-detail/src/synth/__tests__/highlights-declaredOnly-28868.test.ts
packages/plugin-detail/src/__tests__/RecordMetaFooter.ownerOnce-28868.test.tsx`,预期
2 个文件、19 个测试全绿。
- **需要你做的**:无,席位落地。
## What changes
- **No guessed strip.** `deriveHighlightFields`
(`@object-ui/plugin-detail`) returns the object's declared
`highlightFields` minus the title field (the one `resolveTitleField`
names), at most `max`, or `[]`. The preferred-name walk (`owner` /
`owner_id` first, then amount, rating, industry, …), the type filter,
the system-field skip list, the gated-group skip and the retired-type
gate on that walk are deleted, not kept behind a flag. The export and
its signature stay. `statusField` is accepted and no longer read; the
docblock says so.
- **The three readers follow it.**
- The default page (`buildDefaultHighlights`, and the body's
`hideFields`) asks it as before. An undeclared object now gets no
`record:highlights` node and an empty hide list.
- The phone header (`recordPhoneHeader.ts`) uses `declared ?? []`: no
strip and no subtitle when nothing is declared, as on any width.
- The hover card (`RecordPreviewCard.tsx`) asks
`deriveHighlightFields(def, null)`, so an undeclared object shows the
title alone. With no key field it now sends no `$expand`.
`buildExpandFields` reads an empty column list as "every reference
field", which the card would never draw. The new card test caught this.
- **The stage once.** `buildDefaultPageSchema` reads the strip it
actually placed: the default one, or an authored `highlights` slot. When
that strip holds a `record:path`, its `statusField` joins the Details
body's `hideFields`. `buildDefaultTabs` on its own hides what the
default strip for the same options draws. Two private helpers do this,
`drawnPathField` and `headerDrawnFields`. No public type moves: the
exported `buildDefaultTabs` keeps its options type, and the page builder
calls a private `synthTabs` with the computed list.
- **The body's hide list is cut at six too** (a bounded in-place fix,
same defect class). The strip has always drawn at most six, but
`buildDefaultTabs` hid the whole list `RecordDetailView` passes in. So a
declared seventh or eighth entry was drawn by neither the strip nor the
body. `headerDrawnFields` cuts at `RECORD_HIGHLIGHTS_MAX`. The fix is
pinned, and its ablation goes red.
- **The owner once.** `RecordMetaFooter` leaves the owner out of the
meta line when `deriveHighlightFields(objectSchema, null)` holds
`owner_id`. Otherwise it keeps it.
- **One word for the owner.** The ui key `detail.owner` and the spec's
system-field label of `owner_id` (`SYSTEM_FIELD_LABELS` in
`packages/spec/src/system/i18n-resolver.ts`) now say the same word in
every language both declare:
| Language | `detail.owner` (ui pack) | `owner_id` (spec) | Change |
|---|---|---|---|
| en | Owner | Owner | none |
| zh-CN | 负责人 | 负责人 (was 所有者) | spec value |
| ja-JP | 所有者 | 所有者 | none |
| es-ES | Propietario | Propietario | none |
| ko, de, fr, pt, ru, ar | 소유자, Inhaber, Propriétaire, Proprietário,
Владелец, المالك | (no spec row) | none |
The seat chose 「负责人」 for zh: the person who follows the record up. Every
other language keeps the word its ui pack already uses. None of them is
wrong for a record's owner. "Inhaber" is the common German CRM term
(Datensatzinhaber). No ui pack value changes. A label an author wrote is
still never overridden.
## Tests
- **New: `synth/__tests__/highlights-declaredOnly-28868.test.ts`, 11
cases, rules 1–3.**
- The card's account (industry, revenue, website, owner, no declared
list) gets no strip and an empty body hide list.
- A declared list is drawn exactly, minus the title, and the body hides
exactly those fields. A declared entry past the sixth stays in the body.
- An opportunity with a path hides `stage` from the body. Controls:
`stageField: false`, and a status field with no stages. An authored
highlights slot with a path hides the stage, and one without a path does
not. `buildDefaultTabs` on its own follows the same rule.
- **New: `__tests__/RecordMetaFooter.ownerOnce-28868.test.tsx`, 8 cases,
rules 3 (owner) and 4 (one word).** A declared strip naming `owner_id`
drops the owner from the meta line. With no `owner_id` in the strip, or
no strip at all, the owner stays. For en / zh-CN / ja-JP / es-ES,
`translateObject`'s `owner_id` label equals the matching ui pack's
`detail.owner`. 负责人 and Owner are pinned by name.
- **Hover card and phone header.** `RecordPreviewCard.test.tsx` gains
"an object that declares no highlightFields shows the title alone". It
asserts no guessed field and a bare `findOne` with no `$expand`. In
`recordPagePush-27058.test.tsx`, the "no declared highlights" case now
asserts `{ subtitle: '', highlightFields: [] }` instead of "derived, at
most four".
- **Tests that pinned today's guess, changed:**
- `__tests__/buildDefaultPageSchema.retiredFieldType.test.ts` is
deleted. It pinned the retired-type gate on the two selection passes,
and both passes are gone. A retired type is still refused loudly by the
form, inline edit and the body
(`InlineFieldInput.retiredFieldType.test.tsx` and the field widgets).
- `deriveHighlightFields.groupGate-12720.test.ts` is rewritten. An
undeclared object has no strip at all, a declared gated entry is left as
written, and the page body hides nothing and draws the gated group.
- `buildDefaultPageSchema.test.ts`: the four heuristic cases become one
"nothing is guessed" case, and the title-skip case now uses a declared
list. The retired `compactLayout` case now expects `[]`. Three page and
sub-builder cases use a `declaredLeadDef`, and the unused
`getRecordDisplayName` import is dropped.
- In `buildDefaultPageSchema.strictPayload.test.ts` and
`record-highlights.groupGate-12720.test.tsx`, the fixtures declare the
strip they render.
- In `resolveTitleField.sharedLadder-7287.test.ts`, three strip cases
declare their fields, so the title skip still decides.
- **The label pins move from 所有者 to 负责人**: spec `i18n-resolver.test.ts`
(the custom-label case now uses 客户经理, so it still proves an author's
label wins), rest `meta-object-injected-column-i18n.test.ts`, and the
app-shell `DraftChangesPanel.generatedGroup-25890.test.tsx` fixture that
mirrors the read.
## Acceptance notes
- **app-crm loses its strips until #28870.** `examples/app-crm` declares
no `highlightFields`. #28870 declares them (same seat, in parallel);
app-crm is not edited here.
- **Phone width, owner in the 5th or 6th declared slot.** The meta line
asks the declared strip, which holds at most six fields. On a phone, the
header shows at most four after its subtitle. So an object declaring
`owner_id` fifth or sixth, behind four non-text highlights, names the
owner in neither place on a phone. Closing that needs `RecordDetailView`
to hand the footer the strip it drew. That file is outside this card's
surface, and `domain:ui#1` holds it for #28483. carrier: seat.
- **An authored `highlights` slot** still leaves the body hiding the
declared list, as before. Only the stage half now follows the slot.
- **Release-owned text** (`packages/*/CHANGELOG.md`) still describes the
old heuristic in released entries. It is not edited.
## Verification
All readings are on this branch. The final head is `f8e75710`, a merge
of `main` (11 commits, none touching this diff's files except an
unrelated `cancelText` hunk in `i18n-resolver.ts`), unless a block names
another head.
<details><summary>plugin-detail · 362 of 362 files</summary>
Run at `d57d0f80` + fixture commits (`208ff9bd`, `68776a00`) under
`os-verify-lock`, `--maxWorkers=2`, in four batches:
- `src/synth` + `src/renderers`: 126 files. First run 3 files / 7 tests
red, all fixtures that relied on the guess to draw a strip:
`strictPayload` coverage, three `buildDefaultPageSchema.test.ts` page
cases, and the three `record-highlights.groupGate-12720` legs. After the
fixtures declare their strip: 17/17 re-run, 204 tests.
- `src/__tests__` first half: 113 passed, 835 tests.
- `src/__tests__` second half: 112 passed, 1 skipped, 982 tests.
- The package root files plus the new footer test: 11 passed, 83 tests.
</details>
<details><summary>app-shell and console · every test naming the record
page, the strip, the hover card, the phone header or the footer · 265
files</summary>
`git grep -l` over `packages/app-shell/src/**/*.test.ts*` and
`apps/console/src/**/*.test.ts*` for the touched modules,
`record:highlights`, `highlightFields`, `RecordMetaFooter` and 所有者 gave
265 files. Two batches at `--maxWorkers=3`: 138/138 files (1380 tests),
then 127 files with 1 red. The red was the new hover-card pin: an
undeclared object sent `$expand: ['account']`. Fixed in `d4833e5a`, and
`record-preview/` re-ran 3/3 files, 43 tests. This is a declared
narrowing; CI's Test UI runs the rest of app-shell.
At the merged head: plugin-detail `synth/`, the new footer test,
`recordPageV3Face-27055`, `record-highlights.groupGate-12720` and the 20
app-shell files naming `phoneRecordHeader` / `RecordPreviewCard` /
`RecordMetaFooter` / `highlightFields` / the phone record page: 39/39
files, 421 tests.
</details>
<details><summary>spec and rest label pins</summary>
`pnpm --filter @objectstack/spec exec vitest run
src/system/i18n-resolver.test.ts
src/system/i18n-resolver.object-validations.test.ts`: 2/2 files, 386
tests. `pnpm --filter @objectstack/rest exec vitest run
src/meta-object-injected-column-i18n.test.ts`: 1/1, 4 tests. `pnpm
--filter @objectstack/spec check:generated` at the merged head: exit 0,
every generated artifact up to date (a label value moves none).
</details>
<details><summary>Ablations · 7 legs, all red as predicted</summary>
Each leg went through `scripts/ablation-replace.mjs` against the
committed fix. Each restore read blob == HEAD with `git diff HEAD`
empty.
1. The guess put back (undeclared → the first fields): 8 of 11 cases in
`highlights-declaredOnly-28868` red.
2. The path's stage not pushed into the hide list: 3 red (path page,
authored slot, `buildDefaultTabs`).
3. The hide list not cut at six: 1 red (the past-sixth case).
4. The footer ignoring the strip: 1 red (strip naming `owner_id`).
5. The hover card expanding with no key field: 1 red (the new card
case).
6. The phone header guessing again: 1 red (the no-declared case).
7. The spec label back to 所有者: 4 red in spec `i18n-resolver.test.ts`.
The ui cross-package pin (`detail.owner` equals the spec label) reads
`@objectstack/spec`'s dist, so leg 7 was run on the spec's own suite,
which reads source.
</details>
<details><summary>Type check</summary>
`pnpm --filter @object-ui/plugin-detail run type-check && pnpm --filter
@object-ui/app-shell run type-check` (each `tsc --noEmit` plus `tsc -p
tsconfig.test.json`): exit 0, both before and after the merge. Each run
followed `turbo run build --filter='@object-ui/app-shell^...'` (64
tasks).
</details>
<details><summary>Derived gates · 83 commands</summary>
`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived 83 commands at `d4833e5a`:
- 81 exited 0.
- `check-plugin-teardown-shape.mjs --self-test` exited 3 because a
shallow clone could not read its pinned fixture. After `git fetch
--depth=1 origin 621a487…` it exited 0 (48 cases).
- `pnpm check:dual-build-cjs-loads` exited 3, "Run `pnpm build` first …
nothing was measured", because 30 packages outside this diff's closure
have no `dist`. NOT MEASURED locally; CI's Lint & Repo Gates runs it.
- `pnpm --dir ui exec vitest run scripts/` ran after a spec rebuild: 169
files passed, 2 skipped; 4900 tests.
Re-run at the merged head, each exit 0: `check-sdui-manifest.mjs`,
`check:nul-bytes`, `check:cross-package-test-inputs`,
`check:test-source-alias`, `check-empty-changeset.mjs --base
origin/main`, `check:issue-citations` and `check:doc-authoring`. `pnpm
--dir ui run check:new-line-citations` found 0 new citations.
</details>
<details><summary>PR-body gates</summary>
Run with this body as `GITHUB_EVENT_PATH` (or `PR_BODY`), before the
create, each exit 0:
- `check-changeset-no-major.mjs --base origin/main`, which reads
`Metadata-protocol: none` and a `patch` changeset;
- `check-adr-0087-registration.mjs --base origin/main`, which found 1
non-breaking changeset;
- `check-closing-keyword-parity.mjs`;
- `check-partof-closing-keyword.mjs`.
</details>
Diff: 19 files, about 1,000 changed lines, under the 3,000-line line.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01QsR2jU8qzB9Vbw2NdbFxiG)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent a364093 commit 8bb2417
19 files changed
Lines changed: 493 additions & 502 deletions
File tree
- .changeset
- packages
- rest/src
- spec/src/system
- ui/packages
- app-shell/src
- preview/__tests__
- views
- __tests__
- record-preview
- plugin-detail/src
- __tests__
- renderers/__tests__
- synth
- __tests__
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
144 | 144 | | |
145 | 145 | | |
146 | 146 | | |
147 | | - | |
| 147 | + | |
148 | 148 | | |
149 | 149 | | |
150 | 150 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3242 | 3242 | | |
3243 | 3243 | | |
3244 | 3244 | | |
3245 | | - | |
| 3245 | + | |
3246 | 3246 | | |
3247 | 3247 | | |
3248 | 3248 | | |
| |||
3255 | 3255 | | |
3256 | 3256 | | |
3257 | 3257 | | |
3258 | | - | |
| 3258 | + | |
3259 | 3259 | | |
3260 | 3260 | | |
3261 | 3261 | | |
| |||
3270 | 3270 | | |
3271 | 3271 | | |
3272 | 3272 | | |
3273 | | - | |
| 3273 | + | |
3274 | 3274 | | |
3275 | 3275 | | |
3276 | | - | |
| 3276 | + | |
3277 | 3277 | | |
3278 | 3278 | | |
3279 | 3279 | | |
| |||
3294 | 3294 | | |
3295 | 3295 | | |
3296 | 3296 | | |
3297 | | - | |
| 3297 | + | |
3298 | 3298 | | |
3299 | 3299 | | |
3300 | 3300 | | |
| |||
3359 | 3359 | | |
3360 | 3360 | | |
3361 | 3361 | | |
3362 | | - | |
| 3362 | + | |
3363 | 3363 | | |
3364 | 3364 | | |
3365 | 3365 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4013 | 4013 | | |
4014 | 4014 | | |
4015 | 4015 | | |
4016 | | - | |
| 4016 | + | |
4017 | 4017 | | |
4018 | 4018 | | |
4019 | 4019 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
51 | 51 | | |
52 | 52 | | |
53 | 53 | | |
54 | | - | |
| 54 | + | |
55 | 55 | | |
56 | 56 | | |
57 | 57 | | |
| |||
109 | 109 | | |
110 | 110 | | |
111 | 111 | | |
112 | | - | |
| 112 | + | |
113 | 113 | | |
114 | 114 | | |
115 | 115 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
235 | 235 | | |
236 | 236 | | |
237 | 237 | | |
238 | | - | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
239 | 241 | | |
240 | | - | |
241 | | - | |
| 242 | + | |
242 | 243 | | |
243 | 244 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
144 | 144 | | |
145 | 145 | | |
146 | 146 | | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
147 | 162 | | |
148 | 163 | | |
149 | 164 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
32 | | - | |
33 | | - | |
34 | | - | |
35 | | - | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
36 | 37 | | |
37 | 38 | | |
38 | 39 | | |
| |||
106 | 107 | | |
107 | 108 | | |
108 | 109 | | |
109 | | - | |
| 110 | + | |
110 | 111 | | |
111 | 112 | | |
112 | 113 | | |
| |||
169 | 170 | | |
170 | 171 | | |
171 | 172 | | |
172 | | - | |
| 173 | + | |
173 | 174 | | |
174 | 175 | | |
175 | 176 | | |
176 | 177 | | |
177 | | - | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
178 | 182 | | |
179 | 183 | | |
180 | 184 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
16 | | - | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
17 | 19 | | |
18 | 20 | | |
19 | | - | |
20 | | - | |
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
| |||
46 | 46 | | |
47 | 47 | | |
48 | 48 | | |
49 | | - | |
50 | | - | |
| 49 | + | |
| 50 | + | |
51 | 51 | | |
52 | 52 | | |
53 | 53 | | |
| |||
65 | 65 | | |
66 | 66 | | |
67 | 67 | | |
68 | | - | |
69 | | - | |
| 68 | + | |
70 | 69 | | |
71 | 70 | | |
72 | 71 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
| 19 | + | |
19 | 20 | | |
20 | 21 | | |
21 | 22 | | |
| |||
246 | 247 | | |
247 | 248 | | |
248 | 249 | | |
249 | | - | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
250 | 256 | | |
251 | 257 | | |
252 | 258 | | |
| |||
0 commit comments