diff --git a/.formatter.exs b/.formatter.exs index cfd9318..beaf79d 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -11,6 +11,7 @@ locals_without_parens = [ polymorphic_tables: 1, read_actions: 1, relationship_display_fields: 1, + show?: 1, show_action: 1, table_columns: 1, type: 1, diff --git a/dev.exs b/dev.exs index b85f42b..5b59fa4 100644 --- a/dev.exs +++ b/dev.exs @@ -38,7 +38,7 @@ defmodule DemoWeb.Router do pipe_through :browser import AshAdmin.Router - ash_admin("/", apis: [Demo.Accounts.Api, Demo.Tickets.Api]) + ash_admin("/") end end diff --git a/dev/resources/accounts/api.ex b/dev/resources/accounts/api.ex index 39b2993..a3509c6 100644 --- a/dev/resources/accounts/api.ex +++ b/dev/resources/accounts/api.ex @@ -1,6 +1,11 @@ defmodule Demo.Accounts.Api do @moduledoc false - use Ash.Api + use Ash.Api, + extensions: [AshAdmin.Api] + + admin do + show? true + end resources do resource Demo.Accounts.User diff --git a/dev/resources/tickets/api.ex b/dev/resources/tickets/api.ex index 9b1c2ec..634fdcf 100644 --- a/dev/resources/tickets/api.ex +++ b/dev/resources/tickets/api.ex @@ -1,9 +1,14 @@ defmodule Demo.Tickets.Api do @moduledoc false - use Ash.Api + use Ash.Api, + extensions: [AshAdmin.Api] alias Demo.Tickets.{Comment, Customer, Representative, Ticket, TicketLink, Organization} + admin do + show? true + end + resources do resource(Customer) resource(Representative) diff --git a/lib/ash_admin/actor_plug.ex b/lib/ash_admin/actor_plug.ex index b4a93d7..f993c4c 100644 --- a/lib/ash_admin/actor_plug.ex +++ b/lib/ash_admin/actor_plug.ex @@ -36,7 +36,7 @@ defmodule AshAdmin.ActorPlug do session["actor_paused"] end - actor = actor_from_session(session) + actor = actor_from_session(conn.private.phoenix_endpoint, session) authorizing = session_bool(authorizing) actor_paused = session_bool(actor_paused) @@ -56,37 +56,60 @@ defmodule AshAdmin.ActorPlug do def actor_session(conn, _), do: conn - def actor_api_from_session(%{"actor_api" => api}) do - Module.concat([api]) + def actor_api_from_session(endpoint, %{"actor_api" => api}) do + otp_app = endpoint.config(:otp_app) + apis = Application.get_env(otp_app, :ash_apis) + + Enum.find(apis, fn allowed_api -> + AshAdmin.Api.show?(allowed_api) && AshAdmin.Api.name(allowed_api) == api + end) end - def actor_from_session(%{ + def actor_api_from_session(_, _), do: nil + + def actor_from_session(endpoint, %{ "actor_resource" => resource, "actor_api" => api, "actor_primary_key" => primary_key, "actor_action" => action }) when not is_nil(resource) and not is_nil(api) do - resource = Module.concat([resource]) - api = Module.concat([api]) + otp_app = endpoint.config(:otp_app) + apis = Application.get_env(otp_app, :ash_apis) - action = - if action do - Ash.Resource.Info.action(resource, String.to_existing_atom(action), :read) + api = + Enum.find(apis, fn allowed_api -> + AshAdmin.Api.show?(allowed_api) && AshAdmin.Api.name(allowed_api) == api + end) + + resource = + if api do + api + |> Ash.Api.resources() + |> Enum.find(fn api_resource -> + AshAdmin.Resource.name(api_resource) == resource + end) end - case decode_primary_key(resource, primary_key) do - :error -> - nil + if api && resource do + action = + if action do + Ash.Resource.Info.action(resource, String.to_existing_atom(action), :read) + end - {:ok, filter} -> - resource - |> Ash.Query.filter(^filter) - |> api.read_one!(action: action) + case decode_primary_key(resource, primary_key) do + :error -> + nil + + {:ok, filter} -> + resource + |> Ash.Query.filter(^filter) + |> api.read_one!(action: action) + end end end - def actor_from_session(_), do: nil + def actor_from_session(_, _), do: nil def session_bool(value) do case value do diff --git a/lib/ash_admin/api.ex b/lib/ash_admin/api.ex index a17c4ae..eccf09d 100644 --- a/lib/ash_admin/api.ex +++ b/lib/ash_admin/api.ex @@ -4,7 +4,13 @@ defmodule AshAdmin.Api do name: :admin, schema: [ name: [ - type: :string + type: :string, + doc: "The name of the api in the dashboard. Will be derived if not set." + ], + show?: [ + type: :boolean, + default: false, + doc: "Wether or not this api and its resources should be included in the admin dashboard" ] ] } @@ -26,6 +32,10 @@ defmodule AshAdmin.Api do Ash.Dsl.Extension.get_opt(api, [:admin], :name, nil, true) || default_name(api) end + def show?(api) do + Ash.Dsl.Extension.get_opt(api, [:admin], :show?, false, true) + end + defp default_name(api) do split = api |> Module.split() diff --git a/lib/ash_admin/components/hero_icon.ex b/lib/ash_admin/components/hero_icon.ex index 20406df..b1286b4 100644 --- a/lib/ash_admin/components/hero_icon.ex +++ b/lib/ash_admin/components/hero_icon.ex @@ -7,30 +7,30 @@ defmodule AshAdmin.Components.HeroIcon do prop(class, :css_class) def render(assigns) do - ~H""" - {{render_heroicon(@name, @type, assigns)}} + ~F""" + {render_heroicon(@name, @type, assigns)} """ end defp render_heroicon("minus", "solid", assigns) do - ~H""" - + ~F""" + """ end defp render_heroicon("plus", "solid", assigns) do - ~H""" - + ~F""" + """ end defp render_heroicon("search-circle", "solid", assigns) do - ~H""" - + ~F""" + @@ -38,48 +38,48 @@ defmodule AshAdmin.Components.HeroIcon do end defp render_heroicon("key", "solid", assigns) do - ~H""" - + ~F""" + """ end defp render_heroicon("check", "solid", assigns) do - ~H""" - + ~F""" + """ end defp render_heroicon("x", "solid", assigns) do - ~H""" - + ~F""" + """ end defp render_heroicon("information-circle", "solid", assigns) do - ~H""" - + ~F""" + """ end defp render_heroicon("pencil", "solid", assigns) do - ~H""" - + ~F""" + """ end defp render_heroicon("x-circle", "solid", assigns) do - ~H""" - + ~F""" + """ diff --git a/lib/ash_admin/components/resource/attribute_table.ex b/lib/ash_admin/components/resource/attribute_table.ex index ad0fdea..b0ee3a5 100644 --- a/lib/ash_admin/components/resource/attribute_table.ex +++ b/lib/ash_admin/components/resource/attribute_table.ex @@ -5,8 +5,8 @@ defmodule AshAdmin.Components.Resource.AttributeTable do prop(resource, :any, required: true) def render(assigns) do - ~H""" -
+ ~F""" +

Attributes

@@ -24,20 +24,20 @@ defmodule AshAdmin.Components.Resource.AttributeTable do - {{ attribute.name }} + {attribute.name} - {{ attribute_type(attribute) }} + {attribute_type(attribute)} - {{ attribute.description }} - {{ to_string(attribute.primary_key?) }} - {{ to_string(attribute.private?) }} - {{ to_string(attribute.allow_nil?) }} - {{ to_string(attribute.writable?) }} + {attribute.description} + {to_string(attribute.primary_key?)} + {to_string(attribute.private?)} + {to_string(attribute.allow_nil?)} + {to_string(attribute.writable?)} diff --git a/lib/ash_admin/components/resource/data_table.ex b/lib/ash_admin/components/resource/data_table.ex index e90c9aa..bbd6b6a 100644 --- a/lib/ash_admin/components/resource/data_table.ex +++ b/lib/ash_admin/components/resource/data_table.ex @@ -144,25 +144,25 @@ defmodule AshAdmin.Components.Resource.DataTable do end def render(assigns) do - ~H""" + ~F"""
- {{ AshAdmin.Components.Resource.Form.render_attributes(assigns, @resource, @action, form) }} + {AshAdmin.Components.Resource.Form.render_attributes(assigns, @resource, @action, form)}