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

Copy Markdown View Source

Shared helpers for MishkaGervaz.Form.Web.State.

A module that overrides init/3 (via use MishkaGervaz.Form.Web.State) can call any helper here without redefining it; the macro itself imports them as StateHelpers.

Two functional groups:

mode_allowed?/3 — :restricted semantics

The :restricted field on a source map (or a per-mode entry in :access_rules) accepts two shapes, and they behave differently:

  • restricted: true — applies the master gate. The mode is allowed only when state.master_user?.
  • restricted: fn state -> boolean end — the function is the final word; the master gate is not layered on top. Returning true means the user is restricted and the mode is denied, returning false allows the mode unconditionally.

Use the boolean form unless the decision needs the whole state.

See MishkaGervaz.Form.Web.State, MishkaGervaz.Form.Web.State.Access.Default, and MishkaGervaz.Form.Web.Live.

Summary

Functions

Whether field is drawn read-only and left out of what the form saves.

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

The form's layout do footer … end map, or nil when none is declared.

The form's layout do header … end map, or nil when none is declared.

The form's lifecycle hooks as a map, or %{} when the resource declares none.

The grid width of the form, defaulting to a single column.

The form's layout mode, defaulting to :standard when the resource declares none.

How a wizard or tabs form moves between steps — :sequential (the default) or :free.

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

The resolved submit configuration — the three buttons, their position and shared ui.

The uploads do upload … end entries declared on the resource, or [].

The groups belonging to one wizard or tabs step, in the order they were declared.

Whether the current reader may open the form in mode (:create or :update).

The access module used to gate form modes.

Whether the action state.form saves with accepts field or takes it as an argument.

Functions

field_readonly?(field, state)

@spec field_readonly?(map(), map()) :: boolean()

Whether field is drawn read-only and left out of what the form saves.

True when the field declares readonly true or readonly fn state -> … end says so, or when taken_by_action?/2 is false.

if field_readonly?(field, state), do: Map.delete(params, to_string(field.name)), else: params

generate_stream_name(resource)

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

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

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

get_footer(arg1)

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

The form's layout do footer … end map, or nil when none is declared.

get_header(arg1)

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

The form's layout do header … end map, or nil when none is declared.

get_hooks(arg1)

@spec get_hooks(map()) :: map()

The form's lifecycle hooks as a map, or %{} when the resource declares none.

get_layout_columns(arg1)

@spec get_layout_columns(map()) :: 1 | 2 | 3 | 4

The grid width of the form, defaulting to a single column.

A group may override it for itself with ui do columns … end.

get_layout_mode(arg1)

@spec get_layout_mode(map()) :: :standard | :wizard | :tabs

The form's layout mode, defaulting to :standard when the resource declares none.

get_layout_navigation(arg1)

@spec get_layout_navigation(map()) :: :sequential | :free

How a wizard or tabs form moves between steps — :sequential (the default) or :free.

get_notices(arg1)

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

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

get_submit(arg1)

@spec get_submit(map()) :: map()

The resolved submit configuration — the three buttons, their position and shared ui.

Falls back to a full default block rather than nil, so a template can read submit[:create][:label] without guarding first.

get_uploads(arg1)

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

The uploads do upload … end entries declared on the resource, or [].

groups_for_step(groups, steps, step_name)

@spec groups_for_step([map()], [map()], atom()) :: [map()]

The groups belonging to one wizard or tabs step, in the order they were declared.

Returns every group when the step is unknown, which is what makes a :standard form — and a step name that no longer exists — render rather than come back empty.

groups_for_step(state.static.groups, state.static.steps, state.current_step)

mode_allowed?(source, mode, state)

@spec mode_allowed?(map() | nil, atom(), map()) :: boolean()

Whether the current reader may open the form in mode (:create or :update).

Checks, in order: a per-mode access rule, a global access fn mode, state -> … end gate, then source do restricted true end. A form with no source at all is allowed. A per-mode rule written access :update, false denies that mode to everyone.

if mode_allowed?(state.static.source, :create, state), do: DataLoader.new_record(socket, state)

resolve_access(resource)

@spec resolve_access(module()) :: module()

The access module used to gate form modes.

taken_by_action?(arg1, state)

@spec taken_by_action?(map(), map()) :: boolean()

Whether the action state.form saves with accepts field or takes it as an argument.

A virtual field is always taken. When state.form is not an AshPhoenix.Form, or its action is not on its resource, the answer is true and the field is left as declared.