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:
@@ -67,6 +67,11 @@ func compileExtension(pluginID string, cc *CompiledController, fsys fs.FS) error
|
||||
return fmt.Errorf("cabana: admin controller %s/%s: %w", pluginID, id, err)
|
||||
}
|
||||
cc.Actions = actions
|
||||
bulkActions, err := compileBulkActions(cc.Controller)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cabana: admin controller %s/%s: %w", pluginID, id, err)
|
||||
}
|
||||
cc.BulkActions = bulkActions
|
||||
if err := compileClientAssets(pluginID, cc, fsys); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -276,3 +281,30 @@ func compileActions(ctl pact.AdminController) (map[string]pact.AdminAction, erro
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// compileBulkActions collects a controller's registered bulk actions. They
|
||||
// have their own namespace next to the toolbar and widget actions: a name is
|
||||
// unique among the bulk actions, and create and delete stay reserved.
|
||||
func compileBulkActions(ctl pact.AdminController) (map[string]pact.AdminBulkAction, error) {
|
||||
out := map[string]pact.AdminBulkAction{}
|
||||
src, ok := ctl.(pact.HasAdminBulkActions)
|
||||
if !ok || src == nil {
|
||||
return out, nil
|
||||
}
|
||||
for _, action := range src.AdminBulkActions() {
|
||||
if !identifier(action.Name) {
|
||||
return nil, fmt.Errorf("bulk action name %q is not an identifier", action.Name)
|
||||
}
|
||||
if builtinToolbarActions[action.Name] {
|
||||
return nil, fmt.Errorf("bulk action %s uses a reserved built-in name (create, delete)", action.Name)
|
||||
}
|
||||
if _, dup := out[action.Name]; dup {
|
||||
return nil, fmt.Errorf("duplicate bulk action %s", action.Name)
|
||||
}
|
||||
if action.Run == nil {
|
||||
return nil, fmt.Errorf("bulk action %s has no Run function", action.Name)
|
||||
}
|
||||
out[action.Name] = action
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user