From ff3e11701aa7d0f2803b7bede84b7861ad73ca75 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 25 Oct 2026 00:37:03 +0000 Subject: [PATCH 1/2] fix(app-shell): the translation preview draws the positions and permissions groups, at an objectstack pin that declares them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit objectstack 47af3dde42 added `positions` and `permissions` to the per-app TranslationDataSchema. TranslationPreview's CATEGORY_DEFS is exhaustive by `satisfies Record` over that schema's shape, so at that spec app-shell no longer type-checked (TS1360, missing positions, permissions), which is what turned objectstack's Console Pin Gate red. - CATEGORY_DEFS gains the two rows in the schema's order (after flows, before metadataForms): Users for positions, ShieldCheck for permissions, the icons PositionPreview and PermissionPreview already use. - The designer table gains engine.translationPreview.category.positions and .permissions in en ("Positions", "Permission Sets") and zh ("岗位", "权限集", the table's existing words for the two metadata types). - .objectstack-sha moves e649c2d91e -> 47af3dde42 (on objectstack main, 51 commits ahead, 0 behind). The bump repacked three manifests in .objectstack-pin (core, lint, spec), whose only change is zod ^4.6.5 -> ^4.6.6; pnpm-lock.yaml is unchanged and a frozen install passes. - The two rows and the pin move land together: at the old pin the rows are excess properties under the same `satisfies`, and at the new pin the old table is missing two. - Tests: the objectui#11765 fixture table gets a spec-valid entry for each new group, and the objectui#10862 locale sites list the two headings and read coverage over 13 groups. Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_01Usjyy1hT9FNxZHea9u7drp --- .../13478-translation-preview-positions-permissions.md | 8 ++++++++ .objectstack-pin/core/package.json | 2 +- .objectstack-pin/lint/package.json | 2 +- .objectstack-pin/spec/package.json | 2 +- .objectstack-sha | 2 +- packages/app-shell/src/views/metadata-admin/i18n.ts | 4 ++++ .../previews/TranslationPreview.categories-11765.test.tsx | 6 ++++++ .../views/metadata-admin/previews/TranslationPreview.tsx | 4 ++++ .../previews/adminPreviews.i18n-10862-s2.test.tsx | 4 +++- 9 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 .changeset/13478-translation-preview-positions-permissions.md diff --git a/.changeset/13478-translation-preview-positions-permissions.md b/.changeset/13478-translation-preview-positions-permissions.md new file mode 100644 index 0000000000..24dbee1e95 --- /dev/null +++ b/.changeset/13478-translation-preview-positions-permissions.md @@ -0,0 +1,8 @@ +--- +"@object-ui/app-shell": patch +--- + +Clause-②: yes +Metadata-protocol: none + +The metadata designer's translation preview draws the `positions` and `permissions` groups that `@objectstack/spec` now declares on a translation bundle, each with its own card, count and sample, and counts them in the coverage bar. Before, the preview did not type-check against that spec, and a bundle that translated only position or permission-set labels read as empty. diff --git a/.objectstack-pin/core/package.json b/.objectstack-pin/core/package.json index 40d33a91e5..3b1ddbd649 100644 --- a/.objectstack-pin/core/package.json +++ b/.objectstack-pin/core/package.json @@ -29,7 +29,7 @@ "dependencies": { "@objectstack/spec": "18.1.0", "@objectstack/types": "18.1.0", - "zod": "^4.6.5" + "zod": "^4.6.6" }, "keywords": [ "objectstack", diff --git a/.objectstack-pin/lint/package.json b/.objectstack-pin/lint/package.json index 618731e343..d72a5b26f0 100644 --- a/.objectstack-pin/lint/package.json +++ b/.objectstack-pin/lint/package.json @@ -50,7 +50,7 @@ "devDependencies": { "@types/node": "^26.6.3", "vitest": "^4.1.11", - "zod": "^4.6.5" + "zod": "^4.6.6" }, "keywords": [ "objectstack", diff --git a/.objectstack-pin/spec/package.json b/.objectstack-pin/spec/package.json index ba0c88a668..4d08a92f7d 100644 --- a/.objectstack-pin/spec/package.json +++ b/.objectstack-pin/spec/package.json @@ -282,7 +282,7 @@ }, "dependencies": { "pg-connection-string": "^2.14.0", - "zod": "^4.6.5" + "zod": "^4.6.6" }, "peerDependencies": { "ai": "^7.0.0" diff --git a/.objectstack-sha b/.objectstack-sha index 406c7555ce..3b0fbc38a4 100644 --- a/.objectstack-sha +++ b/.objectstack-sha @@ -1 +1 @@ -e649c2d91e270e3da26820bcfe54a28445305a75 +47af3dde42bb4e77fd92025605b89b4a473295a4 diff --git a/packages/app-shell/src/views/metadata-admin/i18n.ts b/packages/app-shell/src/views/metadata-admin/i18n.ts index 1a166d2c26..3eb4498491 100644 --- a/packages/app-shell/src/views/metadata-admin/i18n.ts +++ b/packages/app-shell/src/views/metadata-admin/i18n.ts @@ -1785,6 +1785,8 @@ const ENGINE_STRINGS_EN: Record = { 'engine.translationPreview.category.datasets': 'Datasets', 'engine.translationPreview.category.pages': 'Pages', 'engine.translationPreview.category.flows': 'Flows', + 'engine.translationPreview.category.positions': 'Positions', + 'engine.translationPreview.category.permissions': 'Permission Sets', 'engine.translationPreview.category.metadataForms': 'Metadata Forms', 'engine.translationPreview.category.settingsCommon': 'Settings UI', 'engine.translationPreview.coverage': 'Category coverage:', @@ -5407,6 +5409,8 @@ const ENGINE_STRINGS_ZH: Record = { 'engine.translationPreview.category.datasets': '数据集', 'engine.translationPreview.category.pages': '页面', 'engine.translationPreview.category.flows': '流程', + 'engine.translationPreview.category.positions': '岗位', + 'engine.translationPreview.category.permissions': '权限集', 'engine.translationPreview.category.metadataForms': '元数据表单', 'engine.translationPreview.category.settingsCommon': '设置界面', 'engine.translationPreview.coverage': '分类覆盖率:', diff --git a/packages/app-shell/src/views/metadata-admin/previews/TranslationPreview.categories-11765.test.tsx b/packages/app-shell/src/views/metadata-admin/previews/TranslationPreview.categories-11765.test.tsx index c038d5454f..f595f7c9fd 100644 --- a/packages/app-shell/src/views/metadata-admin/previews/TranslationPreview.categories-11765.test.tsx +++ b/packages/app-shell/src/views/metadata-admin/previews/TranslationPreview.categories-11765.test.tsx @@ -58,6 +58,12 @@ const ONE_ENTRY: Record; key: string; ro }, pages: { data: { home: { label: 'Accueil' } }, key: 'home', row: () => keys(1) }, flows: { data: { onboarding: { label: 'Intégration' } }, key: 'onboarding', row: () => keys(1) }, + positions: { data: { legal_counsel: { label: 'Conseiller juridique' } }, key: 'legal_counsel', row: () => keys(1) }, + permissions: { + data: { contract_reviewer: { label: 'Revue des contrats', description: 'Lire et approuver les contrats' } }, + key: 'contract_reviewer', + row: () => keys(2), + }, metadataForms: { data: { object: { label: 'Objet' } }, key: 'object', row: () => keys(1) }, // `settingsCommon` is one strict object, not a record of author-named nodes: // its members (`sourceLabels`) are what the card counts and samples. diff --git a/packages/app-shell/src/views/metadata-admin/previews/TranslationPreview.tsx b/packages/app-shell/src/views/metadata-admin/previews/TranslationPreview.tsx index 06de276d84..f46d43302a 100644 --- a/packages/app-shell/src/views/metadata-admin/previews/TranslationPreview.tsx +++ b/packages/app-shell/src/views/metadata-admin/previews/TranslationPreview.tsx @@ -43,7 +43,9 @@ import { MessageCircle, PanelsTopLeft, Settings2, + ShieldCheck, SquareChevronDown, + Users, Workflow, } from 'lucide-react'; import { EmptyDescription } from '@object-ui/components'; @@ -94,6 +96,8 @@ const CATEGORY_DEFS = { datasets: { label: 'engine.translationPreview.category.datasets', icon: Database, flat: false }, pages: { label: 'engine.translationPreview.category.pages', icon: PanelsTopLeft, flat: false }, flows: { label: 'engine.translationPreview.category.flows', icon: Workflow, flat: false }, + positions: { label: 'engine.translationPreview.category.positions', icon: Users, flat: false }, + permissions: { label: 'engine.translationPreview.category.permissions', icon: ShieldCheck, flat: false }, metadataForms: { label: 'engine.translationPreview.category.metadataForms', icon: FileText, flat: false }, settingsCommon: { label: 'engine.translationPreview.category.settingsCommon', icon: Settings2, flat: false }, } satisfies Record>; diff --git a/packages/app-shell/src/views/metadata-admin/previews/adminPreviews.i18n-10862-s2.test.tsx b/packages/app-shell/src/views/metadata-admin/previews/adminPreviews.i18n-10862-s2.test.tsx index 63520a7da9..0b8aeda0ed 100644 --- a/packages/app-shell/src/views/metadata-admin/previews/adminPreviews.i18n-10862-s2.test.tsx +++ b/packages/app-shell/src/views/metadata-admin/previews/adminPreviews.i18n-10862-s2.test.tsx @@ -461,6 +461,8 @@ describe('TranslationPreview reads the designer locale (objectui#10862)', () => { key: 'engine.translationPreview.category.datasets' }, { key: 'engine.translationPreview.category.pages' }, { key: 'engine.translationPreview.category.flows' }, + { key: 'engine.translationPreview.category.positions' }, + { key: 'engine.translationPreview.category.permissions' }, { key: 'engine.translationPreview.category.metadataForms' }, { key: 'engine.translationPreview.category.settingsCommon' }, { key: 'engine.translationPreview.categoryEmpty' }, @@ -468,7 +470,7 @@ describe('TranslationPreview reads the designer locale (objectui#10862)', () => { key: 'engine.translationPreview.keyCountOne', vars: { count: 1 } }, ]); // The bundle's own locale is author data, not the designer's language. - expectAsWritten(['French', 'fr-FR', 'account', '"Un"', '2/11 (18%)']); + expectAsWritten(['French', 'fr-FR', 'account', '"Un"', '2/13 (15%)']); }); } }); From 762922fe230d2b770d2cdccc7b09c89cc73e0d72 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 25 Oct 2026 01:11:24 +0000 Subject: [PATCH 2/2] fix(i18n): recognise a served translation document by its positions and permissions groups The pin move to objectstack 47af3dde42 adds `positions` and `permissions` to the served document's shape (GetTranslationsResponseSchema). The console's loadLanguage pin walks that shape and requires a payload carrying any one group, alone, to take the transform branch; SPEC_TRANSLATION_GROUPS lacked the two, so Test shard 16/16 went red with "positions: expected [ 'positions' ] to deeply equal [ 'app' ]". Both groups join the list, and the transform copies them through onto `app` like the others. The changeset gains an @object-ui/i18n patch. Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_01Usjyy1hT9FNxZHea9u7drp --- .../13478-translation-preview-positions-permissions.md | 3 +++ packages/i18n/src/utils/spec-translations.ts | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/.changeset/13478-translation-preview-positions-permissions.md b/.changeset/13478-translation-preview-positions-permissions.md index 24dbee1e95..68b15a2e83 100644 --- a/.changeset/13478-translation-preview-positions-permissions.md +++ b/.changeset/13478-translation-preview-positions-permissions.md @@ -1,8 +1,11 @@ --- "@object-ui/app-shell": patch +"@object-ui/i18n": patch --- Clause-②: yes Metadata-protocol: none The metadata designer's translation preview draws the `positions` and `permissions` groups that `@objectstack/spec` now declares on a translation bundle, each with its own card, count and sample, and counts them in the coverage bar. Before, the preview did not type-check against that spec, and a bundle that translated only position or permission-set labels read as empty. + +`isSpecTranslationData` recognises a served translation document by those two groups as well, so a bundle that translates only positions or permission sets is namespaced under `app` like any other spec bundle instead of being returned untransformed. diff --git a/packages/i18n/src/utils/spec-translations.ts b/packages/i18n/src/utils/spec-translations.ts index 960eff7287..98b3e5b291 100644 --- a/packages/i18n/src/utils/spec-translations.ts +++ b/packages/i18n/src/utils/spec-translations.ts @@ -89,6 +89,11 @@ const SPEC_TRANSLATION_GROUPS = [ // `picklist` metadata kind); added at that bump (objectui#11438). The // transform below copies it through onto `app` like any other group. 'picklists', + // objectstack `47af3dde42` serves `positions` and `permissions` (positions + // and permission sets are translatable); added at the pin move to that + // commit (objectui#13478), copied through onto `app` the same way. + 'positions', + 'permissions', ] as const; function isPlainObject(value: unknown): value is Record {