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

Copy Markdown View Source

Helper functions for MishkaGervaz.Table.Web.State.

Extracted from the __using__ macro so user overrides can reuse the same primitives the default state implementation uses.

Example

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
    StateHelpers.hydrate_filter(filter, acc, state)
  end
end

See MishkaGervaz.Table.Web.State, 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.

Summary

Functions

Maps each sortable column to the database fields it sorts by.

The selected ids for one filter, as strings, with blanks removed.

The stream name derived from a resource module when identity do stream_name … end is omitted.

The archive block's visible flag, defaulting to true when it is not a plain boolean — a function predicate is evaluated later, against live state.

The sort a table opens with.

The feature list this table runs with.

The filter_groups declared on the resource, or [].

Where the filter bar renders — :inline (the default), :sidebar, :modal or :drawer.

The table's layout do footer … end map, or nil when the resource declares none.

The table's layout do header … end map, or nil when the resource declares none.

Every layout do notice … end declared on the resource, in declaration order.

The ceiling a page size is clamped to — the guard against an oversized ?t_page_size= in the URL.

The configured page size, or nil when pagination is off.

The page-size choices offered in the UI, or nil when no dropdown should be drawn.

The names of the columns declared sortable true.

Whether this reader may see the archive toggle.

Resolves the labels for one relation filter's currently selected ids and stores them under the filter's name.

The access module for a resource — its state do access … end override, or the default passed in.

Asks the resource's relation loader for the records behind selected_ids and writes them into acc as that filter's :selected_options.

The relation loader a resource uses — its data_loader do relation … end override, or MishkaGervaz.Table.Web.DataLoader.RelationLoader.Default.

The URL-sync module for a resource — its state do url_sync … end override, or the default passed in.

Functions

build_sort_field_map(columns)

@spec build_sort_field_map([map()]) :: %{required(atom()) => [atom()]}

Maps each sortable column to the database fields it sorts by.

A column falls back to its own name unless it declared sort_field, which is what lets a static true column sort by something it does not display.

iex> build_sort_field_map([%{name: :site_datetime, sortable: true, sort_field: [:inserted_at]}])
%{site_datetime: [:inserted_at]}

extract_selected_ids(filter_values, filter_name)

@spec extract_selected_ids(map(), atom()) :: [String.t()]

The selected ids for one filter, as strings, with blanks removed.

Accepts a single value or a list, so a :search and a :search_multi filter read the same.

iex> extract_selected_ids(%{site_id: ["a", "", nil]}, :site_id)
["a"]

generate_stream_name(resource)

@spec generate_stream_name(module()) :: atom()

The stream name derived from a resource module when identity do stream_name … end is omitted.

iex> generate_stream_name(MyApp.Blog.Post)
:post_stream

get_archive_visible(config)

@spec get_archive_visible(map()) :: boolean()

The archive block's visible flag, defaulting to true when it is not a plain boolean — a function predicate is evaluated later, against live state.

get_default_sort(config, columns)

@spec get_default_sort(map(), [map()]) :: [{atom(), :asc | :desc}]

The sort a table opens with.

The resource's default_sort when it declared a non-empty list; otherwise newest-first if there is a sortable :inserted_at column; otherwise no sort at all.

iex> get_default_sort(%{columns: %{default_sort: [featured: :desc]}}, [])
[featured: :desc]

get_features(config, template)

@spec get_features(map(), module()) :: [atom()]

The feature list this table runs with.

An explicit features [...] is taken as given. :all (the default) means the union of what the current template and every switchable template support, so switching views never asks for a feature the new template cannot draw. :paginate is dropped when the resource has no pagination configured.

iex> get_features(%{presentation: %{features: [:sort, :filter]}}, MyTemplate)
[:sort, :filter]

get_filter_groups(arg1)

@spec get_filter_groups(map()) :: [map()]

The filter_groups declared on the resource, or [].

get_filter_mode(arg1)

@spec get_filter_mode(map()) :: atom()

Where the filter bar renders — :inline (the default), :sidebar, :modal or :drawer.

get_layout_footer(arg1)

@spec get_layout_footer(map()) :: map() | nil

The table's layout do footer … end map, or nil when the resource declares none.

get_layout_header(arg1)

@spec get_layout_header(map()) :: map() | nil

The table's layout do header … end map, or nil when the resource declares none.

get_layout_notices(arg1)

@spec get_layout_notices(map()) :: [map()]

Every layout do notice … end declared on the resource, in declaration order.

get_max_page_size(arg1)

@spec get_max_page_size(map()) :: pos_integer() | nil

The ceiling a page size is clamped to — the guard against an oversized ?t_page_size= in the URL.

get_page_size(arg1)

@spec get_page_size(map()) :: pos_integer() | nil

The configured page size, or nil when pagination is off.

get_page_size_options(arg1)

@spec get_page_size_options(map()) :: [pos_integer()] | nil

The page-size choices offered in the UI, or nil when no dropdown should be drawn.

get_pagination_ui(arg1)

@spec get_pagination_ui(map()) :: struct()

The pagination labels as a MishkaGervaz.Table.Entities.Pagination.Ui struct.

Always a struct: a resource that configured nothing gets one with the defaults, so a template can read ui.load_more_label without checking for nil first.

get_sortable_columns(columns)

@spec get_sortable_columns([map()]) :: [atom()]

The names of the columns declared sortable true.

iex> get_sortable_columns([%{name: :title, sortable: true}, %{name: :body, sortable: false}])
[:title]

get_supports_archive(config, master_user?)

@spec get_supports_archive(map(), boolean()) :: boolean()

Whether this reader may see the archive toggle.

false unless the resource enables archive; an archive do restricted true end narrows it further to master users only.

hydrate_filter(filter, acc, state)

@spec hydrate_filter(map(), map(), MishkaGervaz.Table.Web.State.t()) :: map()

Resolves the labels for one relation filter's currently selected ids and stores them under the filter's name.

Returns acc unchanged when the filter has no selection, which is what makes it safe to fold over every filter.

Enum.reduce(state.static.filters, %{}, &StateHelpers.hydrate_filter(&1, &2, state))

resolve_access(resource, default_access)

@spec resolve_access(module() | nil, module()) :: module()

The access module for a resource — its state do access … end override, or the default passed in.

resolve_and_store_labels(acc, filter, selected_ids, state)

@spec resolve_and_store_labels(
  map(),
  map(),
  [String.t()],
  MishkaGervaz.Table.Web.State.t()
) :: map()

Asks the resource's relation loader for the records behind selected_ids and writes them into acc as that filter's :selected_options.

The entry is shaped like a loaded page with an empty option list — the dropdown fills the options itself on first open; only the labels of what is already selected are needed here.

resolve_relation_loader(resource)

@spec resolve_relation_loader(module()) :: module()

The relation loader a resource uses — its data_loader do relation … end override, or MishkaGervaz.Table.Web.DataLoader.RelationLoader.Default.

loader = resolve_relation_loader(MyApp.Blog.Post)
loader.resolve_selected(filter_map, state, ["1", "2"])

resolve_url_sync(resource, default_url_sync)

@spec resolve_url_sync(module() | nil, module()) :: module()

The URL-sync module for a resource — its state do url_sync … end override, or the default passed in.