Table actions DSL

v0.0.1

The row_actions, row and bulk_actions sections of a resource's table block declare the buttons on each row, the behavior of a row and the actions on a selection of rows.

row_actions.actions_layout

Names which actions draw inline and which collapse into a dropdown. It sits at mishka_gervaz.table.row_actions.actions_layout.

OptionTypeDefaultDescription
position:start | :end:endWhich side of the row holds the actions. The value is compiled into the config, but no built-in template or handler reads it.
stickybooleantrueStick on horizontal scroll.
inlinelist(atom)noneNames of the actions drawn as buttons. Gervaz does not check the names, and a name that matches no action draws nothing. Once this list or dropdown is set, an action that neither names is not drawn.
dropdownlist(atom)[]Names of the dropdown blocks to draw. A dropdown draws only when this list names it.
auto_collapse_afterintegernoneMeant to fold every action past the Nth into the dropdown. The value is compiled into the config, but no built-in template or handler reads it.

row_actions.action

Declares one per-row action. The inline form works too: action :expand, type: :accordion. It sits at mishka_gervaz.table.row_actions.action.

Call: action name

Arguments:

ArgumentTypeDefaultDescription
nameatomnoneRequired. Action identifier.

Options:

OptionTypeDefaultDescription
type:link | :modal | :event | :edit | :destroy | :update | :accordion | :unarchive | :permanent_destroy | :row_click | modulenoneRequired. The action type. Built-in types: :link, :modal, :event, :edit, :destroy, :update, :accordion, :unarchive, :permanent_destroy and :row_click. A module that implements the ActionType behaviour also works. The built-in registry has no :modal entry. See Built-in types.
pathString.t | (any -> any)noneThe link path for :link. A string is used as written, or give a function of the record. An action named :show or :edit goes to the table's route instead of a string path.
eventatom | String.tnoneEvent name to send.
actionatom | {atom, atom}noneThe Ash action an :update action runs: an atom, or a tuple {master_action, tenant_action}.
payload(any -> any)noneEvent payload function fn record -> payload.
confirmString.t | (any -> any)noneA confirmation message shown before the action runs: a string, or a function of the record. Gervaz shows the text as written. The :link and :accordion types ignore it.
restrictedbooleanfalseWhen true, only master users see the action.
visibleboolean | :active | :archived | (any, any -> any):activeWhen the action shows. :active (the default) shows it for active records, :archived for archived records, true always and false never. A function fn record, state -> boolean decides for itself.
js(any -> any)noneJS commands chained onto the click: fn record -> JS.exec(...) end. Only the :edit type reads it.
render(any -> any) | (any, any -> any) | (any, any, any -> any)noneCustom HEEx for the control: fn record -> ... end, fn record, action -> ... end or fn record, action, target -> ... end.

action ui

How the action button is drawn. It sits at mishka_gervaz.table.row_actions.action.ui.

OptionTypeDefaultDescription
labelString.t | (-> any)noneButton label. String or fn -> "Label" end for gettext. Defaults to humanized action name.
iconString.tnoneIcon identifier.
classString.tnoneCSS classes.
extramap%{}Template-specific options. The value is compiled into the config, but no built-in template or handler reads it.

row_actions.dropdown

A dropdown menu of actions. It requires a ui block with a label. It sits at mishka_gervaz.table.row_actions.dropdown.

Call: dropdown name

Arguments:

ArgumentTypeDefaultDescription
nameatomnoneRequired. Dropdown identifier.

dropdown action

An action nested in a dropdown. It takes the same options as a top-level action. It sits at mishka_gervaz.table.row_actions.dropdown.action.

Call: action name

Arguments:

ArgumentTypeDefaultDescription
nameatomnoneRequired. Action identifier.

Options:

OptionTypeDefaultDescription
type:link | :modal | :event | :edit | :destroy | :update | :accordion | :unarchive | :permanent_destroy | :row_click | modulenoneRequired. The action type. Built-in types: :link, :modal, :event, :edit, :destroy, :update, :accordion, :unarchive, :permanent_destroy and :row_click. A module that implements the ActionType behaviour also works. The built-in registry has no :modal entry. See Built-in types.
pathString.t | (any -> any)noneThe link path for :link. A string is used as written, or give a function of the record. An action named :show or :edit goes to the table's route instead of a string path.
eventatom | String.tnoneEvent name to send.
actionatom | {atom, atom}noneThe Ash action an :update action runs: an atom, or a tuple {master_action, tenant_action}.
payload(any -> any)noneEvent payload function fn record -> payload.
confirmString.t | (any -> any)noneA confirmation message shown before the action runs: a string, or a function of the record. Gervaz shows the text as written. The :link and :accordion types ignore it.
restrictedbooleanfalseWhen true, only master users see the action.
visibleboolean | :active | :archived | (any, any -> any):activeWhen the action shows. :active (the default) shows it for active records, :archived for archived records, true always and false never. A function fn record, state -> boolean decides for itself.
js(any -> any)noneJS commands chained onto the click: fn record -> JS.exec(...) end. Only the :edit type reads it.
render(any -> any) | (any, any -> any) | (any, any, any -> any)noneCustom HEEx for the control: fn record -> ... end, fn record, action -> ... end or fn record, action, target -> ... end.

separator

A divider in the dropdown. It sits at mishka_gervaz.table.row_actions.dropdown.separator.

OptionTypeDefaultDescription
labelString.tnoneOptional separator label.

dropdown ui

How the dropdown trigger is drawn. It sits at mishka_gervaz.table.row_actions.dropdown.ui.

OptionTypeDefaultDescription
labelString.t | (-> any)noneRequired. Button label. String or fn -> "Label" end for gettext. The built-in dropdown button draws only its icon.
iconString.tnoneIcon identifier.
classString.tnoneCSS classes. The built-in dropdown button draws only its icon.
extramap%{}Template-specific options. The built-in dropdown button draws only its icon.

row

Selection, row click, per-row classes and whole-row replacement. It sits at mishka_gervaz.table.row.

OptionTypeDefaultDescription
eventString.tnoneThe event a click on the row sends. The value is compiled into the config, but no built-in template or handler reads it.
payload(any -> any) | mapnonePayload for row click. Map or fn record -> map. The value is compiled into the config, but no built-in template or handler reads it.
selectablebooleanfalseDeclares that rows can be selected. This makes source.actions.get required. The checkboxes appear when the template has the :select feature and at least one bulk action is visible, whatever this option says.

class

Per-row classes. It sits at mishka_gervaz.table.row.class.

OptionTypeDefaultDescription
possiblelist(String.t)[]Every class that apply can return. Tailwind scans source files, so listing the literals here keeps them in the build. Nothing reads the list at runtime.
apply(any -> any)noneReturns the class for one row: fn record -> class | nil.

override

Replaces how a row is drawn. It sits at mishka_gervaz.table.row.override.

OptionTypeDefaultDescription
componentatomnoneA LiveComponent that draws the whole row.
render(any, any, any -> any)noneA function that draws the whole row: fn assigns, record, columns -> HEEx.
condition(any -> any)noneThe override applies only when fn record -> boolean returns true.

bulk_actions

Actions on a selection of rows. At least one action is required in the block. It sits at mishka_gervaz.table.bulk_actions.

OptionTypeDefaultDescription
enabledbooleantrueEnable bulk actions. Setting it to false has no effect in the built-in action builder.

action

Declares one bulk action. The inline form works too: action :archive, type: :destroy, confirm: "Archive selected?". It sits at mishka_gervaz.table.bulk_actions.action.

Call: action name

Arguments:

ArgumentTypeDefaultDescription
nameatomnoneRequired. Action identifier.

Options:

OptionTypeDefaultDescription
type:event | :destroy | :update | :unarchive | :permanent_destroynoneA built-in type resolves the handler for you. :event sends an event to the parent LiveView. :destroy soft-deletes with source.actions.destroy. :update runs the Ash action in action. :unarchive restores with the archive restore action. :permanent_destroy deletes archived records with the archive destroy action. When both type and handler are set, handler wins.
actionatom | {atom, atom}noneThe Ash action an :update bulk action runs: an atom, or a tuple {master_action, tenant_action}.
confirmboolean | String.tnoneThe text of the confirmation dialog. true has no default message. {count} becomes the number of rows the action runs on: the checked rows, or with select all the table's total minus the unchecked rows. With select all, {count} stays as written for a :load_more or :infinite table with show_total false while rows are left to load.
eventatomnoneEvent name for :event type. Defaults to action name if not specified.
payload(any -> any)noneThe payload sent with an event: fn selected_ids -> payload. The value is compiled into the config, but no built-in template or handler reads it.
restrictedbooleanfalseShows the action only to master users.
visible:active | :archived | (any -> any):activeWhen the action shows: :active (the default) or :archived, or a function fn state -> boolean.
handleratom | (any, any -> any) | {atom, atom}:parentWho runs the action. :parent (the default) sends {:bulk_action, name, selected_ids} to the parent LiveView. A function fn selected_ids, state -> {:ok, state} runs in the component. An atom names an Ash action, and a tuple {master_action, tenant_action} names one for each role. A built-in type atom acts as type. With type set, the handler is resolved from it.

action ui

How the bulk action button is drawn. It sits at mishka_gervaz.table.bulk_actions.action.ui.

OptionTypeDefaultDescription
labelString.t | (-> any)noneButton label. String or fn -> "Label" end for gettext.
iconString.tnoneIcon identifier.
classString.tnoneCSS classes.
extramap%{}Template-specific options. The value is compiled into the config, but no built-in template or handler reads it.