From c96ea94cd849b981a67bc78986bc33dfa1d4c57e Mon Sep 17 00:00:00 2001 From: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Date: Sun, 7 Jun 2026 18:43:52 +0800 Subject: [PATCH] feat(studio): page create form binds object + page type + kind (#1541) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The page create form only had identity fields (label/name/icon/description), so a record page couldn't be created or bound to an object in Studio — even though the edit form + protocol schema fully support type/object/kind/regions. The root cause was objectui-side: the `page` resource anchor's createFields omitted them (cf. `view`, which includes object + kind). Mirror view's create config — add Object, Page type (default 'record'), Kind (full/slotted) to the page create form. Block layout is still composed in the editor canvas. Co-Authored-By: Claude Opus 4.8 --- .changeset/b1-page-create-fields.md | 7 ++++ .../src/views/metadata-admin/anchors.ts | 40 ++++++++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 .changeset/b1-page-create-fields.md diff --git a/.changeset/b1-page-create-fields.md b/.changeset/b1-page-create-fields.md new file mode 100644 index 000000000..378db77f6 --- /dev/null +++ b/.changeset/b1-page-create-fields.md @@ -0,0 +1,7 @@ +--- +"@object-ui/app-shell": minor +--- + +Studio: the "New page" form can now create a record page bound to an object. + +The page create form was identity-only (label/name/icon/description), so it couldn't make a `pageType: 'record'` page or bind it to an object — even though the page edit form and protocol schema fully support those fields. Mirror the `view` resource's create config: the page create form now exposes **Object**, **Page type** (default `record`), and **Kind** (`full`/`slotted`), so a record page can be created and bound in Studio (#1541). The block layout is then composed in the editor's PagePreview canvas. diff --git a/packages/app-shell/src/views/metadata-admin/anchors.ts b/packages/app-shell/src/views/metadata-admin/anchors.ts index db5e1ade9..02b06ed52 100644 --- a/packages/app-shell/src/views/metadata-admin/anchors.ts +++ b/packages/app-shell/src/views/metadata-admin/anchors.ts @@ -115,11 +115,47 @@ export function registerBuiltinAnchors(): void { groupLabel: 'Pages', order: 40, }], - createFields: ['label', 'name', 'description', 'icon'], + // Mirror `view`'s create form: a page (esp. a *record* page) must be able to + // bind an `object` and pick its page `type` / `kind` at creation — the + // identity-only form (label/name/icon/description) couldn't make a record + // page. The block layout is then composed in the editor's PagePreview canvas. + createFields: ['label', 'name', 'object', 'type', 'kind'], createDerive: [ { from: 'label', to: 'name', transform: 'slugify', untilUserEdits: true }, ], - createDefaults: { regions: [] }, + createSchema: { + type: 'object', + required: ['label', 'name', 'type'], + properties: { + label: { type: 'string', title: 'Label', description: 'Human-readable page title.' }, + name: { + type: 'string', + title: 'Name', + description: 'Page key (snake_case).', + pattern: '^[a-z_][a-z0-9_]*$', + }, + type: { + type: 'string', + title: 'Page type', + enum: ['record', 'app', 'home', 'dashboard', 'utility'], + default: 'record', + description: 'A `record` page renders for an object’s records; pick the object below.', + }, + object: { + type: 'string', + title: 'Object', + description: 'For a record page — the object whose records this page renders.', + }, + kind: { + type: 'string', + title: 'Kind', + enum: ['full', 'slotted'], + default: 'full', + description: 'full = the whole page; slotted = override only named slots of the default.', + }, + }, + }, + createDefaults: { type: 'record', kind: 'full', regions: [] }, }); // A view is the canonical first-class ViewItem ({ viewKind, config }),