From c2f4dcdc299cdc08c3cfb46a2192a9054580e74f Mon Sep 17 00:00:00 2001 From: os-zhuang Date: Fri, 3 Jul 2026 19:04:49 +0800 Subject: [PATCH] chore: drop compactLayout fallback reads (alias retired by framework#2536) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit framework#2539 removed the deprecated spelling from the spec (create() rejects, parse strips, no mirror) — served metadata carries highlightFields only, so these 6 fallback reads can never fire again. deriveHighlightFields tests flipped: the retired spelling is now IGNORED (heuristic applies) instead of read. Co-Authored-By: Claude Fable 5 --- .changeset/drop-compactlayout-fallback.md | 7 +++++++ .../app-shell/src/views/InterfaceListPage.tsx | 8 +++----- packages/app-shell/src/views/ObjectView.tsx | 11 +++-------- .../app-shell/src/views/RecordDetailView.tsx | 13 ++++--------- .../__tests__/buildDefaultPageSchema.test.ts | 18 +++++------------- .../src/synth/buildDefaultPageSchema.ts | 13 ++++--------- packages/plugin-grid/src/ObjectGrid.tsx | 10 ++++------ 7 files changed, 30 insertions(+), 50 deletions(-) create mode 100644 .changeset/drop-compactlayout-fallback.md diff --git a/.changeset/drop-compactlayout-fallback.md b/.changeset/drop-compactlayout-fallback.md new file mode 100644 index 000000000..0225461cb --- /dev/null +++ b/.changeset/drop-compactlayout-fallback.md @@ -0,0 +1,7 @@ +--- +'@object-ui/plugin-grid': patch +'@object-ui/plugin-detail': patch +'@object-ui/app-shell': patch +--- + +Drop the `compactLayout` fallback reads (6 sites: ObjectGrid default columns, deriveHighlightFields, RecordDetailView highlight strip + child preview, ObjectView ×2, InterfaceListPage). The deprecated spelling was retired from the spec by framework#2539 (framework#2536) — served metadata carries `highlightFields` only, so the fallbacks could never fire again; keeping them would teach the retired key to the next reader. diff --git a/packages/app-shell/src/views/InterfaceListPage.tsx b/packages/app-shell/src/views/InterfaceListPage.tsx index 4e5b70ef9..743c391be 100644 --- a/packages/app-shell/src/views/InterfaceListPage.tsx +++ b/packages/app-shell/src/views/InterfaceListPage.tsx @@ -70,8 +70,8 @@ function resolveSourceView(objectDef: any, sourceView?: string): any | undefined * Default column set when the resolved view carries none — mirrors * ObjectView's data-mode fallback so an interface page never renders a * column-less grid. Priority: the `highlightFields` semantic role - * (ADR-0085; deprecated `compactLayout` read as fallback), else the first - * business fields (system/audit columns excluded). + * (ADR-0085), else the first business fields (system/audit columns + * excluded). */ const SYSTEM_FIELDS = new Set([ 'id', 'created_at', 'createdAt', 'updated_at', 'updatedAt', @@ -79,9 +79,7 @@ const SYSTEM_FIELDS = new Set([ 'updated_by', 'updatedBy', '_version', '_rev', ]); function defaultColumnsFromObject(objectDef: any): string[] { - const curated = Array.isArray(objectDef?.highlightFields) && objectDef.highlightFields.length > 0 - ? objectDef.highlightFields - : objectDef?.compactLayout; + const curated = objectDef?.highlightFields; if (Array.isArray(curated) && curated.length > 0) { return curated.filter((n: string) => objectDef.fields?.[n]); } diff --git a/packages/app-shell/src/views/ObjectView.tsx b/packages/app-shell/src/views/ObjectView.tsx index e47eecf97..08507a610 100644 --- a/packages/app-shell/src/views/ObjectView.tsx +++ b/packages/app-shell/src/views/ObjectView.tsx @@ -236,9 +236,7 @@ function ObjectViewInner({ dataSource, objects, onEdit, externalRefreshKey }: an 'updated_by', 'updatedBy', '_version', '_rev', ]); let defaultColumns: string[] = []; - const curated = Array.isArray(objectDef?.highlightFields) && objectDef.highlightFields.length > 0 - ? objectDef.highlightFields - : objectDef?.compactLayout; + const curated = objectDef?.highlightFields; if (Array.isArray(curated) && curated.length > 0) { defaultColumns = curated.filter((n: string) => objectDef.fields?.[n]); } else if (objectDef?.fields) { @@ -489,8 +487,7 @@ function ObjectViewInner({ dataSource, objects, onEdit, externalRefreshKey }: an // Resolve Views from objectDef.listViews (camelCase per @objectstack/spec) const views = useMemo(() => { // Default column resolution priority: - // 1. The `highlightFields` semantic role (ADR-0085; deprecated - // `compactLayout` read as fallback). + // 1. The `highlightFields` semantic role (ADR-0085). // 2. Business fields only — exclude system-managed identifiers/audit // columns (id, created_at, updated_at, …) and fields explicitly // marked hidden/readonly on the schema. First 5 kept for compactness. @@ -500,9 +497,7 @@ function ObjectViewInner({ dataSource, objects, onEdit, externalRefreshKey }: an 'updated_by', 'updatedBy', '_version', '_rev', ]); const resolveDefaultColumns = (): string[] => { - const curated = Array.isArray(objectDef.highlightFields) && objectDef.highlightFields.length > 0 - ? objectDef.highlightFields - : objectDef.compactLayout; + const curated = objectDef.highlightFields; if (Array.isArray(curated) && curated.length > 0) { return curated.filter((n: string) => objectDef.fields?.[n]); } diff --git a/packages/app-shell/src/views/RecordDetailView.tsx b/packages/app-shell/src/views/RecordDetailView.tsx index f0e7c5f41..cf601d7e3 100644 --- a/packages/app-shell/src/views/RecordDetailView.tsx +++ b/packages/app-shell/src/views/RecordDetailView.tsx @@ -1379,12 +1379,9 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri return base; })(); - // Build highlightFields from the object's semantic role (ADR-0085): - // top-level `highlightFields`, with the deprecated `compactLayout` - // spelling as fallback for pre-11.7 metadata that reaches consumers - // un-normalized. Bare field names resolve label/type from the field def. - const rawHighlightFields = - (objectDef as any).highlightFields ?? (objectDef as any).compactLayout ?? []; + // Build highlightFields from the object's semantic role (ADR-0085). + // Bare field names resolve label/type from the field def. + const rawHighlightFields = (objectDef as any).highlightFields ?? []; const highlightFields: HighlightField[] = (Array.isArray(rawHighlightFields) ? rawHighlightFields : []) .map((f: any): HighlightField | null => { const name = typeof f === 'string' ? f : f?.name; @@ -1494,9 +1491,7 @@ export function RecordDetailView({ dataSource, objects, onEdit, objectNameOverri childObjectDef?.displayNameField || (Array.isArray(childObjectDef?.highlightFields) ? childObjectDef.highlightFields[0] - : Array.isArray(childObjectDef?.compactLayout) - ? childObjectDef.compactLayout[0] - : undefined), + : undefined), onNew, onViewAll, onRowClick, diff --git a/packages/plugin-detail/src/synth/__tests__/buildDefaultPageSchema.test.ts b/packages/plugin-detail/src/synth/__tests__/buildDefaultPageSchema.test.ts index fa8988ff2..894389b90 100644 --- a/packages/plugin-detail/src/synth/__tests__/buildDefaultPageSchema.test.ts +++ b/packages/plugin-detail/src/synth/__tests__/buildDefaultPageSchema.test.ts @@ -698,23 +698,15 @@ describe('semantic-role hints (ADR-0085 / #2065)', () => { }); describe('deriveHighlightFields', () => { - it('highlightFields wins over the deprecated compactLayout spelling', () => { + it('reads the highlightFields semantic role', () => { expect( - deriveHighlightFields( - { - ...leadDef, - highlightFields: ['phone', 'rating'], - compactLayout: ['email'], - }, - 'status', - ), + deriveHighlightFields({ ...leadDef, highlightFields: ['phone', 'rating'] }, 'status'), ).toEqual(['phone', 'rating']); }); - it('reads the deprecated compactLayout when highlightFields is absent', () => { - expect( - deriveHighlightFields({ ...leadDef, compactLayout: ['email', 'phone'] }, 'status'), - ).toEqual(['email', 'phone']); + it('ignores the retired compactLayout spelling (framework#2536) — heuristic applies instead', () => { + const derived = deriveHighlightFields({ ...leadDef, compactLayout: ['email', 'phone'] }, 'status'); + expect(derived).not.toEqual(['email', 'phone']); }); it('drops non-string entries and caps the declared list at max', () => { diff --git a/packages/plugin-detail/src/synth/buildDefaultPageSchema.ts b/packages/plugin-detail/src/synth/buildDefaultPageSchema.ts index 4525aeb1a..ca11f78fd 100644 --- a/packages/plugin-detail/src/synth/buildDefaultPageSchema.ts +++ b/packages/plugin-detail/src/synth/buildDefaultPageSchema.ts @@ -40,9 +40,6 @@ export interface ObjectDefLike { /** Semantic role (ADR-0085): the object's most important fields — * drives the highlight strip (first 4). */ highlightFields?: string[]; - /** @deprecated Renamed to `highlightFields` (ADR-0085). Read as a - * fallback for pre-11.7 metadata that reaches consumers un-normalized. */ - compactLayout?: string[]; /** Name of the field that holds the record's display title (e.g. `name`, * `subject`). When present we exclude it from the auto-derived highlight * list to avoid duplicating the page H1. */ @@ -266,14 +263,12 @@ export function deriveHighlightFields( max = 4, ): string[] { if (!def) return []; - // Semantic role first (ADR-0085): top-level `highlightFields`, with the - // deprecated `compactLayout` spelling as a fallback for pre-11.7 metadata - // that reaches consumers un-normalized (the spec mirrors the two on parse). + // Semantic role first (ADR-0085): top-level `highlightFields`. (The + // deprecated `compactLayout` fallback was retired with the alias — + // framework#2536.) const declared = Array.isArray(def.highlightFields) && def.highlightFields.length > 0 ? def.highlightFields - : Array.isArray(def.compactLayout) && def.compactLayout.length > 0 - ? def.compactLayout - : null; + : null; if (declared) { return declared .filter((n): n is string => typeof n === 'string' && n.length > 0) diff --git a/packages/plugin-grid/src/ObjectGrid.tsx b/packages/plugin-grid/src/ObjectGrid.tsx index 209c74f25..daf9effac 100644 --- a/packages/plugin-grid/src/ObjectGrid.tsx +++ b/packages/plugin-grid/src/ObjectGrid.tsx @@ -1201,8 +1201,7 @@ export const ObjectGrid: React.FC = ({ const generatedColumns: any[] = []; // Default columns priority (when schema doesn't specify columns): - // 1. The object's `highlightFields` semantic role (ADR-0085; deprecated - // `compactLayout` spelling read as fallback for pre-11.7 metadata). + // 1. The object's `highlightFields` semantic role (ADR-0085). // 2. Otherwise, all schema fields with system-managed fields pushed to the end. // // Also drop fields that are platform-managed identifiers/audit columns or @@ -1214,14 +1213,13 @@ export const ObjectGrid: React.FC = ({ 'deleted_at', 'deletedAt', 'created_by', 'createdBy', 'updated_by', 'updatedBy', '_version', '_rev', ]); - const compactLayout: string[] | undefined = - (objectSchema as any)?.highlightFields ?? (objectSchema as any)?.compactLayout; + const highlightFields: string[] | undefined = (objectSchema as any)?.highlightFields; const allFieldNames = Object.keys(objectSchema.fields || {}); let fieldsToShow: string[]; if (schemaFields) { fieldsToShow = schemaFields; - } else if (compactLayout?.length) { - fieldsToShow = compactLayout.filter((n) => objectSchema.fields?.[n]); + } else if (highlightFields?.length) { + fieldsToShow = highlightFields.filter((n) => objectSchema.fields?.[n]); } else { // Drop hidden + readonly system-managed fields, then push remaining // system identifier/audit fields to the end as a fallback.