with one click
create-live-resource
// Use when scaffolding a new Backpex LiveResource, setting up admin CRUD views, or configuring adapter_config, fields, filters, and routing for a resource.
// Use when scaffolding a new Backpex LiveResource, setting up admin CRUD views, or configuring adapter_config, fields, filters, and routing for a resource.
Use when creating custom Backpex field types, implementing the Backpex.Field behaviour, or adding fields to a LiveResource's fields/0 callback.
Use when adding a filter to a Backpex LiveResource, creating a filter module, or the user asks about filtering data in Backpex index views.
Use when upgrading Backpex to a newer version, handling breaking changes, or migrating code after a version bump. Also use when the user asks about what changed between versions.
Use when creating custom Backpex item actions, adding action buttons to table rows or the show page, or modifying the default edit/delete/show actions.
Use when creating Backpex resource actions for global operations like bulk exports, invitations, imports, or any action that applies to the resource as a whole rather than individual items.
| name | create-live-resource |
| description | Use when scaffolding a new Backpex LiveResource, setting up admin CRUD views, or configuring adapter_config, fields, filters, and routing for a resource. |
You are an expert at creating LiveResources for Backpex. When the user wants to create a new admin resource, follow this process:
defmodule MyAppWeb.PostLive do
use Backpex.LiveResource,
adapter_config: [
schema: MyApp.Post,
repo: MyApp.Repo,
update_changeset: &MyApp.Post.changeset/3,
create_changeset: &MyApp.Post.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
}
]
end
end
use Backpex.LiveResource Options| Option | Type | Default | Description |
|---|---|---|---|
adapter_config | keyword | required | Ecto adapter configuration (see below) |
adapter | atom | Backpex.Adapters.Ecto | Data layer adapter |
primary_key | atom | :id | Primary key field |
per_page_options | list | [15, 50, 100] | Selectable page sizes |
per_page_default | integer | 15 | Default page size |
init_order | map or fn | %{by: :id, direction: :asc} | Initial sort order |
fluid? | boolean | false | Full-width layout |
full_text_search | atom | nil | PostgreSQL tsvector column name |
save_and_continue_button? | boolean | false | Show "Save & Continue" button |
pubsub | keyword | nil (falls back to :backpex, :pubsub_server app config, topic defaults to module name) | [server: MyApp.PubSub] |
on_mount | atom/list | nil | LiveView on_mount hooks |
| Key | Required | Description |
|---|---|---|
schema | yes | Ecto schema module |
repo | yes | Ecto repo module |
update_changeset | no | fn item, attrs, metadata -> changeset |
create_changeset | no | fn item, attrs, metadata -> changeset |
item_query | no | fn query, live_action, assigns -> query |
The metadata keyword list contains :assigns and :target (the form field that triggered the change).
The item_query function must build on the incoming query argument (use from p in query, ...), not the schema directly.
| Callback | Returns | Description |
|---|---|---|
singular_name/0 | string | e.g. "Post" |
plural_name/0 | string | e.g. "Posts" |
fields/0 | keyword list | Field definitions |
layout/1 | {module, :function} or fn assigns -> ... | Layout to use |
| Callback | Default | Description |
|---|---|---|
can?/3 | always true | fn assigns, action, item -> bool |
filters/0 | [] | Filter definitions |
filters/1 | delegates to filters/0 | Assigns-aware variant for dynamic filters |
panels/0 | [] | Field grouping: [key: "Label"] |
metrics/0 | [] | Index page metrics |
resource_actions/0 | [] | Resource-level actions |
item_actions/1 | returns default_actions unchanged | Modify default item actions |
on_item_created/2 | noop | fn socket, item -> socket |
on_item_updated/2 | noop | fn socket, item -> socket |
on_item_deleted/2 | noop | fn socket, item -> socket |
return_to/5 | index page | Custom redirect after save |
index_row_class/4 | nil | Custom CSS for table rows |
render_resource_slot/3 | default HTML | Override UI slots |
translate/1 | delegates to Backpex.translate/1 | Override UI strings |
import Backpex.Router
scope "/admin", MyAppWeb do
pipe_through :browser
backpex_routes()
live_session :admin, on_mount: Backpex.InitAssigns do
live_resources "/posts", PostLive
live_resources "/users", UserLive
live_resources "/categories", CategoryLive, only: [:index, :show]
end
end
backpex_routes() must appear once per scope. live_resources/3 generates routes for Index, Form (new/edit), and Show views.
Options for live_resources/3:
only: [:index, :show, :new, :edit] to restrict routesexcept: [:new] to exclude specific routesdefmodule MyAppWeb.ProductLive do
use Backpex.LiveResource,
adapter_config: [
schema: MyApp.Product,
repo: MyApp.Repo,
update_changeset: &MyApp.Product.changeset/3,
create_changeset: &MyApp.Product.changeset/3,
item_query: &__MODULE__.item_query/3
],
per_page_default: 25,
init_order: %{by: :inserted_at, direction: :desc}
import Ecto.Query
@impl Backpex.LiveResource
def layout(_assigns), do: {MyAppWeb.Layouts, :admin}
@impl Backpex.LiveResource
def singular_name, do: "Product"
@impl Backpex.LiveResource
def plural_name, do: "Products"
@impl Backpex.LiveResource
def panels do
[details: "Details", metadata: "Metadata"]
end
@impl Backpex.LiveResource
def fields do
[
name: %{
module: Backpex.Fields.Text,
label: "Name",
searchable: true,
panel: :details
},
price: %{
module: Backpex.Fields.Currency,
label: "Price",
panel: :details
},
category: %{
module: Backpex.Fields.BelongsTo,
label: "Category",
display_field: :name,
live_resource: MyAppWeb.CategoryLive,
panel: :details
},
published: %{
module: Backpex.Fields.Boolean,
label: "Published",
index_editable: true
},
inserted_at: %{
module: Backpex.Fields.DateTime,
label: "Created At",
only: [:index, :show],
panel: :metadata
}
]
end
@impl Backpex.LiveResource
def can?(_assigns, :delete, item), do: not item.published
def can?(_assigns, _action, _item), do: true
def item_query(query, _live_action, _assigns) do
from p in query, where: is_nil(p.archived_at)
end
end
lib/my_app_web/live/<resource>_live.exMyAppWeb.<Resource>Live (e.g. MyAppWeb.ProductLive)item, attrs, metadatalayout/1 callback instead of the layout: option (avoids compile-time dependencies)item_query/3