feat(17-01): repeater field type and the dependent dropdown save recheck
- cabana: type repeater with nested form.fields (text, textarea, number, checkbox, switch, dropdown, richeditor), prompt, minItems, maxItems, titleFrom; groups, style, nested repeaters and other types fail boot - rows decoded before projection: only nested keys, coerced scalars, per-row required (field.index.nested), row bounds; ProjectWritableFields exempts repeater lists only, nestedValue unchanged - nested richeditor values sanitized with notices under the row path - dependent dropdowns rechecked on save, top level and per row; null when the sibling takes no choice, 422 form.dependent_invalid otherwise - dependent-options accepts repeater.field; schema carries RepeaterForm - backend lang repeater.max_items, repeater.min_items, form.dependent_invalid; TestCompanionsRepeaterSmoke; docs
This commit is contained in:
@@ -1189,6 +1189,14 @@
|
||||
"description": "FirstDay is the first day of the week, 0 (Sunday) to 6.",
|
||||
"type": "integer"
|
||||
},
|
||||
"form": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/cabana.RepeaterForm"
|
||||
}
|
||||
],
|
||||
"description": "Form holds the nested fields of a `type: repeater` field, one set per\nrow (D-07)."
|
||||
},
|
||||
"format": {
|
||||
"description": "Format is a datepicker's WinterCMS (PHP date) display format;\nDisplayFormat is the same format in the SPA's moment-style tokens.",
|
||||
"type": "string"
|
||||
@@ -1218,6 +1226,10 @@
|
||||
"description": "MaxFilesize is the largest accepted file in megabytes.",
|
||||
"type": "number"
|
||||
},
|
||||
"maxItems": {
|
||||
"description": "MaxItems and MinItems bound a repeater's row count, checked on save.",
|
||||
"type": "integer"
|
||||
},
|
||||
"mimeTypes": {
|
||||
"description": "MimeTypes are the allowed MIME patterns (or extensions) of a\nfileupload field.",
|
||||
"items": {
|
||||
@@ -1229,6 +1241,9 @@
|
||||
"description": "MinDate and MaxDate bound a datepicker's calendar date (YYYY-MM-DD),\nchecked again on save.",
|
||||
"type": "string"
|
||||
},
|
||||
"minItems": {
|
||||
"type": "integer"
|
||||
},
|
||||
"mode": {
|
||||
"description": "Mode is the fileupload mode (image or file, default file), the\ndatepicker mode (date, datetime or time, default datetime) or the\npermissioneditor mode (radio or checkbox).",
|
||||
"type": "string"
|
||||
@@ -1301,6 +1316,10 @@
|
||||
],
|
||||
"description": "ThumbOptions carries the preview thumbnail mode."
|
||||
},
|
||||
"titleFrom": {
|
||||
"description": "TitleFrom names the nested field whose value titles a repeater row.",
|
||||
"type": "string"
|
||||
},
|
||||
"translatable": {
|
||||
"description": "Translatable is true when a plugin field type's value is a map of\ncontent locale to string.",
|
||||
"type": "boolean"
|
||||
@@ -2287,6 +2306,20 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"cabana.RepeaterForm": {
|
||||
"properties": {
|
||||
"fields": {
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/cabana.FormField"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"fields"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"cabana.RowAction": {
|
||||
"properties": {
|
||||
"label": {
|
||||
@@ -4104,7 +4137,7 @@
|
||||
},
|
||||
"/{vendor}/{plugin}/{controller}/fields/{field}/dependent-options": {
|
||||
"get": {
|
||||
"description": "Choices of a `type: dropdown` field with `dependsOn`, from the controller's pact.DependentOptionsProvider, for the value of the sibling field the dropdown depends on. The sibling's value is passed as the query parameter `values[\u003csibling\u003e]` (for example `values[type]=acme-post`); a missing or empty value is null. `applies` is false when that value takes no choice at all (the field then stores null) and `options` is then empty; with `applies` true an empty `options` means there is nothing to choose yet. `depth` is the nesting level of a choice taken from a tree (0 at the top); labels are localized. A field that is not a dependsOn dropdown of the controller's form answers 404.",
|
||||
"description": "Choices of a `type: dropdown` field with `dependsOn`, from the controller's pact.DependentOptionsProvider, for the value of the sibling field the dropdown depends on. The sibling's value is passed as the query parameter `values[\u003csibling\u003e]` (for example `values[type]=acme-post`); a missing or empty value is null. `applies` is false when that value takes no choice at all (the field then stores null) and `options` is then empty; with `applies` true an empty `options` means there is nothing to choose yet. `depth` is the nesting level of a choice taken from a tree (0 at the top); labels are localized. For a dropdown inside a repeater row, {field} is `\u003crepeater\u003e.\u003cfield\u003e` and `values[\u003csibling\u003e]` is the row's sibling value. A field that is not a dependsOn dropdown of the controller's form answers 404.",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Vendor",
|
||||
@@ -4134,7 +4167,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Dropdown field name",
|
||||
"description": "Dropdown field name, or repeater.field for a dropdown in a repeater row",
|
||||
"in": "path",
|
||||
"name": "field",
|
||||
"required": true,
|
||||
@@ -4522,7 +4555,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.",
|
||||
"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`.",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Vendor",
|
||||
|
||||
Reference in New Issue
Block a user