Skip to content

spec: the dashboard authoring form has no channel for ITEM-level property names — header.actions[] columns render as raw keys in every locale, and columns documents a default it never declares #16458

Description

@hotlong

Upstream half of objectui#8218 (Studio 「界面」 property panel de-developerization). Filed from that card after measuring where the fix actually belongs; the rendering-side half stayed in objectui.

Not on any release path — objectui#8218 is explicitly decoupled from the cloud#1955 v1 launch, and so is this.

What the maker sees

Studio's interface property panel renders dashboardForm + the DashboardSchema JSONSchema through the console's generic SchemaForm. The 「页眉 → 操作按钮」 array renders as a table whose column headers are label / actionUrl / actionType / icon — raw machine keys, sitting inside an otherwise fully Chinese panel.

Three separable upstream gaps, measured

1. The item property schemas carry no title — so the keys leak in en-US too

DashboardHeaderAction's fields carry .describe(...) but no title, so z.toJSONSchema(DashboardSchema, { io: 'input' }) emits, verbatim:

"label":      { "description": "Action button label",              "type": "string" },
"actionUrl":  { "type": "string", "description": "URL or target for the action" },
"actionType": { "description": "Type of action", "type": "string", "enum": ["script","url","modal","flow","api","form"] },
"icon":       { "description": "Icon identifier for the action button", "type": "string" }

The console's table header is items.properties[k].title ?? k. With no title on any of the four, that fallback is the arm that ALWAYS runs — for every locale, English included. So this is not primarily a translation gap: it is a missing authoring label in the contract.

Same shape applies to every repeater item schema, not only this one; header.actions is just where it was caught.

2. There is no localization channel that can reach those headers at all

The only localization path for these forms is resolveMetadataFormLabels (packages/spec/src/system/i18n-resolver.ts), which decorates the FormView field specs — label / helpText / placeholder on FormFieldSpec nodes, synthesizing composite/repeater children from bundle entries.

The array table headers come from a DIFFERENT object: the JSONSchema, which no overlay touches. So the fix the objectui card originally guessed at — adding dashboard.fields['header.actions[].label'] to the generated catalogs — would land on a FormFieldSpec the console's master-detail widget never reads (its props do not even include fieldSpec). Necessary-but-not-sufficient at best, and today not even reachable.

Deciding this needs a spec-side call on which of these the item-level name is:

  • A. the JSONSchema's title, authored on the Zod item schema, with the resolver learning to overlay titles onto a derived JSONSchema; or
  • B. a FormFieldSpec.fields enumeration that the repeater widget is taught to prefer over the schema-derived columns.

A is the smaller change and fixes the English surface immediately; B keeps all authoring copy in one object but needs the console change too. Recommend A, with B available later if item columns ever need per-column widgets.

3. zh-CN.metadata-forms.generated.ts is stale for this very form

packages/platform-objects/src/apps/translations/zh-CN.metadata-forms.generated.ts, dashboard.fields:

4. Related: columns documents a default it does not declare

DashboardSchema.columns emits { description: "Number of grid columns (default 12)", type: "integer", minimum: 1, maximum: 24 } — no default key. The 12 exists only as prose plus a renderer-side fallback.

objectui#8218 made numeric fields gray schema.default in as a placeholder, so an empty box reads "using the default" rather than "unknown". For columns / gap / refreshInterval that placeholder is empty, because the contract declares no default to show. Declaring .default(12) on columns (and auditing sibling props whose describe text names a default) makes the documented value machine-readable rather than prose. A number invented on the renderer side would be a second source of truth, so it was deliberately not hard-coded there.

Acceptance

  • z.toJSONSchema(DashboardSchema).properties.header.properties.actions.items.properties.label.title is a human string, and the same holds for the other three;
  • a locale bundle can name an item-level property, by whichever of A / B is chosen, with the mechanism written down;
  • WITHDRAWN, see the correction above: this asked the catalogs to name refreshInterval rather than refreshIntervalSeconds, which is backwards — the first is a retired tombstone. What is genuinely owed is only the second half: all four generated catalogs (en, es-ES, ja-JP, zh-CN) carry the header.* children;
  • columns declares the default its own description advertises.

Back-link: objectui#8218.


Generated by Claude Code

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions