Packages
backpex
0.24.0
0.24.1
0.24.0
0.23.0
0.22.0
0.21.0
0.20.0
0.19.7
0.19.6
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.19.0
0.18.3
0.18.2
0.18.1
0.18.0
0.17.4
0.17.3
0.17.2
0.17.1
0.17.0
0.16.3
0.16.2
0.16.1
0.16.0
0.15.3
0.15.2
0.15.1
0.15.0
0.14.0
0.13.0
0.12.0
0.11.0
0.10.0
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.1
0.7.0
0.6.0
0.5.1
0.5.0
0.4.0
0.3.2
0.3.1
0.3.0
0.2.0
0.1.1
Highly customizable administration panel for Phoenix LiveView applications.
Current section
Files
Jump to
Current section
Files
usage-rules.md
# Backpex usage rules
Backpex builds admin panels in Phoenix LiveView apps. A LiveResource module configures the index, show and form views of one Ecto schema; fields, filters, actions and metrics are modules implementing Backpex behaviours. Docs and guides of the released version: https://hexdocs.pm/backpex (https://hexdocs.pm/backpex/llms.txt lists every guide as Markdown). Read the guide of the area you work in; the module docs list every option.
## Setup
- `mix igniter.install backpex` (or `mix backpex.install` once the dependency is added) runs the steps of the [installation guide](https://hexdocs.pm/backpex/installation.html), except the `LiveSocket` params: set those yourself.
- `app.js`: `import { Hooks as BackpexHooks, backpexParams } from 'backpex'`, then `new LiveSocket('/live', Socket, { params: backpexParams({ _csrf_token: csrfToken }), hooks: { ...Hooks, ...BackpexHooks } })`. `backpexParams` takes a params object; for params computed in a function, merge `BackpexPreferences.connectParams()` into its result.
- Styles need Tailwind CSS 4 and daisyUI 5, with `@source "../../deps/backpex/**/*.*ex";` and `@source "../../deps/backpex/assets/js/**/*.*js";` in the stylesheet. `@tailwindcss/forms` conflicts with daisyUI.
- `config :backpex, :pubsub_server, MyApp.PubSub`, and `import_deps: [:backpex]` in `.formatter.exs`.
## Routing
```elixir
import Backpex.Router
scope "/admin", MyAppWeb do
pipe_through [:browser, :require_admin]
backpex_routes()
live_session :admin, on_mount: Backpex.InitAssigns do
live_resources "/posts", PostLive
live_resources "/categories", CategoryLive, only: [:index, :show]
end
end
```
- `backpex_routes/0` adds the preferences endpoint: once per scope, behind the same authentication plugs as the LiveResources.
- `Backpex.InitAssigns` assigns `@current_url` and the preference assigns the layout reads. `live_resources/3` takes `only:` and `except:` with `:index`, `:new`, `:edit`, `:show`.
## LiveResource
```elixir
defmodule MyAppWeb.PostLive do
use Backpex.LiveResource,
adapter_config: [
schema: MyApp.Blog.Post,
repo: MyApp.Repo,
update_changeset: &MyApp.Blog.Post.update_changeset/3,
create_changeset: &MyApp.Blog.Post.create_changeset/3
]
@impl Backpex.LiveResource
def layout(_assigns), do: {MyAppWeb.Layouts, :admin}
@impl Backpex.LiveResource
def singular_name, do: "Post"
@impl Backpex.LiveResource
def plural_name, do: "Posts"
@impl Backpex.LiveResource
def fields do
[
title: %{module: Backpex.Fields.Text, label: "Title", searchable: true},
category: %{
module: Backpex.Fields.BelongsTo,
label: "Category",
display_field: :name,
live_resource: MyAppWeb.CategoryLive
}
]
end
end
```
- Return the layout from `c:Backpex.LiveResource.layout/1`; the `layout:` option is deprecated. The layout wraps its content in `Backpex.HTML.Layout.app_shell/1` and renders `Backpex.HTML.Layout.flash_messages/1`.
- `singular_name/0` and `plural_name/0` have no default. Every other callback has one: `fields/0`, `filters/0` (or `filters/1` with assigns), `panels/0`, `metrics/0`, `item_actions/1`, `resource_actions/0`, `can?/3`, the `on_item_*` hooks, `return_to/5`, `render_resource_slot/3`, `translate/1`.
- The options of `use Backpex.LiveResource` (`primary_key`, `init_order`, `per_page_default`, `full_text_search`, `fluid?`, `persist`, `context_assigns`, …) are validated against the schema in the `Backpex.LiveResource` docs. Set `primary_key:` when the key is not `:id`; Backpex supports one primary key column, not compound keys.
- `adapter_config` belongs to `Backpex.Adapters.Ecto`: `schema` and `repo` are required; the changeset functions take `(item, attrs, metadata)`, where `metadata` holds `:assigns` and `:target`; `item_query` takes `(query, live_action, assigns)` and builds on the given query (`from p in query, where: ...`).
## Fields
- `fields/0` returns a keyword list of `name: %{module: Backpex.Fields.<Type>, label: "..."}`. Built-in types: `Text`, `Textarea`, `Number`, `Currency`, `Email`, `URL`, `Boolean`, `Date`, `DateTime`, `Time`, `Select`, `MultiSelect`, `Checkgroup`, `Upload`, `BelongsTo`, `HasMany`, `HasManyThrough`, `InlineCRUD`.
- Options shared by all fields are in `Backpex.Field` (e.g. `searchable`, `orderable`, `only`/`except` with `:new`, `:edit`, `:show`, `:index`, `visible`, `can?`, `readonly`, `panel`, `index_editable`, `select` for computed values, `help_text`, `default`); options of a type are in its module docs. An unknown or mistyped option raises with the field and LiveResource name.
- A custom field does `use Backpex.Field, config_schema: @config_schema` with a NimbleOptions schema and implements `render_value/1` and `render_form/1` ([custom fields guide](https://hexdocs.pm/backpex/custom-fields.html)). The form passes only the params of the fields an admin may edit to the changeset; a field whose form submits params under other names than its own returns them from `param_keys/2`.
## Filters, actions and metrics
- `filters/0` returns `field_name: %{module: MyAppWeb.Filters.Published, label: "Published?"}`, optionally with `default:` and `presets:`. A filter module uses a built-in base and implements its callbacks: `Backpex.Filters.Boolean` (`options/1` returning maps with `label`, `key` and a `dynamic` `predicate`), `Backpex.Filters.Select` and `Backpex.Filters.MultiSelect` (`prompt/0`, `options/1`), `Backpex.Filters.Range` (`type/0`: `:number`, `:date` or `:datetime`). A fully custom filter does `use BackpexWeb, :filter` and implements `query/4`, `render/1` and `render_form/1`.
- `item_actions(default_actions)` receives `show:`, `edit:` and `delete:` and returns the keyword list to use, e.g. `Keyword.delete(default_actions, :delete) ++ [archive: %{module: MyAppWeb.ItemActions.Archive, only: [:row, :show]}]`. An item action module does `use BackpexWeb, :item_action` and implements `icon/2`, `label/2` and either `handle/3` or `link/2`; `fields/0` and `changeset/3` add a form.
- `resource_actions/0` returns `invite: %{module: MyAppWeb.ResourceActions.Invite}`; the module does `use Backpex.ResourceAction` and implements `title/0`, `label/0`, `fields/0`, `changeset/3` and `handle/2`.
- `metrics/0` returns `total: %{module: Backpex.Metrics.Value, label: "Total", select: dynamic([p], sum(p.amount)), format: &to_string/1}`. `Backpex.Metrics.Value` needs all four keys (`format: nil` shows the value as it is); the value follows the search and filters of the index view ([metrics guide](https://hexdocs.pm/backpex/metrics.html)).
## Authorization
- `can?/3` defaults to `true`, so a LiveResource allows every action until it overrides the callback: `def can?(assigns, action, item)` with `action` in `:index`, `:new`, `:show`, `:edit`, `:delete` or the key of an item or resource action. Return a boolean; any other value raises.
- Backpex checks it before every write and raises `Backpex.ForbiddenError` for an unauthorized item; `:index` and `:show` are checked in the views. Fields restrict themselves with the `can?` option, filters with the `can?/1` callback. Authenticate in the router pipeline.
## Translations
Backpex passes every text as `{msg, opts}` to the functions in `config :backpex, translator_function: {MyAppWeb.CoreComponents, :translate_backpex}, error_translator_function: {MyAppWeb.CoreComponents, :translate_error}`; the msgids are in `deps/backpex/priv/gettext/backpex.pot`. A LiveResource changes single texts with `translate/1`. See the [translations guide](https://hexdocs.pm/backpex/translations.html).
## Tests and upgrades
- `Backpex.Testing` finds the paths and elements of a LiveResource for `Phoenix.LiveViewTest`: `path/5`, `select_item/2`, `click_item_action/3`, `confirm_item_action/1`, `submit_form/2`.
- Backpex is 0.x and minor versions break APIs: read every upgrade guide between the old and the new version (`https://hexdocs.pm/backpex/v0-<minor>.html`) before bumping the dependency.
- Claude Code users get skills for LiveResources, fields, filters, actions and upgrades from the Backpex plugin: `/plugin marketplace add naymspace/backpex`, then `/plugin install backpex@naymspace-backpex`.