diff --git a/.changeset/23610-record-page-seed-default.md b/.changeset/23610-record-page-seed-default.md new file mode 100644 index 0000000000..5c3efd4878 --- /dev/null +++ b/.changeset/23610-record-page-seed-default.md @@ -0,0 +1,14 @@ +--- +'@object-ui/plugin-detail': patch +'@object-ui/types': patch +--- + +A new record page seeded in Studio is saved with the `default` layout template instead of `full-width`, and the page node's `template` member is typed by reference to the spec's (part of objectstack#23610). + +`@objectstack/spec` closes `PageSchema.template` to four layout names — `default`, `header-sidebar-main`, `three-column`, `dashboard` — and retires `full-width` by name, naming `default` as its replacement; the save path refuses a page that still carries it. + +- **`buildDefaultPageSchema` seeds `template: 'default'`.** Studio's "new record page" seed takes its template from this synthesis, so with the old value the first save of a new record page was refused. The renderer maps `default` and `full-width` to the same `FullWidthTemplate`, so a seeded page lays out exactly as before. +- **`PageNodeSchema.template` is `SpecPage['template']`.** The member was re-declared as `string` over the spec's inherited one; once the spec closes the set, that widening is a TypeScript error (TS2430) on the interface. Against today's spec, whose member is still `string`, the type is unchanged. +- **The zod mirror's `template` is the spec's member too.** `PageNodeSchema` in the zod face declared `template: z.string()`, which accepts every name; once the spec closes the set it measures wider than the TS face, so `full-width` would still pass `objectui validate`. It now takes the spec's own member (defaults stripped, as for every imported member), and against today's spec it accepts exactly what it accepted before. + +The renderer still recognises `full-width`, so pages already stored with it keep rendering. diff --git a/packages/app-shell/src/utils/__tests__/pageSchemaIntrospect.test.ts b/packages/app-shell/src/utils/__tests__/pageSchemaIntrospect.test.ts index 79d20e58b9..db0ad764b3 100644 --- a/packages/app-shell/src/utils/__tests__/pageSchemaIntrospect.test.ts +++ b/packages/app-shell/src/utils/__tests__/pageSchemaIntrospect.test.ts @@ -82,7 +82,7 @@ describe('stripDiscussionNodes', () => { type: 'record', pageType: 'record', object: 'account', - template: 'full-width', + template: 'default', regions: [ { name: 'main', @@ -99,7 +99,7 @@ describe('stripDiscussionNodes', () => { expect(types(stripped)).toEqual(['record', 'page:header', 'page:tabs', 'page:tab']); // Everything else about the page survives, including the scalars that are // not nodes at all. - expect(stripped.template).toBe('full-width'); + expect(stripped.template).toBe('default'); expect(stripped.regions[0].name).toBe('main'); expect(stripped.regions[0].width).toBe('full'); }); diff --git a/packages/plugin-detail/src/synth/__tests__/buildDefaultPageSchema.test.ts b/packages/plugin-detail/src/synth/__tests__/buildDefaultPageSchema.test.ts index 771e3d3561..dc326dd77c 100644 --- a/packages/plugin-detail/src/synth/__tests__/buildDefaultPageSchema.test.ts +++ b/packages/plugin-detail/src/synth/__tests__/buildDefaultPageSchema.test.ts @@ -201,12 +201,13 @@ describe('deriveHighlightFields', () => { }); describe('buildDefaultPageSchema', () => { - it('emits a record Page with full-width template + main region', () => { + it('emits a record Page with the default template + main region', () => { const page = buildDefaultPageSchema(leadDef); expect(page.type).toBe('record'); expect(page.pageType).toBe('record'); expect(page.object).toBe('lead'); - expect(page.template).toBe('full-width'); + // The spec retires `full-width` by name; a seed carrying it is refused at save. + expect(page.template).toBe('default'); expect(page.regions).toHaveLength(1); expect(page.regions[0].name).toBe('main'); }); diff --git a/packages/plugin-detail/src/synth/buildDefaultPageSchema.ts b/packages/plugin-detail/src/synth/buildDefaultPageSchema.ts index bc4939b76c..727bb7a7c8 100644 --- a/packages/plugin-detail/src/synth/buildDefaultPageSchema.ts +++ b/packages/plugin-detail/src/synth/buildDefaultPageSchema.ts @@ -989,7 +989,7 @@ export function buildDefaultAttachments(): any { * page. * * Shape: - * { type:'record', template:'full-width', regions:[ { name:'main', + * { type:'record', template:'default', regions:[ { name:'main', * components: [page:header, record:highlights?, record:path?, * page:tabs, record:discussion?] } ] } * For `enable.files: true` objects the tabs node carries a peer @@ -1172,7 +1172,11 @@ export function buildDefaultPageSchema( type: 'record', pageType: 'record', object: def?.name, - template: 'full-width', + // `default`, not `full-width`: the spec's `PageSchema.template` names four + // layouts and retires `full-width` by name (its replacement is `default`), + // so a Studio seed carrying it is refused at save. The renderer maps both + // names to the same `FullWidthTemplate`, so the seed lays out unchanged. + template: 'default', regions, }; } diff --git a/packages/types/src/layout.ts b/packages/types/src/layout.ts index 89b76bcc5e..a6831f0d17 100644 --- a/packages/types/src/layout.ts +++ b/packages/types/src/layout.ts @@ -1643,8 +1643,13 @@ export interface PageNodeSchema extends BaseSchema, Omit