A form declaration can hold settings its layout family never reads #185

Open
opened 2026-10-06 21:25:23 +00:00 by cgalo5758 · 2 comments
Owner

forms.FormSpec and forms.Binding are flat structs, so either can carry settings only one family uses: Wide (bar), Columns (table), CommitAction, RowCommit and field placement (rows), MessageAfter (preview), and on the binding Body, Staged, Rows, Tray (rows, in two modes). A declaration also names its family, which its kind decides. About a dozen rules in internal/forms/invariants.go refuse wrong combinations, checkRowsBinding and checkRowCommitBinding panic on first render, and family == X branches spread over Render, renderFieldAs, boxFor and CommitClasses.

Done when: the family is derived from the kind; each family's settings live in a value only that family carries; one check that the value matches the kind replaces the per-setting rules and panics; and the form-library spec says how a declaration gives them.

`forms.FormSpec` and `forms.Binding` are flat structs, so either can carry settings only one family uses: `Wide` (bar), `Columns` (table), `CommitAction`, `RowCommit` and field placement (rows), `MessageAfter` (preview), and on the binding `Body`, `Staged`, `Rows`, `Tray` (rows, in two modes). A declaration also names its family, which its kind decides. About a dozen rules in `internal/forms/invariants.go` refuse wrong combinations, `checkRowsBinding` and `checkRowCommitBinding` panic on first render, and `family == X` branches spread over `Render`, `renderFieldAs`, `boxFor` and `CommitClasses`. Done when: the family is derived from the kind; each family's settings live in a value only that family carries; one check that the value matches the kind replaces the per-setting rules and panics; and the form-library spec says how a declaration gives them.
cgalo5758 added the
kind
design
area/operator-ui
labels 2026-10-06 21:25:23 +00:00
Author
Owner

Two rules a declaration could state are checked only when a form is submitted. A Min or Max that cannot be read is ignored when the form is submitted, and a Pattern that does not compile refuses every value (internal/forms/parse.go). No declaration uses Pattern today, and Min and Max appear on two fields. When each family's settings move into a value of their own, the bounds and the pattern can be checked where the registry test checks every declaration (forms.CheckInvariants). A pattern is compiled on first use and kept in a cache keyed by the pattern; compiling it once when a form is registered, if the check moves there, would replace that cache.

Two rules a declaration could state are checked only when a form is submitted. A `Min` or `Max` that cannot be read is ignored when the form is submitted, and a `Pattern` that does not compile refuses every value (`internal/forms/parse.go`). No declaration uses `Pattern` today, and `Min` and `Max` appear on two fields. When each family's settings move into a value of their own, the bounds and the pattern can be checked where the registry test checks every declaration (`forms.CheckInvariants`). A pattern is compiled on first use and kept in a cache keyed by the pattern; compiling it once when a form is registered, if the check moves there, would replace that cache.
Author
Owner

The registry test checks every registered form, and four declarations are built per request instead of registered: the org type default form (orgTypeDefaultFormSpecFor), the entitlement set rules form (entitlementSetRulesSpecFor), the integration settings form (settingsFormFor) and the list search (listSearchForm).

The first two are held to forms.CheckInvariants by TestPerRequestFormsSatisfyTheInvariants (internal/server/forms_golden_test.go). The settings form has a test of its own that skips the two hint rules. The list search has none. listSearchForm (internal/server/list_scale_forms.go) builds its declaration and returns only the rendered view, so no test can pass the declaration to the check. Its fields and its way out are set per list, and its placeholder comes from each list's ListNav. Twelve lists set a placeholder, and the placeholder rule never reads them. All twelve would pass it today.

When one check replaces the per-setting rules here, it should reach the declarations built per request as well as the registered ones. The smallest step is a builder that returns the list search's declaration, as the other three have, added to TestPerRequestFormsSatisfyTheInvariants.

The registry test checks every registered form, and four declarations are built per request instead of registered: the org type default form (`orgTypeDefaultFormSpecFor`), the entitlement set rules form (`entitlementSetRulesSpecFor`), the integration settings form (`settingsFormFor`) and the list search (`listSearchForm`). The first two are held to `forms.CheckInvariants` by `TestPerRequestFormsSatisfyTheInvariants` (`internal/server/forms_golden_test.go`). The settings form has a test of its own that skips the two hint rules. The list search has none. `listSearchForm` (`internal/server/list_scale_forms.go`) builds its declaration and returns only the rendered view, so no test can pass the declaration to the check. Its fields and its way out are set per list, and its placeholder comes from each list's `ListNav`. Twelve lists set a placeholder, and the placeholder rule never reads them. All twelve would pass it today. When one check replaces the per-setting rules here, it should reach the declarations built per request as well as the registered ones. The smallest step is a builder that returns the list search's declaration, as the other three have, added to `TestPerRequestFormsSatisfyTheInvariants`.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: wiki-cafe/member-console#185