edisonywh / backoffice

Admin tool built with the PETAL stack
MIT License
217 stars 15 forks source link

RFC: DSL? #1

Closed edisonywh closed 3 years ago

edisonywh commented 3 years ago

Right now users configure pages with just functions (as callbacks to behaviour), but do we want to continue to do that, or go with a DSL approach that looks similar to Ecto? I generally prefer to keep things as functions and stray away from DSL as much as possible, but I can see a couple of benefits here. I'd love to hear arguments for both side.

Pros

With DSL, we: 1) don't need to have a weird id: nil just to display data. I find it pretty strange to pass in nil just to display something. 2) we can most likely do some compile time check to make sure the types are valid (and hence able to be rendered into form fields or something), for example:

def MyWeb.UserLive.Index do
  use Backoffice.Resources, ...

  index do
    field :id, :string
    field :age, :integer, label: "User Age"
  end

  form do
    field :id, :string
    field :age, :integer, label: "User Age"
    field :what, :non_existent_type

    belongs_to :team, Team
  end
end

We map types into form fields, so if we don't know how to render :non_existent_type, we can error out during compilation.

With DSL we can also maybe simplify the set-up, so we don't need to repeat things like "search_fields/1", and instead:

index do
  field :id, :string # defaults to searchable
  field :age, :string, search: true,
  field :private, :string, search: false
  field :verified, :boolean, filter: true
end

You can define everything in one DSL itself.

The filter field, along with the type field, most likely doesn't matter in index, but only in form, but when used in index, it can help us build out a more complex FilterComponent (multiple filters, and we know what fields to render.

Questions

def index do
  [
    custom: %{label: "Custom", value: fn resource -> ... end}
  ]
end

But if we go DSL which does it on compile time, how can we allow user to customize the field with a function? Can we capture a function during compile time, or can we do via MFA?