docs(cabana): widget element contract and payload fixture (quick-261006-eyj)
- acme-demo-lookup fixture is a reorder widget: a click reverses its items, sends the new id order as detail.payload and renders the returned items from the data attribute and the summer-result event with textContent, no HTTP - partials-and-widgets gains a Widget element contract subsection listing the attributes the SPA sets and the summer-action / summer-result events - cabana README names both events in the form widgets bullet
This commit is contained in:
@@ -72,6 +72,22 @@ lookup:
|
||||
|
||||
The SPA posts `record_id`, the fill snapshot `values` and, when the element supplied one, `payload` to `.../widgets/{field}`. cabana checks the CSRF header, the controller's and the action's permissions and the record scope, then calls the action's `Run` with a `pact.AdminActionInput`. The action reads the payload from the `Payload` field as raw JSON (any value up to 64 KiB, exactly the bytes the client sent, nil when absent) and decodes it itself; it must treat any ids inside the payload as untrusted input and re-check them against its own scope, because the framework never uses the payload to select the record. The answer's `pact.AdminActionResult` carries a message and the fill values; keys outside `fill` and values that are not scalars are dropped before the response is written. It may also carry `Data`, any JSON value up to 256 KiB encoded, which is passed through as `data` and is not filtered like `fill` (a larger or unencodable value is a 500). Toolbar and record actions refuse a payload. An action may return a `cabana.ValidationError` to answer 422 on a field.
|
||||
|
||||
### Widget element contract
|
||||
|
||||
The SPA talks to the plugin element through attributes and two events, nothing else. It sets these attributes:
|
||||
|
||||
- `record-id` (empty on the create form), `field-name`, `locale`, `fill-values` (the current values of the `fill` fields as JSON, updated as the form changes), `label` and `busy-label`;
|
||||
- `busy` while a request runs, removed when it ends;
|
||||
- `state` set to `error` after a failed action, removed when the next one starts;
|
||||
- `data` holding the serialized response data after a successful action, removed when the answer carried none.
|
||||
|
||||
The events:
|
||||
|
||||
- `summer-action` is dispatched by the element (with `bubbles` and `composed`) to ask for its action. Its optional `detail.payload` is any JSON value; the SPA posts it as `payload`. A detail without a `payload` property sends none.
|
||||
- `summer-result` is dispatched by the SPA on the element after a successful action, with `detail` `{data, fill, message}`: the response data as returned (`undefined` when none), the fill object and the message. A failed action dispatches nothing.
|
||||
|
||||
The element never receives a token, a cookie, a Vue instance or a function, and it must not make requests of its own: the SPA owns HTTP and the admin session. Render server data with `textContent`, not `innerHTML`: `data` is the plugin's own answer, but it still came over the wire. The `acme-demo-lookup` fixture under `modules/cabana/testdata/extension/assets/js/lookup.js` is a complete reorder widget: a click sends the new id order as the payload and the returned item list is rendered from the `data` attribute and the `summer-result` event.
|
||||
|
||||
## Toolbar actions
|
||||
|
||||
Names in `toolbar.buttons` of `config_list.yaml`, other than the built-in `create` and `delete`, are actions the controller registers through `pact.HasAdminActions`. Each needs a label. A toolbar action runs with an empty body and no record IDs, so it can never become an unscoped lookup of IDs the client chose. The list schema lists only the actions the administrator may run.
|
||||
|
||||
Reference in New Issue
Block a user