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
17 changes: 17 additions & 0 deletions .changeset/11914-select-option-default.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
'@object-ui/plugin-form': patch
---

A create form preselects the option a field's option list marks `default: true` (objectui#11914).

A `select` field that declares no `defaultValue` but marks one option `default: true` opened on the "Select an option" placeholder in every object-form container, the console's create dialog included. The server stores the marked option when a create omits the field, so the objectstack tutorial's Create Ticket form showed Priority and Status empty and could not be submitted until the user picked the values the metadata had already chosen.

The create form now reads the option list the way the server's insert path does:

- only when the field declares no `defaultValue`. A field-level default, static or runtime, always wins, and the option flag is then not seeded;
- a single-valued field takes the first marked option;
- a multi-valued field (`multiselect`, or `select` with `multiple: true`) takes every marked option, as an array.

A value the caller seeds or the user picks still wins. Edit forms are unchanged: they show the stored record.

Nothing is added to the package entry: no export, prop or type member.
21 changes: 12 additions & 9 deletions packages/plugin-form/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,8 @@ the form looks validated while validating nothing.
### What a create form opens with

A create form has no persisted record, so its opening values come from the
object schema's declared field `defaultValue`s. Every object-form container
object schema's declared defaults: a field's `defaultValue`, or the option its
option list marks `default: true`. Every object-form container
(`ObjectForm`, `ModalForm`, `DrawerForm`, `TabbedForm`, `SplitForm`,
`WizardForm`) resolves them the same way, through `schemaDefaults`:

Expand All @@ -282,20 +283,22 @@ object schema's declared field `defaultValue`s. Every object-form container
| `defaultValue: 'draft'` (any static literal) | `draft`, preselected and submittable | the value is known; making the user pick it is busywork, and on a status-like field every wrong option is one click away |
| `defaultValue: 'NOW()'` / `'current_user'` (a runtime token) | empty | the token is an *instruction*, not a value. The server resolves it at insert — but only for fields that arrive empty, so seeding the literal text would suppress it |
| `defaultValue: cel\`today()\`` (an Expression envelope) | empty | same reason: the server evaluates it per insert |
| an option's `default: true` | empty | see below |
| an option's `default: true`, and no `defaultValue` | that option, preselected and submittable | the server stores the marked option when the field is omitted; see below |
| nothing | empty | no default is invented |

`initialData` / `initialValues` passed by the caller always outrank a schema
default — a lookup prefill or a "duplicate this record" seed is the more
specific instruction.

Only the **field-level** `defaultValue` is read, never a select option's
`default: true`, even though `@objectstack/spec`'s `SelectOptionSchema` declares
that key. The server's insert path resolves `defaultValue` and nothing else, so
a form that also seeded from option-level `default` would preselect values the
server would never have applied on its own — a renderer-side second default
contract (AGENTS.md #0.1). If option-level `default` is meant to mean "the
initial value", that belongs at the producer.
An option's `default: true` is read the way the server's insert path reads it
(`ObjectQL.applyFieldDefaults`, which falls back to the marked option), so the
form preselects exactly what omitting the field would store:

- only when the field declares no `defaultValue` — a field-level default,
static or runtime, always wins, and the flag is then not seeded at all;
- a single-valued field takes the **first** marked option;
- a multi-valued field (`@objectstack/spec`'s `isMultiValueField`: `multiselect`,
or `select` with `multiple: true`) takes **every** marked option, as an array.

**Edit forms are never seeded.** An edit form shows the row as the server holds
it; folding a default in over a column the record leaves unset would arm a
Expand Down
Loading
Loading