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:

  • it names refreshIntervalSeconds, but the spec's field is refreshInterval — that entry can never match;
  • it carries no header.showTitle / header.showDescription / header.actions entries at all, so the composite's children are unlocalized in the platform's own catalog. objectui currently ships a private overlay of its own for exactly those three, which is why the panel reads 显示标题 / 显示描述 / 操作按钮 today despite the catalog being silent.

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;
  • zh-CN (and the sibling generated catalogs) name refreshInterval, not refreshIntervalSeconds, and carry the header.* children;
  • columns declares the default its own description advertises.

Back-link: objectui#8218.

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

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions