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:

  1. :after_bulk_action runs with (summary, state) regardless of outcome.
  2. Branch on summary.status:
    • :success:on_bulk_action_success runs; no default flash (the table reload is the user-visible feedback).
    • :partial_success:on_bulk_action_success runs 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_error runs first; same override semantics, defaulting to the formatted error flash. The selection is preserved so the user can retry.
  3. For the unarchive partial-skip path (rows whose identity is already taken by an active row), :on_bulk_action_success runs with a summary whose :skipped_count / :skipped_record_ids describe 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
end

Wired in the DSL:

mishka_gervaz do
  table do
    events do
      bulk_action MyApp.CustomBulkActionHandler
    end
  end
end

2. 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
end

See 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.

Types

bulk_action()

@type bulk_action() :: map()

selected_ids()

@type selected_ids() :: list() | :all | {:all_except, list()}

socket()

@type socket() :: Phoenix.LiveView.Socket.t()

state()

@type state() :: MishkaGervaz.Table.Web.State.t()

Callbacks

build_bulk_query(resource, state, filter)

@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.

execute(bulk_action, selected_ids, state, socket)

@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.

execute_ash_bulk_action(action, ash_action, selected_ids, state, socket)

@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.