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:
@@ -110,7 +110,7 @@ The WinterCMS widgets that are not in this list (the code editor, the color pick
|
||||
|
||||
### Field options
|
||||
|
||||
A field takes `label`, `comment`, `type`, `required`, `default`, `tab`, `span` (`left`, `right`, `full`, `auto`, `row`), `size` (`tiny`, `small`, `large`, `huge`, `giant`), `context`, `attributes` (scalar HTML attributes for the input), `options` and `emptyOption`, plus `nameFrom` and `relation` on relation fields, `preset` on text and mltext fields, `dependsOn` on dropdowns (see [Dependent dropdowns](#dependent-dropdowns)), `currency`, `currencyFrom`, `scale` and `max` on money fields (see [Money](#money)), and `mode`, `separator` and `customTags` on taglist fields (see [Taglist](#taglist)). WinterCMS keys outside this set, such as `readOnly`, `disabled` or `trigger`, are refused.
|
||||
A field takes `label`, `comment`, `type`, `required`, `default`, `tab`, `span` (`left`, `right`, `full`, `auto`, `row`), `size` (`tiny`, `small`, `large`, `huge`, `giant`), `context`, `attributes` (scalar HTML attributes for the input), `options` and `emptyOption`, plus `nameFrom` and `relation` on relation fields, `preset` on text and mltext fields, `dependsOn` on dropdowns (see [Dependent dropdowns](#dependent-dropdowns)), `currency`, `currencyFrom`, `scale` and `max` on money fields (see [Money](#money)), `mode`, `separator` and `customTags` on taglist fields (see [Taglist](#taglist)), and `trigger` (see [Triggers](#triggers)). WinterCMS keys outside this set, such as `readOnly` or `disabled`, are refused.
|
||||
|
||||
`context: update` shows a field only on the update form, and `context: create` only on the create form; a list of contexts is also accepted, and `context: preview` shows a field only on the [preview screen](#preview-screen). The context is enforced on the server too: a field that is hidden on a form is never written by that form's save, whatever the request body holds.
|
||||
|
||||
@@ -131,6 +131,33 @@ Multilingual pairs follow the locale the administrator works in. An `mltext` tar
|
||||
|
||||
A `preset` on another field type (`mltextarea` and `mlmarkdown` included), an unknown type, or a source that is not a text or mltext field of the same form stops the start-up, and the key is not accepted on settings forms or relation forms. An `mltextarea` field is neither a preset target nor a preset source, like `textarea`.
|
||||
|
||||
### Triggers
|
||||
|
||||
`trigger` disables or hides a field while a switch or checkbox of the same form is on or off, WinterCMS's field trigger. The Administrators form uses it to make the permission overrides read-only while the Superuser switch is on, because a superuser holds every permission anyway:
|
||||
|
||||
```yaml
|
||||
permissions:
|
||||
label: backend::lang.user.permission_overrides
|
||||
type: permissioneditor
|
||||
mode: radio
|
||||
trigger:
|
||||
action: disable
|
||||
field: is_superuser
|
||||
condition: checked
|
||||
```
|
||||
|
||||
| Key | Values |
|
||||
|-----|--------|
|
||||
| `action` | `disable` shows the field read-only with a note above the control ("Not editable while “Superuser” is on."); `hide` removes it from the form, and a tab whose every field is hidden disappears. |
|
||||
| `field` | Another field of the same form, of type `switch` or `checkbox` (a virtual switch counts). |
|
||||
| `condition` | `checked`: the trigger acts while the field is on; `unchecked`: while it is off. |
|
||||
|
||||
The admin evaluates the trigger against the whole form's values on every change, so the controlling field may sit on another tab. A controlling field that is not in the form for this request (removed for this administrator, or excluded by its `context`) counts as off. The preview screen applies `hide` only.
|
||||
|
||||
A disabled or hidden field is left out of the save body, so the server keeps its stored value; values typed before the field was disabled stay in the form and return when it is enabled. The trigger is a display rule only: the server does not evaluate it, and every rule that must hold is enforced in the save, whatever the client sends.
|
||||
|
||||
The mapping must hold exactly `action`, `field` and `condition`. A missing or extra key, another action or condition (WinterCMS's `value[...]` is not supported), a `field` that names no field of the form, names the field itself or names a field that is not a switch or checkbox stops the start-up with an error naming the controller, the field and the key. Triggers are evaluated on controller forms only: repeater rows, settings forms and relation forms refuse the key.
|
||||
|
||||
## Dependent dropdowns
|
||||
|
||||
A `type: dropdown` field with `dependsOn` takes its options from the value of a sibling field, WinterCMS's dependent dropdown. A menu entry's reference dropdown, for example, lists the posts when its type dropdown says "post" and the categories when it says "category":
|
||||
|
||||
@@ -154,14 +154,14 @@ Plugins that show an administrator, such as an author box, read the subtitle wit
|
||||
Settings → System → Administrators (`summercms.cabana.users`, `cabana.AdministratorsControllerID`) lists the backend administrators and opens a preview of each; it needs `backend.manage_users`. The list searches login, names and email and filters by role, superuser access, activation and last sign-in. The form has two tabs:
|
||||
|
||||
- **Account:** login, email, first and last name, the password with its confirmation, and the role. A password is required when an administrator is created and optional when one is edited (blank keeps the current one); it needs at least 4 characters, at most 72 bytes (bcrypt's limit) and an equal confirmation, and is hashed at `admin.password.bcrypt_cost`. A login or email another administrator already uses, in either field and ignoring case, is refused on the field; when only a deleted administrator holds it, the message says so, so you can restore that account instead. A new administrator is created activated, like `admin:create`, and no mail is sent.
|
||||
- **Permissions:** the superuser switch and the per-administrator permission overrides (inherit, allow, deny for each code in the catalog), stored in `backend_users.permissions` and applied last over the role's grants.
|
||||
- **Permissions:** the superuser switch and the per-administrator permission overrides (inherit, allow, deny for each code in the catalog), stored in `backend_users.permissions` and applied last over the role's grants. While the superuser switch is on, the overrides are read-only (a field `trigger`, see [Triggers](forms.md#triggers)) and a save keeps the stored ones.
|
||||
|
||||
The server enforces these rules on every save, whatever the client sends:
|
||||
|
||||
- Only an administrator who is a superuser (signed in, or with a personal API token of full scope) sees superusers at all: for everyone else they are left out of the list, their ids answer 404, and the superuser switch, column and filter are not in the schemas. Sending `is_superuser` without being a superuser is refused with 403, even when the field is hidden.
|
||||
- An administrator cannot grant more than they hold. Permissions they lack are locked in the override editor (a changed locked value is refused with 403), and roles whose grants (stored and code-declared) they do not hold themselves are locked in the role picker: assigning one is refused, while an administrator who already has such a role keeps it when other fields change.
|
||||
- An administrator who is not a superuser cannot change, deactivate or delete an administrator whose grants they do not all hold themselves.
|
||||
- On their own record an administrator may change login, email and names. A change of their own role, superuser flag or permission overrides is refused with 403, and so is a password: an administrator changes their own password in My account, which checks the current one.
|
||||
- On their own record an administrator may change login, email and names. Their own permission overrides are shown locked, with a note. A change of their own role, superuser flag or permission overrides is refused with 403, and so is a password: an administrator changes their own password in My account, which checks the current one.
|
||||
- A superuser cannot be demoted when it is the last active superuser.
|
||||
|
||||
Administrators are deactivated, deleted and restored, never removed:
|
||||
@@ -179,7 +179,7 @@ Setting the password of another administrator ends that administrator's sessions
|
||||
|
||||
Settings → System → Roles (`summercms.cabana.roles`, `cabana.RolesControllerID`) lists, creates, edits and deletes the roles in `backend_user_roles`; it needs `backend.manage_roles`. A role has a name (unique), a code (filled from the name until you edit it, and unique too), a description, and on the Permissions tab the permission codes it grants, stored in the role's `permissions`.
|
||||
|
||||
- **System roles** are the roles with `is_system` set (the seeded developer and publisher roles) and every role whose code plugins grant permissions to through `pact.Permission` `Roles`. Their code cannot be changed and they cannot be deleted; name, description and stored grants stay editable. A role created on this screen is never a system role. The grants plugins declare in code are merged with the stored ones when an administrator signs in, so they apply whether or not they are stored.
|
||||
- **System roles** are the roles with `is_system` set (the seeded developer and publisher roles) and every role whose code plugins grant permissions to through `pact.Permission` `Roles`. Their code cannot be changed and they cannot be deleted; name, description and stored grants stay editable. A role created on this screen is never a system role. The grants plugins declare in code are merged with the stored ones when an administrator signs in, so they apply whether or not they are stored. The role's editor shows them checked and locked, with the note that a plugin grants them; a save keeps them as stored.
|
||||
- An administrator who is not a superuser cannot grant more than they hold: permissions they lack are locked in the role's editor, so they can neither add nor remove them on any role.
|
||||
- A role that any administrator holds, deleted administrators included, cannot be deleted; the refusal names the role and how many administrators hold it. Give them another role first. A refused role in a bulk delete rolls back the whole selection.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user