From 92205e28f6b45d6f80c9920d76abcdacb5c9ea0e Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 2 Oct 2026 03:09:48 +0000 Subject: [PATCH 1/2] docs(spec): the master-detail detail entry's inlineMode and formFields describes state both renderer paths An entry that names both relationshipField and at least one column is kept as authored by the renderer: an omitted inlineMode is not resolved from the relationship's inlineEdit and an omitted formFields is not derived. The two describes, and the factory's docblock clause that repeated the inlineMode claim, now say what happens on that path and on the derived one. Claude-Session: https://claude.ai/code/session_01UtnxvdiN376GF3sgXwAw4d Co-authored-by: Claude --- .changeset/21284-detail-entry-describes.md | 12 ++++++++++++ packages/spec/src/ui/component.zod.ts | 7 ++++--- 2 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 .changeset/21284-detail-entry-describes.md diff --git a/.changeset/21284-detail-entry-describes.md b/.changeset/21284-detail-entry-describes.md new file mode 100644 index 00000000000..d59378e53a7 --- /dev/null +++ b/.changeset/21284-detail-entry-describes.md @@ -0,0 +1,12 @@ +--- +'@objectstack/spec': patch +--- + +docs(spec): an `object-master-detail-form` detail entry's `inlineMode` and `formFields` describes say what happens when the key is omitted on both of the renderer's paths (#21284) + +Clause-②: no + +- **Derived entry** (any entry that does not name both `relationshipField` and at least one column): an omitted `inlineMode` is resolved from the relationship field's `inlineEdit`, else from the child object's shape, and an omitted `formFields` is derived from the child object's fields. This is unchanged. +- **Entry kept as authored** (one that names both `relationshipField` and at least one column): the renderer resolves and derives nothing. An omitted `inlineMode` renders the collection as a grid, which offers the per-row form only when `formFields` lists more fields than `columns`. An omitted `formFields` means the per-row form is offered only when `inlineMode` is `form`, and it then draws the child object's full field list. +- The `inlineMode` describe used to say only "resolved from the relationship field's `inlineEdit` when omitted", and the `formFields` describe only "derived from the child object's editable fields when omitted". Neither holds for an entry kept as authored. The `formFields` describe also no longer says "editable": the derived list keeps `readonly` fields, as `deriveInlineRowFormFields` (`@objectstack/spec/data`) does. +- No schema accepts or refuses anything new. Only the two describes, the reference page that lifts them, and one source comment change. diff --git a/packages/spec/src/ui/component.zod.ts b/packages/spec/src/ui/component.zod.ts index 5eb2a657697..0d953a969ab 100644 --- a/packages/spec/src/ui/component.zod.ts +++ b/packages/spec/src/ui/component.zod.ts @@ -5006,7 +5006,8 @@ const MASTER_DETAIL_DETAIL_HISTORY = * child-collection surfaces. The three it adds are the renderer's own: * `formFields` (the per-row expand form), `inlineMode` (the two form factors * a relationship field's `inlineEdit` names; absence takes the relationship's - * own resolution) and `sortField` (the line-position field the grid stamps on + * own resolution only on an entry the renderer derives, and its describe + * states both paths) and `sortField` (the line-position field the grid stamps on * drag-reorder). `title` and `addLabel` are plain strings because the * renderer draws them as a React child and a button label without resolving a * locale map. @@ -5030,8 +5031,8 @@ function masterDetailDetailEntry() { childObject: z.string().describe('Child object whose records are entered inline'), relationshipField: z.string().optional().describe('FK on the child pointing back to the parent (auto-detected from the child\'s master_detail/lookup field when omitted)'), columns: z.array(InlineGridColumnSchema).optional().describe("Editable grid columns (derived from the child object when omitted). Each entry is the strict, name-keyed inline grid column a relationship field's `inlineColumns` takes ({ name, label?, type?, … } — objectui GridColumn); identity-only entries ({ name }) hydrate everything else from the child object's fields. Unknown keys and the retired `field` spelling are refused at parse."), - formFields: z.array(z.string()).optional().describe("Child field names for the per-row expand form (derived from the child object's editable fields when omitted)"), - inlineMode: z.enum(['grid', 'form']).optional().describe("Inline-edit form factor: 'grid' = editable cells; 'form' = read-only list + per-row full form. Resolved from the relationship field's `inlineEdit` when omitted"), + formFields: z.array(z.string()).optional().describe("Child field names for the per-row expand form. When omitted they are derived from the child object's fields — except on an entry that names both `relationshipField` and at least one column, which is kept as authored: nothing is derived, and the per-row form is offered only when `inlineMode` is 'form', where it draws the child object's full field list"), + inlineMode: z.enum(['grid', 'form']).optional().describe("Inline-edit form factor: 'grid' = editable cells; 'form' = read-only list + per-row full form. When omitted it is resolved from the relationship field's `inlineEdit`, else from the child object's shape — except on an entry that names both `relationshipField` and at least one column, which is kept as authored: nothing is resolved, the collection renders as a grid, and the per-row form is offered only when `formFields` lists more fields than `columns`"), amountField: z.string().optional().describe('Numeric child column summed for the running total'), sortField: z.string().optional().describe('Child field holding the line sort position, stamped on drag-reorder (derived from a `position` / `sort_order` / … field when omitted)'), totalField: z.string().optional().describe('Parent field to receive the rolled-up sum'), From e21f622b6512432103df79a6df6eb53a721722d6 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 2 Oct 2026 03:20:15 +0000 Subject: [PATCH 2/2] docs(references): regenerate the ui component reference for the detail entry describes Claude-Session: https://claude.ai/code/session_01UtnxvdiN376GF3sgXwAw4d Co-authored-by: Claude --- content/docs/references/ui/component.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/docs/references/ui/component.mdx b/content/docs/references/ui/component.mdx index a8c1d725f1a..bcda35e83eb 100644 --- a/content/docs/references/ui/component.mdx +++ b/content/docs/references/ui/component.mdx @@ -976,8 +976,8 @@ Sort field and direction pair | **childObject** | `string` | ✅ | Child object whose records are entered inline | | **relationshipField** | `string` | optional | FK on the child pointing back to the parent (auto-detected from the child's master_detail/lookup field when omitted) | | **columns** | `{ name: string; label?: string; type?: Enum<'text' \| 'number' \| 'currency' \| 'date' \| 'datetime' \| 'time' \| 'select' \| 'lookup' \| 'file'>; width?: number; … }[]` | optional | Editable grid columns (derived from the child object when omitted). Each entry is the strict, name-keyed inline grid column a relationship field's `inlineColumns` takes (`{ name, label?, type?, … }` — objectui GridColumn); identity-only entries (`{ name }`) hydrate everything else from the child object's fields. Unknown keys and the retired `field` spelling are refused at parse. | -| **formFields** | `string[]` | optional | Child field names for the per-row expand form (derived from the child object's editable fields when omitted) | -| **inlineMode** | `Enum<'grid' \| 'form'>` | optional | Inline-edit form factor: 'grid' = editable cells; 'form' = read-only list + per-row full form. Resolved from the relationship field's `inlineEdit` when omitted | +| **formFields** | `string[]` | optional | Child field names for the per-row expand form. When omitted they are derived from the child object's fields — except on an entry that names both `relationshipField` and at least one column, which is kept as authored: nothing is derived, and the per-row form is offered only when `inlineMode` is 'form', where it draws the child object's full field list | +| **inlineMode** | `Enum<'grid' \| 'form'>` | optional | Inline-edit form factor: 'grid' = editable cells; 'form' = read-only list + per-row full form. When omitted it is resolved from the relationship field's `inlineEdit`, else from the child object's shape — except on an entry that names both `relationshipField` and at least one column, which is kept as authored: nothing is resolved, the collection renders as a grid, and the per-row form is offered only when `formFields` lists more fields than `columns` | | **amountField** | `string` | optional | Numeric child column summed for the running total | | **sortField** | `string` | optional | Child field holding the line sort position, stamped on drag-reorder (derived from a `position` / `sort_order` / … field when omitted) | | **totalField** | `string` | optional | Parent field to receive the rolled-up sum |