MishkaGervaz.Table.Web.Events.BulkActionHandler behaviour
(MishkaGervaz v0.0.1-alpha.3)
Copy Markdown
View Source
Handles bulk action execution for Events module.
Runs Ash bulk operations on the selection, classifies the outcome, and routes through the lifecycle hooks before falling back to a sensible default flash.
Lifecycle (Ash bulk paths)
Per bulk action:
:after_bulk_actionruns with(summary, state)regardless of outcome.- Branch on
summary.status::success—:on_bulk_action_successruns; no default flash (the table reload is the user-visible feedback).:partial_success—:on_bulk_action_successruns first; if the hook returns the socket, a default info flash fires ("X succeeded, Y failed."). Hooks return{:halt, socket}to suppress the default.:error—:on_bulk_action_errorruns first; same override semantics, defaulting to the formatted error flash. The selection is preserved so the user can retry.
- For the unarchive partial-skip path (rows whose identity is already
taken by an active row),
:on_bulk_action_successruns with a summary whose:skipped_count/:skipped_record_idsdescribe the skipped rows; default flash is"X unarchived, Y skipped — a record with the same name already exists.". Skipped rows stay selected.
See MishkaGervaz.Table.Web.Events.BulkActionResult for the summary
shape; MishkaGervaz.Table.Web.Events.BulkActionHooks for silence/1
and use_default/1.
Customization
Two layers of customization:
1. Replace the handler module for full control:
defmodule MyApp.CustomBulkActionHandler do
use MishkaGervaz.Table.Web.Events.BulkActionHandler
def execute_ash_bulk_action(action, ash_action, selected_ids, state, socket) do
MyApp.Logger.info("bulk", action: ash_action, count: length(selected_ids))
super(action, ash_action, selected_ids, state, socket)
end
endWired in the DSL:
mishka_gervaz do
table do
events do
bulk_action MyApp.CustomBulkActionHandler
end
end
end2. Just adjust messaging via per-action hooks (most common):
hooks do
on_bulk_action_success :master_destroy, fn summary, _state, socket ->
socket
|> Phoenix.LiveView.put_flash(:info, "#{summary.succeeded_count} deleted.")
|> MishkaGervaz.Table.Web.Events.BulkActionHooks.silence()
end
on_bulk_action_error :master_destroy, fn summary, _state, socket ->
Logger.error("delete failed: #{inspect(summary.failed_errors)}")
MishkaGervaz.Table.Web.Events.BulkActionHooks.silence(socket)
end
endSee MishkaGervaz.Table.Web.Events,
MishkaGervaz.Table.Entities.BulkAction,
MishkaGervaz.Table.Web.DataLoader,
MishkaGervaz.Table.Web.Events.BulkActionResult,
MishkaGervaz.Table.Web.Events.BulkActionHooks,
and the sibling handlers SanitizationHandler, RecordHandler,
SelectionHandler, HookRunner, RelationFilterHandler.
Summary
Callbacks
Builds a query for bulk operations.
Executes a bulk action based on its handler type.
Executes an Ash bulk action.
Types
@type bulk_action() :: map()
@type socket() :: Phoenix.LiveView.Socket.t()
@type state() :: MishkaGervaz.Table.Web.State.t()
Callbacks
@callback build_bulk_query( resource :: module(), state :: state(), filter :: {:exclude, list()} | nil ) :: Ash.Query.t()
Builds a query for bulk operations.
Applies any necessary filters based on the selection.
@callback execute( bulk_action :: bulk_action() | nil, selected_ids :: selected_ids(), state :: state(), socket :: socket() ) :: {:noreply, socket()}
Executes a bulk action based on its handler type.
Dispatches to the appropriate handler: :parent, function, or Ash action.
@callback execute_ash_bulk_action( action :: bulk_action(), ash_action :: atom(), selected_ids :: selected_ids(), state :: state(), socket :: socket() ) :: {:noreply, socket()}
Executes an Ash bulk action.
Handles both bulk_update and bulk_destroy based on action type.