MishkaGervaz.Table.Web.State (MishkaGervaz v0.0.2)

Copy Markdown View Source

Single state struct for MishkaGervaz table.

All table state is held in this struct rather than in separate assigns.

State shape

State is split into two parts:

  • static - Configuration that never changes (same reference for O(1) comparison)
  • Dynamic fields - User interaction state that triggers re-renders

This separation allows LiveView to skip re-rendering static parts (columns, filters, etc.) when only dynamic state (page, filter_values, etc.) changes.

Sub-builders

State initialization is composed of sub-builders that can be overridden:

  • ColumnBuilder - Builds columns from DSL and resource
  • FilterBuilder - Builds filters from DSL and resource
  • ActionBuilder - Builds row/bulk actions
  • Presentation - Resolves UI adapter and templates
  • UrlSync - Handles URL state synchronization
  • Access - Handles access control

User Override

Override the entire state module:

defmodule MyApp.Table.State do
  use MishkaGervaz.Table.Web.State

  def init(id, resource, user) do
    state = super(id, resource, user)
    %{state | custom_field: :value}
  end
end

Override specific sub-builders:

defmodule MyApp.Table.State do
  use MishkaGervaz.Table.Web.State,
    column: MyApp.Table.ColumnBuilder,
    filter: MyApp.Table.FilterBuilder
end

Or override via DSL:

mishka_gervaz do
  table do
    state do
      column MyApp.Table.ColumnBuilder
      filter MyApp.Table.FilterBuilder
    end
  end
end

Override entire state module via DSL:

mishka_gervaz do
  table do
    state module: MyApp.Table.CustomState
  end
end

Helper Functions

Helper functions are available in MishkaGervaz.Table.Web.State.Helpers and can be used when overriding state functions:

defmodule MyApp.Table.State do
  use MishkaGervaz.Table.Web.State
  alias MishkaGervaz.Table.Web.State.Helpers, as: StateHelpers

  def hydrate_relation_filter_labels(state) do
    # Use helpers in your override
    StateHelpers.hydrate_filter(filter, acc, state)
  end
end

See MishkaGervaz.Table.Web.State.Helpers, MishkaGervaz.Table.Web.State.ColumnBuilder, MishkaGervaz.Table.Web.State.FilterBuilder, MishkaGervaz.Table.Web.State.ActionBuilder, MishkaGervaz.Table.Web.State.Presentation, MishkaGervaz.Table.Web.State.UrlSync, MishkaGervaz.Table.Web.State.Access, MishkaGervaz.Table.Web.AutoState, MishkaGervaz.Table.Web.Refresh, MishkaGervaz.Table.Web.UrlSync.

Summary

Functions

Applies a mount's own presentation choices over the resource's — see the __using__ version.

See MishkaGervaz.Table.Web.State.Default.apply_url_state/2.

See MishkaGervaz.Table.Web.State.Default.bidirectional_url_sync?/1.

See MishkaGervaz.Table.Web.State.Default.can_modify_record?/2.

See MishkaGervaz.Table.Web.State.Default.default_init/3.

See MishkaGervaz.Table.Web.State.Default.get_action/2.

See MishkaGervaz.Table.Web.State.Default.get_preloads/1.

Hydrate relation filter state with labels for selected values from URL

See MishkaGervaz.Table.Web.State.Default.init/3.

See MishkaGervaz.Table.Web.State.Default.record_visible?/2.

See MishkaGervaz.Table.Web.State.Default.switch_template/2.

See MishkaGervaz.Table.Web.State.Default.template_switching_enabled?/1.

See MishkaGervaz.Table.Web.State.Default.update/2.

Types

archive_status()

@type archive_status() :: :active | :archived

loading_status()

@type loading_status() :: :initial | :loading | :loaded | :error

loading_type()

@type loading_type() :: :initial | :reset | :more

t()

@type t() :: %MishkaGervaz.Table.Web.State{
  archive_status: archive_status(),
  base_path: String.t() | nil,
  current_page_size: pos_integer() | nil,
  current_user: map() | nil,
  dismissed_notices: MapSet.t(),
  excluded_ids: MapSet.t(any()),
  expanded_data: struct() | nil,
  expanded_id: String.t() | nil,
  filter_values: map(),
  has_initial_data?: boolean(),
  has_more?: boolean(),
  loaded_records: list(),
  loading: loading_status(),
  loading_type: loading_type(),
  master_user?: boolean(),
  page: integer(),
  path_params: map(),
  preload_aliases: %{required(atom()) => atom()},
  preserved_params: map(),
  records_result: struct(),
  relation_filter_state: %{required(atom()) => map()},
  saved_active_state: map() | nil,
  saved_archived_state: map() | nil,
  select_all?: boolean(),
  selected_ids: MapSet.t(any()),
  sort_fields: [{atom(), :asc | :desc}],
  static: MishkaGervaz.Table.Web.State.Static.t(),
  supports_archive: boolean(),
  template: module(),
  total_count: integer() | nil,
  total_pages: integer() | nil
}

Functions

apply_presentation(state, assigns)

Applies a mount's own presentation choices over the resource's — see the __using__ version.

apply_url_state(state, url_state)

@spec apply_url_state(t(), map() | nil) :: t()

See MishkaGervaz.Table.Web.State.Default.apply_url_state/2.

bidirectional_url_sync?(state)

@spec bidirectional_url_sync?(t()) :: boolean()

See MishkaGervaz.Table.Web.State.Default.bidirectional_url_sync?/1.

can_modify_record?(state, record)

@spec can_modify_record?(t(), map()) :: boolean()

See MishkaGervaz.Table.Web.State.Default.can_modify_record?/2.

default_init(id, resource, current_user)

@spec default_init(String.t(), module(), map() | nil) :: t()

See MishkaGervaz.Table.Web.State.Default.default_init/3.

get_action(state, action_type)

@spec get_action(t(), atom()) :: atom()

See MishkaGervaz.Table.Web.State.Default.get_action/2.

get_preloads(state)

@spec get_preloads(t()) :: [atom()]

See MishkaGervaz.Table.Web.State.Default.get_preloads/1.

hydrate_relation_filter_labels(state)

@spec hydrate_relation_filter_labels(t()) :: t()

Hydrate relation filter state with labels for selected values from URL

init(id, resource, current_user)

@spec init(String.t(), module(), map() | nil) :: t()

See MishkaGervaz.Table.Web.State.Default.init/3.

record_visible?(state, record)

@spec record_visible?(t(), map()) :: boolean()

See MishkaGervaz.Table.Web.State.Default.record_visible?/2.

switch_template(state, template)

@spec switch_template(t(), atom()) :: {:ok, t()} | {:error, :template_not_allowed}

See MishkaGervaz.Table.Web.State.Default.switch_template/2.

template_switching_enabled?(state)

@spec template_switching_enabled?(t()) :: boolean()

See MishkaGervaz.Table.Web.State.Default.template_switching_enabled?/1.

update(state, updates)

@spec update(t(), keyword() | map()) :: t()

See MishkaGervaz.Table.Web.State.Default.update/2.