View Source Dumper.Config behaviour (Dumper v0.2.0)
Provides sensible defaults for how data should be rendered.
If you'd like your own customizations, define a module that implements
the Dumper.Config
behaviour:
# An example dumper config module
defmodule MyApp.DumperConfig do
use Dumper.Config
@impl Dumper.Config
def ids_to_schema() do
%{
book_id: Library.Book,
author_id: Library.Author
}
end
@impl Dumper.Config
def display(%{field: :last_name} = assigns) do
~H|<span style="color: red"><%= @value %></span>|
end
@impl Dumper.Config
def custom_record_links(%Library.Book{} = book) do
[
{~p"/logging/#{book.id}", "Logs"},
{"https://goodreads.com/search?q=#{book.title}", "Goodreads"},
]
end
end
Then tell your config.exs
where to find the module:
config :dumper,
otp_app: :my_app,
repo: MyApp.Repo,
config_module: MyApp.DumperConfig # <---- add this
See ids_to_schema/0
for examples of how you can configure
automatic links of ids to records, display/1
for examples of fine-grained
control over how column values are rendered, and custom_record_links/1
for examples of
how to add custom metadata to the record page.
The use Dumper.Config
brings in the default definitions of behavior, so you can
choose to define one, all, or none of them. As such, even this is a valid implementation
(although it would be functionally the same as not defining a config module at all):
defmodule MyApp.DumperConfig do
use Dumper.Config
end
Summary
Callbacks
Additional records to be rendered on the given record's page.
A mapping from schema module => list of its fields that will be rendered.
Custom links rendered when viewing a specific record.
Fine-grained control over how any field is rendered. This is a functional component that takes
in an assigns
map and returns a valid heex
expression.
A mapping from schema module => list of its fields that will be excluded from being rendered.
A map of ids (as atoms) to the schema module they should link to.
Callbacks
Additional records to be rendered on the given record's page.
@impl Dumper.Config
def additional_associations(%Book{id: book_id}) do
# look up reviews on goodreads
[goodreads_reviews: [top_review, lowest_review]]
end
For a given record, return a keyword list of association name to list of records. Overriding this callback allows you to render more data at the bottom of the page. This is useful when the given record doesn't explicitly define an association, or the data you want to display doesn't live in the database.
Note that while regular associations are paginated, since these are custom we can't automatically paginate them. It's recommended to cap the number of records returned.
@callback allowed_fields() :: nil | :map | {:map, :strict | :lenient}
A mapping from schema module => list of its fields that will be rendered.
Can return
nil
: all fields in all tables are shown- a map: a field is only displayed if the exact Schema + field pairing exists in the map
{map, :strict}
: a field is only displayed if the exact Schema + field pairing exists in the map{map, :lenient}
: a field is displayed if the exact Schema + field pairing exists in the map or the schema module is not present in the map
Here's an example where we return a mapping of schema modules to the fields we want to allow displayed:
@impl Dumper.Config
def allowed_fields() do
%{
Patron => [:id, :last_name],
Book => [:title]
}
end
In the above example, the returned map defaults to strict mode. Rendered fields would
include patron.last_name
and book.title
. Hidden fields would include fields like
patron.first_name
and author.last_name
.
@impl Dumper.Config
def allowed_fields() do
map = %{
Patron => [:id, :last_name],
Book => [:title]
}
{map, :lenient}
end
In the above example, lenient
strictness means that author.last_name
would now be rendered even though the Author
key not explicitly defined in the returned mapping.
It's recommended to at least include the primary key field in the list so that there is at least one field to display.
excluded_fields/0
is ignored if:
- this callback is implemented and returns strict mode (or returns only a map)
- this callback is implemented and returns lenient mode, but the schema key is present in the map
Custom links rendered when viewing a specific record.
This function takes a record you can pattern match on, and must return a list of {route, text}
tuples.
@impl Dumper.Config
def custom_record_links(%Book{} = book) do
[
{~p"/logging/#{book.id}", "Logs"},
{"https://goodreads.com/search?q=#{book.title}", "Goodreads"},
]
end
def custom_record_links(%Ticket{} = ticket),
do: [{"https://jira.com/#{ticket.project}/#{ticket.id}", "Jira"}]
In the above example, any Book
record you visit in the Dumper will display two links labelled
"Logs" and "Goodreads" at the top of the page. Any Ticket
record will likewise display one
link, "Jira", in that spot. Routes can be internal or external, verified routes, or plain strings.
Logs, dashboards, traces, support portals, etc are all common use cases, but any {route, text}
pair is possible.
@callback display(assigns :: map()) :: Phoenix.LiveView.Rendered.t()
Fine-grained control over how any field is rendered. This is a functional component that takes
in an assigns
map and returns a valid heex
expression.
By default, Dumper has some sensible defaults for how redacted fields, values like true
, false
, nil
, and data types like dates and datetimes are rendered.
It is useful to define as many display/1
function heads as you want, pattern matching on specific values to pick out the specific ones you'd like to customize.
The assigns
that is passed in is a map of the following form:
# assigns
%{
module: Library.Author,
field: :last_name,
resource: %Library.Author{ ... }, # the entire ecto struct
value: "Smith",
type: :binary, # the Ecto data type
redacted: false
%}
So for example, if you wanted every last name to be red except for the Author table, which should have blue last names, you could do the following:
@impl Dumper.Config
def display(%{field: :last_name, module: Library.Author} = assigns) do
~H|<span style="color: blue"><%= @value %></span>|
end
def display(%{field: :last_name} = assigns) do
~H|<span style="color: red"><%= @value %></span>|
end
In this way, you can have near complete control over how a particular field, data type, or entire module is displayed.
Note that LiveDashboard ships with Bootstrap 4.6, so you are free to use Bootstrap classes in your styling to help achieve a consistent look and feel.
@callback excluded_fields() :: :map
A mapping from schema module => list of its fields that will be excluded from being rendered.
@impl Dumper.Config
def excluded_fields() do
%{
Library.Patron => [:email_address, :date_of_birth],
Library.Book => [:purchase_price]
}
end
In the above example, when displaying any patron record, the email_address
and date_of_birth
fields will not be rendered. All others fields will be displayed. The email_address
and
date_of_birth
fields will not even be sent down through the display/1
callback. The
same for any book record; the purchase_price
field will never be rendered. All other
schemas are unaffected - for example a Author
schema would display all of its fields, even
though it is not included in the returned map.
The excluded fields will only hide fields for a module if the module exists as a key in the returned map.
It's recommended to at least include the primary key field in the list so that there is at least one field to display.
See allowed_fields/0
for cases where excluded_fields/0
is ignored.
@callback ids_to_schema() :: :map
A map of ids (as atoms) to the schema module they should link to.
Each key/value pair in the map will automatically render as a clickable link that navigates the user to the dumper page for that specific record.
By default this map is empty.
Example:
def ids_to_schema() do
%{
book_id: Library.Book,
author_id: Library.Author
}
end
Here, any field in any schema named book_id
would render as a link to the Book
record,
via a Repo.get!(id)
call under the hood, instead of just printing the value. This allows
you to easily navigate through your data by clicking connected links.