Hi, I’m contemplating writing an admin library, similar to Kaffy and LiveAdmin, but filling a few gaps found while using Kaffy. For that I figure I would leverage protocols instead of giant configs (LiveAdmin) or magic admin modules (Kaffy). But after some initial coding I see a few problems.
What I have right now is this:
defimpl Admin.Resource, for: App.Accounts.User do
def name(_), do: "User"
def slug(_), do: "user"
def form(user) do
import Admin.FormBuilder
new(user)
|> title(if user.id, do: "User #{user.id}", else: "New user")
|> field(:email)
|> field(:first_name)
|> field(:last_name)
|> build()
end
end
This is nice, but obviously the number of customizable things grows in time. Not only I want to have customizable form, but also records lists, their fields, custom actions, custom mass actions etc. On the other hand, I don’t want to force user to define all functions when they just may use defaults (for example, no need for custom slug or resource name).
So far I have two ideas and I want to know what you think:
1. Have a macro with default
defimpl Admin.Resource, for: App.Accounts.User do
# I don't want to customize slug and name
def form(user) do
# ...
end
use Admin.Resource.DefaultImplementations
end
This has a problem with either having the users remember to put it at the end of the module, so default implementation does not shadow custom implemementations - this is not POLS and what is usually done with use
. Also, it generates warnings. Alternatively, there would have to be an option to what default implementations to use, for example:
defimpl Admin.Resource, for: App.Accounts.User do
use Admin.Resource.DefaultImplementations, except: [:form, :custom_actions]
end
Both are not really great in my opinion, I would especially hate generating many warnings for the user (so using import
instead is not great too).
2. Use many small protocols
Alternatively, I could have a protocol for just about anything that is customizable and user would choose what to implement. So we will have Admin.Resource
, Admin.ResourceTable.Columns
, Admin.ResourceTable.Actions
, Admin.ResourceTable.MassActions
, Admin.ResourceTable.Query
, Admin.ResourceTable.SearchQuery
, Admin.Resource.FormCustomActions
etc. Each one of these will probably will end up with just one function (call
?). Seems sensible to some extent, but I feel that having to implement these many protocols might put people off.
Which solution appeals to you more? Or maybe there’s some alternative I missing? Or maybe using protocols for that wasn’t such a great idea…