Skip to content

fix(app-shell): resolve inline locale-map view and page labels; a map view label no longer blanks the Console - #25997

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-otrnlz
Oct 26, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-otrnlz

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Steve · project thread
Fixes #25901

Clause-②: no
Metadata-protocol: none

What was wrong

@objectstack/spec types a list view's label, and a page's label / description, as I18nLabel: a string or an inline locale map. Two Console readers did not handle the map.

  1. View labels (p1, measured). viewTabLabel returned view.label untouched. On the served branch it was drawn as given. On the other branch it was handed to the bundle's viewLabel as the fallback, and the bundle returns the fallback unchanged on a miss. The server does not stop a map from reaching it: translateObjectListViews / translateView only overlay catalog text, so a map with no _views.KEY.label entry is served as authored. On a /view/NAME route the app header rendered that object as a React child and threw Objects are not valid as a React child (found: object with keys {en, zh-CN}). AppHeader is mounted by ConsoleLayout, outside the only route ErrorBoundary in AppContent, so the throw unmounted the whole Console. That held for a served view and for a client-derived one alike. Measurement posted on the card before any code: console: a page or list view whose label is an inline locale map shows a machine name (InterfaceListPage) or reaches viewTabLabel raw (AppHeader view branch, ObjectView tab bar) #25901 (comment) The same value also fed the object page's tab bar, the mobile view switcher and the record page's way back.
  2. Interface list page (p2). The heading and the record drawer's title read typeof page.label === 'string' ? page.label : page.name, so a map label showed the machine name. A map description was dropped.

The fix (producer side)

  • viewTabLabel (ui/packages/app-shell/src/views/viewTabLabel.ts) takes the viewer's language and resolves the label with metadataText before either branch. This is the app-shell helper fix(app-shell,components): resolve a page's inline locale label and description to the viewer's language (objectui#13488) objectui#13501 used. The served/derived split is unchanged: a served view's resolved text is drawn as given, and any other view's resolved text becomes viewLabel's fallback, so a catalog entry still wins there. A map that resolves to no text counts as no label and is drawn as the object's plural label, like a label-less view.
  • Its five call sites pass language from useObjectTranslation(), the same channel the header's other metadataText titles use, so the header and the tab agree. Four are in ObjectView.tsx, in the view-tab regions only (mobile switcher, record way back twice, tab bar), plus the hook destructure. The fifth is the AppHeader.tsx view-route title.
  • InterfaceListPage resolves page.label and page.description with metadataText. The machine name is the heading, and cfg.source || 'Record' the drawer title, only when no label resolves.
  • plugin-view's ViewTabBar is not changed. Its ViewTabItem.label is typed string, and the producer now honours that type.

Tests

  • AppHeader.inlineViewLabel-25901.test.tsx: a served map view and a derived map view, each in en and zh-CN, plus an empty map, with an empty bundle so no catalog entry can stand in for the map.
  • viewTabLabel.inlineLabel-25901.test.ts: the served branch never asks the bundle; the derived branch hands the bundle the resolved text; a catalog entry still wins; an empty or blank map gives the unlabelled text; string controls.
  • InterfaceListPage.inlineLabel-25901.test.tsx: the real MetadataProvider under a real I18nProvider. Map heading and description in en and zh-CN, an empty map falls back to the machine name, and a string control.
  • Ablation (fix committed first; viewTabLabel.ts and InterfaceListPage.tsx restored to base 0c372288, with a trap restoring from HEAD): 12 failed | 4 passed (16). The 4 that stayed green are the controls (catalog wins, string control, empty-map machine-name fallback, string page). Restore was proven by an empty git diff HEAD.
  • Local: the three new files 16 passed (16). At head 615a9c05, the 119 app-shell test files whose names match ObjectView / AppHeader / InterfaceListPage / viewTabLabel / ServedView / servedLabels: Test Files 119 passed (119), Tests 995 passed (995). Declared narrowing: the whole app-shell suite (1725 files) did not finish in 40 minutes under the shared verify lock and was stopped, so it is left to CI (Test Core).
  • pnpm --filter @object-ui/app-shell type-check (both tsc projects) exit 0.

Gates

node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 34 families at 615a9c05. All 34 ran locally with exit 0. --ran reconciliation: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN (a derived zero, with every exit code recorded). Everything else is CI's.

Acceptance notes

  • ObjectView's delete-view confirmation interpolates targetView?.label || vid into its prompt. A map label there would read [object Object]. It is reachable only for saved (sys_view-backed) views, whose labels come from the Console's own add and rename inputs as strings. This is outside the view-tab regions and was left alone. Carrier: none.
  • AppHeader sits outside every error boundary, so any render throw in the header blanks the whole Console, not just the route. This PR removes the trigger that was measured. The boundary placement itself is unchanged. Noted, not filed. Carrier: none.
  • Scope of the measurement: the header crash was rendered (harness above). The tab-bar, mobile-switcher and record way-back surfaces were read from the code, not rendered, and share the fixed producer.

Generated by Claude Code

… drawing them

viewTabLabel resolves the view's I18nLabel in the viewer's language before
either branch, so a map label never reaches the header, tab bar, mobile
switcher or record back-link as an object. InterfaceListPage resolves its
page label and description the same way.

Claude-Session: https://claude.ai/code/session_01WVwANq56oyBZtcDWbWGfva
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Oct 26, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · ACCEPT · seat domain:ui#1 · 2026-10-26T08:41Z

Head 615a9c05cfeb (read from the PR object).

  • Shape. Draft on main; Fixes #25901; Clause-②: no, Metadata-protocol: none; changeset .changeset/25901-inline-view-label.md in the root .changeset/ (patch, app-shell).
  • Checks pinned to the head. 54 named check runs, latest per name: 46 success, 8 skipped, 0 failing, 0 pending. Lint & Repo Gates, TypeScript Type Check, Test UI 16/16, Type Check UI all success. The full app-shell suite that did not finish locally is covered by CI's Test UI shards.
  • Governed surface. check-governed-merges.mjs --pr 25997: 0 of 8 paths governed.
  • Fix at the producer. viewTabLabel resolves an I18nLabel map through metadataText in the viewer's language before the served/derived split, so every reader (the app header outside the route error boundary, the tab bar, the mobile switcher, the record page's way back) gets a string. A map that resolves to nothing counts as no label. InterfaceListPage resolves label / description the same way. Each changeset sentence matches the code.
  • Serial constraint held. In ObjectView.tsx, only the four view-tab viewTabLabel call sites and their dependency arrays change, not the Loading-chart fallbacks fix(i18n): localise the console's round-3 leftovers — data table titles, chart fallback, react pages, References columns, Flow Runs diagnostics #25978 holds.
  • Grade. The card measured a whole-Console white screen (comment 6410211342). The seat asked triage to apply its conditional p1 (pm:retriage). Regrading stays with triage; it does not hold this PR.

Landing: ready + auto-merge through the relay.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 26, 2026 08:43
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 26, 2026 08:43
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 26, 2026
Merged via the queue into main with commit 416e96f Oct 26, 2026
55 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-otrnlz branch October 26, 2026 09:06
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 tests tooling

Projects

None yet

2 participants