Skip to content

Repository files navigation

Ash Backpex

You got your Ash in my Backpex. You got your Backpex in my Ash.

An integration library that brings together Ash Framework's powerful resource system with Backpex's admin interface capabilities. This library provides a clean DSL for creating admin interfaces directly from your Ash resources.

Warning! {: .error}

Backpex itself is pre-1.0, so expect its API to change. AshBackpex passes the current actor through normal reads, creates, and updates, but Backpex's bulk delete adapter callback does not provide the actor. For now, use AshBackpex in a high-trust environment such as internal tooling.

This is a partial implementation - feel free to open a github issue to request additional features or submit a PR if you're into that kind of thing ;)

Installation

Add ash_backpex to your list of dependencies in mix.exs:

def deps do
  [
    {:ash_backpex, "~> 0.1.12"}
  ]
end

Basic Usage

# myapp_web/live/admin/post_live.ex
defmodule MyAppWeb.Live.Admin.PostLive do
    use AshBackpex.LiveResource

    backpex do
      resource MyApp.Blog.Post
      load [:author]
      layout &MyAppWeb.Layouts.admin/1

      fields do
        field :title
        field :published_at

        field :author do
          display_field(:name)
          live_resource(MyAppWeb.Live.Admin.AuthorLive)
        end
      end
    end
end

Custom Field Type Mappings

AshBackpex automatically maps Ash types to Backpex field modules, but you can customize these mappings globally or per-application.

Configuration

# config/config.exs

# Global config (applies to all apps using AshBackpex)
config :ash_backpex,
  field_type_mappings: %{
    MyApp.Types.Money => Backpex.Fields.Currency,
    MyApp.Types.RichText => Backpex.Fields.Textarea
  }

# Or use a function for conditional logic
config :ash_backpex,
  field_type_mappings: fn type, constraints ->
    case type do
      MyApp.Types.Money -> Backpex.Fields.Currency
      _ -> nil  # Fall back to default
    end
  end

Precedence

Field type resolution follows this order:

  1. Explicit module option in the field DSL
  2. App-scoped config (config :my_app, AshBackpex, ...)
  3. Global config (config :ash_backpex, ...)
  4. Default Ash type mappings

See AshBackpex.LiveResource module docs for more examples and details.

Repeating Child Forms

Opt a has_many relationship into Backpex's InlineCRUD field to edit child records directly in the parent form:

field :rows do
  module Backpex.Fields.InlineCRUD
  except [:index]

  child_fields do
    field :title

    field :config, Backpex.Fields.Textarea do
      label "Configuration"
    end

    field :category do
      display_field :name
      typeahead true
    end
  end
end

AshBackpex derives child modules and relationship options from the related child resource using the same rules as top-level fields. It also derives type: :assoc, adds move-up and move-down controls, translates the add/delete/order form parameters to an ordered list for Ash, and preserves child primary keys for updates. The parent Ash actions must expose an array-of-maps argument and use manage_relationship, typically with type: :direct_control.

The child_fields DSL is recursive for typed embedded Ash resources. Repeated embedded children use InlineCRUD with an inferred type: :embed; singular embedded children use AshBackpex.Fields.Embedded. Each nested field is derived against its immediate embedded resource rather than the root resource.

field :sections do
  module Backpex.Fields.InlineCRUD

  child_fields do
    field :title

    field :columns do
      module Backpex.Fields.InlineCRUD

      child_fields do
        field :heading

        field :target do
          module AshBackpex.Fields.Embedded

          child_fields do
            field :kind
            field :path
          end
        end
      end
    end
  end
end

See the Inline CRUD guide for the complete resource and LiveResource setup.

Typeahead Relationship Fields

Large belongs_to relationships can use a server-backed, single-select typeahead without loading every related record into the form:

field :author do
  display_field :name
  typeahead true
  typeahead_limit 10
  debounce 300
  prompt "Choose an author"
end

The search uses display_field and preserves the relationship's Ash filter, sort, read action, context, actor, tenant, and authorization through the generated options_query. Opening the dropdown preloads up to typeahead_limit options from that query; typing replaces them with matching results.

Filters and Actions

Development

See the contribution guide for setup and pull-request expectations. The repository knowledge map links architecture, testing, and maintenance guidance to the authoritative source and test files.

Thanks!

Building this little integration seemed easier than any alternatives to get the admin I wanted, which is a credit to the great work of the Backpex team!

About

Ash Integration for Backpex

Topics

Resources

Code of conduct

Contributing

Stars

31 stars

Watchers

3 watching

Forks

Releases

Packages

Contributors

Languages