Repository navigation
Commit 73b712f
fix(app-shell): draw a served app label as served on every Console surface that names an app (#30443)
<!-- claude-projects-attribution: {"github_login":"os-sales"} -->
_Requested by **Sales** · [project
thread](https://claude.ai/code/project/chan_01D5bWFY3rFzgJcytD5gD4Uu?thread=cmsg_01D5bWFY3rFzgJcytD5gD4UuXjFYoeducAp4ExBhc3f6eL)_
domain:ui#5 · os-sales · session_01L6bhgVwQZbHRRM9CaXeKif
Fixes #30311
Clause-②: no
Metadata-protocol: none
## 维护者速读
- 改了什么:控制台所有显示应用名的地方(应用切换器、侧栏标题、首页应用卡片/应用条/最近访问、无权限页、AI
对话、应用市场「打开应用」按钮、报表索引)改为直接显示服务端已翻译好的应用名;应用卡片的描述同理。
- 为什么改:客户在 `.custom` 配对包里给已安装应用改名后,服务端(#30353)已按裁定顺序返回新名字,但前端又用基础包的
`apps.NAME.label` 译文盖回去,中文下仍显示旧名。
- 风险与回滚:只改 `ui/packages/app-shell`
的读取顺序;草稿预览(`?preview=draft`)、键式标签、无标签应用仍走前端词条,未改名的应用显示不变。回滚即撤本 PR,无数据迁移。
- 先看:`ui/packages/app-shell/src/hooks/useServedAppLabel.ts`(新 helper
的取值顺序),再看 `layout/AppSwitcher.tsx` 一处调用点。
- 两分钟验证:`pnpm --dir ui exec vitest run
packages/app-shell/src/hooks/__tests__/useServedAppLabel-30311.test.tsx`,预期
18 条全绿;修复前的取值顺序下其中 5 条是红的。
- 需要你做的:无,席位落地。
## What changes
- New private hook `useServedAppLabel`
(`ui/packages/app-shell/src/hooks/useServedAppLabel.ts`).
`appLabel(app)` draws a served `label` (a string, or an inline locale
map resolved by `metadataText`) as given; `appDescription(app)` does the
same for `description`. The bundle (`useObjectLabel().appLabel` /
`appDescription`, the `apps.NAME.label` lookup) is asked only for text
no server translated: an item stamped `_draft: true` by
`?preview=draft`, a keyed `{ key, defaultValue }` label (still resolved
through `t`, as before), or an app with no label / description.
- Every app-shell surface that named an app through
`useObjectLabel().appLabel({ name, label:
resolveKeyedI18nLabel(app.label, t) })` now calls
`useServedAppLabel().appLabel(app)`: 17 call sites in 11 files, taken
from the tree at `fdd06415` (`AppSwitcher` x3, `AiChatPage` x4,
`HomePage` x2, `UnifiedSidebar`, `AppHeader` hidden-app menu,
`AppNoAccessEmptyState`, `AppCard` label and description,
`HomeAppsStrip`, `MarketplacePage`, `MarketplacePackagePage`,
`AppReportIndexView`).
- `useNavTargetLabel.ts` and `ui/packages/i18n/**` are untouched (claim
fences); the hook only imports the exported `metadataText`.
- Root changeset `.changeset/30311-served-app-labels.md`
(`@object-ui/app-shell` patch).
## Why
Since #30353 the server serves an overridden app's label in the ruled
order (the `.custom` pair's own text over the base package's
translation). The Console handed that served label to the bundle lookup
as its fallback, so the base package's `apps.NAME.label` translation won
it back and a renamed app kept its old name on zh-CN. The object / view
half of #30311 landed in #30388 with the same served-first rule; this is
the app half.
## Tests
-
`ui/packages/app-shell/src/hooks/__tests__/useServedAppLabel-30311.test.tsx`
(new, 18 cases): the real hook over the real `useObjectLabel` inside a
real `I18nProvider` with a packaged catalogue, en and zh-CN: a renamed
served label and description draw as served; an unedited one shows the
server's translation; an inline locale map resolves in the active
language; controls for a `_draft` item, a keyed label, an absent / empty
label and a translation-only description keep the bundle. Plus a census:
no non-test source under `app-shell/src` other than the hook
destructures `appLabel` / `appDescription` from `useObjectLabel()` (with
a positive control that the walk reaches the hook and `AppSwitcher.tsx`,
and that the pattern matches the banned shape).
## Acceptance notes
- **Evidence branch deviation.** The dispatch asked for screenshots on a
never-merged evidence branch; this card thread can push only its
designated branch, so the PNGs were committed at `71a58ff3` and removed
again in the next commit. The PR squash-merges, so they never reach
`main`; the links below point at that commit.
- **CommandPalette** already drew `resolveKeyedI18nLabel(app.label, t)`
without the bundle, so it showed the served name before this PR and is
unchanged.
- The live leg exercised the app switcher pill, the sidebar title and
Home (app card, recent row app name). The marketplace "Open app" button,
the AI chat, the no-access state and the report index's other-app links
are pinned by the census and the hook cases, not browser-measured.
## Verification
<details><summary>Live, showcase --fresh, zh-CN, Console from ui/ src
through Vite, 1440 wide</summary>
Override written the way the platform takes it: `POST
/api/v1/packages/com.example.showcase/ensure-customization` (pair
`com.example.showcase.custom`, created), then `PUT
/api/v1/meta/app/showcase_app?package=com.example.showcase.custom&mode=draft`
with the served app body, `label: Showcase Hub (renamed-30311)` and
`overrides: { package: 'com.example.showcase', basedOn: '0.1.0' }`, then
`POST
/api/v1/meta/app/showcase_app/publish?package=com.example.showcase.custom`
(seq 2). `GET /meta/app/showcase_app` then serves `Showcase Hub
(renamed-30311)` under both `Accept-Language: zh-CN` and `en`; the zh-CN
catalogue keeps `apps.showcase_app.label` = 功能展示.
| Console, zh-CN, same override | `origin/main` app-shell sources
(`fdd06415`, restored into the tree, Vite `--force`) | this branch |
|:--|:--|:--|
| app switcher pill | 功能展示 | Showcase Hub (renamed-30311) |
| `/apps/showcase_app` page text matches | renamed 0, 功能展示 1 | renamed
1, 功能展示 0 |
| Home matches (app card + recent row) | renamed 0, 功能展示 1 | renamed 2,
功能展示 0 |
Screenshots (commit `71a58ff3`):
[before
app](https://github.com/objectstack-ai/objectstack/blob/71a58ff38d730b7ab0d64e958438deb1b72f68c0/evidence/30311/before-app-1440.png?raw=true)
·
[after
app](https://github.com/objectstack-ai/objectstack/blob/71a58ff38d730b7ab0d64e958438deb1b72f68c0/evidence/30311/after-app-1440.png?raw=true)
·
[before
Home](https://github.com/objectstack-ai/objectstack/blob/71a58ff38d730b7ab0d64e958438deb1b72f68c0/evidence/30311/before-home-1440.png?raw=true)
·
[after
Home](https://github.com/objectstack-ai/objectstack/blob/71a58ff38d730b7ab0d64e958438deb1b72f68c0/evidence/30311/after-home-1440.png?raw=true)
</details>
<details><summary>Tests, ablation, typecheck, lint (sources at
6f7c06c)</summary>
- New pin: `Test Files 1 passed (1)`, `Tests 18 passed (18)`, lock
VERDICT command-exit 0.
- Ablation 1 (via `scripts/ablation-replace.mjs`, anchor 1 to 0,
restored blob == HEAD, `git diff HEAD` empty): the hook's served-text
rung replaced by `return undefined` (the old bundle-first order) turns
exactly the 5 predicted cells red: renamed label en / zh-CN, inline
locale map, renamed description en / zh-CN; `Tests 5 failed | 13 passed
(18)`.
- Ablation 2: `AppSwitcher.tsx` back on `useObjectLabel()` turns the
census red naming `layout/AppSwitcher.tsx`; `Tests 1 failed | 17 passed
(18)`; restored, blob == HEAD.
- Consumer sweep: every test file under `ui/` that names one of the 11
changed modules or `appLabel` (310 files): `Test Files 310 passed
(310)`, `Tests 2598 passed (2598)`, lock VERDICT command-exit 0.
- `turbo run type-check --filter=@object-ui/app-shell`: `Tasks: 68
successful, 68 total`, VERDICT command-exit 0.
- eslint on the changed files: 0 new errors; the 2 errors it reports
(`react-hooks` "Cannot create components during render" in `AppCard.tsx`
and `HomeAppsStrip.tsx`) are on `origin/main` unchanged.
- `ui/scripts/check-new-cross-file-line-citations.mjs`: 0 new, exit 0.
</details>
<details><summary>Derived gates (dispatch-gates --commands, head
6f7c06c)</summary>
`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derives 36 commands from 14 paths; each was
run with its exit code captured before any pipe: all 35 node / pnpm
check commands exit 0, and `pnpm --dir ui exec vitest run scripts/` ran
under `os-verify-lock` with `--maxWorkers=2` (result in the
os-dev-report on #30311). The two evidence commits add and remove the
same files, so the derived set is unchanged at the final head.
</details>
## 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_01L6bhgX1ZNco5W3wXZFLVbh
---
_Generated by [Claude
Code](https://claude.ai/code/session_01L6bhgX1ZNco5W3wXZFLVbh)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent ab12a3b commit 73b712f
14 files changed
Lines changed: 296 additions & 53 deletions
File tree
- .changeset
- ui/packages/app-shell/src
- console
- ai
- home
- marketplace
- hooks
- __tests__
- layout
- views
| 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 | |
|---|---|---|---|
| |||
40 | 40 | | |
41 | 41 | | |
42 | 42 | | |
43 | | - | |
44 | | - | |
| 43 | + | |
| 44 | + | |
45 | 45 | | |
46 | 46 | | |
47 | 47 | | |
| |||
65 | 65 | | |
66 | 66 | | |
67 | 67 | | |
68 | | - | |
| 68 | + | |
69 | 69 | | |
70 | | - | |
| 70 | + | |
71 | 71 | | |
72 | 72 | | |
73 | 73 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
19 | | - | |
| 19 | + | |
| 20 | + | |
20 | 21 | | |
21 | 22 | | |
22 | 23 | | |
| |||
2181 | 2182 | | |
2182 | 2183 | | |
2183 | 2184 | | |
2184 | | - | |
| 2185 | + | |
2185 | 2186 | | |
2186 | 2187 | | |
2187 | 2188 | | |
| |||
2202 | 2203 | | |
2203 | 2204 | | |
2204 | 2205 | | |
2205 | | - | |
| 2206 | + | |
2206 | 2207 | | |
2207 | 2208 | | |
2208 | 2209 | | |
| |||
2214 | 2215 | | |
2215 | 2216 | | |
2216 | 2217 | | |
2217 | | - | |
| 2218 | + | |
2218 | 2219 | | |
2219 | 2220 | | |
2220 | 2221 | | |
| |||
2223 | 2224 | | |
2224 | 2225 | | |
2225 | 2226 | | |
2226 | | - | |
| 2227 | + | |
2227 | 2228 | | |
2228 | 2229 | | |
2229 | 2230 | | |
| |||
2387 | 2388 | | |
2388 | 2389 | | |
2389 | 2390 | | |
2390 | | - | |
| 2391 | + | |
2391 | 2392 | | |
2392 | 2393 | | |
2393 | 2394 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
11 | | - | |
12 | | - | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
13 | 14 | | |
14 | 15 | | |
15 | 16 | | |
| |||
40 | 41 | | |
41 | 42 | | |
42 | 43 | | |
43 | | - | |
| 44 | + | |
44 | 45 | | |
45 | 46 | | |
46 | 47 | | |
47 | | - | |
48 | | - | |
| 48 | + | |
| 49 | + | |
49 | 50 | | |
50 | 51 | | |
51 | 52 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
40 | 40 | | |
41 | 41 | | |
42 | 42 | | |
43 | | - | |
44 | | - | |
| 43 | + | |
| 44 | + | |
45 | 45 | | |
46 | 46 | | |
47 | 47 | | |
| |||
168 | 168 | | |
169 | 169 | | |
170 | 170 | | |
171 | | - | |
| 171 | + | |
172 | 172 | | |
173 | 173 | | |
174 | 174 | | |
| |||
228 | 228 | | |
229 | 229 | | |
230 | 230 | | |
231 | | - | |
| 231 | + | |
232 | 232 | | |
233 | 233 | | |
234 | 234 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
27 | | - | |
28 | | - | |
| 27 | + | |
29 | 28 | | |
30 | 29 | | |
31 | 30 | | |
| |||
46 | 45 | | |
47 | 46 | | |
48 | 47 | | |
49 | | - | |
50 | 48 | | |
51 | 49 | | |
52 | 50 | | |
| |||
364 | 362 | | |
365 | 363 | | |
366 | 364 | | |
367 | | - | |
| 365 | + | |
368 | 366 | | |
369 | 367 | | |
370 | 368 | | |
| |||
509 | 507 | | |
510 | 508 | | |
511 | 509 | | |
512 | | - | |
| 510 | + | |
513 | 511 | | |
514 | 512 | | |
515 | 513 | | |
| |||
804 | 802 | | |
805 | 803 | | |
806 | 804 | | |
807 | | - | |
| 805 | + | |
808 | 806 | | |
809 | 807 | | |
810 | 808 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
46 | 46 | | |
47 | 47 | | |
48 | 48 | | |
49 | | - | |
| 49 | + | |
50 | 50 | | |
| 51 | + | |
51 | 52 | | |
52 | 53 | | |
53 | 54 | | |
| |||
84 | 85 | | |
85 | 86 | | |
86 | 87 | | |
87 | | - | |
| 88 | + | |
88 | 89 | | |
89 | 90 | | |
90 | 91 | | |
| |||
186 | 187 | | |
187 | 188 | | |
188 | 189 | | |
189 | | - | |
| 190 | + | |
190 | 191 | | |
191 | 192 | | |
192 | 193 | | |
| |||
969 | 970 | | |
970 | 971 | | |
971 | 972 | | |
| 973 | + | |
972 | 974 | | |
973 | | - | |
974 | 975 | | |
975 | 976 | | |
976 | 977 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
29 | | - | |
| 29 | + | |
| 30 | + | |
30 | 31 | | |
31 | 32 | | |
32 | 33 | | |
| |||
47 | 48 | | |
48 | 49 | | |
49 | 50 | | |
50 | | - | |
| 51 | + | |
51 | 52 | | |
52 | 53 | | |
53 | 54 | | |
| |||
309 | 310 | | |
310 | 311 | | |
311 | 312 | | |
312 | | - | |
| 313 | + | |
313 | 314 | | |
314 | 315 | | |
315 | 316 | | |
| |||
619 | 620 | | |
620 | 621 | | |
621 | 622 | | |
| 623 | + | |
622 | 624 | | |
623 | | - | |
624 | 625 | | |
625 | 626 | | |
626 | 627 | | |
| |||
0 commit comments