feat(12.1-01): declared bulk actions on admin lists

- pact.HasAdminBulkActions with AdminBulkAction, its input and result
- config_list.yaml bulkActions, compiled fail-loud, needs showCheckboxes
- POST .../{controller}/bulk/{action}: ids resolved and locked through the
  list scope in one transaction; partial selection is 409
- list schema offers declared actions per principal, with confirm text
- admin SPA bulk actions menu with confirm, busy state and failure toasts
- acme.roster fixture, tracer test, OpenAPI, TS types, dist, READMEs, docs
This commit is contained in:
Jakub Zych
2026-10-04 23:28:30 +02:00
parent ca9e9c0557
commit a879d6388c
45 changed files with 2007 additions and 38 deletions

View File

@@ -396,6 +396,28 @@ func AdminCreate() {}
// @Router /{vendor}/{plugin}/{controller}/bulk-delete [post]
func AdminBulkDelete() {}
// AdminBulkAction documents the declared bulk action route.
//
// @Summary Run a declared bulk action
// @Description Runs a bulk action the controller registers and the list's bulkActions declares. The ids are resolved and row-locked through the controller's list scope in one transaction before the action runs: a selection that matches no scoped row answers affected 0 without running the action, and a partial selection is a 409 that changes nothing.
// @Tags admin
// @Accept json
// @Produce json
// @Security BackendBearer
// @Param vendor path string true "Vendor"
// @Param plugin path string true "Plugin"
// @Param controller path string true "Controller"
// @Param action path string true "Bulk action name"
// @Param body body AdminIDsRequest true "Record ids"
// @Success 200 {object} Envelope[BulkActionResult]
// @Failure 401 {object} ErrorEnvelope
// @Failure 403 {object} ErrorEnvelope
// @Failure 404 {object} ErrorEnvelope
// @Failure 409 {object} ErrorEnvelope
// @Failure 422 {object} ErrorEnvelope
// @Router /{vendor}/{plugin}/{controller}/bulk/{action} [post]
func AdminBulkAction() {}
// AdminActionRequest is the body of a widget or toolbar action. record_id is
// the record a widget on the update form belongs to (absent on create and
// always absent for a toolbar action); values is the widget's snapshot of its