GithubHelp home page GithubHelp logo

ash-project / ash_admin Goto Github PK

View Code? Open in Web Editor NEW
94.0 7.0 44.0 2.9 MB

A super-admin UI dashboard for Ash Framework applications, built with Phoenix LiveView.

Home Page: https://hexdocs.pm/ash_admin

License: MIT License

Elixir 49.71% JavaScript 41.86% CSS 8.43%
ash elixir admin

ash_admin's Introduction

ash_admin's People

Contributors

arianics avatar axelson avatar carlgleisner avatar dependabot[bot] avatar esdrasedu avatar girishramnani avatar hanrelan avatar jeremygrant avatar jimsynz avatar joshprice avatar kevinam99 avatar minibikini avatar nayminlwin avatar nduatik avatar nicolkill avatar peterhartman avatar revati avatar rgraff avatar sevenseacat avatar shirishgoyal avatar skanderm avatar st3fan avatar theosaurus-rex avatar totorigolo avatar twistingtwists avatar vasspilka avatar vonagam avatar wolfdan avatar woutdp avatar zachdaniel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

ash_admin's Issues

error editing fields of type Map

I'm not sure if this is an error of ash_admin or I should write the implementation for the Map type.

Protocol.UndefinedError at GET /admin/Layer/DeviceScreen/update/update/g3QAAAABZAACaWRhAw==

protocol Phoenix.HTML.Safe not implemented for %{"min_capture_length" => 3} of type Map. This protocol is implemented for the following type(s): Decimal, Ash.NotLoaded, Ash.CiString, Phoenix.LiveComponent.CID, Phoenix.LiveView.Comprehension, Phoenix.LiveView.Component, Phoenix.LiveView.Rendered, Atom, Time, BitString, Tuple, DateTime, List, NaiveDateTime, Integer, Phoenix.HTML.Form, Date, Float

Not all scripts and styles have CSP nonces defined

Describe the bug
Not all scripts are using the CSP nonce

To Reproduce
In the browser pipeline set (as per Readme)

plug :put_secure_browser_headers, %{"content-security-policy" => "default-src 'nonce-ash_admin-Ed55GFnX' 'self'"}

Current behavior
Failure to load jsoneditor and easymde resources

Expected behavior
No console warnings or network failures

Additional context
Ideally ash_admin would allow you to supply your own nonces in the same way as Phoenix.LiveDashboard, eg:

ash_admin "/admin", csp_nonce_assign_key: :csp_nonce_value

Creating/updating a record with two belongs_to relationships has form fields resetting

I think a video will show it better than I can describe it!

Screen.Recording.2024-03-19.at.1.48.26.pm.mov

The previously filled out form field is reset when a second one is edited :(

When editing an existing record, editing the first field is fine (the second doesn't disappear) but editing the second nukes the first.

To Reproduce

I've tested it with a few different resources, but this is some config for probably the simplest one:

  attributes do
    uuid_primary_key :id, generated?: true
  end

  relationships do
    belongs_to :risk, MyApp.Risk, allow_nil?: false
    belongs_to :control, MyApp.Control, allow_nil?: false
  end

  actions
    create :create do
      primary? true

      argument :risk_id, :uuid
      argument :control_id, :uuid

      change manage_relationship(:risk_id, :risk, type: :append_and_remove)
      change manage_relationship(:control_id, :control, type: :append_and_remove)
    end
  end

Expected behavior

I should be able to fill out one field, and then the other, and then submit both successfully.

Runtime

  • Elixir version 1.15.4-otp-26
  • Erlang version 26.0.2
  • OS macOS Sonoma
  • Ash version 2.20.1
  • AshAdmin 0.10.7

Blank edit page after upgrading to 0.9.8

Describe the bug

On 0.9.5 I was able to edit both my resources (yea, I only have 2), after upgrading to 0.9.8 one of my resources just renders a blank page when I try to edit it. I can still edit the User resource, but not the other.

To Reproduce

All I know at the time of this writing is to upgrade an app to Ash Authentication 0.9.8 and try to edit a resource that is not the user. I do not see any errors in the server logs or the web console. If there are debugging steps I can take, I will gladly do that.

Expected behavior

Render the edit form for the resource.

Runtime

  • Elixir version 1.15.4
  • Erlang version 26
  • OS MacOS
  • Ash version 2.17.3
  • any related extension versions
ash                         2.17.3   2.17.3  Up-to-date
ash_admin                   0.9.8    0.9.8   Up-to-date
ash_authentication          3.12.0   3.12.0  Up-to-date
ash_authentication_phoenix  1.9.0    1.9.0   Up-to-date
ash_phoenix                 1.2.23   1.2.23  Up-to-date
ash_postgres                1.3.62   1.3.62  Up-to-date
ecto_sql                    3.11.0   3.11.0  Up-to-date
esbuild                     0.8.1    0.8.1   Up-to-date
finch                       0.16.0   0.16.0  Up-to-date
floki                       0.35.2   0.35.2  Up-to-date
gettext                     0.23.1   0.23.1  Up-to-date
jason                       1.4.1    1.4.1   Up-to-date
mix_test_watch              1.1.1    1.1.1   Up-to-date
nimble_csv                  1.2.0    1.2.0   Up-to-date
phoenix                     1.7.10   1.7.10  Up-to-date
phoenix_ecto                4.4.3    4.4.3   Up-to-date
phoenix_html                3.3.3    3.3.3   Up-to-date
phoenix_live_dashboard      0.8.3    0.8.3   Up-to-date
phoenix_live_reload         1.4.1    1.4.1   Up-to-date
phoenix_live_view           0.20.1   0.20.1  Up-to-date
plug_cowboy                 2.6.1    2.6.1   Up-to-date
postgrex                    0.17.3   0.17.3  Up-to-date
swoosh                      1.14.1   1.14.1  Up-to-date
tailwind                    0.2.2    0.2.2   Up-to-date
telemetry_metrics           0.6.1    0.6.1   Up-to-date
telemetry_poller            1.0.0    1.0.0   Up-to-date

Additional context

If I roll ash_admin back to 0.9.5 with all the other dependencies on latest, the problem disappears.

Here is the blank page where the form is supposed to be:
Screenshot 2023-11-22 at 10 36 10 PM

Admin links are not aware of the scope where ash_admin is called

Actual behavior

AshAdmin.Router.ash_admin/2 take account of the scope prefix to set the admin route. However, the links in the admin are not aware of. Its just take the path without the scope prefix.

To Reproduce

In router.ex:

    scope "/dev" do
      pipe_through :browser

      ash_admin("/admin")
      forward "/mailbox", Plug.Swoosh.MailboxPreview
    end

Here, the admin route will be /dev/admin/*route, however the links in the admin will goes to /admin.

Expected behavior

Links of the admin should take account of the scope where ash_admin was called, i.e. /dev/admin in the example above.

Workaround

My workaround, still in router.ex:

    scope "/dev" do
      pipe_through :browser

      forward "/mailbox", Plug.Swoosh.MailboxPreview
    end

    scope "/" do
      pipe_through :browser

      # Warning: the Ash admin seems not to be aware of the scope prefix,
      # that's why `ash_admin` is called into a "/" scope
      ash_admin("/dev/admin")
    end

Runtime

  • Elixir version: 1.14.0
  • Erlang version: 25.2-3
  • OS: Archlinux, GNU/Linux 6.2.2-arch1-1
  • Ash version: 2.6.17
  • Phoenix version: 1.7.1

no function clause matching in AshAdmin.PageLive.handle_event/3

Describe the bug

Liveview crashes when editing the tenant

** (FunctionClauseError) no function clause matching in AshAdmin.PageLive.handle_event/3
    (ash_admin 0.9.0) lib/ash_admin/pages/page_live.ex:284: AshAdmin.PageLive.handle_event("stop_editing_tenant", %{"value" => ""},

Runtime

  • Ash Admin 0.9.0

Handle error messages not implementing AshPhoenix.Form.Error

Is your feature request related to a problem? Please describe.
Using AshAdmin to test illegal state changes with AshStateMachine naturally causes errors to be thrown. These are, according to @zachdaniel, not rendered unless they implement AshPhoenix.Form.Error. In the case of illegal state changes the errors will therefore not be rendered.

Describe the solution you'd like
Solutions suggested by @zachdaniel on the forums:

However, AshAdmin is an admin tool, and so we should do the following:

  1. by default, if there is an exception that isn’t implemented, we show a message like “Got N messages that could not be rendered, please check the server logs for more” and then log the errors.
  2. allow a configuration that will show external messages that defaults to off.

Describe alternatives you've considered
See above.

Express the feature either with a change to resource syntax, or with a change to the resource interface
See above.

Additional context

`AshPostgres.polymorphic?/1` is undefined

Describe the bug
It seems that for some reason AshAdmin is dependent on AshPostgres

To Reproduce
Set up a minimal project with ets data layer

Expected behavior
AshAdmin should work on any datalayer

** Runtime

  • Elixir version 1.13.4
  • Erlang version 25 [erts-13.0.3]
  • OS macOS 12.3.1
  • Ash version 1.53.3
  • AshAdmin version 0.5.2

Setting user in schema based multitenancy throws error

Describe the bug

Trying to set the current user with the key-button int he UI in a schema based multitenancy setup throws an error.

Queries against the MyApp.Accounts.User resource require a tenant to be specified

To Reproduce

defmodule MyApp.Accounts do
  use Ash.Api,
    extensions: [AshAdmin.Api]

  resources do
    resource MyApp.Accounts.User
    resource MyApp.Accounts.Token
    resource MyApp.Accounts.Organization
  end

  admin do
    show? true
  end
end
defmodule MyApp.Accounts.Organization do
  use Ash.Resource,
    data_layer: AshPostgres.DataLayer,
    extensions: [AshAdmin.Resource]

  attributes do
    uuid_primary_key :id

    attribute :subdomain, :ci_string, allow_nil?: false

  end

  actions do
    defaults [:create, :read, :update, :destroy]
  end

  postgres do
    table "organizations"
    repo MyApp.Repo

    manage_tenant do
      template ["org_", :id]
    end
  end
end
defmodule MyApp.Accounts.User do
  use Ash.Resource,
    data_layer: AshPostgres.DataLayer,
    extensions: [AshAuthentication, AshAdmin.Resource],
    authorizers: [Ash.Policy.Authorizer]

  attributes do
    uuid_primary_key :id

    attribute :email, :ci_string, allow_nil?: false
    attribute :hashed_password, :string, allow_nil?: false, sensitive?: true, private?: true
  end

  authentication do
    api MyApp.Accounts

    strategies do
      password :password do
        identity_field :email
      end
    end

    tokens do
      enabled? true
      token_resource MyApp.Accounts.Token

      signing_secret fn _, _ ->
        Application.fetch_env(:my_app, :token_signing_secret)
      end
    end
  end

  actions do
    defaults [:read, :update, :destroy]
  end

  identities do
    identity :unique_email, [:email]
  end

  # A safe default that only allows user data to be interacted with via AshAuthentication.
  policies do
    bypass AshAuthentication.Checks.AshAuthenticationInteraction do
      authorize_if always()
    end

    policy always() do
      forbid_if always()
    end
  end

  multitenancy do
    strategy :context
  end

  postgres do
    table "users"
    repo MyApp.Repo
  end

  admin do
    actor? true
  end
end

Set tenant and confirm that this is working fine in other respects than setting the user.

screenshot-set-user-tenant-id-missing

Then try to set the user with the key button.

screenshot-set-user-tenant-id-missing2

That crashes the LiveView process with the following error.

[debug] HANDLE EVENT "set_actor" in AshAdmin.PageLive
  Parameters: %{"api" => "Elixir.MyApp.Accounts", "pkey" => "7795ffa9-4d0d-463d-b095-98651bff887f", "resource" => "Elixir.MyApp.Accounts.User", "value" => ""}
[error] GenServer #PID<0.856.0> terminating
** (Ash.Error.Invalid) Input Invalid

* Queries against the MyApp.Accounts.User resource require a tenant to be specified
  (elixir 1.16.1) lib/process.ex:860: Process.info/2
  (ash 2.21.8) lib/ash/error/exception.ex:59: Ash.Error.Invalid.TenantRequired.exception/1
  (ash 2.21.8) lib/ash/actions/read/read.ex:1163: Ash.Actions.Read.validate_multitenancy/1
  (ash 2.21.8) lib/ash/actions/read/read.ex:304: anonymous fn/5 in Ash.Actions.Read.do_read/4
  (ash 2.21.8) lib/ash/engine/engine.ex:514: anonymous fn/4 in Ash.Engine.async/2
  (elixir 1.16.1) lib/task/supervised.ex:101: Task.Supervised.invoke_mfa/2
  (elixir 1.16.1) lib/task/supervised.ex:36: Task.Supervised.reply/4
    (elixir 1.16.1) lib/process.ex:860: Process.info/2
    (ash 2.21.8) lib/ash/error/exception.ex:59: Ash.Error.Invalid.exception/1
    (ash 2.21.8) lib/ash/error/error.ex:602: Ash.Error.choose_error/2
    (ash 2.21.8) lib/ash/error/error.ex:260: Ash.Error.to_error_class/2
    (ash 2.21.8) lib/ash/actions/read/read.ex:292: Ash.Actions.Read.do_run/3
    (ash 2.21.8) lib/ash/actions/read/read.ex:50: anonymous fn/3 in Ash.Actions.Read.run/3
    (ash 2.21.8) lib/ash/actions/read/read.ex:49: Ash.Actions.Read.run/3
    (ash 2.21.8) lib/ash/api/api.ex:2612: Ash.Api.read_one/3
    (ash 2.21.8) lib/ash/api/api.ex:2599: Ash.Api.read_one!/3
    (ash_admin 0.10.9) lib/ash_admin/pages/page_live.ex:381: AshAdmin.PageLive.handle_event/3
    (phoenix_live_view 0.20.14) lib/phoenix_live_view/channel.ex:507: anonymous fn/3 in Phoenix.LiveView.Channel.view_handle_event/3
    (telemetry 1.2.1) /Users/carlgleisner/Developer/my_app/deps/telemetry/src/telemetry.erl:321: :telemetry.span/3
    (phoenix_live_view 0.20.14) lib/phoenix_live_view/channel.ex:260: Phoenix.LiveView.Channel.handle_info/2
    (stdlib 5.1.1) gen_server.erl:1077: :gen_server.try_handle_info/3
    (stdlib 5.1.1) gen_server.erl:1165: :gen_server.handle_msg/6
    (stdlib 5.1.1) proc_lib.erl:241: :proc_lib.init_p_do_apply/3
Last message: %Phoenix.Socket.Message{topic: "lv:phx-F8M_oBHxitqXUyTB", event: "event", payload: %{"event" => "set_actor", "type" => "click", "value" => %{"api" => "Elixir.MyApp.Accounts", "pkey" => "7795ffa9-4d0d-463d-b095-98651bff887f", "resource" => "Elixir.MyApp.Accounts.User", "value" => ""}}, ref: "202", join_ref: "201"}
State: %{socket: #Phoenix.LiveView.Socket<id: "phx-F8M_oBHxitqXUyTB", endpoint: MyAppWeb.Endpoint, view: AshAdmin.PageLive, parent_pid: nil, root_pid: #PID<0.856.0>, router: MyAppWeb.Router, assigns: %{id: nil, table: nil, record: nil, prefix: "/admin", params: %{"action" => "read", "action_type" => "read", "api" => "Accounts", "resource" => "User", "route" => [], "table" => ""}, resource: MyApp.Accounts.User, action: %Ash.Resource.Actions.Read{arguments: [], description: nil, filter: nil, get_by: [], get?: false, manual: nil, metadata: [], modify_query: nil, name: :read, pagination: false, preparations: [], primary?: true, touches_resources: [], timeout: nil, transaction?: false, type: :read}, __changed__: %{}, flash: %{}, tables: [], api: MyApp.Accounts, primary_key: nil, tenant: "org_cdbd5349-26ac-4a6e-b9e2-956092bc780e", actor: nil, live_action: :page, apis: [MyApp.Accounts], action_type: :read, polymorphic_actions: nil, authorizing: false, actor_paused: true, editing_tenant: false, actor_api: nil, url_path: "/admin", tab: nil, actor_resources: [{MyApp.Accounts, MyApp.Accounts.User}]}, transport_pid: #PID<0.847.0>, ...>, components: {%{1 => {AshAdmin.Components.TopNav, "top_nav", %{id: "top_nav", open: false, prefix: "/admin", resource: MyApp.Accounts.User, __changed__: %{}, flash: %{}, api: MyApp.Accounts, tenant: "org_cdbd5349-26ac-4a6e-b9e2-956092bc780e", actor: nil, set_tenant: "set_tenant", myself: %Phoenix.LiveComponent.CID{cid: 1}, apis: [MyApp.Accounts], authorizing: false, actor_paused: true, editing_tenant: false, actor_api: nil, actor_resources: [{MyApp.Accounts, MyApp.Accounts.User}], clear_actor: "clear_actor", clear_tenant: "clear_tenant", toggle_actor_paused: "toggle_actor_paused", toggle_authorizing: "toggle_authorizing", nav_collapsed: false}, %{lifecycle: %Phoenix.LiveView.Lifecycle{after_render: [], handle_async: [], handle_event: [], handle_info: [], handle_params: [], mount: []}, live_temp: %{}, root_view: AshAdmin.PageLive, children_cids: [6, 5]}, {148060397520760006710221863373862312843, %{1 => {131016450657116420037473116728389064313, %{3 => {193117531274676238663499316904078091610, %{}}}}, 2 => 323659859598785054574994542540331106742, 3 => {288055939197927762304529307924563788880, %{0 => {51478131608043983236170183579808818613, %{2 => {145606693040105998035254632725030243907, %{}}, 6 => {138038591087602664711848583458530382947, %{0 => {10907819869706596814376658420644338192, %{0 => {131016450657116420037473116728389064313, %{3 => {178003258052215265257989775076931059304, %{}}}}}}}}}}}}, 4 => {52452721994246833135358052505681706306, %{0 => {180493659858002504575080165245409507118, %{1 => {177309640539645176365905376703197149830, %{}}, 2 => {141661402952870611029419311691675797224, %{}}}}}}}}}, 2 => {AshAdmin.Components.Resource, MyApp.Accounts.User, %{id: MyApp.Accounts.User, table: nil, record: nil, prefix: "/admin", params: %{"action" => "read", "action_type" => "read", "api" => "Accounts", "resource" => "User", "route" => [], "table" => ""}, resource: MyApp.Accounts.User, action: %Ash.Resource.Actions.Read{arguments: [], description: nil, filter: nil, get_by: [], get?: false, manual: nil, metadata: [], modify_query: nil, name: :read, pagination: false, preparations: [], primary?: true, touches_resources: [], timeout: nil, transaction?: false, type: :read}, __changed__: %{}, flash: %{}, tables: [], api: MyApp.Accounts, primary_key: nil, tenant: "org_cdbd5349-26ac-4a6e-b9e2-956092bc780e", actor: nil, set_actor: "set_actor", myself: %Phoenix.LiveComponent.CID{cid: 2}, action_type: :read, polymorphic_actions: nil, authorizing: false, url_path: "/admin", tab: nil, filter_open: false}, %{lifecycle: %Phoenix.LiveView.Lifecycle{after_render: [], handle_async: [], handle_event: [], handle_info: [], handle_params: [], mount: []}, live_temp: %{}, root_view: AshAdmin.PageLive, children_cids: [4, 3]}, {116549564983629548503950293970224204311, %{0 => {198509498940223282628687766034426527391, %{0 => {131016450657116420037473116728389064313, %{3 => {216715932998474834650148707730297806747, %{}}}}, 1 => {283810406251810921612151390347975945762, %{0 => {131016450657116420037473116728389064313, %{3 => {232574604184611946196318217149198693703, %{}}}}}}}}, 6 => {194783921231291960685782404229296793506, %{}}}}}, 3 => {AshAdmin.Components.TopNav.Dropdown, "Elixir.MyApp.Accounts.User_data_dropdown", %{active: false, id: "Elixir.MyApp.Accounts.User_data_dropdown", name: "Read", open: false, __changed__: %{}, class: "", flash: %{}, myself: %Phoenix.LiveComponent.CID{cid: 3}, group_labels: [], groups: [[%{active: false, text: "Sign In With Password", to: "/admin?api=Accounts&resource=User&table=&action_type=read&action=sign_in_with_password"}, %{active: false, text: "Get By Subject", to: "/admin?api=Accounts&resource=User&table=&action_type=read&action=get_by_subject"}, %{active: true, text: "Read", to: "/admin?api=Accounts&resource=User&table=&action_type=read&action=read"}]]}, %{lifecycle: %Phoenix.LiveView.Lifecycle{after_render: [], handle_async: [], handle_event: [], handle_info: [], handle_params: [], mount: []}, live_temp: %{}, root_view: AshAdmin.PageLive, children_cids: []}, {132048723562976016917943051661893721681, %{}}}, 4 => {AshAdmin.Components.Resource.DataTable, "Elixir.MyApp.Accounts.User_table", %{data: {:ok, [#MyApp.Accounts.User<__meta__: #Ecto.Schema.Metadata<:loaded, "org_cdbd5349-26ac-4a6e-b9e2-956092bc780e", "users">, id: "7795ffa9-4d0d-463d-b095-98651bff887f", email: #Ash.CiString<"[email protected]">, first_name: "First name", last_name: "Last name", phone: "555-123 456 79", is_a (truncated)

Expected behavior

The current user, fetched from the users table of the set tenant, to be set.

Runtime

  • elixir 1.16.1-otp-26
  • erlang 26.1.2
  • macOS Sonoma 14.4.1 (Darwin Kernel Version 23.4.0)
  • ash 2.21.8
  • ash_admin 0.10.9
  • ash_postgres 1.5.23

Additional context

Comment from @zachdaniel on Discord:

"there are some interesting implications there, we'll need to track the actor_tenant in the session to make sure we can look up the user properly"

Can't unset required boolean values in the admin panel

Describe the bug
I have:

    attribute :demo_mode, :boolean, allow_nil?: false, default: false

When I try to set this value to false in the admin panel after it's been set, it says "is invalid" or "is required" and won't let me unset it.

Expected behavior
I can set the value to false.

Runtime

  • Elixir version: 1.15
  • Erlang version: 25
  • OS: Linux
  • Ash version: 2.13.3
  • any related extension versions
    ash_admin: 0.9.4

function Phoenix.HTML.Tag.csrf_meta_tag/0 is undefined (module Phoenix.HTML.Tag is not available)

Describe the bug

#AshAdmin
When loading the url set up on the router, the error pop up

To Reproduce

Just followed the readme to implement it on my small project (2 API's)

defmodule MyApp.Accounts.User do
  use Ash.Resource,
    data_layer: AshPostgres.DataLayer,
    extensions: [AshAuthentication, AshAdmin.Resource],
    authorizers: [Ash.Policy.Authorizer]

  admin do
    actor?(true)
  end

And the second one

defmodule MyApp.Items.Item do
  use Ash.Resource,
    data_layer: AshPostgres.DataLayer,
    authorizers: [Ash.Policy.Authorizer],
    extensions: [AshAdmin.Resource]

Expected behavior

To open the admin

Runtime

  • Elixir version: Elixir 1.15.7 (compiled with Erlang/OTP 26)
  • Erlang version: 26.1.1
  • OS: macos-x64
  • Ash version 2.18
  • any related extension versions
    {:ash, "> 2.18"},
    {:ash_admin, "
    > 0.10"},
    {:ash_authentication, "> 3.12"},
    {:ash_authentication_phoenix, "
    > 1.9"},
    {:ash_phoenix, "> 1.3"},
    {:ash_postgres, "
    > 1.4"},

Additional context

New to Ash, so I guess im doing something wrong, sry

Router file

  use AshAuthentication.Phoenix.Router
  import AshAdmin.Router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_live_flash
    plug :put_root_layout, {MyAppWeb.Layouts, :root}
    plug :protect_from_forgery
    # plug :put_secure_browser_headers
    plug :put_secure_browser_headers, %{
      "content-security-policy" => "default-src 'nonce-ash_admin-Ed55GFnX' 'self'"
    }

    # Ash AUTHENTICATION
    plug :load_from_session
  end

And the related route

  # ONLY for AshAdmin
  scope "/" do
    pipe_through :browser

    ash_admin("/admin")
  end

  scope "/", MyAppWeb do
    pipe_through :browser

Allow Adding high level links

Is your feature request related to a problem? Please describe.
It is currently not possible to add a link in the app for example to logout the admin user.

Describe the solution you'd like
Add a configuration that would allow dynamically adding links top most level again example ( sign out, settings, etc)

Describe alternatives you've considered
A way to override the default template ?

Express the feature either with a change to resource syntax, or with a change to the resource interface

For example

  admin do
    links do
       link :settings, "/settings"
    end
  end

Dropdown component missed item in Surface conversion

Describe the bug

Ash Admin renders { @label_text } in place of the group label in the drop down list for selecting which resource to edit.

image

It looks like lib > ash_admin > components > top_nav > dropdown.ex missed the full Surface --> Heex conversion treatment (~line 107).

To Reproduce

In the admin section of a resource definition, add a value for resource_group

Expected behavior

The value for resource group is used to label the group of resources in the UI.

Runtime

  • Elixir version : 1.15.4
  • Erlang version: Erlang/OTP 26
  • OS: MacOS 13.6
  • Ash version: 2.15.17
  • any related extension versions: Ash_admin: 0.9.5

Additional context

PR incoming - no issue reported, and not fixed in current codebase.

UI improvements

I've create a wireframe/visual design to visualize a potential new user interface for Ash Admin.

The base idea is to give more room to the navigation - to replace the current buttons and selects in the top bar with navigation items in de sidebar.

The screens incorporate ideas for more intuitive interactions by using button labels, such as the disconnect actor buttons.

To prioritize data visibility, I've minimized the color palette, with a couple of brand color touches.

Ash Admin UX.pdf

Single screen:

20231112 Ash Admin UX - User set

Missing ThingyWeb.LayoutView module

Describe the bug

I'm currently poking with the stick into ash_example.
Then I try to add and use ash_admin, I've got an exception about missing ThingyWeb.LayoutView module:

Server: localhost:4000 (http)
Request: GET /
** (exit) an exception was raised:
    ** (UndefinedFunctionError) function ThingyWeb.LayoutView.render/2 is undefined (module ThingyWeb.LayoutView is not available)
        ThingyWeb.LayoutView.render("root.html", %{__changed__: %{actor: true, ash_live_config: true, me: true, tickets: true}, actor: #Helpdesk.Accounts.User<__meta__: #Ecto.Schema.Metadata<:loaded, "users">, id: "ca908d60-bc4c-4740-a4e9-1edbe770674d", first_name: "mef", last_name: nil, representative: false, admin: true, aggregates: %{}, calculations: %{}, __order__: nil, ...>, ash_live_config: %{me: %{callback: #Function<2.17681511/1 in HelpdeskWeb.HomeLive.mount/3>, last_fetched_at: -576460734887, opts: [results: :keep, refetch_interval: 300000, subscribe: ["ticket:assigned_to:ca908d60-bc4c-4740-a4e9-1edbe770674d"]]}, tickets: %{callback: #Function<3.17681511/2 in HelpdeskWeb.HomeLive.mount/3>, last_fetched_at: -576460734873, opts: [api: Helpdesk.Tickets.Api, results: :keep, refetch_interval: 60000, subscribe: ["user:updated:ca908d60-bc4c-4740-a4e9-1edbe770674d", "ticket:updated:ca908d60-bc4c-4740-a4e9-1edbe770674d"]]}}, conn: %Plug.Conn{adapter: {Plug.Cowboy.Conn, :...}, assigns: %{__changed__: %{actor: true, ash_live_config: true, me: true, tickets: true}, actor: #Helpdesk.Accounts.User<__meta__: #Ecto.Schema.Metadata<:loaded, "users">, id: "ca908d60-bc4c-4740-a4e9-1edbe770674d", first_name: "mef", last_name: nil, representative: false, admin: true, aggregates: %{}, calculations: %{}, __order__: nil, ...>, ash_live_config: %{me: %{callback: #Function<2.17681511/1 in HelpdeskWeb.HomeLive.mount/3>, last_fetched_at: -576460734887, opts: [results: :keep, refetch_interval: 300000, subscribe: ["ticket:assigned_to:ca908d60-bc4c-4740-a4e9-1edbe770674d"]]}, tickets: %{callback: #Function<3.17681511/2 in HelpdeskWeb.HomeLive.mount/3>, last_fetched_at: -576460734873, opts: [api: Helpdesk.Tickets.Api, results: :keep, refetch_interval: 60000, subscribe: ["user:updated:ca908d60-bc4c-4740-a4e9-1edbe770674d", "ticket:updated:ca908d60-bc4c-4740-a4e9-1edbe770674d"]]}}, content: {:safe, ["", ["", [60, "div"], "", [" data", 45, "phx-main", 61, 34, "true", 34, " data", 45, "phx-session", 61, 34, "SFMyNTY.g2gDaAJhBXQAAAAIZAACaWRtAAAAFHBoeC1GelZpNHRJME9nT01WQUFsZAAMbGl2ZV9zZXNzaW9uaAJkAAdkZWZhdWx0bggA0dXtddRiNRdkAApwYXJlbnRfcGlkZAADbmlsZAAIcm9vdF9waWRkAANuaWxkAAlyb290X3ZpZXdkABtFbGl4aXIuSGVscGRlc2tXZWIuSG9tZUxpdmVkAAZyb3V0ZXJkABlFbGl4aXIuSGVscGRlc2tXZWIuUm91dGVyZAAHc2Vzc2lvbnQAAAAAZAAEdmlld2QAG0VsaXhpci5IZWxwZGVza1dlYi5Ib21lTGl2ZW4GAAa961-FAWIAAVGA.A3XPnfaTIjTIQLEyHMTYT3bynM7GVas0hw7obMAG4n0", 34, " data", 45, "phx-static", 61, 34, "SFMyNTY.g2gDaAJhBXQAAAADZAAKYXNzaWduX25ld2wAAAABZAAFYWN0b3JqZAAFZmxhc2h0AAAAAGQAAmlkbQAAABRwaHgtRnpWaTR0STBPZ09NVkFBbG4GAAi961-FAWIAAVGA.4a6FjBrNlSIF6hNahzCSlUvjzSip9Qs5gwAIEuCNFJQ", 34, " id=\"", "phx-FzVi4tI0OgOMVAAl", 34], "", '>', "", ["", ["<main role=\"main\" class=\"container\">\n", ["", ["\n  <section class=\"phx-hero\">\n    <h1>", "Welcome to Helpdesk, Anonymous user!", "</h1>\n    <h2>Please pass user ID into <code>User-Id</code> header to log in</h2>\n  </section>\n"], ""], "\n</main>\n"], ""], "", [60, 47, "div", 62], ""], ""]}, flash: %{}, layout: false, live_action: nil, live_module: HelpdeskWeb.HomeLive, me: nil, tickets: %{__first__?: true, __struct__: Ash.Page.Offset, count: 0, limit: 5, more?: false, offset: 0, rerun: {#Ash.Query<resource: Helpdesk.Tickets.Ticket, filter: #Ash.Filter<representative.id == "ca908d60-bc4c-4740-a4e9-1edbe770674d">, limit: 6>, [page: [count: true, limit: 5], verbose?: false, actor: #Helpdesk.Accounts.User<__meta__: #Ecto.Schema.Metadata<:loaded, "users">, id: "ca908d60-bc4c-4740-a4e9-1edbe770674d", first_name: "mef", last_name: nil, representative: false, admin: true, aggregates: %{}, calculations: %{}, __order__: nil, ...>, authorize?: false, return_query?: false]}, results: []}}, body_params: %{}, cookies: %{"_helpdesk_key" => "SFMyNTY.g3QAAAACbQAAAAtfY3NyZl90b2tlbm0AAAAYeEI4TDQ5T3Rrd3ROQnhYaXliZFROY1JZbQAAAAd1c2VyX2lkbQAAACRjYTkwOGQ2MC1iYzRjLTQ3NDAtYTRlOS0xZWRiZTc3MDY3NGQ.0w9UtKmxxAfHefVTRW5X6dqC7ICSnK770uG5VrOwyrE"}, halted: false, host: "localhost", method: "GET", owner: #PID<0.646.0>, params: %{}, path_info: [], path_params: %{}, port: 4000, private: %{HelpdeskWeb.Router => {[], %{Absinthe.Plug => ["gql"], Absinthe.Plug.GraphiQL => ["playground"]}}, :before_send => [#Function<0.20795500/1 in Plug.CSRFProtection.call/2>, #Function<2.36663997/1 in Phoenix.Controller.fetch_flash/2>, #Function<0.84243074/1 in Plug.Session.before_send/2>, #Function<0.11807388/1 in Plug.Telemetry.call/2>, #Function<1.86886788/1 in Phoenix.LiveReloader.before_send_inject_reloader/3>], :phoenix_endpoint => HelpdeskWeb.Endpoint, :phoenix_flash => %{}, :phoenix_format => "html", :phoenix_layout => false, :phoenix_live_view => {HelpdeskWeb.HomeLive, [action: nil, router: HelpdeskWeb.Router], %{extra: %{session: %{}}, name: :default, vsn: 1672351501289117137}}, :phoenix_request_logger => {"request_logger", "request_logger"}, :phoenix_root_layout => {ThingyWeb.LayoutView, :root}, :phoenix_router => HelpdeskWeb.Router, :phoenix_template => "template.html", :phoenix_view => Phoenix.LiveView.Static, :plug_session => %{"_csrf_token" => "xB8L49OtkwtNBxXiybdTNcRY", "user_id" => "ca908d60-bc4c-4740-a4e9-1edbe770674d"}, :plug_session_fetch => :done}, query_params: %{}, query_string: "", remote_ip: {127, 0, 0, 1}, req_cookies: %{"_helpdesk_key" => "SFMyNTY.g3QAAAACbQAAAAtfY3NyZl90b2tlbm0AAAAYeEI4TDQ5T3Rrd3ROQnhYaXliZFROY1JZbQAAAAd1c2VyX2lkbQAAACRjYTkwOGQ2MC1iYzRjLTQ3NDAtYTRlOS0xZWRiZTc3MDY3NGQ.0w9UtKmxxAfHefVTRW5X6dqC7ICSnK770uG5VrOwyrE"}, req_headers: [{"accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"}, {"accept-encoding", "gzip, deflate, br"}, {"accept-language", "en-US,en;q=0.8,ru-RU;q=0.5,ru;q=0.3"}, {"connection", "keep-alive"}, {"cookie", "_helpdesk_key=SFMyNTY.g3QAAAACbQAAAAtfY3NyZl90b2tlbm0AAAAYeEI4TDQ5T3Rrd3ROQnhYaXliZFROY1JZbQAAAAd1c2VyX2lkbQAAACRjYTkwOGQ2MC1iYzRjLTQ3NDAtYTRlOS0xZWRiZTc3MDY3NGQ.0w9UtKmxxAfHefVTRW5X6dqC7ICSnK770uG5VrOwyrE"}, {"host", "localhost:4000"}, {"sec-fetch-dest", "document"}, {"sec-fetch-mode", "navigate"}, {"sec-fetch-site", "none"}, {"sec-fetch-user", "?1"}, {"upgrade-insecure-requests", "1"}, {"user-agent", "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0"}, {"user-id", "ca908d60-bc4c-4740-a4e9-1edbe770674d"}], request_path: "/", resp_body: nil, resp_cookies: %{}, resp_headers: [{"cache-control", "max-age=0, private, must-revalidate"}, {"x-request-id", "FzVi4tGYmfIVjFQAAAAF"}, {"x-frame-options", "SAMEORIGIN"}, {"x-xss-protection", "1; mode=block"}, {"x-content-type-options", "nosniff"}, {"x-download-options", "noopen"}, {"x-permitted-cross-domain-policies", "none"}, {"cross-origin-window-policy", "deny"}], scheme: :http, script_name: [], secret_key_base: :..., state: :unset, status: nil}, content: {:safe, ["", ["", [60, "div"], "", [" data", 45, "phx-main", 61, 34, "true", 34, " data", 45, "phx-session", 61, 34, "SFMyNTY.g2gDaAJhBXQAAAAIZAACaWRtAAAAFHBoeC1GelZpNHRJME9nT01WQUFsZAAMbGl2ZV9zZXNzaW9uaAJkAAdkZWZhdWx0bggA0dXtddRiNRdkAApwYXJlbnRfcGlkZAADbmlsZAAIcm9vdF9waWRkAANuaWxkAAlyb290X3ZpZXdkABtFbGl4aXIuSGVscGRlc2tXZWIuSG9tZUxpdmVkAAZyb3V0ZXJkABlFbGl4aXIuSGVscGRlc2tXZWIuUm91dGVyZAAHc2Vzc2lvbnQAAAAAZAAEdmlld2QAG0VsaXhpci5IZWxwZGVza1dlYi5Ib21lTGl2ZW4GAAa961-FAWIAAVGA.A3XPnfaTIjTIQLEyHMTYT3bynM7GVas0hw7obMAG4n0", 34, " data", 45, "phx-static", 61, 34, "SFMyNTY.g2gDaAJhBXQAAAADZAAKYXNzaWduX25ld2wAAAABZAAFYWN0b3JqZAAFZmxhc2h0AAAAAGQAAmlkbQAAABRwaHgtRnpWaTR0STBPZ09NVkFBbG4GAAi961-FAWIAAVGA.4a6FjBrNlSIF6hNahzCSlUvjzSip9Qs5gwAIEuCNFJQ", 34, " id=\"", "phx-FzVi4tI0OgOMVAAl", 34], "", '>', "", ["", ["<main role=\"main\" class=\"container\">\n", ["", ["\n  <section class=\"phx-hero\">\n    <h1>", "Welcome to Helpdesk, Anonymous user!", "</h1>\n    <h2>Please pass user ID into <code>User-Id</code> header to log in</h2>\n   (truncated)

There can I fetch this module from? Google failed to find something related to this.

To Reproduce

  1. Clone this repo https://github.com/dolfinus/ash_example, branch test
  2. mix phx.server
  3. Open http://localhost:4000
    изображение

Expected behavior

A clear and concise description of what you expected to happen.

Runtime
Erlang/OTP 25 [erts-13.1.3] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit:ns]
Elixir 1.14.0 (compiled with Erlang/OTP 25)
Linux 6.1.1-1-MANJARO #1 SMP PREEMPT_DYNAMIC Wed Dec 21 23:21:50 UTC 2022 x86_64 GNU/Linux

Dependency resolution completed:
  absinthe 1.7.0
  absinthe_plug 1.5.8
  ash 2.4.30
  ash_admin 0.7.1
  ash_graphql 0.22.3
  ash_phoenix 1.2.3
  ash_postgres 1.2.6
  castore 0.1.20
  comparable 1.0.0
  connection 1.1.0
  cowboy 2.9.0
  cowboy_telemetry 0.4.0
  cowlib 2.11.0
  dataloader 1.0.10
  db_connection 2.4.3
  decimal 2.0.0
  ecto 3.9.4
  ecto_psql_extras 0.7.10
  ecto_sql 3.9.2
  elixir_make 0.7.3
  ets 0.8.1
  file_system 0.2.10
  floki 0.34.0
  gettext 0.20.0
  jason 1.4.0
  mime 2.0.3
  nimble_options 0.5.2
  nimble_parsec 1.2.3
  phoenix 1.6.15
  phoenix_ecto 4.4.0
  phoenix_html 3.2.0
  phoenix_live_dashboard 0.7.2
  phoenix_live_reload 1.4.1
  phoenix_live_view 0.18.3
  phoenix_pubsub 2.1.1
  phoenix_template 1.0.0
  phoenix_view 2.0.2
  picosat_elixir 0.2.3
  plug 1.14.0
  plug_cowboy 2.6.0
  plug_crypto 1.2.3
  postgrex 0.16.5
  ranch 1.8.0
  sourceror 0.11.2
  spark 0.3.2
  stream_data 0.5.0
  surface 0.9.1
  table_rex 3.1.1
  telemetry 1.1.0
  telemetry_metrics 0.6.1
  telemetry_poller 1.0.0
  typable 0.3.0

Additional context

Actions are accessible despite not being enabled?

Describe the bug

I thought if I set read_actions in a resource, that I would not be able to access any other read action. The dropdown UI correctly only lists the actions that are listed in read_actions, but editing the URL allows any action to be accessed?

To Reproduce

eg. in a resource:

  actions do
    defaults [:read, :create, :update]

    read :find_by_appointment_id do
      argument :appointment_id, :uuid, allow_nil?: false

      prepare build(sort: [event_ts: :desc], load: [:occurred_at])
      filter expr(appointment_id == ^arg(:appointment_id))
    end
  end

  admin do
    read_actions [:read]
  end

Accessing http://localhost:4000/admin?api=MyApi&resource=MyResource&table=&action_type=read&action=find_by_appointment_id still works, renders the form to enter an appointment ID, and then will run the query.

Expected behavior

An error when accessing a disabled action.

Runtime

  • Ash version main at 7b5a3267beb385b22c174c979649cae4ff57635d
  • Ash Admin main at 92f9997

Templates broken in LiveView 0.20

Describe the bug

The admin pages render unresolved markup, while the developer console spews errors "only HTML element tags are allowed at the root of components.

admin-template-errors

To Reproduce

  1. Follow the steps in Get Started with Ash and Phoenix.
  2. Follow the steps in the ash_admin README to add Admin pages.
  3. Start server and visit any admin page.

The problem is clearly introduced withphoenix_live_view version 0.20, as it disappears with a downgrade using deps config {:phoenix_live_view, "0.19.5"}.

Missing dependency with Phoenix 1.7

Describe the bug

In Phoenix 1.7 project compilation fails with this error:

== Compilation error in file lib/ash_admin/layout_view.ex ==
** (CompileError) lib/ash_admin/layout_view.ex:3: module Phoenix.View is not loaded and could not be found
    (elixir 1.14.2) expanding macro: Kernel.use/2
    lib/ash_admin/layout_view.ex:3: AshAdmin.LayoutView (module)
    expanding macro: AshAdmin.Web.__using__/1
    lib/ash_admin/layout_view.ex:3: AshAdmin.LayoutView (module)
    (elixir 1.14.2) expanding macro: Kernel.use/2
    lib/ash_admin/layout_view.ex:3: AshAdmin.LayoutView (module)

Adding {:phoenix_view, "~> 2.0"}, to my mix.exs fixes the problem. Perhaps it should be mentioned in the README.

To Reproduce

Add AshAdmin to a Phoenix 1.7 project.

Expected behavior

No errors

Runtime

  • Elixir version 1.14.2
  • Erlang version 25
  • Ash version 2.4.24
  • AshAdmin 0.7.0
  • Phoenix 1.7-rc0
  • Phoenix LiveView 0.18.3

Exception when loading relationships in an update

Describe the bug
After updating to the latest ash_admin, I can no longer load relationships in an update action.

For the following action:

    update :manage_templates do
      accept []
      argument :templates, {:array, :map}

      change manage_relationship(:templates, type: :direct_control)
    end

When I click the Load button in the admin panel for templates, I get the following exception:

** (AshPhoenix.Form.NoFormConfigured) templates at path [] must be configured in the form to be used with `inputs_for`. For example:

Available forms:

Example Setup:

    Form.for_create(
[truncated]
    (ash_phoenix 1.2.16) lib/ash_phoenix/form/form.ex:4429: Phoenix.HTML.FormData.AshPhoenix.Form.to_form/4
    (phoenix_live_view 0.19.5) lib/phoenix_component.ex:2364: Phoenix.Component."inputs_for (overridable 1)"/1
    (phoenix_live_view 0.19.5) lib/phoenix_live_view/tag_engine.ex:68: Phoenix.LiveView.TagEngine.component/3
    (ash_admin 0.9.3) lib/ash_admin/components/resource/form.ex:348: anonymous fn/2 in AshAdmin.Components.Resource.Form.render_relationship_input/5

Expected behavior
It would allow me to add and remove templates.
Runtime

  • Elixir version: 1.15
  • Erlang version: 25
  • OS: Mac OS
  • Ash version:
  • any related extension versions:
    ash_admin: 0.9.3
    ash_phoenix: 1.2.16
    ash: 2.10.2

Additional context

In this particular example, the template array was empty when I hit the error.

Error on `mix migrate_tenants` command

To work on ash_admin, you'll want to be able to run the dev app. You'll need to have postgres setup locally, at which point you can do the following:

mix ash_postgres.create
mix migrate
mix migrate_tenants
Then, you can start the app with: mix dev

if you make changes to the resources, you can generate migrations with mix generate_migrations

The mix migrate_tenants step produces this error:

** (Mix) Could not find migrations directory "dev/repo/tenant_migrations"
for repo Demo.Repo.

This may be because you are in a new project and the
migration directory has not been created yet. Creating an
empty directory at the path above will fix this error.

If you expected existing migrations to be found, please
make sure your repository has been properly configured
and the configured path exists.

To Reproduce

Clone down main and follow the development instructions. The command: mix migrate_tenants will throw an error.

Expected behavior

No error when running tenant migrations.

Runtime

  • Elixir version: 1.14.3
  • Erlang version 25.2.2
  • OS macOS 13.2.1
  • Ash version 2.4.2

compiler complains about missing phoenix_view

added ash_admin as a depencency to the project and got this error

➜  tryash git:(main) ✗ mix deps.compile ash_admin
warning: the :phoenix compiler is no longer required in your mix.exs.

Please find the following line in your mix.exs and remove the :phoenix entry:

    compilers: [..., :phoenix, ...] ++ Mix.compilers(),

  (phoenix 1.7.0-rc.2) lib/mix/tasks/compile.phoenix.ex:8: Mix.Tasks.Compile.Phoenix.run/1
  (mix 1.14.2) lib/mix/task.ex:421: anonymous fn/3 in Mix.Task.run_task/4
  (mix 1.14.2) lib/mix/tasks/compile.all.ex:92: Mix.Tasks.Compile.All.run_compiler/2
  (mix 1.14.2) lib/mix/tasks/compile.all.ex:72: Mix.Tasks.Compile.All.compile/4
  (mix 1.14.2) lib/mix/tasks/compile.all.ex:59: Mix.Tasks.Compile.All.with_logger_app/2
  (mix 1.14.2) lib/mix/tasks/compile.all.ex:33: Mix.Tasks.Compile.All.run/1

==> ash_admin
Compiling 29 files (.ex)

== Compilation error in file lib/ash_admin/layout_view.ex ==
** (CompileError) lib/ash_admin/layout_view.ex:3: module Phoenix.View is not loaded and could not be found
    (elixir 1.14.2) expanding macro: Kernel.use/2
    lib/ash_admin/layout_view.ex:3: AshAdmin.LayoutView (module)
    expanding macro: AshAdmin.Web.__using__/1
    lib/ash_admin/layout_view.ex:3: AshAdmin.LayoutView (module)
    (elixir 1.14.2) expanding macro: Kernel.use/2
    lib/ash_admin/layout_view.ex:3: AshAdmin.LayoutView (module)
could not compile dependency :ash_admin, "mix compile" failed. Errors may have been logged above. You can recompile this dependency with "mix deps.compile ash_admin", update it with "mix deps.upda
te ash_admin" or clean it with "mix deps.clean ash_admin"

On discord, Zach suggested to add phoenix_view to my projects dependencies.
Doing so removed the error but now mix is warning with:

warning: Phoenix.View.template_path_to_name/2 defined in application :phoenix_view is used by the current application but the current application does not depend on :phoenix_view. To fix this, you must do one of:

  1. If :phoenix_view is part of Erlang/Elixir, you must include it under :extra_applications inside "def application" in your mix.exs

  2. If :phoenix_view is a dependency, make sure it is listed under "def deps" in your mix.exs

  3. In case you don't want to add a requirement to :phoenix_view, you may optionally skip this warning by adding [xref: [exclude: [Phoenix.View]]] to your "def project" in mix.exs

  lib/ash_admin/layout_view.ex:1: AshAdmin.LayoutView

Generated ash_admin app

To Reproduce

Follow instructions to configure ash in a fresh project.

Expected behavior

a clean install.

Runtime

  • Elixir version 1.4.12
  • Erlang version 25
  • OS osx
  • Ash version 2.5.10
  • any related extension versions

deps from the project

  {:phoenix, "~> 1.7.0-rc.2", override: true},
  {:phoenix_ecto, "~> 4.4"},
  {:ecto_sql, "~> 3.6"},
  {:postgrex, ">= 0.0.0"},
  {:phoenix_html, "~> 3.0"},
  {:phoenix_live_reload, "~> 1.2", only: :dev},
  {:phoenix_live_view, "~> 0.18.3"},
  {:heroicons, "~> 0.5"},
  {:floki, ">= 0.30.0", only: :test},
  {:phoenix_live_dashboard, "~> 0.7.2"},
  {:esbuild, "~> 0.5", runtime: Mix.env() == :dev},
  {:tailwind, "~> 0.1.8", runtime: Mix.env() == :dev},
  {:swoosh, "~> 1.3"},
  {:finch, "~> 0.13"},
  {:telemetry_metrics, "~> 0.6"},
  {:telemetry_poller, "~> 1.0"},
  {:gettext, "~> 0.20"},
  {:jason, "~> 1.2"},
  {:plug_cowboy, "~> 2.5"},
  {:ash_postgres, "~> 1.3.2"},
  {:ash, "~> 2.5.10"},
  {:ash_authentication, "~> 3.7.0"},
  {:ash_admin, "~> 0.7.1"},
  {:phoenix_view, "~> 2.0.2"}

Additional context

Add any other context about the problem here.

Phoenix.HTML.Safe not implemented for #AshPhoenix.Form

Describe the bug

Navigating to the update action of a resource with a belongs_to relationship to another resource crashes with the error protocol Phoenix.HTML.Safe not implemented for #AshPhoenix.Form[…].

Please note that this works just fine in my Phoenix app ⚠️

To Reproduce

The resource that belongs_to another resource. It is redacted and reduced to what is pertinent because that is what I provide at the moment.

defmodule MyApp.MyDomain.MyResource do
  use Ash.Resource,
    domain: MyApp.MyDomain,
    data_layer: AshPostgres.DataLayer,
    extensions: [AshAdmin.Resource, AshStateMachine]

  postgres do
    table "my_domain_my_resources"
    repo MyApp.Repo
  end

  attributes do
    uuid_primary_key :id

    create_timestamp :created_at
    create_timestamp :updated_at
  end

  relationships do
    belongs_to :my_related_resource, MyApp.MyDomain.MyRelatedResource do
      allow_nil? false
    end
  end

  actions do
    defaults [:read, :destroy]
    default_accept :*

    create :create do
      primary? true

      argument :my_related_resource_id, :uuid do
        allow_nil? false
      end

      argument :court_id, :uuid do
        allow_nil? false
      end

      argument :claims_harvester_id, :uuid

      change manage_relationship(:my_related_resource_id, :my_related_resource, type: :append_and_remove)

      change relate_actor(:created_by)
    end

    update :update do
      argument :my_related_resource_id, :uuid do
        allow_nil? false
      end

      require_atomic? false

      change manage_relationship(:my_related_resource_id, :my_related_resource, type: :append_and_remove)
    end
  end


  admin do
    form do
      field :some_comment, type: :long_text
    end
  end
end

The related resource that the previous one belongs to.

defmodule MyApp.MyDomain.MyRelatedResource do
  use Ash.Resource,
    domain: MyApp.MyDomain,
    data_layer: AshPostgres.DataLayer,
    extensions: [AshAdmin.Resource, AshArchival.Resource]

  postgres do
    table "my_domain_my_realted_resources"
    repo MyApp.Repo
  end

  attributes do
    uuid_primary_key :id

    create_timestamp :created_at
    create_timestamp :updated_at
  end

  actions do
    defaults [:create, :read, :update]
    default_accept :*

    destroy :destroy do
      require_atomic? false
    end
  end
end

The error output.

[error] GenServer #PID<0.9786.0> terminating
** (Protocol.UndefinedError) protocol Phoenix.HTML.Safe not implemented for #AshPhoenix.Form<resource: MyApp.MyDomain.MyRelatedResource, action: :read, type: :read, params: %{"id" => "c24b2a79-a013-4111-8191-b841c7c4f991"}, source: #Ash.Query<resource: MyApp.MyDomain.MyRelatedResource, filter: #Ash.Filter<archived_at is nil>>, name: "form[my_resource_id]", data: #MyApp.MyDomain.MyRelatedResource<__meta__: #Ecto.Schema.Metadata<:loaded, "my_domain_my_resource">, archived_at: nil, id: "c24b2a79-a013-4111-8191-b841c7c4f991", name: "name", something_id: "[redacted]", something_else_id: "[redacted]", created_at: ~U[2024-03-06 02:40:16.910858Z], updated_at: ~U[2024-03-06 02:40:16.910858Z], aggregates: %{}, calculations: %{}, ...>, form_keys: [], forms: %{}, domain: MyApp.MyDomain, method: "post", submit_errors: nil, id: "form_my_resource_id", transform_errors: #Function<3.101091702/2 in AshAdmin.Components.Resource.Form.assign_form/1>, original_data: nil, transform_params: #Function<39.62187671/3 in AshPhoenix.Form.Auto.related/3>, prepare_params: nil, prepare_source: nil, warn_on_unhandled_errors?: true, any_removed?: false, added?: false, changed?: false, touched_forms: MapSet.new(["id"]), valid?: true, errors: false, submitted_once?: false, just_submitted?: false, ...> of type AshPhoenix.Form (a struct). This protocol is implemented for the following type(s): Ash.CiString, Ash.NotLoaded, Atom, BitString, Date, DateTime, Decimal, Float, Integer, List, Money, NaiveDateTime, Phoenix.LiveComponent.CID, Phoenix.LiveView.Component, Phoenix.LiveView.Comprehension, Phoenix.LiveView.JS, Phoenix.LiveView.Rendered, Time, Tuple, URI
    (phoenix_html 4.1.1) lib/phoenix_html/safe.ex:1: Phoenix.HTML.Safe.impl_for!/1
    (phoenix_html 4.1.1) lib/phoenix_html/safe.ex:15: Phoenix.HTML.Safe.to_iodata/1
    (phoenix_html 4.1.1) lib/phoenix_html.ex:238: Phoenix.HTML.build_attrs/1
    (phoenix_html 4.1.1) lib/phoenix_html.ex:191: Phoenix.HTML.attributes_escape/1
    (ash_admin 0.10.10-rc.1) lib/ash_admin/components/core_components.ex:366: anonymous fn/2 in AshAdmin.CoreComponents."input (overridable 1)"/1
    (ash_admin 0.10.10-rc.1) /Users/username/Developer/my_app/deps/ash_admin/lib/ash_admin/components/resource/form.ex:776: AshAdmin.Components.Resource.Form.render_attribute_input/6
    (elixir 1.16.1) lib/enum.ex:2528: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 0.20.14) lib/phoenix_live_view/diff.ex:389: Phoenix.LiveView.Diff.traverse/7
    (phoenix_live_view 0.20.14) lib/phoenix_live_view/diff.ex:546: anonymous fn/4 in Phoenix.LiveView.Diff.traverse_dynamic/7
    (elixir 1.16.1) lib/enum.ex:2528: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 0.20.14) lib/phoenix_live_view/diff.ex:389: Phoenix.LiveView.Diff.traverse/7
    (phoenix_live_view 0.20.14) lib/phoenix_live_view/diff.ex:573: anonymous fn/3 in Phoenix.LiveView.Diff.traverse_comprehension/5
    (elixir 1.16.1) lib/enum.ex:1826: Enum."-map_reduce/3-lists^mapfoldl/2-0-"/3
    (elixir 1.16.1) lib/enum.ex:1826: Enum."-map_reduce/3-lists^mapfoldl/2-0-"/3
    (elixir 1.16.1) lib/enum.ex:1826: Enum."-map_reduce/3-lists^mapfoldl/2-0-"/3
    (elixir 1.16.1) lib/enum.ex:1826: Enum."-map_reduce/3-lists^mapfoldl/2-0-"/3
    (phoenix_live_view 0.20.14) lib/phoenix_live_view/diff.ex:494: Phoenix.LiveView.Diff.traverse/7
    (phoenix_live_view 0.20.14) lib/phoenix_live_view/diff.ex:546: anonymous fn/4 in Phoenix.LiveView.Diff.traverse_dynamic/7
Last message: {:continue, :handle_connection}
State: {%ThousandIsland.Socket{socket: #Port<0.59>, transport_module: ThousandIsland.Transports.TCP, read_timeout: 60000, silent_terminate_on_error: false, span: %ThousandIsland.Telemetry{span_name: :connection, telemetry_span_context: #Reference<0.2781554790.1804337155.144331>, start_time: -576460661694657815, start_metadata: %{telemetry_span_context: #Reference<0.2781554790.1804337155.144331>, remote_port: 60242, remote_address: {127, 0, 0, 1}, parent_telemetry_span_context: #Reference<0.2781554790.1804337155.142621>}}}, %{opts: %{http: [], websocket: [], http_1: [], http_2: []}, plug: {Phoenix.Endpoint.SyncCodeReloadPlug, {MyAppWeb.Endpoint, []}}, handler_module: Bandit.InitialHandler, http_1_enabled: true, http_2_enabled: true}}

Expected behavior

The admin liveview should render properly, that is not crash but rather show a field for the relationship to the related resource.

Runtime

  • Elixir 1.16.1-otp-26
  • Erlang 26.1.2
  • macOS Sonoma 14.4.1 Darwin Kernel Version 23.4.0
  • ash 3.0.0-rc.27, ash_admin 0.10.10-rc.1, ash_phoenix 2.0.0-rc.6

Additional context

Please note that this works just fine in my Phoenix app ⚠️

Displays resource attributes which are marked as sensitive.

I can see why there may be a reason you'd want an admin to see these attributes.

At the very minimum it should have a click-to-display widget but should probably have a configuration option (which defaults to off) which lets the user choose between showing it, showing a redacted version or now showing the field at all.

Screenshot 2023-03-15 at 2 15 46 PM

Screenshot 2023-03-15 at 2 22 07 PM

Hide resources on demand.

Is your feature request related to a problem? Please describe.
I'm using ash_paper_trail for my resources, and since all resources in the API are included, Version resources make the list too messy.

Describe the solution you'd like
In the resource, I can set it to be hidden.

Express the feature either with a change to resource syntax, or with a change to the resource interface

use Ash.Resource, extensions: [AshAdmin.Resource]

admin do
  show? false
end

Admin panel doesn't recognize a drop down is not empty if it's left on its first value

Describe the bug
When you have a dropdown from, for example:

    attribute :type, :atom,
      constraints: [one_of: [:a, :b, :c]],
      allow_nil?: false

In the admin panel, if you don't change the dropdown and leave it on 'a', you get a "type field is required" error when trying to save.

Changing type to 'b' and then back to 'a' fixes it.

Expected behavior
It allows you to save while 'a' is set without having to change it first.

Runtime

  • Elixir version: 1.15
  • Erlang version: 25
  • OS: Mac OS
  • Ash version: 2.13.3
  • any related extension versions: ash_admin: 0.9.4

PageLive crashes in the dev app when attempting to view/edit a Ticket resource

It seems to be related to changes around to_one_relationships made recently?

This error gets generated when the liveview crashes -

 ** (CaseClauseError) no case clause matching: #Demo.Tickets.Ticket<reporter_name: 
#Ash.NotLoaded<:aggregate>, destination_links: #Ash.NotLoaded<:relationship>, source_links: 
#Ash.NotLoaded<:relationship>, comments: #Ash.NotLoaded<:relationship>, organization: 
#Demo.Tickets.Organization<tickets: #Ash.NotLoaded<:relationship>, __meta__: 
#Ecto.Schema.Metadata<:loaded, "organizations">, id: "1b2b526e-d801-4b1f-8a28-bf58f8648ebd", name: 
"Ash Project", aggregates: %{}, calculations: %{}, ...>, ...>
        (ash_admin 0.9.5) lib/ash_admin/pages/page_live.ex:256: AshAdmin.PageLive.handle_params/3
        ....

Which is here -

https://github.com/ash-project/ash_admin/blob/main/lib/ash_admin/pages/page_live.ex#L256-L264

record is previously set to a resource struct, so will never match anything in that case statement.

I feel like the warning could possibly move up into the socket.assigns.api.load case clause, and the rest deleted?

Phoenix 1.7 release causing issues w/ ash_admin compilation

Describe the bug
Getting an error when trying to compile Ash Admin to use with Phoenix 1.7. Getting the following error.

==> ash_admin
Compiling 29 files (.ex)

== Compilation error in file lib/ash_admin/layout_view.ex ==
** (CompileError) lib/ash_admin/layout_view.ex:3: module Phoenix.View is not loaded and could not be found
    (elixir 1.14.2) expanding macro: Kernel.use/2
    lib/ash_admin/layout_view.ex:3: AshAdmin.LayoutView (module)
    expanding macro: AshAdmin.Web.__using__/1
    lib/ash_admin/layout_view.ex:3: AshAdmin.LayoutView (module)
    (elixir 1.14.2) expanding macro: Kernel.use/2
    lib/ash_admin/layout_view.ex:3: AshAdmin.LayoutView (module)

To Reproduce
Attempt to compile Ash Admin with Phoenix 1.7

Expected behavior
Ash Admin compiles successfully :)

** Runtime

  • Elixir version: 1.14.2
  • Erlang version: 25.1.1
  • OS: MacOS
  • Ash version: 2.4.12
  • Ash Admin: commit# d255aa0
  • Phoenix: 1.7

Updating the value of a belongs_to relationship field raises an error

Describe the bug

I've seen this trigger two different errors and I can't work out the difference between the two resources/actions.

  1. Map error
  attributes do
    uuid_primary_key :id

    attribute :name, :string, allow_nil?: false

    create_timestamp :inserted_at
    update_timestamp :updated_at
  end

  relationships do
    belongs_to :business, MyApp.Business
  end

  actions do
    create :create do
      primary? true

      argument :business_id, :uuid do
        allow_nil? false
      end

      accept [:name]

      change manage_relationship(:business_id, :business, type: :append_and_remove)
    end

Visiting the page to create a new record allows the "Business Id" field to be selected and populated, but editing the field (eg. pasting the same ID value again, or backspacing to delete a character) raises an error:

[error] GenServer #PID<0.3034.0> terminating
** (BadMapError) expected a map, got: "c6e78ebd-71fd-4aae-bdda-08cc7d97f25e"
    (ash_admin 0.10.7) lib/ash_admin/components/resource/form.ex:1311: AshAdmin.Components.Resource.Form.put_in_creating/3
    (elixir 1.15.4) lib/map.ex:916: Map.update!/3
    (ash_admin 0.10.7) lib/ash_admin/components/resource/form.ex:1298: AshAdmin.Components.Resource.Form.handle_event/3
    (phoenix_live_view 0.20.14) lib/phoenix_live_view/channel.ex:734: anonymous fn/4 in Phoenix.LiveView.Channel.inner_component_handle_event/4
    (telemetry 1.2.1) /Users/rebecca/Projects/work/my_client/my_app/deps/telemetry/src/telemetry.erl:321: :telemetry.span/3
    (phoenix_live_view 0.20.14) lib/phoenix_live_view/diff.ex:209: Phoenix.LiveView.Diff.write_component/4
    (phoenix_live_view 0.20.14) lib/phoenix_live_view/channel.ex:661: Phoenix.LiveView.Channel.component_handle/4
    (stdlib 5.0.2) gen_server.erl:1077: :gen_server.try_handle_info/3
    (stdlib 5.0.2) gen_server.erl:1165: :gen_server.handle_msg/6
    (stdlib 5.0.2) proc_lib.erl:241: :proc_lib.init_p_do_apply/3
  1. Form.for_create error
  attributes do
    uuid_primary_key :id, generated?: true
  end

  relationships do
    belongs_to :risk, MyApp.Risk.Risk, allow_nil?: false
    belongs_to :control, MyApp.Risk.Control, allow_nil?: false
  end

  actions do
    create :create do
      primary? true

      argument :risk_id, :uuid
      argument :control_id, :uuid

      change manage_relationship(:risk_id, :risk, type: :append_and_remove)
      change manage_relationship(:control_id, :control, type: :append_and_remove)
    end

Visiting the page to create a new record allows the "Risk Id" field to be selected and populated, but editing the field (eg. pasting the same ID value again, or backspacing to delete a character) raises an error that then gets the page into an infinite crash/reload loop -

[error] GenServer #PID<0.3076.0> terminating
** (AshPhoenix.Form.NoActionConfigured) Attempted to add a form at path: "form[risk_id]", but no `create_action` was configured.

For example:
    Form.for_create(
      Resource,
      :action,
      params,
      forms: [
        # For forms over existing data
        nested_form: [
          type: :list,
          as: "form_name",
          resource: RelatedResource,
          update_action: :create
        ]
      ]
    )

    (ash_phoenix 1.3.4) lib/ash_phoenix/form/form.ex:1385: anonymous fn/7 in AshPhoenix.Form.validate_nested_forms/6
    (elixir 1.15.4) lib/enum.ex:2510: Enum."-reduce/3-lists^foldl/2-0-"/3
    (ash_phoenix 1.3.4) lib/ash_phoenix/form/form.ex:1117: AshPhoenix.Form.validate/3
    (ash_phoenix 1.3.4) lib/ash_phoenix/form/form.ex:1036: AshPhoenix.Form.validate/3
    (ash_admin 0.10.7) lib/ash_admin/components/resource/form.ex:1305: AshAdmin.Components.Resource.Form.handle_event/3
    (phoenix_live_view 0.20.14) lib/phoenix_live_view/channel.ex:734: anonymous fn/4 in Phoenix.LiveView.Channel.inner_component_handle_event/4
    (telemetry 1.2.1) /Users/rebecca/Projects/work/my_client/my_app/deps/telemetry/src/telemetry.erl:321: :telemetry.span/3
    (phoenix_live_view 0.20.14) lib/phoenix_live_view/diff.ex:209: Phoenix.LiveView.Diff.write_component/4
    (phoenix_live_view 0.20.14) lib/phoenix_live_view/channel.ex:661: Phoenix.LiveView.Channel.component_handle/4
    (stdlib 5.0.2) gen_server.erl:1077: :gen_server.try_handle_info/3
    (stdlib 5.0.2) gen_server.erl:1165: :gen_server.handle_msg/6
    (stdlib 5.0.2) proc_lib.erl:241: :proc_lib.init_p_do_apply/3

To Reproduce

see above

Expected behavior

The page to not crash! :D

Runtime

  • Elixir version 1.15.4-otp-26
  • Erlang version 26.0.2
  • OS macOS Sonoma
  • Ash version 2.20.1
  • AshPhoenix version 1.3.4
  • AshAdmin version 0.10.7

LiveView crash when removing one element of a many-to-many relationship on a Create form

Describe the bug
On a Create form for a new resource that has a many-to-many relationship with another resource, Ash admin builds a section to add/remove new records of the relationship. eg. in our app we have a resource that has many_to_many :competencies:

Screen Shot 2022-05-18 at 3 49 01 pm

When clicking the minus icon to remove one of the items in the list, the LiveView crashes:

** (Protocol.UndefinedError) protocol Phoenix.HTML.FormData not implemented for #Ash.Changeset<action_type: :create, action: :create, (lots of other stuff omitted)> of type Ash.Changeset (a struct). This protocol is implemented for the following type(s): AshPhoenix.FilterForm, AshPhoenix.FilterForm.Predicate, AshPhoenix.Form, Atom, Ecto.Changeset, Plug.Conn
    (phoenix_html 3.2.0) lib/phoenix_html/form_data.ex:1: Phoenix.HTML.FormData.impl_for!/1
    (phoenix_html 3.2.0) lib/phoenix_html/form_data.ex:34: Phoenix.HTML.FormData.input_value/3
    (ash_admin 0.4.4) lib/ash_admin/components/resource/form.ex:1119: AshAdmin.Components.Resource.Form.remove_value/3
    (ash_admin 0.4.4) lib/ash_admin/components/resource/form.ex:1036: AshAdmin.Components.Resource.Form.handle_event/3

Expected behavior
The element (form field and minus icon) should be removed from the page, without LiveView crashing.

** Runtime

  • Elixir version - 1.13.3
  • Erlang version - 24.3
  • OS - MacOS Monterey 12.3
  • Ash version - main branch (sha 0f24ac78ae6a551c30e7d45419672c0ed72dbd64)
  • Ash admin version - 0.4.4

Can't update value of a `map`-type field

Describe the bug

When updating and saving a record for a resource that has a map field in it, an error is generated and the resource won't save.

Resource:

defmodule MyApp.Accounts.UserSetting do 
  use Ash.Resource,
    data_layer: AshPostgres.DataLayer,
    authorizers: [Ash.Policy.Authorizer]

  postgres do
    table "user_settings"
    repo MyApp.Repo

    references do
      reference :user, on_delete: :delete
    end
  end

  attributes do
    attribute :setting, :string, primary_key?: true, allow_nil?: false
    attribute :value, :map, allow_nil?: false
  end

  relationships do
    belongs_to :user, MyApp.Accounts.User do
      primary_key? true
      allow_nil? false
    end
  end

  # Other unrelated stuff (I think) omitted

UI:

Screenshot 2024-03-18 at 2 20 51 pm

Error:

Upon pressing Save, an error in red text is displayed at the top of the form:

Internal Error: ** (Protocol.UndefinedError) protocol Jason.Encoder not implemented for 
dynamic([], [ "934c5b0b-65d8-4448-b79d-29bcc375dfd5", "07884d7b-0031-4abf-9d3e-12558cdf01ca", 
"0118bb2a-9d18-4402-aba7-a81a3de0503e", "noun-goggles-3360310.svg", "noun-safety-1909223.svg" ]) 
of type Ecto.Query.DynamicExpr (a struct), Jason.Encoder protocol must always be explicitly 
implemented.

Runtime

  • Elixir version 1.15.4-otp-26
  • Erlang version 26.0.2
  • OS macOS Sonoma something
  • Ash version 2.20.1
  • Ash Admin 0.10.7

Relationship's private field in table columns causes query to produce no result

Describe the bug

Under domain Accounts

  1. A User resource
    1.1. with fields :id and :email
    1.2 with relationship belongs_to :role
  2. A Role resource
    2.1 with fields :id and :name
    2.2 with relationship has_many :users

To Reproduce

Query:

Accounts.User |> Ash.Query.select([])|> Ash.Query.load([:email, :role])|>Ash.read(page: [count: true, limit: 20], domain: Accounts)

Query similiar to above is being used in Admin to fetch results but it doesn't show any error or warning

Expected behavior

It should show role field with nil value
OR
show warning in console that private field is being exposed in query

Instead we get below error

{:error,
 %Ash.Error.Unknown{
   errors: [
     %Ash.Error.Unknown.UnknownError{
       error: "filter: Could not cast expression: Ash.Query.Operator.In id [#Ash.NotLoaded<:attribute, field: :role_id>]",
       field: nil,
       splode: Ash.Error,
       bread_crumbs: [],
       vars: [],
       path: [:role, :filter],
       stacktrace: #Splode.Stacktrace<>,
       class: :unknown
     }
   ],
   changeset: nil,
   query: #Ash.Query<
     resource: Accounts.User,
     load: [role: #Ash.Query<resource: Accounts.Role>],
     errors: [
       %Ash.Error.Unknown.UnknownError{
         error: "filter: Could not cast expression: Ash.Query.Operator.In id [#Ash.NotLoaded<:attribute, field: :role_id>]",
         field: nil,
         splode: Ash.Error,
         bread_crumbs: [],
         vars: [],
         path: [:role, :filter],
         stacktrace: #Splode.Stacktrace<>,
         class: :unknown
       }
     ],
     select: [:email, :id]
   >,
   action_input: nil,
   splode: Ash.Error,
   bread_crumbs: [],
   vars: [],
   path: [:role],
   stacktrace: #Splode.Stacktrace<>,
   class: :unknown
 }}

Runtime

  • Elixir version 1.16.2
  • Erlang version 26.2.3
  • OS manjaro
  • Ash version 3.0.0-rc
  • any related extension versions

Ash.Unions don't render correctly

Describe the bug

An embedded resource with a field defined as an Array of Unions renders like this in Ash Admin:

Screen Shot 2023-08-21 at 6 11 48 pm

To Reproduce

Setup a resource with a field that is an array of Union types.

Expected behavior

Another field containing list of non-union embedded types renders fine.

Presumably it's possible to have this render in some sensible default way despite the fact that each item could be different?

Runtime

  • Elixir 1.14.4
  • Erlang 25.3.2
  • OS mac
  • Ash main
  • Ash Admin main

Support union types

Describe the bug
Union types are not rendered as inputs in form

To Reproduce

defmodule Resource.PathElement do
  use Ash.Type.NewType,
    subtype_of: :union,
    constraints: [
      types: [
        integer: [type: :integer],
        string: [type: :string]
      ]
    ]
end

Expected behavior
Have input

Runtime

  • Ash admin version: 0.10.10-rc.1

Additional context

[error] GenServer #PID<0.5962.0> terminating
** (RuntimeError) Got no "_union_type" parameter, and no union type had a tag & tag_value pair matching the params.

If you are adding a form, select a type using params: %{"_union_type" => "type_name"}, or if one
or more of your types is using a tag you can set that tag with params: %{"tag" => "tag_value"}.

Params:

nil

Available types:

[integer: [type: :integer], string: [type: :string]]

(ash_phoenix 2.0.0-rc.8) lib/ash_phoenix/form/auto.ex:263: AshPhoenix.Form.Auto.determine_type/3
(ash_phoenix 2.0.0-rc.8) lib/ash_phoenix/form/auto.ex:155: anonymous fn/5 in AshPhoenix.Form.Auto.unions/3
(ash_phoenix 2.0.0-rc.8) lib/ash_phoenix/form/form.ex:3156: AshPhoenix.Form.update_opts/3
(ash_phoenix 2.0.0-rc.8) lib/ash_phoenix/form/form.ex:1213: anonymous fn/9 in AshPhoenix.Form.validate_nested_forms/6
(elixir 1.16.2) lib/enum.ex:2528: Enum."-reduce/3-lists^foldl/2-0-"/3
(ash_phoenix 2.0.0-rc.8) lib/ash_phoenix/form/form.ex:1210: anonymous fn/7 in AshPhoenix.Form.validate_nested_forms/6
(elixir 1.16.2) lib/enum.ex:2528: Enum."-reduce/3-lists^foldl/2-0-"/3
(ash_phoenix 2.0.0-rc.8) lib/ash_phoenix/form/form.ex:1058: AshPhoenix.Form.validate/3
(ash_phoenix 2.0.0-rc.8) lib/ash_phoenix/form/form.ex:1279: anonymous fn/9 in AshPhoenix.Form.validate_nested_forms/6
(elixir 1.16.2) lib/enum.ex:2528: Enum."-reduce/3-lists^foldl/2-0-"/3
(ash_phoenix 2.0.0-rc.8) lib/ash_phoenix/form/form.ex:1210: anonymous fn/7 in AshPhoenix.Form.validate_nested_forms/6
(elixir 1.16.2) lib/enum.ex:2528: Enum."-reduce/3-lists^foldl/2-0-"/3
(ash_phoenix 2.0.0-rc.8) lib/ash_phoenix/form/form.ex:1058: AshPhoenix.Form.validate/3
(ash_phoenix 2.0.0-rc.8) lib/ash_phoenix/form/form.ex:1279: anonymous fn/9 in AshPhoenix.Form.validate_nested_forms/6
(elixir 1.16.2) lib/enum.ex:2528: Enum."-reduce/3-lists^foldl/2-0-"/3
(ash_phoenix 2.0.0-rc.8) lib/ash_phoenix/form/form.ex:1210: anonymous fn/7 in AshPhoenix.Form.validate_nested_forms/6
(elixir 1.16.2) lib/enum.ex:2528: Enum."-reduce/3-lists^foldl/2-0-"/3
(ash_phoenix 2.0.0-rc.8) lib/ash_phoenix/form/form.ex:1058: AshPhoenix.Form.validate/3
(ash_phoenix 2.0.0-rc.8) lib/ash_phoenix/form/form.ex:985: AshPhoenix.Form.validate/3
(ash_admin 0.10.10-rc.1) lib/ash_admin/components/resource/form.ex:1275: AshAdmin.Components.Resource.Form.handle_event/3

Crash when a resource has no actions defined.

ash_admin assumes that a resource will have at least one read action. When it doesn't it crashes due to a match error:

** (ArgumentError) errors were found at the given arguments:

  * 1st argument: not a nonempty list

    :erlang.hd([])
    (ash_admin 0.8.0) lib/ash_admin/components/top_nav/dropdown.ex:62: anonymous fn/4 in AshAdmin.Components.TopNav.Dropdown."render (overridable 1)"/1
    (elixir 1.14.3) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
    (ash_admin 0.8.0) lib/ash_admin/components/top_nav/dropdown.ex:60: anonymous fn/2 in AshAdmin.Components.TopNav.Dropdown."render (overridable 1)"/1
    (phoenix_live_view 0.18.16) lib/phoenix_live_view/diff.ex:398: Phoenix.LiveView.Diff.traverse/7
    (phoenix_live_view 0.18.16) lib/phoenix_live_view/diff.ex:544: anonymous fn/4 in Phoenix.LiveView.Diff.traverse_dynamic/7
    (elixir 1.14.3) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 0.18.16) lib/phoenix_live_view/diff.ex:373: Phoenix.LiveView.Diff.traverse/7
    (phoenix_live_view 0.18.16) lib/phoenix_live_view/diff.ex:717: Phoenix.LiveView.Diff.render_component/9
    (phoenix_live_view 0.18.16) lib/phoenix_live_view/diff.ex:210: Phoenix.LiveView.Diff.write_component/4
    (phoenix_live_view 0.18.16) lib/phoenix_live_view/channel.ex:544: Phoenix.LiveView.Channel.component_handle_event/6
    (stdlib 4.3) gen_server.erl:1123: :gen_server.try_dispatch/4
    (stdlib 4.3) gen_server.erl:1200: :gen_server.handle_msg/6
    (stdlib 4.3) proc_lib.erl:240: :proc_lib.init_p_do_apply/3

Adding the admin API to the router causes a lot extra compilations

Describe the bug
Adding a snippet like ash_admin "/admin", apis: [GenTracker.API] to your phoenix app's router, causes the router to have a lot of compile-time dependencies.

To Reproduce
Add a line of ash_admin "/admin", apis: [GenTracker.API] to a phoenix app's router and check the output of mix xref graph --format dot

Expected behavior
Adding ash_admin to not add significant compile-time dependencies to the router.

** Runtime

  • Elixir version: Elixir 1.12.0-rc.0
  • Erlang version: 24.0-rc2
  • OS: Arch Linux
  • Ash version: 1.41.6
  • any related extension versions ash_admin 0.2.10

Additional context
Add any other context about the problem here.
Screenshot 2021-04-19 08 27 20

Add seed to demo

AshAdmin has a demo to help to test the libray, but I couldn't see any seed to it.

The idea is create couple resources to facilitate the interation with the demo.

In the admin panel, changing an embedded json field in a relationship causes all the fields below that to get deleted

Describe the bug
I have the following action:

    update :manage_templates do
      accept []
      argument :templates, {:array, :map}

      change manage_relationship(:templates, type: :direct_control)
    end

My Template resource has an attribute like this:

    attribute :config, :map, allow_nil?: true

If I have several templates, for example, template 1, 2, 3, and template 2 has some keys/values in its config map, then editing those values in the manage_templates action using the tree editor causes template 3 to be deleted.

Expected behavior

It allows me to edit template 2's config without deleting the other templates.

Runtime

  • Elixir version: 1.15
  • Erlang version: 25
  • OS: Mac OS
  • Ash version: 2.13.3
  • any related extension versions: ash_admin: 0.9.4

Compilation error with Phoenix 1.7

Describe the bug

In Phoenix 1.7 project compilation fails with this error:

== Compilation error in file lib/my_app_web/router.ex ==
** (RuntimeError) attempting to redefine live_session :default.
live_session routes must be declared in a single named block.

    (phoenix_live_view 0.18.3) lib/phoenix_live_view/router.ex:237: Phoenix.LiveView.Router.__live_session__/3
    lib/my_app_web/router.ex:37: (module)
    (elixir 1.14.2) lib/kernel/parallel_compiler.ex:346: anonymous fn/5 in Kernel.ParallelCompiler.spawn_workers/7

To Reproduce
Add ash_admin macro to the router file of Phoenix 1.7-rc0 application.

Expected behavior
No errors

Runtime

  • Elixir version 1.14.2
  • Erlang version 25
  • Ash version 2.4.24
  • AshAdmin 0.7.0
  • Phoenix 1.7-rc0
  • Phoenix LiveView 0.18.3

Manage_relationship calls are not satisfying "allow_nil? false"

Describe the bug

Manage_relationship calls are not satisfying allow_nil? false in AshAdmin

image

OR

an issue assigning an argument / attribute to a relationship's "Attribute Defaults" (without assigning a "source_attribute").

OR

both


To Reproduce

Use the attached Livebook (remove the .txt extension)
AshAdminRelationshipIssue.livemd.txt

If I create the changeset by hand everything executes fine. (As seen in the livebook)

Recreate these resources in an ash admin webpage, attempt to add a family_id to a person using the create action.

NOTE: The livebook is running ETS as the data layer but I am using Postgres in the project. ( I can provide the config is needed )


Expected behavior

Adding A family_id when creating a person generates no errors and the 'person' resource is created without issue.

Runtime

  • Elixir version 1.16.2
  • Erlang version OTP 26
  • OS macOS 14.5 (M1 Macbook Pro)
  • Ash version 0.11.0
  • any related extension versions
     {:phoenix, "~> 1.7.12"},
     {:phoenix_ecto, "~> 4.4"},
     {:ecto_sql, "~> 3.10"},
     {:postgrex, ">= 0.0.0"},
     {:phoenix_html, "~> 4.0"},
     {:phoenix_live_reload, "~> 1.2", only: :dev},
     {:phoenix_live_view, "~> 0.20.2"},
     {:floki, ">= 0.30.0", only: :test},
     {:phoenix_live_dashboard, "~> 0.8.3"},
     {:esbuild, "~> 0.8", runtime: Mix.env() == :dev},
     {:tailwind, "~> 0.2", runtime: Mix.env() == :dev},
     {:heroicons,
      github: "tailwindlabs/heroicons",
      tag: "v2.1.1",
      sparse: "optimized",
      app: false,
      compile: false,
      depth: 1},
     {:swoosh, "~> 1.5"},
     {:finch, "~> 0.13"},
     {:telemetry_metrics, "~> 1.0"},
     {:telemetry_poller, "~> 1.0"},
     {:gettext, "~> 0.20"},
     {:jason, "~> 1.2"},
     {:dns_cluster, "~> 0.1.1"},
     {:bandit, "~> 1.2"},
     {:ash, "~> 3.0"},
     {:picosat_elixir, "~> 0.2.3"},
     {:ash_postgres, "~> 2.0"},
     {:ash_phoenix, "~> 2.0"},
     {:ash_admin, "~> 0.11.0"}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.