Repository navigation
Commit 8c9f48f
fix(app-shell): draw a served report, page or dashboard label as served in the Console header, report index and recent list (#30308)
<!-- claude-projects-attribution: {"github_login":"os-support-ai"} -->
_Requested by **Yibo Wang** · [project
thread](https://claude.ai/code/project/chan_01BVUyyPie8gHwoPM18iABwB?thread=cmsg_01BVUyyPie8gHwoPM18iABwBKmABkq9Ha7c3RZSdaCFLLj)_
Fixes #30244
Clause-②: no
Metadata-protocol: none
## 维护者速读
- 改了什么:Console
页眉的报表面包屑和页面标题、应用的报表索引、最近访问列表(报表、页面、仪表盘三类,以及侧边栏里未写标签、指向仪表盘的导航项)改为直接显示服务端返回的标签;只有服务端没给标签时才去查客户端词典。
- 为什么改:客户在 `.custom` 覆盖包里给已安装包的报表或仪表盘改了名,服务端按 #30193 的顺序返回新名字,Studio
也显示新名字;但 Console 拿着服务端的标签去查词典,词典里基础包的旧译名又把它盖了回去,用户在页眉和最近列表看到的是旧名字。
- 风险与回滚:未改动的条目显示不变(服务端本来就用同一份词典翻译过,实测 zh-CN
一致);切换语言时元数据整体重读,不会残留旧语言。回滚即还原本 PR。页面一项要等 #30062 服务端补上页面的 packagedBase
后才看得出效果;应用标签本 PR 未改,见 Acceptance notes。
- 先看:① `ui/packages/app-shell/src/layout/AppHeader.tsx` 报表与页面两个分支;②
`ui/packages/app-shell/src/hooks/useNavTargetLabel.ts` 仪表盘分支(草稿标签仍走词典);③
`ui/packages/app-shell/src/hooks/useRecentItemLabel.ts` 页面与报表分支。
- 两分钟验证:`pnpm --dir ui exec vitest run
packages/app-shell/src/layout/__tests__/AppHeader.servedLabels-11295.test.tsx
packages/app-shell/src/hooks/__tests__/useRecentItemLabel.test.tsx
packages/app-shell/src/views/__tests__/AppReportIndex-13020.test.tsx`,预期
3 个文件 49 个测试全部通过。
- 需要你做的:无,席位落地。
## What changes
- **The rule, at the callers that hold a served document.** 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 `reportLabel` /
`pageLabel` / `dashboardLabel`) is asked only when no served label is at
hand: the humanized slug, an item served with no label, a pending
draft's label. This is the rule the header's dashboard branch already
follows (objectui#11295).
- `AppHeader.tsx`: the report crumb and the page's phone title.
- `appReportIndex.ts` (`useAppReportEntries`): a report row's label.
- `useRecentItemLabel.ts`: a page row and a report row.
- `useNavTargetLabel.ts`: the dashboard target, which labels a recent
dashboard row and an unlabelled sidebar entry that opens a dashboard. A
pending draft's label still goes through the catalog.
- **The helpers are unchanged.** `pageLabel`, `reportLabel` and
`dashboardLabel` stay the catalog lookup for text no server translated,
because some of their callers pass exactly that: `plugin-dashboard`'s
`DashboardRenderer` passes a schema's `header.title`, and every caller
of `appLabel` passes a keyed label the client translates. Flipping a
helper would have changed those callers too. Their docblocks now say
that a caller holding a served label draws it as given. Adding a served
variant to `useObjectLabel` was weighed and not taken: 148 test files
mock `useObjectLabel` with a fixed member list, and the caller-side form
needs no new member.
- **Test fixtures that served English in a zh-CN session.** Three suites
(`RecentApps.labelAtRender-11678`,
`useRecentItemLabel.readsByName-29235`,
`useNavigationSync.standardEntryLocalizes-11201`) served an English
label in a zh-CN session and let a client catalog key translate over it.
The Console's catalog is the server's own
`/api/v1/i18n/translations/:locale` answer
(`ui/apps/console/src/loadLanguage.ts`), and the server translates a
served label with that same catalog, so that world does not occur:
measured on the showcase, `pages.showcase_task_schedule` is absent from
the server's zh-CN catalog and the page is served in English;
`pages.showcase_capability_map` is present and the page is served as
能力地图. The fixtures now serve what the server serves in that language;
each suite's assertion is unchanged.
## Per-caller reading (what each caller holds)
| Caller | What it holds | Where it comes from | Verdict |
|:--|:--|:--|:--|
| `AppHeader` report crumb | the report document | `metadata.reports`
(`/meta/report`), translated by the server | served: drawn as given |
| `AppHeader` page title | the page document | the app bundle, else
`/meta/page` by name | served: drawn as given |
| `useAppReportEntries` | the report document | `metadata.reports` |
served: drawn as given |
| `useRecentItemLabel` page / report | the page / report document | the
app bundle or `/meta` by name | served: drawn as given |
| `useNavTargetLabel` dashboard | the dashboard document, else a pending
draft row | the app bundle or `/meta/dashboard`; `_drafts` | served: as
given; draft: catalog, as before |
A language switch does not leave a served label stale: `ConsoleShell`
clears the adapter cache and remounts `MetadataProvider` with
`key={language}`, and the app bundle reads live inside it, so every
served label is read again in the new language.
## Tests
- New: one top-level describe in `AppHeader.servedLabels-11295.test.tsx`
(report crumb and page title, en and zh-CN, renamed / unedited / not
served / no catalogue entry); one in `useRecentItemLabel.test.tsx`
(report, page and dashboard each on its own cell, plus controls); one in
`AppReportIndex-13020.test.tsx` (renamed, unedited, served with no
label). Controls: an item the read did not serve, or served with no
label, is still named by the catalog key; en with no catalogue entry
keeps the humanized slug or machine name.
- Ablation (the four source files restored to `origin/main` `31260ca8`
with `git restore --source`, markers counted at 0 on disk, restored with
`git checkout HEAD --`, `git status` clean after): 8 failed | 41 passed.
The 8 are exactly the renamed cells (report crumb en/zh, page title
en/zh, report index, recent report, recent page, recent dashboard);
every control stayed green.
<details><summary>Test runs</summary>
- New pins, fix in place: `Test Files 3 passed (3)`, `Tests 49 passed
(49)`, `VERDICT command-exit 0`.
- Ablation leg: `Test Files 3 failed (3)`, `Tests 8 failed | 41 passed
(49)`.
- Consumer sweep (124 app-shell test files that import the four changed
modules, render `AppHeader`, `UnifiedSidebar`, Home, the report index or
the recent surfaces): `Test Files 3 failed | 121 passed (124)`, `Tests 4
failed | 936 passed (940)`. The 4 reds were the three fixture suites
above; after the fixture change: `Test Files 3 passed (3)`, `Tests 11
passed (11)`.
- 30 more test files carrying a zh-CN dashboard, page or report fixture:
`Test Files 30 passed (30)`, `Tests 290 passed (290)`.
- After merging `origin/main` (head 0aa33ca), the touched suites plus
the whole `@object-ui/i18n` package: `Test Files 101 passed (101)`,
`Tests 1503 passed | 13 skipped (1516)`.
- `pnpm --filter @object-ui/app-shell run type-check` and `pnpm --filter
@object-ui/i18n run type-check`: `VERDICT command-exit 0`. `eslint` on
the changed files: 0 errors.
</details>
## Live (showcase, zh-CN)
The CRM example ships no report, so the live leg ran on the showcase
(`pnpm dev -- --fresh`, the Console from `ui/` src through Vite).
Overrides were written the way Studio's Customize writes them: `POST
/api/v1/packages/com.example.showcase/ensure-customization` (pair
`com.example.showcase.custom`), then `PUT
/meta/TYPE/NAME?package=com.example.showcase.custom&mode=draft` with
`overrides: { package: 'com.example.showcase', basedOn: '0.1.0' }` and a
new `label`, then publish.
| Served under `Accept-Language: zh-CN` | Before the override | After
the override |
|:--|:--|:--|
| report `showcase_hours_by_status` (item and list) | 按状态统计工时(汇总) |
Effort by Status (renamed-30244) |
| dashboard `showcase_ops_dashboard` | 交付运营 | Delivery Cockpit
(renamed-30244) |
| page `showcase_capability_map` | 能力地图 | 能力地图 (en serves the override)
|
The report and the dashboard follow the #30193 order on `main`. The page
does not yet: the server passes no `packagedBase` for a page
(`PACKAGED_BASE_ACCESSORS` lists object, dashboard, view and report),
which is #30062's server half. The page caller takes the same rule
anyway; it is unmeasurable until #30062 lands, with the reading above as
its before.
| Console, zh-CN, same overrides | `origin/main` ui | this branch |
|:--|:--|:--|
| header crumb on the report | 按状态统计工时(汇总) | Effort by Status
(renamed-30244) |
| report index row | 按状态统计工时(汇总) | Effort by Status (renamed-30244) |
| sidebar recent: report / dashboard / page | 按状态统计工时(汇总) / 交付运营 / 能力地图
| Effort by Status (renamed-30244) / Delivery Cockpit (renamed-30244) /
能力地图 |
| Studio item properties | | Effort by Status (renamed-30244) |
## Acceptance notes
- **App labels are left as they are.** The card's Wanted box names the
app document too. On `main` the server passes no `packagedBase` for an
app either, so an overridden app is served the base's translation today
and the Console agrees with it. The app callers (about sixteen: the
header, the app switcher, the sidebar, Home, AI chat, the no-access
state and the report index's other-apps list) pass
`resolveKeyedI18nLabel(app.label, t)`, which may be a keyed label the
client translates, so a served-first rule there has to tell a served
string from a keyed label first. Raised to the seat as an open question;
it can ride with #30062.
- **Same class, not touched here:** an object's and a list view's label
in `useNavTargetLabel` and the recent `object` row (`objectPluralLabel`)
still ask the catalog over the served label. The server keeps an
overridden object's own text (it passes `packagedBase` for object and
view), so a renamed object would show its base translation in the
sidebar and recent list. Reported to the seat for a family card.
- The claim's file surface did not list `useNavTargetLabel.ts`; the
recent list's dashboard row is labelled through it, so it is touched
here.
## Verification
- Derived gates: `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` at 0aa33ca: 35 commands, 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`.
- Changeset: `.changeset/30244-served-labels-console-header.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; `pnpm lint` passes.
- [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_01WGufzjFKVx21wuZt6HYZ3J
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 665db00 commit 8c9f48f
12 files changed
Lines changed: 323 additions & 58 deletions
File tree
- .changeset
- ui/packages
- app-shell/src
- console/home/__tests__
- hooks
- __tests__
- layout
- __tests__
- views
- __tests__
- i18n/src
| 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 | |
|---|---|---|---|
| |||
27 | 27 | | |
28 | 28 | | |
29 | 29 | | |
30 | | - | |
31 | | - | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
32 | 34 | | |
33 | 35 | | |
34 | 36 | | |
| |||
72 | 74 | | |
73 | 75 | | |
74 | 76 | | |
75 | | - | |
| 77 | + | |
76 | 78 | | |
77 | 79 | | |
78 | 80 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
27 | | - | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
28 | 30 | | |
29 | 31 | | |
30 | 32 | | |
| |||
147 | 149 | | |
148 | 150 | | |
149 | 151 | | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
150 | 157 | | |
151 | 158 | | |
152 | 159 | | |
153 | 160 | | |
154 | | - | |
| 161 | + | |
155 | 162 | | |
156 | 163 | | |
157 | 164 | | |
| |||
180 | 187 | | |
181 | 188 | | |
182 | 189 | | |
183 | | - | |
| 190 | + | |
184 | 191 | | |
185 | 192 | | |
186 | 193 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
17 | | - | |
18 | | - | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
19 | 20 | | |
20 | 21 | | |
21 | 22 | | |
| |||
42 | 43 | | |
43 | 44 | | |
44 | 45 | | |
45 | | - | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
46 | 60 | | |
47 | 61 | | |
48 | 62 | | |
49 | 63 | | |
50 | 64 | | |
51 | 65 | | |
52 | 66 | | |
53 | | - | |
| 67 | + | |
54 | 68 | | |
55 | 69 | | |
56 | 70 | | |
57 | | - | |
| 71 | + | |
58 | 72 | | |
59 | 73 | | |
60 | 74 | | |
| |||
69 | 83 | | |
70 | 84 | | |
71 | 85 | | |
72 | | - | |
| 86 | + | |
73 | 87 | | |
74 | 88 | | |
75 | 89 | | |
| |||
101 | 115 | | |
102 | 116 | | |
103 | 117 | | |
104 | | - | |
| 118 | + | |
105 | 119 | | |
106 | 120 | | |
107 | 121 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
28 | | - | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
29 | 36 | | |
30 | 37 | | |
31 | 38 | | |
| |||
37 | 44 | | |
38 | 45 | | |
39 | 46 | | |
40 | | - | |
41 | | - | |
42 | | - | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
43 | 50 | | |
44 | 51 | | |
45 | 52 | | |
| |||
51 | 58 | | |
52 | 59 | | |
53 | 60 | | |
54 | | - | |
55 | | - | |
56 | | - | |
57 | | - | |
58 | | - | |
59 | | - | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
60 | 74 | | |
61 | 75 | | |
62 | | - | |
| 76 | + | |
63 | 77 | | |
64 | 78 | | |
65 | 79 | | |
| |||
68 | 82 | | |
69 | 83 | | |
70 | 84 | | |
71 | | - | |
| 85 | + | |
72 | 86 | | |
73 | 87 | | |
74 | 88 | | |
| |||
144 | 158 | | |
145 | 159 | | |
146 | 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
37 | 37 | | |
38 | 38 | | |
39 | 39 | | |
40 | | - | |
41 | | - | |
42 | | - | |
43 | | - | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
44 | 46 | | |
45 | 47 | | |
46 | 48 | | |
| |||
186 | 188 | | |
187 | 189 | | |
188 | 190 | | |
189 | | - | |
190 | | - | |
191 | | - | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
192 | 199 | | |
193 | 200 | | |
194 | 201 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
28 | | - | |
29 | | - | |
30 | | - | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
37 | | - | |
38 | | - | |
39 | | - | |
40 | | - | |
41 | | - | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
| |||
111 | 111 | | |
112 | 112 | | |
113 | 113 | | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
114 | 117 | | |
115 | 118 | | |
116 | | - | |
117 | | - | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
118 | 122 | | |
119 | 123 | | |
120 | 124 | | |
121 | | - | |
122 | | - | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
123 | 128 | | |
124 | 129 | | |
125 | 130 | | |
| |||
0 commit comments