How domain defaults work
v0.0.1
Most resources in an application share their Ash actions, page sizes, labels and adapter. Gervaz lets you declare those once on the Ash domain, and every resource in the domain inherits them. This page explains which keys a resource inherits, in which order Gervaz settles a conflict, and how the submit buttons and the archive actions merge.
What it is and why
The MishkaGervaz.Domain extension adds a mishka_gervaz block to an Ash domain. It has a table section and a form section that mirror a resource's, plus a navigation section. A resource that sets nothing gets the domain's values, so a new admin resource needs only what is specific to it. The options of the domain block are in Domain DSL.
A table needs a read action, and a form with any field needs a create, an update and a read action. Gervaz reports a missing one when it compiles a table that has a route. Declaring those actions on the domain once is usually the most useful default.
How a conflict is settled
- A resource key wins over the same key on the domain. The merge is per key and not per block, so a resource that sets one pagination key still inherits the others.
falseis an answer, not an absence. A resource withrealtime do enabled false endturns realtime off even when the domain turns it on. A key left out inherits. Name a key you depend on, such asui_adapter, in a resource that writes its section.- The merge happens in two places. The compile-time transformers copy a domain value into a key the resource left unset. For some sections, such as pagination, realtime, refresh, URL sync and archive,
MishkaGervaz.Resource.Info.Table.config/1finishes the merge when you read the config.
Read the merged result with MishkaGervaz.Resource.Info.Table.config/1 and MishkaGervaz.Resource.Info.Form.config/1. Read the domain's own values with MishkaGervaz.Domain.Info.Table.defaults/1 and MishkaGervaz.Domain.Info.Form.defaults/1. The config/1 function of either module returns the whole domain config, both sides.
What a resource inherits
| Table | Form |
|---|---|
ui_adapter, ui_adapter_opts | ui_adapter, ui_adapter_opts |
actor_key, master_check | actor_key, master_check |
actions: read, get, destroy | actions: create, update, read |
pagination: type, page_size, page_size_options, max_page_size | layout: navigation, persistence, columns, responsive |
realtime: enabled, pubsub | template, features |
theme: header_class, row_class, border_class | theme: form_class, field_class, label_class, error_class |
archive, url_sync, refresh | submit, merged per button |
Everything else is resource-only. Identity, columns, filters, row and bulk actions, groups, steps, uploads, hooks and the override modules belong to the resource. A form's layout mode and its steps are not inherited either.
The domain also holds navigation menu groups. These are domain-wide data and not table defaults. See Domain DSL.
How the archive actions merge
Archive applies only to a resource that has AshArchival.Resource. For such a resource, the archive block of the resource wins per key, and a missing key falls back to the domain. If neither side names an action, Gervaz uses a built-in set: {:master_archived, :archived}, {:master_get_archived, :get_archived}, {:master_unarchive, :unarchive} and {:master_permanent_destroy, :permanent_destroy}. enabled false on the resource's block turns archive off for that resource. restricted defaults to false and visible to true.
Example
The tags resource of Mishka Blog declares no actions and no pagination. Its domain supplies them. The resource adds the parts that are its own: its identity and route, columns, filters and its adapter and templates. It overrides the adapter that the domain sets as the default:
# In the domain (MishkaBlog)
mishka_gervaz do
table do
ui_adapter MishkaGervaz.UIAdapters.Tailwind
pagination do
type :load_more
page_size 20
end
end
end
# In the resource (MishkaBlog.Tag)
presentation do
template MishkaBlogWeb.Templates.TagCard
ui_adapter MishkaCmsCoreWeb.UIAdapters.Admin
end