Repository navigation
fix(app-shell): judge the machine-name chip on the untranslated source label (#8231) - #10320
Conversation
…e label FieldRow compared prettify(name) with the visible, possibly translated, label, so a localized panel showed the chip beside every field and the English panel hid it beside the same fields. The locale overlay now keeps each field's pre-translation label under a module-private symbol, and FieldRow judges that source label, so the chip answers alike in every locale. mergeServerFields copies shallowly so the stamp survives, and the sectioned row schema's title takes the source label rather than the translation. The #8218 chip pin is rewritten with its reason. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D486C1axmXnrkJMNUfz2eb
…free leaf SchemaForm read the stamp through metadata-form-i18n, which pulled @objectstack/spec/system into SchemaForm's static import closure for one symbol. The symbol, its writer and its reader now live in field-source-label.ts, which imports nothing at runtime. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D486C1axmXnrkJMNUfz2eb
|
changeset-claim-re-read
|
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Contract reviewServed-tier: 75/75 Adopted from an isolated at-tier reviewer by ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Fixes #8231
Clause-②: no
What changed
The machine-name chip in
SchemaForm'sFieldRownow comparesprettify(name)with the field's untranslated source label, not with the visible label, as ruling 1 (comment 5749674288) requires. Before this change, the zh dashboard panel chipped every translated field while the en panel hid the chip beside the same fields. Now both locales show the same chip set.field-source-label.ts(new leaf with no runtime imports). It holds a module-private symbol with a writer (stampSourceLabel) and a reader (untranslatedFieldLabel). A field that an overlay translated returns the label it arrived with, which is undefined when the form authored none. A field that no overlay touched returns its ownlabel.metadata-form-i18n.ts. BeforeresolveMetadataFormLabelsruns,localizeMetadataFormstamps every field with its incoming label. It works on copies and never mutates its input. The resolver copies fields with object spread, which carries own symbol keys, so the stamp reachesSchemaForm. After resolving, fields the resolver synthesized, such as theheadercomposite's bundle-enumerated children, are stamped with an undefined source. An English locale, or a type the bundle does not carry, still returns the same object as before.SchemaForm.tsx,FieldRow. The source label isuntranslatedFieldLabel(fieldSpec), elseschema.title, elseprettify(name). That is the chainlabelfollows with every translation step removed, so it is the label the row would show in English. This also covers the raw-schema road (translateSchemaFieldLabel, e.g.sourceshown as 源节点), which had the same defect.SchemaForm.tsx, sectioned rows. The row schema'stitleoverride now takes the source label instead off.label. Without this,FieldRow'sschema.titlefallback would receive the translation that the stamp keeps out, so the fix would not hold. Every reader of the title prefersfieldSpec.label, which still holds the translation, so nothing visible changes:FieldRowreadsfieldSpec.labelfirst, and the color widget'saria-labelreadsfieldSpec?.labelbeforeschema.title.mergeServerFields.ts. The form is now copied shallowly instead of being round-tripped through JSON.JSON.stringifydrops symbol keys, so any dashboard with a server-only field lost the stamp. The function only ever appended a section to a fresh array, and its existing tests stay green.The pipe cost: measured small, so option 1 landed and fallback 3 was not taken
FormFieldSpecis untouched, and so is theSchemaFormprops type. The stamp is a symbol key: not authorable, not serialized, absent fromObject.keys.field-source-label.tsis not re-exported from the package index.mergeServerFields). I measured the import closure:SchemaForm.tsxstatically reaches one file more than at base (the new leaf; the absolute count is method-dependent: 19 to 20 by the implementer, 24 to 25 by the reviewer), and still zero@objectstack/spec/systemimporters. My first commit read the stamp through the overlay module, which pulledspec/systeminto that closure. The second commit moves the stamp into the leaf.Pin rewritten, with its reason (not deleted)
SchemaForm.deDeveloperize-8218.test.tsxsection 1 used a hand-written 「列数」 label and read the chip besidecolumns. Its comment called the always-on chip the mechanism. That shape was the defect. After this change the old fixture would have stayed green for the wrong reason: a hand-written 「列数」 never passes through the overlay, so it counts as its own source. The pin now builds its fixture through the reallocalizeMetadataForm. It asserts the chip is absent besidegap(no source label) and present besidecolumns(source label "Grid width"), in both locales. The tooltip assertions use the chip that is present. The comment explains why the earlier shape was the defect this card removes. Section 3 still uses the oldCOLUMNS_FORM, but it only reads the numeric control.A ruling premise that did not hold (the direction still holds)
The ruling's example, "shown for
refreshInterval/ Auto refresh everywhere", assumed the spec gives that field an English label. The spec does not. EverydashboardFormfield is authored without alabel(onlyhelpText), and the field is namedrefreshIntervalSeconds. So in both locales all four layout fields (columns/gap/refreshIntervalSeconds/header) now hide the chip, which is what the English panel always did. The "present" half of the predicate is shown with a fixture whose source label does not spell the name ("Grid width" forcolumns), through the real overlay.Red before, green after (zh and en)
The fix is committed. I reverted
SchemaForm.tsx,metadata-form-i18n.tsandmergeServerFields.tsto base8b1f06619, kept the new tests, and restored withgit checkout HEAD --under an EXIT trap. The restore was proven bygit diff HEADbeing empty and by each path's blob hash matchingHEAD:sourcein zh only, and the rewritten 8218 zh case is red. The en cases are green before and after. That is the inversion: en never showed these chips.mergeServerFields.test.ts: 3 files, 31 passed.Local verification (at
d35e00806)pnpm exec vitest run --maxWorkers=2 packages/app-shell/src/views/metadata-admin/: 287 files passed, 3081 tests passed, 1 skipped.pnpm --filter @object-ui/app-shell type-check(tsc --noEmitandtsc -p tsconfig.test.json, whose include coverssrc/**/*.test.tsx): exit 0. The dependency closure was built first withturbo run build --filter=@object-ui/app-shell^..., 28 of 28 tasks.SchemaForm.tsx/mergeServerFields.ts.check-changeset-presence,changeset:check,check:changeset-claims,check:pending-changeset-literals,check:new-line-citations(0 new),check:control-bytes,check:test-path-roots,check:unreferenced-sources,check:spec-symbols,check:vi-mock-specifiers, andgoverned --test(NOT GOVERNED).check:eager-closure. Reason: it needsapps/console/dist/eager-closure.jsonfrom a console build, which was not run locally. The static-closure measurement above is the local substitute. The fullpnpm test/pnpm lint/pnpm type-checkruns are left to CI.Acceptance notes
SchemaForm.tsx,metadata-form-i18n.ts, the 8218 pin, new tests and a changeset. This PR also touchesfield-source-label.ts(new leaf, see above) andmergeServerFields.ts, which is the producer-side copy that dropped the stamp. Both are needed for the predicate to hold on the real dashboard path.recordwidget rebuilds its key row's spec as a fresh object fromkeyField.label. A translated key label there would lose the stamp. No overlay covers arecordkey today.Spec Main Shape Gatered, if it appears, is upstream objectui#10287.Session:
https://claude.ai/code/session_01D486C1axmXnrkJMNUfz2ebGenerated by Claude Code