Skip to content

fix(app-shell): draw a served report, page or dashboard label as served in the Console header, report index and recent list - #30308

Merged
objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/project-thread-61aum1
Nov 5, 2026
Merged

objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/project-thread-61aum1

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Yibo Wang · project thread

Fixes #30244

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:Console 页眉的报表面包屑和页面标题、应用的报表索引、最近访问列表(报表、页面、仪表盘三类,以及侧边栏里未写标签、指向仪表盘的导航项)改为直接显示服务端返回的标签;只有服务端没给标签时才去查客户端词典。
  • 为什么改:客户在 .custom 覆盖包里给已安装包的报表或仪表盘改了名,服务端按 i18n: an override's own label loses to the base's translation on page, dataset, app and book, and a translation in the .custom pair never wins on any type #30193 的顺序返回新名字,Studio 也显示新名字;但 Console 拿着服务端的标签去查词典,词典里基础包的旧译名又把它盖了回去,用户在页眉和最近列表看到的是旧名字。
  • 风险与回滚:未改动的条目显示不变(服务端本来就用同一份词典翻译过,实测 zh-CN 一致);切换语言时元数据整体重读,不会残留旧语言。回滚即还原本 PR。页面一项要等 Declared overrides: a mapping override publishes but is never served, doc and mapping overrides cannot be restored, and an override's label can be hidden by translation #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 (i18n: an override's own label loses to the base's translation on page, dataset, app and book, and a translation in the .custom pair never wins on any type #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.
Test runs
  • 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.

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 Declared overrides: a mapping override publishes but is never served, doc and mapping overrides cannot be restored, and an override's label can be hidden by translation #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

  • 1. Schemas start as Zod; packages/spec holds no runtime logic.
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint passes.
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset.
  • 6. packages/spec touched: its generated artifacts are regenerated and committed. (not touched)
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English.
  • The Before Submitting list in CONTRIBUTING.md is done.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WGufzjFKVx21wuZt6HYZ3J

…ed in the Console header and recent list

The header's report crumb and page title, the app report index and the
recent-items list handed the label a /meta read served to the
useObjectLabel catalog lookup as its fallback, so the packaged catalog
key won and re-applied the base package's translation over the server's
answer for an overridden item. The served label is now drawn as given;
the catalog is asked only when no served label is at hand.

Claude-Session: https://claude.ai/code/session_01WGufzjFKVx21wuZt6HYZ3J
Co-authored-by: Claude <noreply@anthropic.com>
… header, report index and recent list

Adds a changeset for the served-label fix.

Claude-Session: https://claude.ai/code/session_01WGufzjFKVx21wuZt6HYZ3J
Co-authored-by: Claude <noreply@anthropic.com>
… served-label rule reads

Three suites served an English label in a zh-CN session and relied on the
client catalog to translate it over the served one. The Console's catalog
is the server's own /i18n/translations answer, and the server translates
a /meta label with it, so a zh-CN session holds the translated label; the
fixtures now serve that.

Claude-Session: https://claude.ai/code/session_01WGufzjFKVx21wuZt6HYZ3J
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface labels Nov 5, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#1 · os-support-ai · session_01WGufzfE4V9fzZgJLrLDmMC

维护者速读(席位终稿)

席位核对 · ACCEPT · head 0aa33ca0 · 2026-11-05T05:46Z

  1. Shape: draft, base main, Fixes #30244. One changeset: @object-ui/app-shell patch, Clause-②: no / Metadata-protocol: none. 12 files, +323/−58. check-governed-merges --pr 30308: NOT governed.
  2. Read by the seat: each caller now draws metadataText(def.label, language) as given and asks the catalog (pageLabel / reportLabel / dashboardLabel) only when no served label is at hand, the humanized slug or a pending draft's label still going through the catalog. Same rule the header's dashboard branch already used (objectui#11295). The helpers themselves are unchanged (other callers pass unserved or keyed text). A language switch remounts MetadataProvider keyed on language after clearing the adapter cache, so no served label goes stale. Shot after-report-crumb-and-recent.png: crumb, title and recent rows read the renamed report and dashboard.
  3. Accepted deviations: (a) useNavTargetLabel.ts touched beyond the Claim's list (the recent dashboard row is labelled through it); Claim surface amended here. (b) Three existing fixtures that served English under a zh-CN client catalog key now serve what the server serves; assertions unchanged. (c) Page follows the same rule but is unmeasurable until Declared overrides: a mapping override publishes but is never served, doc and mapping overrides cannot be restored, and an override's label can be hidden by translation #30062's server half adds packagedBase for page (before reading: 能力地图 in zh-CN). (d) App callers unchanged (keyed-label input, no server packagedBase for app): moved to Console sidebar and recent list re-translate an overridden object, list view or app label with the base package's translation, over the server's answer #30311 with the object/list-view rungs. The seat keeps Fixes #30244: report and dashboard are measured fixed, page carries the rule, and what remains is Console sidebar and recent list re-translate an overridden object, list view or app label with the base package's translation, over the server's answer #30311's.
  4. Evidence: new pins 3 files / 49 tests; ablation (4 source files back to main) 8 red, exactly the renamed cells, every control green; after merging main, 101 files / 1503 tests green; app-shell + i18n type-check exit 0; eslint 0 errors; dispatch-gates 35/35 exit 0 with --ran reconciled. Live on the showcase (zh-CN): main shows 按状态统计工时(汇总)/ 交付运营, this branch shows the renamed labels. CI on this head running at review time; auto-merge waits on it.
  5. Out of scope: Console sidebar and recent list re-translate an overridden object, list view or app label with the base package's translation, over the server's answer #30311 filed (object / list-view rungs of useNavTargetLabel, the recent object row, and app after Declared overrides: a mapping override publishes but is never served, doc and mapping overrides cannot be restored, and an override's label can be hidden by translation #30062). Skills-docs: n/a.
  6. Landing: ordinary queue, now: relay pr_ready + automerge_enable, follow to MERGED, landing record on Console header and recent list re-translate an overridden report or page label with the base package's translation, over the server's answer #30244.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Console header and recent list re-translate an overridden report or page label with the base package's translation, over the server's answer

1 participant