Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/drop-compactlayout-fallback.md
Original file line number Diff line number Diff line change
@@ -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.
8 changes: 3 additions & 5 deletions packages/app-shell/src/views/InterfaceListPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,18 +70,16 @@ 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',
'deleted_at', 'deletedAt', 'created_by', 'createdBy',
'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]);
}
Expand Down
11 changes: 3 additions & 8 deletions packages/app-shell/src/views/ObjectView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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.
Expand All @@ -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]);
}
Expand Down
13 changes: 4 additions & 9 deletions packages/app-shell/src/views/RecordDetailView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down
13 changes: 4 additions & 9 deletions packages/plugin-detail/src/synth/buildDefaultPageSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down Expand Up @@ -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)
Expand Down
10 changes: 4 additions & 6 deletions packages/plugin-grid/src/ObjectGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1201,8 +1201,7 @@ export const ObjectGrid: React.FC<ObjectGridProps> = ({

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
Expand All @@ -1214,14 +1213,13 @@ export const ObjectGrid: React.FC<ObjectGridProps> = ({
'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.
Expand Down
Loading