feat(19.6.1-02): field trigger and admin build

- fields.yaml trigger (action disable|hide, field, condition checked|unchecked) compiled to FormField.Trigger
- boot errors for malformed triggers, controlling fields that are not a switch or checkbox, and triggers in repeater rows, settings and relation forms
- Administrators permissions overrides are disabled while Superuser is on (D-06)
- SPA: trigger.ts (triggerState, applyTriggers), FORM_TRIGGER_NOTES, the trigger note in FormField, FormView tabs/banner/payload after triggers, PreviewView hide only
- regenerated admin OpenAPI and schema.d.ts; rebuilt modules/boardwalk/dist; docs and README
This commit is contained in:
Jakub Zych
2026-10-22 11:43:58 +02:00
parent 705f94d9e5
commit 7091d09699
27 changed files with 501 additions and 35 deletions

View File

@@ -1194,6 +1194,25 @@
],
"type": "object"
},
"cabana.FieldTrigger": {
"properties": {
"action": {
"type": "string"
},
"condition": {
"type": "string"
},
"field": {
"type": "string"
}
},
"required": [
"action",
"condition",
"field"
],
"type": "object"
},
"cabana.FieldTypeAssets": {
"properties": {
"element": {
@@ -1551,6 +1570,14 @@
"description": "Translatable is true when a plugin field type's value is a map of\ncontent locale to string.",
"type": "boolean"
},
"trigger": {
"allOf": [
{
"$ref": "#/components/schemas/cabana.FieldTrigger"
}
],
"description": "Trigger disables or hides the field in the admin while a switch or\ncheckbox of the same form is checked or unchecked (fields.yaml\ntrigger). A disabled or hidden field is left out of the save body; the\nserver keeps its stored value and never relies on the trigger."
},
"twelveHour": {
"description": "TwelveHour shows a 12-hour clock.",
"type": "boolean"
@@ -5287,7 +5314,7 @@
},
"/{vendor}/{plugin}/{controller}/schema/form": {
"get": {
"description": "The form of a controller, localized. `preview` is present when config_form.yaml declares a preview block: the form then has a read-only preview screen, which shows the fields whose context allows preview, the record actions and, when preview.headerPartial is set, that partial as a status hint. A `type: password` field and every other field the controller lists as virtual is sent in a save body and never has a value in a record response. `preset` on a text or mltext field names the text or mltext field it follows on the create form (type slug or exact; an mltext pair follows per locale) until the administrator edits it. A `type: permissioneditor` field carries `permissionOptions`, the permissions the controller offers the requesting administrator; its value in a record response and in a save body is an object of permission code to integer (radio mode 1 or -1, checkbox mode 1). A `type: relation` field over a protected foreign key is `readOnly` unless its contract declares the key writable. A field whose type a plugin registers carries `element` (the custom-element tag the admin renders), `translatable` (its value is an object of content locale to string) and `typeOptions` (the type's own fields.yaml keys). A `type: dropdown` field with `dependsOn` names the sibling field whose value selects its options and carries no options: they come from the field's dependent-options route. A `type: richeditor` field's value is a string of HTML, sanitized on every save; what the sanitizer removed is reported in the save response's `meta.notices`. A `type: repeater` field carries `form.fields` (the fields of one row), `prompt`, `maxItems`, `minItems` and `titleFrom`; its value in a record response and in a save body is a list of row objects keyed by the nested field names, and a row's errors are keyed `\u003cfield\u003e.\u003cindex\u003e.\u003cnested\u003e`.",
"description": "The form of a controller, localized. `preview` is present when config_form.yaml declares a preview block: the form then has a read-only preview screen, which shows the fields whose context allows preview, the record actions and, when preview.headerPartial is set, that partial as a status hint. A `type: password` field and every other field the controller lists as virtual is sent in a save body and never has a value in a record response. `preset` on a text or mltext field names the text or mltext field it follows on the create form (type slug or exact; an mltext pair follows per locale) until the administrator edits it. A `type: permissioneditor` field carries `permissionOptions`, the permissions the controller offers the requesting administrator; its value in a record response and in a save body is an object of permission code to integer (radio mode 1 or -1, checkbox mode 1). A `type: relation` field over a protected foreign key is `readOnly` unless its contract declares the key writable. A field whose type a plugin registers carries `element` (the custom-element tag the admin renders), `translatable` (its value is an object of content locale to string) and `typeOptions` (the type's own fields.yaml keys). A `type: dropdown` field with `dependsOn` names the sibling field whose value selects its options and carries no options: they come from the field's dependent-options route. `trigger` ({action, field, condition}) disables (action disable: shown read-only) or hides (action hide) the field while the switch or checkbox `field` of the same form is checked or unchecked; the admin leaves such a field out of the save body and the server keeps its stored value, so the trigger is a display rule only. A `type: richeditor` field's value is a string of HTML, sanitized on every save; what the sanitizer removed is reported in the save response's `meta.notices`. A `type: repeater` field carries `form.fields` (the fields of one row), `prompt`, `maxItems`, `minItems` and `titleFrom`; its value in a record response and in a save body is a list of row objects keyed by the nested field names, and a row's errors are keyed `\u003cfield\u003e.\u003cindex\u003e.\u003cnested\u003e`.",
"parameters": [
{
"description": "Vendor",