KQ-1683 · BATCH/RUNNER
Batch Runner
A bulk-action dialog that confirms its scope as one small cell per item, then runs inside itself: a soft band glides down the grid a row at a time on springs.glide while each cell under it is stamped done on springs.flick, so every row reads as a ripple, and failures fill red with their reason and never bounce. Escape pauses after the item in flight, Stop leaves the rest untouched, and finishing folds the live counts into one plain sentence with the failures grouped by reason; Retry failed reruns only the red cells. The action is a roving radiogroup and the cells a role="grid" with one tab stop, arrows, Home/End and Page keys.
Archive 248 conversations?
From Open · Coldbrook Support
Arrow keys move between cells, Home and End to the ends of a row, Page Up and Page Down five rows. Escape pauses a run.
They leave the inbox and keep their history. A new reply brings a conversation back.
248 selected · confirm to run
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/batch-runner
Props
- items
- BatchItem[]
- default defaultBatchItems
- The selection, in reading order: { id, label, detail?, error?, recovers? } (error and recovers drive the built-in simulation only).
- actions
- BatchAction[]
- default defaultBatchActions
- The actions in the picker: { id, label, past, progressive, description, icon?, targetLabel?, targets? }.
- action / defaultAction
- string
- default — / first action
- The chosen action, controlled or initial.
- onActionChange
- (action: string) => void
- default —
- Fires from the press or key that picked another action.
- run
- (item, { action, target, attempt }) => void | Promise<void>
- default simulated
- The work for one item, called one at a time in reading order; a throw or rejection fails it with the error's message as its reason.
- pace
- number
- default 24
- Milliseconds per item for the built-in simulation; a retry takes at least 280ms per item so each can be seen.
- autoStart
- boolean
- default false
- Start the run by itself the first time the dialog scrolls into view.
- itemLabel
- { one: string; other: string }
- default { one: "conversation", other: "conversations" }
- What one item is called, in titles, counts and the summary.
- source
- string
- default "From Open · Coldbrook Support"
- Where the selection came from, under the title.
- onRun
- ({ action, target, ids }) => void
- default —
- The primary press started the run.
- onRetry
- (ids: string[]) => void
- default —
- Retry failed was pressed, with the ids it reruns.
- onCancel
- (progress: { done, failed, left }) => void
- default —
- Cancel (before the run) or Stop (during it) was pressed.
- onPauseChange
- (paused: boolean) => void
- default —
- The run paused (Escape or Pause) or resumed.
- onProgress
- (progress: { done, failed, left }) => void
- default —
- Fires as each item lands, with counts across the whole selection.
- onComplete
- (summary: BatchSummary) => void
- default —
- A pass finished or stopped: totals, failures grouped by reason, and whether it was cancelled.
- onClose
- () => void
- default —
- Done was pressed, or Escape on the summary.
- cellShape
- "square" | "round" | "bar"
- default "square"
- Rounded squares, dots, or tall tally bars that fold the selection into fewer, taller rows.
- cellSize
- number
- default 11
- The largest cell edge in px; cells shrink below it to keep the grid under maxGridHeight.
- palette
- "cobalt" | "moss" | "graphite" | "dusk"
- default "cobalt"
- The done pigment, the row band and the progress line; failures stay red in every palette.
- maxGridHeight
- number
- default 200
- Tallest the grid may grow, px, before its cells shrink to fit.
- status
- "ready" | "loading" | "error"
- default "ready"
- Loading shows breathing placeholder cells and holds the primary; error offers Try again.
- onReload
- () => void
- default —
- Try again was pressed after the selection failed to load.
- modal
- boolean
- default false
- Trap Tab inside the dialog and set aria-modal; pass it when you render it in an overlay.
- disabled
- boolean
- default false
- Nothing can be started, paused or retried.
- className
- string
- default —
- Classes for the dialog panel.
| Prop | Type | Default | Description |
|---|---|---|---|
| items | BatchItem[] | defaultBatchItems | The selection, in reading order: { id, label, detail?, error?, recovers? } (error and recovers drive the built-in simulation only). |
| actions | BatchAction[] | defaultBatchActions | The actions in the picker: { id, label, past, progressive, description, icon?, targetLabel?, targets? }. |
| action / defaultAction | string | — / first action | The chosen action, controlled or initial. |
| onActionChange | (action: string) => void | — | Fires from the press or key that picked another action. |
| run | (item, { action, target, attempt }) => void | Promise<void> | simulated | The work for one item, called one at a time in reading order; a throw or rejection fails it with the error's message as its reason. |
| pace | number | 24 | Milliseconds per item for the built-in simulation; a retry takes at least 280ms per item so each can be seen. |
| autoStart | boolean | false | Start the run by itself the first time the dialog scrolls into view. |
| itemLabel | { one: string; other: string } | { one: "conversation", other: "conversations" } | What one item is called, in titles, counts and the summary. |
| source | string | "From Open · Coldbrook Support" | Where the selection came from, under the title. |
| onRun | ({ action, target, ids }) => void | — | The primary press started the run. |
| onRetry | (ids: string[]) => void | — | Retry failed was pressed, with the ids it reruns. |
| onCancel | (progress: { done, failed, left }) => void | — | Cancel (before the run) or Stop (during it) was pressed. |
| onPauseChange | (paused: boolean) => void | — | The run paused (Escape or Pause) or resumed. |
| onProgress | (progress: { done, failed, left }) => void | — | Fires as each item lands, with counts across the whole selection. |
| onComplete | (summary: BatchSummary) => void | — | A pass finished or stopped: totals, failures grouped by reason, and whether it was cancelled. |
| onClose | () => void | — | Done was pressed, or Escape on the summary. |
| cellShape | "square" | "round" | "bar" | "square" | Rounded squares, dots, or tall tally bars that fold the selection into fewer, taller rows. |
| cellSize | number | 11 | The largest cell edge in px; cells shrink below it to keep the grid under maxGridHeight. |
| palette | "cobalt" | "moss" | "graphite" | "dusk" | "cobalt" | The done pigment, the row band and the progress line; failures stay red in every palette. |
| maxGridHeight | number | 200 | Tallest the grid may grow, px, before its cells shrink to fit. |
| status | "ready" | "loading" | "error" | "ready" | Loading shows breathing placeholder cells and holds the primary; error offers Try again. |
| onReload | () => void | — | Try again was pressed after the selection failed to load. |
| modal | boolean | false | Trap Tab inside the dialog and set aria-modal; pass it when you render it in an overlay. |
| disabled | boolean | false | Nothing can be started, paused or retried. |
| className | string | — | Classes for the dialog panel. |