Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions lib/ash_backpex/live_resource/dsl.ex
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,12 @@ defmodule AshBackpex.LiveResource.Dsl do
doc:
"Panels to be displayed in the admin create/edit forms. Format: [panel_key: \"Panel Title\"]"
],
field_mappings: [
type: {:map, :atom, :atom},
default: %{},
doc:
"Override default Ash type to Backpex field module mappings. Format: %{Ash.Type.DateTime => MyApp.Fields.CustomDateTime}"
],
pubsub: [
doc: "PubSub configuration.",
type: :keyword_list,
Expand Down
110 changes: 59 additions & 51 deletions lib/ash_backpex/live_resource/transformers/generate_backpex.ex
Original file line number Diff line number Diff line change
Expand Up @@ -146,82 +146,90 @@ defmodule AshBackpex.LiveResource.Transformers.GenerateBackpex do

try_derive_module = fn attribute_name ->
type = derive_type.(attribute_name)
field_mappings = Spark.Dsl.Extension.get_opt(__MODULE__, [:backpex], :field_mappings) || %{}

case type do
Ash.Type.Boolean ->
Backpex.Fields.Boolean
# Check custom mappings first, then fall back to defaults
case Map.get(field_mappings, type) do
nil ->
case type do
Ash.Type.Boolean ->
Backpex.Fields.Boolean

Ash.Type.String ->
attribute_name |> select_or.(Backpex.Fields.Text)
Ash.Type.String ->
attribute_name |> select_or.(Backpex.Fields.Text)

Ash.Type.Atom ->
attribute_name |> select_or.(Backpex.Fields.Text)
Ash.Type.Atom ->
attribute_name |> select_or.(Backpex.Fields.Text)

Ash.Type.CiString ->
attribute_name |> select_or.(Backpex.Fields.Text)
Ash.Type.CiString ->
attribute_name |> select_or.(Backpex.Fields.Text)

Ash.Type.Time ->
Backpex.Fields.Time
Ash.Type.Time ->
Backpex.Fields.Time

Ash.Type.Date ->
Backpex.Fields.Date
Ash.Type.Date ->
Backpex.Fields.Date

Ash.Type.UtcDatetime ->
Backpex.Fields.DateTime
Ash.Type.UtcDatetime ->
Backpex.Fields.DateTime

Ash.Type.UtcDatetimeUsec ->
Backpex.Fields.DateTime
Ash.Type.UtcDatetimeUsec ->
Backpex.Fields.DateTime

Ash.Type.DateTime ->
Backpex.Fields.DateTime
Ash.Type.DateTime ->
Backpex.Fields.DateTime

Ash.Type.NaiveDateTime ->
Backpex.Fields.DateTime
Ash.Type.NaiveDateTime ->
Backpex.Fields.DateTime

Ash.Type.Integer ->
attribute_name |> select_or.(Backpex.Fields.Number)
Ash.Type.Integer ->
attribute_name |> select_or.(Backpex.Fields.Number)

Ash.Type.Float ->
attribute_name |> select_or.(Backpex.Fields.Number)
Ash.Type.Float ->
attribute_name |> select_or.(Backpex.Fields.Number)

:belongs_to ->
Backpex.Fields.BelongsTo
:belongs_to ->
Backpex.Fields.BelongsTo

:has_many ->
Backpex.Fields.HasMany
:has_many ->
Backpex.Fields.HasMany

:count ->
Backpex.Fields.Number
:count ->
Backpex.Fields.Number

:exists ->
Backpex.Fields.Boolean
:exists ->
Backpex.Fields.Boolean

:sum ->
Backpex.Fields.Number
:sum ->
Backpex.Fields.Number

:max ->
Backpex.Fields.Number
:max ->
Backpex.Fields.Number

:min ->
Backpex.Fields.Number
:min ->
Backpex.Fields.Number

:avg ->
Backpex.Fields.Number
:avg ->
Backpex.Fields.Number

{:array, Ash.Type.Atom} ->
attribute_name |> multiselect_or.(Backpex.Fields.Text)
{:array, Ash.Type.Atom} ->
attribute_name |> multiselect_or.(Backpex.Fields.Text)

{:array, Ash.Type.String} ->
attribute_name |> multiselect_or.(Backpex.Fields.Text)
{:array, Ash.Type.String} ->
attribute_name |> multiselect_or.(Backpex.Fields.Text)

{:array, Ash.Type.CiString} ->
attribute_name |> multiselect_or.(Backpex.Fields.Text)
{:array, Ash.Type.CiString} ->
attribute_name |> multiselect_or.(Backpex.Fields.Text)

{:array, Ash.Type.Integer} ->
attribute_name |> multiselect_or.(Backpex.Fields.Number)
{:array, Ash.Type.Integer} ->
attribute_name |> multiselect_or.(Backpex.Fields.Number)

{:array, Ash.Type.Float} ->
attribute_name |> multiselect_or.(Backpex.Fields.Number)
end

{:array, Ash.Type.Float} ->
attribute_name |> multiselect_or.(Backpex.Fields.Number)
custom_module ->
custom_module
end
end

Expand Down
10 changes: 10 additions & 0 deletions test/ash_backpex/live_resource/transformer_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,16 @@ defmodule AshBackpex.LiveResource.TransformerTest do
assert Keyword.get(fields, :author).module == Backpex.Fields.BelongsTo
end

test "derive custom Backpex field types with field overrides" do
fields = TestCustomFieldMappingsLive.fields()

# this one is standard and not overridden
assert Keyword.get(fields, :title).module == Backpex.Fields.Text

# this one would be Ash.Type.DateTime if not overridden
assert Keyword.get(fields, :published_at).module == Demo.Backpex.Fields.CustomDateTime
end

test "derive default and non-default primary key with init_order" do
assert TestPostLive.config(:primary_key) == :id

Expand Down
34 changes: 34 additions & 0 deletions test/support/test_live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,37 @@ defmodule TestNonDefaultPrimaryKeyNameLive do
end
end
end

defmodule Demo.Backpex.Fields.CustomDateTime do
@moduledoc "Dummy field module for testing :field_mappings config override"
use Backpex.Field

@impl Backpex.Field
def render_value(assigns) do
~H"<span>{@value}</span>"
end

@impl Backpex.Field
def render_form(assigns) do
~H"""
<input type="datetime-local" />
"""
end
end

defmodule TestCustomFieldMappingsLive do
@moduledoc false
use AshBackpex.LiveResource

backpex do
resource(AshBackpex.TestDomain.Post)
layout({TestLayout, :admin})

field_mappings(%{Ash.Type.DateTime => Demo.Backpex.Fields.CustomDateTime})

fields do
field(:title)
field(:published_at)
end
end
end
Loading