#102 add show_resources option (#148)

This commit is contained in:
Roberts Guļāns 2024-05-15 21:10:36 +03:00 committed by GitHub
parent 514ff491da
commit bd4b5581c8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 158 additions and 7 deletions

View file

@ -15,6 +15,7 @@ spark_locals_without_parens = [
resource_group_labels: 1, resource_group_labels: 1,
show?: 1, show?: 1,
show_action: 1, show_action: 1,
show_resources: 1,
show_sensitive_fields: 1, show_sensitive_fields: 1,
table_columns: 1, table_columns: 1,
type: 1, type: 1,

View file

@ -5,6 +5,13 @@ defmodule Demo.Tickets.Domain do
admin do admin do
show? true show? true
show_resources [
Demo.Tickets.Customer,
Demo.Tickets.Representative,
Demo.Tickets.Ticket,
Demo.Tickets.Comment,
Demo.Tickets.Organization
]
end end
resources do resources do

View file

@ -20,6 +20,7 @@ Configure the admin dashboard for a given domain.
|------|------|---------|------| |------|------|---------|------|
| [`name`](#admin-name){: #admin-name } | `String.t` | | The name of the domain in the dashboard. Will be derived if not set. | | [`name`](#admin-name){: #admin-name } | `String.t` | | The name of the domain in the dashboard. Will be derived if not set. |
| [`show?`](#admin-show?){: #admin-show? } | `boolean` | `false` | Whether or not this domain and its resources should be included in the admin dashboard. | | [`show?`](#admin-show?){: #admin-show? } | `boolean` | `false` | Whether or not this domain and its resources should be included in the admin dashboard. |
| [`show_resources`](#admin-show_resources){: #admin-show_resources } | `atom \| list(atom)` | `:*` | List of resources that should be included in the admin dashboard |
| [`default_resource_page`](#admin-default_resource_page){: #admin-default_resource_page } | `:schema \| :primary_read` | `:schema` | Set the default page for the resource to be the primary read action or the resource schema. Schema is the default for backwards compatibility, if a resource doesn't have a primary read action it will fallback to the schema view. | | [`default_resource_page`](#admin-default_resource_page){: #admin-default_resource_page } | `:schema \| :primary_read` | `:schema` | Set the default page for the resource to be the primary read action or the resource schema. Schema is the default for backwards compatibility, if a resource doesn't have a primary read action it will fallback to the schema view. |
| [`resource_group_labels`](#admin-resource_group_labels){: #admin-resource_group_labels } | `keyword` | `[]` | Humanized names for each resource group to appear in the admin area. These will be used as labels in the top navigation dropdown. If a key for a group does not appear in this mapping, the label will not be rendered. | | [`resource_group_labels`](#admin-resource_group_labels){: #admin-resource_group_labels } | `keyword` | `[]` | Humanized names for each resource group to appear in the admin area. These will be used as labels in the top navigation dropdown. If a key for a group does not appear in this mapping, the label will not be rendered. |

View file

@ -85,7 +85,7 @@ defmodule AshAdmin.ActorPlug.Plug do
defp actor_resources(domains) do defp actor_resources(domains) do
for domain <- domains, for domain <- domains,
resource <- Ash.Domain.Info.resources(domain), resource <- AshAdmin.Domain.show_resources(domain),
AshAdmin.Helpers.primary_action(resource, :read) && AshAdmin.Resource.actor?(resource), AshAdmin.Helpers.primary_action(resource, :read) && AshAdmin.Resource.actor?(resource),
do: {domain, resource} do: {domain, resource}
end end
@ -120,7 +120,7 @@ defmodule AshAdmin.ActorPlug.Plug do
resource = resource =
if domain do if domain do
domain domain
|> Ash.Domain.Info.resources() |> AshAdmin.Domain.show_resources()
|> Enum.find(&(AshAdmin.Resource.name(&1) == resource)) |> Enum.find(&(AshAdmin.Resource.name(&1) == resource))
end end

View file

@ -143,7 +143,7 @@ defmodule AshAdmin.Components.TopNav do
end end
defp dropdown_groups(prefix, current_resource, domain) do defp dropdown_groups(prefix, current_resource, domain) do
for resource <- Ash.Domain.Info.resources(domain) do for resource <- AshAdmin.Domain.show_resources(domain) do
%{ %{
text: AshAdmin.Resource.name(resource), text: AshAdmin.Resource.name(resource),
to: to:
@ -180,7 +180,7 @@ defmodule AshAdmin.Components.TopNav do
defp show_tenant_form?(domains) do defp show_tenant_form?(domains) do
Enum.any?(domains, fn domain -> Enum.any?(domains, fn domain ->
domain domain
|> Ash.Domain.Info.resources() |> AshAdmin.Domain.show_resources()
|> Enum.any?(fn resource -> |> Enum.any?(fn resource ->
Ash.Resource.Info.multitenancy_strategy(resource) Ash.Resource.Info.multitenancy_strategy(resource)
end) end)

View file

@ -13,6 +13,11 @@ defmodule AshAdmin.Domain do
doc: doc:
"Whether or not this domain and its resources should be included in the admin dashboard." "Whether or not this domain and its resources should be included in the admin dashboard."
], ],
show_resources: [
type: {:wrap_list, :atom},
default: :*,
doc: "List of resources that should be included in the admin dashboard"
],
default_resource_page: [ default_resource_page: [
type: {:in, [:schema, :primary_read]}, type: {:in, [:schema, :primary_read]},
default: :schema, default: :schema,
@ -28,7 +33,9 @@ defmodule AshAdmin.Domain do
] ]
} }
use Spark.Dsl.Extension, sections: [@admin] use Spark.Dsl.Extension,
sections: [@admin],
transformers: [AshAdmin.ShowResourcesTransformer]
@moduledoc """ @moduledoc """
A domain extension to alter the behavior of a domain in the admin UI. A domain extension to alter the behavior of a domain in the admin UI.
@ -42,6 +49,10 @@ defmodule AshAdmin.Domain do
Spark.Dsl.Extension.get_opt(domain, [:admin], :show?, false, true) Spark.Dsl.Extension.get_opt(domain, [:admin], :show?, false, true)
end end
def show_resources(domain) do
Spark.Dsl.Extension.get_opt(domain, [:admin], :show_resources, [], true)
end
def default_resource_page(domain) do def default_resource_page(domain) do
Spark.Dsl.Extension.get_opt(domain, [:admin], :default_resource_page, :schema, true) Spark.Dsl.Extension.get_opt(domain, [:admin], :default_resource_page, :schema, true)
end end

View file

@ -124,7 +124,7 @@ defmodule AshAdmin.PageLive do
defp assign_resource(socket, resource) do defp assign_resource(socket, resource) do
if socket.assigns.domain do if socket.assigns.domain do
resources = Ash.Domain.Info.resources(socket.assigns.domain) resources = AshAdmin.Domain.show_resources(socket.assigns.domain)
resource = resource =
Enum.find(resources, fn domain_resources -> Enum.find(resources, fn domain_resources ->

View file

@ -194,7 +194,7 @@ defmodule AshAdmin.Resource do
defp find_polymorphic_tables(resource, domains) do defp find_polymorphic_tables(resource, domains) do
domains domains
|> Enum.flat_map(&Ash.Domain.Info.resources/1) |> Enum.flat_map(&AshAdmin.Domain.show_resources/1)
|> Enum.flat_map(&Ash.Resource.Info.relationships/1) |> Enum.flat_map(&Ash.Resource.Info.relationships/1)
|> Enum.filter(&(&1.destination == resource)) |> Enum.filter(&(&1.destination == resource))
|> Enum.map(& &1.context[:data_layer][:table]) |> Enum.map(& &1.context[:data_layer][:table])

View file

@ -0,0 +1,28 @@
defmodule AshAdmin.ShowResourcesTransformer do
use Spark.Dsl.Transformer
def transform(dsl) do
module = Spark.Dsl.Transformer.get_persisted(dsl, :module)
all_resources = Ash.Domain.Info.resources(dsl)
resources =
case AshAdmin.Domain.show_resources(dsl) do
[:*] ->
all_resources
resources ->
case Enum.find(resources, &(&1 not in all_resources)) do
nil ->
resources
bad_resource ->
raise Spark.Error.DslError,
module: module,
path: [:admin, :show_resources],
message: "#{inspect(bad_resource)} is not a valid resource in #{inspect(module)}"
end
end
{:ok, Spark.Dsl.Transformer.set_option(dsl, [:admin], :show_resources, resources)}
end
end

View file

@ -1,4 +1,91 @@
defmodule AshAdmin.Test.AshAdminTest do defmodule AshAdmin.Test.AshAdminTest do
@moduledoc false @moduledoc false
use ExUnit.Case, async: true use ExUnit.Case, async: true
test "all resources are shown by default", _ do
defmodule Domain do
@moduledoc false
use Ash.Domain,
extensions: [AshAdmin.Domain]
admin do
show? true
end
resources do
resource AshAdmin.Test.Post
resource AshAdmin.Test.Comment
end
end
assert AshAdmin.Domain.show_resources(Domain) === [
AshAdmin.Test.Post,
AshAdmin.Test.Comment
]
end
test "all resources are shown when :* option is selected", _ do
defmodule Domain do
@moduledoc false
use Ash.Domain,
extensions: [AshAdmin.Domain]
admin do
show? true
show_resources :*
end
resources do
resource AshAdmin.Test.Post
resource AshAdmin.Test.Comment
end
end
assert AshAdmin.Domain.show_resources(Domain) === [
AshAdmin.Test.Post,
AshAdmin.Test.Comment
]
end
test "selected resources are shown", _ do
defmodule Domain do
@moduledoc false
use Ash.Domain,
extensions: [AshAdmin.Domain]
admin do
show? true
show_resources AshAdmin.Test.Post
end
resources do
resource AshAdmin.Test.Post
resource AshAdmin.Test.Comment
end
end
assert AshAdmin.Domain.show_resources(Domain) === [
AshAdmin.Test.Post
]
end
test "if shown resrouces option not eixsting resource providede error", _ do
assert_raise(Spark.Error.DslError, "[AshAdmin.Test.AshAdminTest.Domain]\n admin -> show_resources:\n SomeRandom is not a valid resource in AshAdmin.Test.AshAdminTest.Domain", fn ->
defmodule Domain do
@moduledoc false
use Ash.Domain,
extensions: [AshAdmin.Domain]
admin do
show? true
show_resources [AshAdmin.Test.Post, SomeRandom]
end
resources do
resource AshAdmin.Test.Post
resource AshAdmin.Test.Comment
end
end
end)
end
end end

View file

@ -9,5 +9,6 @@ defmodule AshAdmin.Test.Domain do
resources do resources do
resource(AshAdmin.Test.Post) resource(AshAdmin.Test.Post)
resource(AshAdmin.Test.Comment)
end end
end end

View file

@ -0,0 +1,15 @@
defmodule AshAdmin.Test.Comment do
@moduledoc false
use Ash.Resource,
domain: AshAdmin.Test.Domain,
data_layer: Ash.DataLayer.Ets
attributes do
uuid_primary_key(:id)
attribute :body, :string do
allow_nil?(false)
public?(true)
end
end
end