ObjectStackObjectStack

Bulk Action

Bulk Action protocol schemas

Bulk Action Schemas

The vocabulary of a list view's bulkActionDefs — one entry per button in the multi-select toolbar. Use a def for a mass data-plane mutation that no action expresses (operation: 'update' with a patch, or 'delete'), or for an operation: 'custom' + execution: 'aggregate' entry that dispatches the action it NAMES once for the whole selection.

For the per-record dispatch, name the action in the view's bulkActions: ['<name>'] instead — the bare-string form, promoted with the action's own label, params and visible.

Source: packages/spec/src/ui/bulk-action.zod.ts

TypeScript Usage

import { BulkActionDefSchema, BulkActionExecutionSchema, BulkActionOperationSchema, BulkActionParamSchema } from '@objectstack/spec/ui';
import type { BulkActionDef, BulkActionExecution, BulkActionOperation, BulkActionParam } from '@objectstack/spec/ui';

// Validate data
const result = BulkActionDefSchema.parse(data);

BulkActionDef

Properties

PropertyTypeRequiredDescription
namestringStable identifier — the audit-log action key, and (for an aggregate def) the name of the object action to dispatch.
labelstringoptionalButton + dialog-header text. Plain string: an authored def is not i18n-resolved (declare a real action and name it in bulkActions to get localization).
iconstringoptionalLucide icon name (e.g. "user-check", "trash-2").
variantEnum<'primary' | 'secondary' | 'danger' | 'ghost' | 'outline'>optionalVisual treatment of the button.
operationEnum<'update' | 'delete' | 'custom'>What the executor does: 'update'/'delete' are data-plane mass mutations; 'custom' dispatches an object action (see execution).
executionEnum<'perRecord' | 'aggregate'>optionalFor operation: 'custom' — 'aggregate' dispatches the named action ONCE for the whole selection, carrying every id in params._selectedIds (objectui#3139). Required on a custom def: the per-record form is declared as bulkActions: ['<name>'] instead.
patchRecord<string, any>optionalFor operation: 'update' — static field values applied to every selected record, merged UNDER the user-supplied params so a fixed value can be declared without exposing it in the dialog.
params({ name: string; label?: string; help?: string; type: Enum<'text' | 'textarea' | 'email' | 'url' | 'phone' | 'password' | 'secret' | …>; … } & Record<string, any>)[]optionalInputs collected once before the run. Omit to skip the params step and go straight to confirm.
confirmTextstringoptionalConfirmation text shown above the affected-record summary.
confirmLabelstringoptionalCustom Confirm button label (default: "Run").
visiblestring | { dialect: Enum<'cel' | 'cron' | 'template'>; source?: string; ast?: any; meta?: object }optionalEligibility predicate (CEL) — a string or a {dialect, source} envelope, i.e. action.visible without its boolean-literal arm (#5970): a per-record predicate has nothing to say as a constant. Evaluated once PER SELECTED RECORD with that record bound: the button is offered when at least one passes, the run covers only those, and the rest are reported as skipped. A record-free predicate (features.x, current_user.y) therefore behaves as a plain button-level gate. Fail-closed — a predicate that faults excludes the record.
requiredPermissionsstring[]optional[ADR-0066 D4] Capability gate on the button, action.requiredPermissions semantics verbatim: absent or empty always passes, several are AND-ed, and a client that cannot resolve the caller's capabilities fails OPEN (the server stays the authority). This key exists for INLINE defs — notably the update/delete data-plane forms, which dispatch no action and so have nothing to inherit a gate from; a def promoted from bulkActions: ['<name>'] (or an aggregate def naming a declared action) inherits the action's own declaration instead. On a data-plane def the gate governs visibility only — the write itself is still authorized by the data API's object permissions and server hooks.
maxRecordsintegeroptionalSelection size above which the run is blocked. Set it on defs whose server work is expensive — an aggregate def carries every selected id in one request.
batchSizeintegeroptionalRecords per executor batch (default 200). Data-plane operations only — an aggregate run is a single call by definition.

BulkActionExecution

Allowed Values

  • perRecord
  • aggregate

BulkActionOperation

Allowed Values

  • update
  • delete
  • custom

BulkActionParam

Properties

PropertyTypeRequiredDescription
namestringParam key — becomes params[name] in the patch / action params bag.
labelstringoptionalField label in the dialog. Plain string: an authored def is not i18n-resolved (see module header).
helpstringoptionalHelp text under the field. (An ActionParam spells this helpText — known divergence, module header.)
typeEnum<'text' | 'textarea' | 'email' | 'url' | 'phone' | 'password' | 'secret' | 'markdown' | 'html' | 'richtext' | 'number' | 'currency' | 'percent' | 'date' | … +35 more>Field widget to render, from the standard field-type vocabulary (text/number/select/lookup/date/…).
requiredbooleanoptionalBlocks the Confirm button until a value is present.
defaultanyoptionalValue applied when the dialog opens. (An ActionParam spells this defaultValue.)
options({ label: string; value: string | number | boolean } & Record<string, any>)[]optionalStatic options for select-style widgets. Each entry is { label, value } plus any extra widget config — the entry is open (.passthrough()) because the renderer forwards unknown option keys to the field widget, which reads color / icon / disabled / visibleWhen beyond the declared pair.
objectstringoptionalTarget object for a lookup widget. (An ActionParam spells this reference.)
labelFieldstringoptionalRelated-object field used as the option label for a lookup widget (defaults to name/full_name/email/id).
multiplebooleanoptionalAllow picking multiple values — the param value becomes an array and is written to the patch as-is.
placeholderstringoptionalPlaceholder text.

Allowed Values: BulkActionParam.type

  • text
  • textarea
  • email
  • url
  • phone
  • password
  • secret
  • markdown
  • html
  • richtext
  • number
  • currency
  • percent
  • date
  • datetime
  • time
  • boolean
  • toggle
  • select
  • multiselect
  • radio
  • checkboxes
  • lookup
  • master_detail
  • tree
  • user
  • image
  • file
  • avatar
  • video
  • audio
  • formula
  • summary
  • autonumber
  • composite
  • repeater
  • record
  • location
  • address
  • code
  • json
  • color
  • rating
  • slider
  • signature
  • qrcode
  • progress
  • tags
  • vector

On this page