You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(ui): field-group derivation is authorized by fieldGroups, not by field.group alone (#5458) (#5763)
Two UI guides taught that form sectioning derives from `field.group` by
itself, and neither page mentioned `fieldGroups` at all. Copying either
one yields a FLAT form: `deriveFieldGroupLayout` (ADR-0085 §5) buckets
only fields whose `group` matches a declared `fieldGroups[].key`, and
with no declared group it returns null outright — so an undeclared
`group` renders exactly like no `group`, and `os lint` reports
`field-group-undeclared`. Same falsehood as #5443, one layer up: that
issue fixed the showcase object the two pages link to as their runnable
example; this fixes the prose that cites it.
- create-vs-edit-form.mdx §2: the derivation's authorization source, the
undeclared-equals-unwritten equivalence, and the lint rule name. Also
drops "equivalent grouped form" for the two measured differences a
derived form really has (platform-injected `owner_id` lands in the
trailing untitled section; `columns` is a form-view knob the group
declaration cannot carry).
- field-grouping-and-order.mdx: same three facts on the semantic-grouping
section, and its sample — previously a `fields: {…}` fragment with no
declaration side — becomes a self-contained `ObjectSchema.create` with
the matching `fieldGroups`, marked `{/* os:check */}` so the gate
type-checks it against the built spec instead of leaving the corrected
example ungated.
Co-authored-by: Claude <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: content/docs/ui/create-vs-edit-form.mdx
+17-5Lines changed: 17 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -23,14 +23,25 @@ The create-form subset is not an arbitrary pick; it is *derivable* from signals
23
23
|`readonly` / formula / rollup / autonumber / system-stamped |**never** on create (you can't set it) |
24
24
|`defaultValue` present |**can be omitted** from create (it self-fills) |
25
25
|`hidden`| off everywhere by default |
26
-
|`group`| which section the field belongs to (semantic, travels with the model) |
26
+
|`group`| which section the field belongs to (semantic, travels with the model — and only once that group is **declared** in `fieldGroups`; see §2) |
27
27
|*declaration order*| the order you write fields in **is** the default order everywhere — there is no `field.order`|
28
28
29
29
So a sensible create form is: *editable, required-or-core fields, in declaration order* — and it **falls out** of the object. This is ADR-0047's guardrail: **omission is correct** — emit nothing extra and you still get a complete, correct form.
30
30
31
-
### 2. The default (edit) form derives from `field.group`
31
+
### 2. The default (edit) form derives from `field.group` — as authorized by `fieldGroups`
32
32
33
-
The full edit form materialises each `field.group` into a section. You can omit it entirely and let the platform derive an equivalent grouped form. When you do write it, list fields as **bare strings** so each one inherits its type / validation / FLS / default from the object — the form carries layout only, never data semantics.
33
+
`field.group` on its own does not create a section. The **authorization source is the object's `fieldGroups` declaration**: `deriveFieldGroupLayout` (ADR-0085 §5) — the single derivation every renderer and the i18n walker consume — sections only those fields whose `group` matches a declared `fieldGroups[].key`.
34
+
35
+
- An **undeclared**`group` renders **exactly like no `group` at all**: the field drops into a trailing untitled bucket.
36
+
- Declare **no**`fieldGroups` at all and grouping does not apply — the derivation yields nothing and you get a flat form.
37
+
- Either way, `os lint` (and `os build` / `os validate`) reports every unmatched reference as **`field-group-undeclared`**.
38
+
39
+
So tag the fields **and** declare the groups — [`contact.object.ts`](#runnable-example) does both. With both halves present, the full edit form materialises each declared group into a section, and you can omit the `form` view entirely and let the platform derive the grouped form. Two ways the derived form still differs from the hand-written one below:
40
+
41
+
- fields the platform injects and you never grouped (`owner_id`, under `sharingModel: 'private'`) surface in that trailing untitled section;
42
+
-`columns` is a **form-view** knob, and the group declaration has no column count to give — a derived section carries only `key` / `label` / `icon` / `description` / `collapse` and its member fields — so a hand-written `columns: 2` is not part of what derivation gives back.
43
+
44
+
When you do write the form, list fields as **bare strings** so each one inherits its type / validation / FLS / default from the object — the form carries layout only, never data semantics.
34
45
35
46
### 3. Hand-shape the create form *only when layout or flow diverges*
// Full edit form — grouped by field.group; bare strings inherit field defs.
64
+
// Full edit form — one section per group DECLARED in the object's
65
+
// `fieldGroups`; bare strings inherit field defs.
54
66
form: {
55
67
type: 'simple', data,
56
68
sections: [
@@ -102,7 +114,7 @@ Rule of thumb: **"different field subset" → derive. "different layout or flow"
102
114
103
115
## Runnable example
104
116
105
-
- Object: [`examples/app-showcase/src/data/objects/contact.object.ts`](https://github.com/objectstack-ai/objectstack/blob/main/examples/app-showcase/src/data/objects/contact.object.ts) — flat, grouped, intent-tagged field set.
117
+
- Object: [`examples/app-showcase/src/data/objects/contact.object.ts`](https://github.com/objectstack-ai/objectstack/blob/main/examples/app-showcase/src/data/objects/contact.object.ts) — flat, intent-tagged field set, with the four `fieldGroups` its `group` tags point at.
106
118
- Views: [`examples/app-showcase/src/ui/views/contact.view.ts`](https://github.com/objectstack-ai/objectstack/blob/main/examples/app-showcase/src/ui/views/contact.view.ts) — full edit form + sparse `formViews.create` + `addRecord` binding.
Copy file name to clipboardExpand all lines: content/docs/ui/field-grouping-and-order.mdx
+28-10Lines changed: 28 additions & 10 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -25,17 +25,34 @@ So "flat vs grouped" is not a contradiction — it's one flat set seen through d
25
25
26
26
There are **two** grouping concepts. Keep them distinct:
27
27
28
-
**1. Semantic grouping — `field.group` (on the object).** A field's logical home ("billing", "contact_info", "system"). It travels with the model. The Studio field editor folds fields by it, and auto-generated forms use it as the **default** sectioning — so you are not starting from zero.
28
+
**1. Semantic grouping — `field.group`+ `fieldGroups`(on the object).** A field's logical home ("billing", "contact_info", "system"). It travels with the model. The Studio field editor folds fields by it, and auto-generated forms use it as the **default** sectioning — so you are not starting from zero.
29
29
30
+
Semantic grouping has **two halves, and you need both**. `fieldGroups` on the object is the **authorization source** for the derivation: `deriveFieldGroupLayout` (ADR-0085 §5) — the one implementation every renderer and the i18n walker consume — sections only those fields whose `group` matches a declared `fieldGroups[].key`. An **undeclared**`group` renders **exactly like no `group` at all** (the field falls into a trailing untitled bucket); with **no**`fieldGroups` declared at all, grouping does not apply and the form comes out flat. `os lint` (and `os build` / `os validate`) reports the mismatch as **`field-group-undeclared`**.
**2. Layout grouping — form `sections` (on a view).** A specific form's explicit arrangement: which fields, which section, how many columns, collapsible. It can **inherit**`field.group`as the default or **override**it per form.
55
+
**2. Layout grouping — form `sections` (on a view).** A specific form's explicit arrangement: which fields, which section, how many columns, collapsible. It can **inherit**the object's declared groups as its default or **override**them per form.
39
56
40
57
```ts
41
58
form: {
@@ -68,17 +85,18 @@ Keeping grouping off the field (beyond an optional semantic hint) is what lets *
68
85
69
86
## Runnable example
70
87
71
-
-[`examples/app-showcase/src/data/objects/contact.object.ts`](https://github.com/objectstack-ai/objectstack/blob/main/examples/app-showcase/src/data/objects/contact.object.ts) — fields tagged with `group`.
88
+
-[`examples/app-showcase/src/data/objects/contact.object.ts`](https://github.com/objectstack-ai/objectstack/blob/main/examples/app-showcase/src/data/objects/contact.object.ts) — four declared `fieldGroups`, and the fields tagged with the matching`group`.
72
89
-[`examples/app-showcase/src/ui/views/contact.view.ts`](https://github.com/objectstack-ai/objectstack/blob/main/examples/app-showcase/src/ui/views/contact.view.ts) — sections that materialise those groups.
73
90
74
91
## Anti-patterns
75
92
76
93
-**Adding structural nesting to the data model to satisfy a form.** The model is flat; let the form group.
77
-
-**Re-typing the grouping in every form.** Declare `field.group` once; forms inherit and only override on real divergence.
94
+
-**Re-typing the grouping in every form.** Declare the groups (`fieldGroups`) and tag the fields (`field.group`) once; forms inherit and only override on real divergence.
95
+
-**Tagging fields with a `group` you never declared in `fieldGroups`.** The tag reads as intent but authorizes nothing — the fields render ungrouped, and `os lint` says so as `field-group-undeclared`.
78
96
-**Assuming a grid "group" will section your form fields.** It buckets rows by value — a different axis entirely.
79
97
80
98
## See also
81
99
82
100
-[Create form ≠ edit form](/docs/ui/create-vs-edit-form).
0 commit comments