Repository navigation
Commit efcc1a7
fix(app-shell): draw a served object or list view label as served in the Console sidebar, recent list and object list header (#30388)
<!-- claude-projects-attribution: {"github_login":"os-bill"} -->
_Requested by **Bill** · [project
thread](https://claude.ai/code/project/chan_016iMXWSZDzqWRWvWzdNo8wg?thread=cmsg_016iMXWSZDzqWRWvWzdNo8wgRs2m6UxsYUoAdT4puvameb)_
domain:ui#3 · os-bill · session_01Utp6CbPN5UYMnBaNJPJWfG
Refs #30311
Clause-②: no
Metadata-protocol: none
## 维护者速读
- 改了什么:Console
侧栏里未写标签的对象/列表视图入口、侧栏与首页的「最近访问」里的对象行和列表视图行、对象列表页标题、顶栏对象标题、对象 `/data`
页标题,改为直接显示服务端返回的名字;只有服务端没给名字(客户端自己派生的视图、还没读到的对象、待发布草稿)时才查客户端词典。
- 为什么改:客户在 `.custom` 里给已安装包的对象或列表视图改了名,服务端返回新名字,但 Console
拿服务端的名字再去查词典,基础包的旧译名又把它盖回去;实测 zh-CN 下对象页标题和最近访问仍显示「任务」「进行中」。
- 风险与回滚:未改名的条目显示不变(服务端本就用同一份词典翻译);记录页、表单、抽屉等其余约 43 处同类调用本 PR
未改,交席位立收口卡。回滚即还原本 PR。应用名一半等 #30062 服务端,所以写 Refs 不关卡。
- 先看:①
`ui/packages/app-shell/src/hooks/useNavTargetLabel.ts`(object/view 分支与
`servedObjectPluralLabel`);②
`ui/packages/app-shell/src/views/ObjectView.tsx` 的
`listTitleOf`(标题、收藏、无标签视图同一来源);③
`ui/packages/app-shell/src/layout/AppHeader.tsx` 对象分支。
- 两分钟验证:`pnpm --dir ui exec vitest run
packages/app-shell/src/hooks/__tests__/useRecentItemLabel.test.tsx
packages/app-shell/src/layout/__tests__/AppHeader.servedLabels-11295.test.tsx
packages/app-shell/src/views/ObjectView.listTitlePlural-11696.test.tsx
packages/app-shell/src/views/ObjectDataPage.listTitlePlural-11696.test.tsx`,预期
4 个文件全部通过。
- 需要你做的:无,席位落地。
## What changes
- **The rule (the one PR #30308 applied to report, page and
dashboard).** A label the `/meta` read or the app bundle served is
already translated by the server, by its label order for an overridden
item (#30193), so it is drawn as given. The catalog key
(`useObjectLabel`'s `objectLabel` / `objectPluralLabel` / `viewLabel`)
is asked only for text no server translated.
- `useNavTargetLabel.ts`
- `object` target (an unlabelled sidebar entry): the served object's
label as given; a pending draft's label still goes through the catalog.
- `view` target (an unlabelled sidebar entry, and a recent view row): a
served view's label as given, decided by `isServedView` — the identity
question the object page's view tabs already ask (objectui#11295,
objectui#11336). A view the client derived (a container expansion) still
goes through `viewLabel`. By name, the served reads are the names-only
scope's own `served` and `views`, from the same `readObjectScope` call
`readObjectsByName` makes, so no new request.
- New private helper `servedObjectPluralLabel(def, language,
objectPluralLabel)`: what a served object's list is called — served
`pluralLabel`, else served `label`, else the catalog under its name.
Internal to app-shell (not in the package index).
- `useRecentItemLabel.ts`: the recent object row uses
`servedObjectPluralLabel`.
- The object list header (Expected names the header; the seat widened
the claim's surface, comment 6652505627, narrowed in 6652679548):
- `ObjectView.tsx`: one `listTitleOf` feeds the page header's object
crumb (`ObjectViewPageHeader`), the list favorite's label and an
unlabelled view's tab text, so the three still agree (the header
compares the tab text with the plural).
- `AppHeader.tsx`: the object route's title, and the unlabelled-view
fallback on a view route.
- `ObjectDataPage.tsx`: the `/data` page title.
- **Not changed:** `ui/packages/i18n` (`useObjectLabel` is published;
changing its order is a `Clause-②` question). The rest of the family —
record pages, record forms, drawers, preview cards, and call sites
outside app-shell — is listed in Acceptance notes for the seat's closing
card.
## Tests
- New, one top-level describe per existing harness:
- `useRecentItemLabel.test.tsx` (objectstack#30311 describe, 9 cases):
renamed object and view in the recent list and in `useNavTargetLabel`
(whole-list and names-only-scope reads), served plural first, a view
embedded in the served object document; controls: a client-derived view,
an object the cache does not hold, a pending draft object, en.
- `AppHeader.servedLabels-11295.test.tsx` (4 cases),
`ObjectView.listTitlePlural-11696.test.tsx` (2),
`ObjectDataPage.listTitlePlural-11696.test.tsx` (2).
- **Fixtures that served English in a zh-CN session** (the world PR
#30308 named as not occurring: the Console's catalog is the server's own
`/api/v1/i18n/translations/:locale` answer, and the server translates a
served label with it): `useRecentItemLabel.objectPlural-11733`,
`ObjectView.listTitlePlural-11696`, `ObjectView.listLinksPlural-11733`,
`ObjectView.labelLessViewTab-12774`,
`ObjectDataPage.listTitlePlural-11696`,
`AppHeader.objectCrumbPlural-11696`,
`AppHeader.labelLessViewTitle-12805`,
`StudioDesignSurface.standardNavEntries-11201` (8 files) now serve the
zh-CN answer in zh-CN. Every existing assertion is unchanged.
- **Ablation** (the five source files restored to `ff3f83bb` with `git
restore --source`, marker count 0 on disk, restored with `git checkout
HEAD --`, `git status` clean and blob hashes equal to HEAD after):
`Tests 9 failed | 63 passed (72)`. The 9 are exactly the renamed cells
(object page title, app header en/zh, `/data` title, recent object,
recent plural, recent/nav view, names-only scope, embedded view); every
control stayed green.
<details><summary>Test runs</summary>
- Pins, fix in place: `Test Files 6 passed (6)`, `Tests 72 passed (72)`,
`VERDICT command-exit 0`.
- Consumer sweep 1 (before the header half; 563 test files in app-shell
and the Console that reference a module importing either hook): `Test
Files 1 failed | 562 passed (563)`, `Tests 1 failed | 4324 passed
(4325)`. The red was `StudioDesignSurface.standardNavEntries-11201`
(English served in zh-CN), fixed as above.
- Consumer sweep 2 (after merging `origin/main` and rebuilding, head
`23114841`): the 6 pin files plus 136 more test files that reference
`ObjectView`, `ObjectDataPage` or `AppHeader`: `Test Files 1 failed |
140 passed (141)`, `Tests 2 failed | 1395 passed (1397)`. The 2 reds
were `ObjectView.listLinksPlural-11733`'s zh-CN cells (English served in
zh-CN), fixed as above; that file then `Tests 7 passed (7)` at
`ec3b0e69`. This sweep ran 136 of the 298 test files its own reference
search found, not all of them (see Acceptance notes).
- Consumer sweep 3 (CI at `ec3b0e69` red on 7 zh-CN cells in
`AppHeader.objectCrumbPlural-11696`,
`AppHeader.labelLessViewTitle-12805` and
`ObjectView.labelLessViewTab-12774`, reproduced locally, fixtures fixed
at `1553cdd6`): every `AppHeader.*`, `ObjectView.*` and
`ObjectDataPage.*` test in app-shell, `Test Files 114 passed (114)`,
`Tests 929 passed (929)`; then all 298 files of sweep 2's reference
search at `6583026f` (`origin/main` merged in, no `ui/` file among the
37 it brought), in three locked runs: `Test Files 97 passed (97)` / `101
passed (101)` / `100 passed (100)`, `Tests 905` / `790` / `950 passed`,
each `VERDICT command-exit 0`.
- `eslint --no-inline-config` on the changed TypeScript files (at
`23114841`): 0 errors (104 warnings, all on lines this PR does not
touch).
- `pnpm exec turbo run type-check --filter=@object-ui/app-shell
--concurrency=2` at `ec3b0e69`: `Tasks 68 successful`, `VERDICT
command-exit 0`.
</details>
## Live (showcase `--fresh`, zh-CN, Console from `ui/` src through Vite)
Overrides written the way the platform takes them: `POST
/api/v1/packages/com.example.showcase/ensure-customization` (pair
`com.example.showcase.custom`); the object through an `object_extension`
(`PUT
/api/v1/meta/object_extension/showcase_task?package=com.example.showcase.custom&mode=draft`
with `extend`, `label: Work Item (renamed-30311)`, `pluralLabel: Work
Items (renamed-30311)`, then publish — an object `overrides` save is
refused `NOT_OVERRIDABLE`, ADR-0146 D10); the view through a view
override (`showcase_task.in_progress`, `label: In flight
(renamed-30311)`, `overrides: { package: 'com.example.showcase',
basedOn: '0.1.0' }`, then publish).
Served under `Accept-Language: zh-CN` after the overrides:
`/meta/object/showcase_task` → `Work Item (renamed-30311)` / `Work Items
(renamed-30311)`; `/meta/view/showcase_task.in_progress` → `In flight
(renamed-30311)`; the app bundle `/meta/app/showcase_app/bundle` carries
the renamed object too. The zh-CN catalog keeps
`objects.showcase_task.label` = 任务 and `_views.in_progress.label` = 进行中.
| Console, zh-CN, same overrides | `origin/main` ui (`ff3f83bb` sources)
| this branch |
|:--|:--|:--|
| object list page title (crumb) | 任务 / 全部任务 | Work Items
(renamed-30311) / 全部任务 |
| view page title | 任务 / In flight (renamed-30311) | Work Items
(renamed-30311) / In flight (renamed-30311) |
| sidebar 「最近使用」 | 客户 · 任务 · 进行中 | 客户 · Work Items (renamed-30311) · In
flight (renamed-30311) |
| Home 「最近访问」 | 客户 · 任务 · 进行中 | 客户 · Work Items (renamed-30311) · In
flight (renamed-30311) |
Each leg restarted the Console's Vite (`--force`) after switching the
five sources and checked that the served modules carried (or lacked) the
change before the run: the first after-run read a stale transform from
Vite's watcher. Screenshots (1440×900 at 2×, before/after of the object
page, the view page, the expanded sidebar recent group and Home) are in
the project's files at `ui-seat3/30311-shots/`; this channel cannot
upload images to the PR body, so the table above is their text.
The live leg did not reach an unlabelled sidebar entry: every showcase
navigation entry carries its own label, so the sidebar's object/view
rows draw those (unchanged). That path is pinned by the
`useNavTargetLabel` cases.
## Acceptance notes
- **The card's premise "the object's own page shows the new name" did
not hold.** Measured above: on `origin/main` the object page title also
showed 任务. The seat folded the header into this PR and named the rest of
the family for a closing card.
- **The rest of the family, not touched here** (`objectLabel(` /
`objectPluralLabel(` over a served definition, at `23114841`): in
app-shell, `AppContent` 4, `ActivityObjectLabel` 1, `ConsoleLayout` 1,
`ObjectView` 3 more (import wizard, delete confirmations,
`objectLabelOf`), `ObjectDataPage` 1 (record drawer title),
`RecordDetailView` 11, `RecordFormPage` 2, `appReportIndex` 2,
`RecordPreviewCard` 1, `recordDrawerStack` 2, `PackagedActionsSection`
1, `WidgetRefCellFaces` 1; outside app-shell: `fields` `RecordHoverCard`
1, `plugin-detail` 3, `plugin-form` 2, `plugin-gantt` 1, `plugin-grid`
1. Some pass text no server translated (`{ name, label: name }`
fallbacks, a widget ref's own `label`), so each needs a per-site
reading. The other way to close the class is to change
`useObjectLabel`'s own order, a `Clause-②` card.
- **A rename of `label` alone keeps the served plural.** The server
translates `label` and `pluralLabel` separately: an extension that
renames only `label` still serves the base's translated `pluralLabel`,
so a list title (which reads the plural first) keeps it. That is the
server's answer and Studio's; the live leg renamed both.
- **Deviation: an incomplete consumer sweep.** Sweep 2 was described as
covering every test file that references `ObjectView`, `ObjectDataPage`
or `AppHeader`; it ran 136 of the 298 its search found. Three of the 162
it skipped carried the same English-in-zh-CN fixture and went red in CI
at `ec3b0e69`. They are fixed at `1553cdd6` and the full 298 now pass
(sweep 3).
- **App labels** are unchanged (the app half waits for #30062's server
half), hence `Refs`.
## Verification
- Since `ec3b0e69` the branch gained three test-fixture files
(`1553cdd6`) and a merge of `origin/main` (`6583026f`, no `ui/` file).
`dispatch-gates --commands` at `1553cdd6` derives the same 35 commands;
they were not re-run there. `pnpm --filter @objectstack/spec
check:liveness` at `6583026f`: exit 0 (#30367 fixed on `main` by
#30368).
- Derived gates on `ec3b0e69`: `node scripts/pm/dispatch-gates.mjs
--commands --repo objectstack-ai/objectstack` lists 35 commands (the
same list as at `23114841`), each run with its exit code captured before
any pipe, all 35 exit 0; `--ran` reconciliation: 35 derived, 35 run, 0
NOT-MEASURED, 0 UNRUN, exit 0. `pnpm --dir ui exec vitest run scripts/`
ran under `os-verify-lock` with `--maxWorkers=2` (`Test Files 170 passed
| 2 skipped (172)`): its first run at `23114841`, with the showcase
stack up, was SIGKILLed for memory.
- `ui/scripts/check-new-cross-file-line-citations.mjs` at `ec3b0e69`: 0
new citations, exit 0.
- Changeset: `.changeset/30311-served-object-view-labels.md`,
`@object-ui/app-shell` patch, both declaration lines.
## 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.
- [x] 3. No formatter ran; `eslint` on the changed files reports 0
errors (the repo-wide `pnpm lint` is CI's).
- [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: its generated artifacts are
regenerated and committed. (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.
- [x] The *Before Submitting* list in CONTRIBUTING.md is done.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01Utp6CZywtebM5fE7KZuMEM
<!-- signed: domain:ui#3 · os-bill · session_01Utp6CbPN5UYMnBaNJPJWfG
-->
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 10ecafd commit efcc1a7
16 files changed
Lines changed: 482 additions & 79 deletions
File tree
- .changeset
- ui/packages/app-shell/src
- hooks
- __tests__
- layout
- __tests__
- views
- studio-design
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
38 | 38 | | |
39 | 39 | | |
40 | 40 | | |
41 | | - | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
42 | 52 | | |
43 | 53 | | |
44 | 54 | | |
45 | | - | |
| 55 | + | |
46 | 56 | | |
47 | 57 | | |
48 | 58 | | |
| |||
69 | 79 | | |
70 | 80 | | |
71 | 81 | | |
72 | | - | |
| 82 | + | |
73 | 83 | | |
74 | 84 | | |
75 | 85 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
| 25 | + | |
25 | 26 | | |
26 | 27 | | |
27 | 28 | | |
| |||
32 | 33 | | |
33 | 34 | | |
34 | 35 | | |
35 | | - | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
36 | 49 | | |
37 | 50 | | |
38 | | - | |
| 51 | + | |
39 | 52 | | |
40 | 53 | | |
41 | 54 | | |
| |||
53 | 66 | | |
54 | 67 | | |
55 | 68 | | |
56 | | - | |
57 | | - | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
58 | 74 | | |
59 | 75 | | |
60 | 76 | | |
| |||
65 | 81 | | |
66 | 82 | | |
67 | 83 | | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
68 | 88 | | |
69 | 89 | | |
70 | 90 | | |
71 | 91 | | |
72 | | - | |
| 92 | + | |
73 | 93 | | |
74 | 94 | | |
75 | 95 | | |
76 | | - | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
77 | 99 | | |
78 | 100 | | |
79 | 101 | | |
| |||
212 | 234 | | |
213 | 235 | | |
214 | 236 | | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 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 | + | |
0 commit comments