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
9 changes: 9 additions & 0 deletions .changeset/11114-master-detail-fields-text.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@object-ui/plugin-form': patch
---

The `object-master-detail-form` registration's `fields` description no longer calls that key "the submitted set" (objectui#11114).

The sentence told an author, or an AI authoring metadata, that the parent field pool bounds what Save writes. It does not, and it was never meant to: `fields` bounds what the parent form DRAWS and edits, and on a create the parent leg of the atomic batch is the drawn fields plus any parent value seeded through `initialValues` (or its alternate spelling `initialData`), drawn or not. The description now says exactly that, and adds that a seed for an undeclared, server-owned, computed or read-only field is still stripped, as on any save.

Text only. The description is a declared input of a public-tier block, so it reaches the published `sdui.manifest.json`; no input, type, default or accepted value moves, and no runtime behaviour changes. The parent leg is deliberately not filtered to `fields`: that would silently drop author-seeded values, which is how a hidden parent key reaches a record.
8 changes: 5 additions & 3 deletions packages/plugin-form/src/ObjectForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1650,9 +1650,11 @@ const SimpleObjectForm: React.FC<{ schema: LocalizedObjectFormSchema; dataSource
// section whole, heading included.
//
// ⛔ The intersection itself is NOT the defect and is deliberately left
// standing: `fields` is the parent field pool for values, create
// defaults and the submitted set as well as for layout, so resolving
// these members here would change what a landed schema writes. What WAS
// standing: `fields` is the parent field pool that bounds what this form
// DRAWS and edits, so resolving these members here would change what a
// landed schema draws and lets a user edit. It does not bound the write
// itself: a value seeded through `initialValues` is written whether or
// not it is drawn (objectui#11114). What WAS
// the defect is that the loss was silent, plus this block's registration
// claiming `fields` is "Ignored when `sections` is given" — a claim its
// three sibling `fields` registrations never made and the one shared
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@
* - `{ name }` is tolerated as the same member as the bare name;
* - ⚠️ the key bounds what is DRAWN, not what the PARENT leg of the atomic
* batch WRITES: a seeded parent field it does not list is still written.
* That is pinned as behaviour and handed back, not changed here, because
* the registration's description calls this key the parent pool for "the
* submitted set". Changing it is a decision about the renderer or the
* declaration, and this card writes pins only.
* That is the ruled behaviour (objectui#11114), not a defect: the
* registration's `fields` description says that, on a create, the submitted
* set is the drawn fields plus any seeded `initialValues`, and this row is
* what keeps that sentence true.
*
* `MasterDetailForm` reads none of this itself. The `parentSchema` memo copies
* `fields` onto an `object-form`-shaped node rendered through a DIRECTLY
Expand Down Expand Up @@ -268,10 +268,11 @@ describe('object-master-detail-form `fields` — the member shape (objectui#8071
const ops = dataSource.batchTransaction.mock.calls[0][0] as Array<Record<string, any>>;
expect(ops).toHaveLength(1);
expect(ops[0]).toMatchObject({ object: 'invoice', action: 'create' });
// Pinned as BEHAVIOUR and handed back rather than changed here: the
// registration's `fields` description calls this key the parent pool for
// "the submitted set", and a seeded field outside it is written all the
// same. Hiding a field with `fields` does not stop its seed being saved.
// The ruled behaviour, not an accident (objectui#11114): the registration's
// `fields` description says that, on a create, the submitted set is the
// drawn fields plus any seeded `initialValues`, so a seeded field outside
// `fields` is written all the same. Hiding a field with `fields` does not
// stop its seed being saved.
expect(ops[0].data).toEqual({ status: 'draft', memo: 'seeded' });
});
});
2 changes: 1 addition & 1 deletion packages/plugin-form/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ ComponentRegistry.register('object-master-detail-form', MasterDetailFormRenderer
// Declaring them would mint choices an authoring UI offers and this block
// cannot honour.
{ name: 'formType', type: 'enum', enum: ['simple', 'tabbed'], description: 'How the PARENT half of the form is presented. The detail grids below it are unaffected.' },
{ name: 'fields', type: 'array', description: 'Which parent fields to show, in order — and it is NOT ignored when `sections` is given: the two INTERSECT. The parent field pool is built from this key first and every section then resolves its own members against that pool, so a section member this key does not list is dropped from the rendered form, and a section that loses EVERY member that way disappears with its heading. Each such drop is reported once via `console.warn` (objectui#9884); it is not repaired, because this key is also the parent pool for values, create defaults and the submitted set. Author one or the other, or list every section member here too. Members are bare field names (`{ name }` tolerated); NOT the spec `FormFieldSchema` object `sections[].fields` accepts (identity key `field`) — that shape resolves to no name here and is silently skipped (the parent form renders through the same `ObjectForm` / `SimpleObjectForm` as `object-form` — see its `fields` description).' },
{ name: 'fields', type: 'array', description: 'Which parent fields to show, in order — and it is NOT ignored when `sections` is given: the two INTERSECT. The parent field pool is built from this key first and every section then resolves its own members against that pool, so a section member this key does not list is dropped from the rendered form, and a section that loses EVERY member that way disappears with its heading. Each such drop is reported once via `console.warn` (objectui#9884); it is not repaired, because this key bounds what the form DRAWS and edits, not what Save writes: on a create, the submitted set is the drawn fields plus any parent value seeded through `initialValues` (or its alternate spelling `initialData`), drawn or not. A seed for an undeclared, server-owned, computed or read-only field is still stripped, as on any save. Author one or the other, or list every section member here too. Members are bare field names (`{ name }` tolerated); NOT the spec `FormFieldSchema` object `sections[].fields` accepts (identity key `field`) — that shape resolves to no name here and is silently skipped (the parent form renders through the same `ObjectForm` / `SimpleObjectForm` as `object-form` — see its `fields` description).' },
// The three labels are the spec's `I18nLabel` (`ComponentPropsMap
// ['object-master-detail-form']`), and `MasterDetailForm` resolves a map
// with `pickLocalized` against the active UI language (objectui#10935). So
Expand Down
Loading