tfwright / live_admin

Low-config admin UI for Phoenix apps, built on LiveView
MIT License
251 stars 22 forks source link

Allow admin-instance resource config #34

Closed tfwright closed 1 year ago

tfwright commented 1 year ago

See https://github.com/tfwright/live_admin/pull/33

Problems:

1) right now default config must be defined at the app level, which makes it awkward to use a different set of default configs for different admin UIs (if more than 1 is desired for whatever reason).

2) since overrides are likely to be desired for most resources, the router config is large/noisy (see this thread)

Proposed solution: deprecate app level default config, and add support for passing a module, which specifies all configuration, including resources:

defmodule MyApp.AdminA do
  use LiveAdmin, 
    ecto_repo: MyApp.RepoA, 
    create_with: {MyApp.AdminContext, :default_create, []},
    update_with: :schema_function_name,
    resources: :get_resources

    def get_resources, do: [MyApp.SchemaA]
end

defmodule MyApp.AdminB do
  use LiveAdmin, 
    ecto_repo: MyApp.RepoB,
    resources: [MyApp.SchemaB]
end

Alternatives:

live_admin "/admin_url", title: "MyAdmin" do
  admin_resource "/a", MyApp.SchemaA, create_with: :create
  admin_resource "/b", MyApp.SchemaB, create_with: :something
end

It might be that these are two separate problems with config that need to be addressed separately.

tejpochiraju commented 1 year ago

@tfwright - thanks a lot for your work here. Just discovered live_admin and it fit our needs perfectly. Specifically, I stumbled upon this issue when looking for multi-repo support. However, I realised, accidentally, that this is already supported out of the box.

I am documenting our use case and how we got it working so someone else looking for the same thing doesn't spend too long on this. We have 3 apps each with a separate repo. Let's call them AppA.Repo, AppB.Repo and AppC.Repo. Of these, AppA is the parent app to which AppB and AppC are dependencies.

To get live_admin working on all of these with their schemas, all we had to do was the following:

In AppA's config.exs

config :app_a,
  ecto_repos: [AppC.Repo, AppB.Repo, AppA.Repo]

The reason AppA.Repo is listed last is because some of its migrations depend on AppB and AppC and this way migrations run in the correct order when you run mix ecto.migrate.

Then, in AppAWeb's router.ex,

live_admin("/admin",
      resources: [
        AppA.SomeSchema,
        AppB.SomeSchema,
        AppC.SomeSchema
      ]
)

This works because (and I didn't know this previously), AppA.Repo.all(%AppB.SomeSchema{}) just works as long as AppB.Repo is included in ecto_repos for AppA.

Ignore if this is known behaviour but it certainly surprised me and Kaffy's autodetection only picks up AppA schemas.

tfwright commented 1 year ago

Definitely not expected behavior! I haven't tried to use multiple Ecto repos myself, so I'm not sure, but LiveAdmin currently executes all queries in the context of whatever repo is set in its config. I am surprised that it would work with any other repos.

tejpochiraju commented 1 year ago

Here's a simple example that demos this behaviour: https://github.com/tejpochiraju/multi_repo_live_admin

tfwright commented 1 year ago

Hm, just a guess but I think the key implementation detail there is that the same db is being used. I think that means that even though LiveAdmin is still using the "wrong" repo when querying whatever schemas are "supposed" to be on the other repo, since the db is the same the queries end up being directed to the same place. My expectation would be if you alter the AppB.Repo config to point at a different file with the AppB schema tables, and remove those tables from AppA.Repo file, then AppB schema resources will no longer work in LiveAdmin

tejpochiraju commented 1 year ago

You are right. With separate DBs (SQLite3 or Postgres), I get the following error:

[error] GenServer #PID<0.851.0> terminating
** (Postgrex.Error) ERROR 42P01 (undefined_table) relation "users" does not exist

Nevertheless, this is still useful behaviour if possibly undocumented on the Ecto side of things (I can't seem to find a reference). Before I stumbled upon this approach, I was considering my options.

EDIT