A MishkaGervaz custom table template: an activity log drawn as a vertical timeline — a rail with a severity-tinted node per event, day headings across it — rather than a table.
A template owns the whole table, so the chrome is here: the filter bar (render_filters/1) and the
footer (render_pagination/1). The bar is generic — a :select with few options becomes a
segmented switch, a long one a dropdown, a :text filter the search box and a :date_range a pair
of date inputs — so the resource stays the single source of truth and no filter is named here.
Row content comes from each column's render, mapped by position: 0 the event (message + badge),
1 the actor, 2 the date, 3+ inline badges.
What a resource has to give it
Columns and filters are read off the resource, but three things come from the record itself:
:severity— an atom field (:info,:warn,:error) tinting the node and the actor avatar of a row that carries no:tone; an unknown or unloaded one renders the:infotint.:tone— an optional atom field (:created,:updated,:destroyed) a content-change row carries. When present it tints the node and the actor avatar by action rather than severity, so a create reads green, an update blue and a destroy red; a row without one (a job, a compile, a draft) isniland falls back to:severity.__metadata__.first_of_day?/__metadata__.day_count— the day heading. A LiveView stream never hands a row its predecessor, so the READ decides which row opens a day and how many events that day holds; a row without them simply gets no heading.- a timestamp field, named by the
:timestamptemplate option.
Template options
:timestamp— the record's timestamp field (default:inserted_at).:max_cap— the read's scan ceiling, when it has one. A count that reaches it is only a floor, so it reads10,000+rather than claiming an exact total. Defaultnil— counts are exact.
Used by MishkaCmsCore.Activity.ActivityEntry (the unified log at
/admin/dashboard/runtime/activity) and MishkaDocument.EventLog (the document event log at
/admin/dashboard/document/event-logs).
See MishkaCmsCore.Activity.Query and MishkaCmsCoreWeb.Live.Admin.Dashboard.Activity.Index.
Summary
Functions
The bg-/text- pair an actor avatar carries for a row of this palette value — the same tint the
node beside it uses, so the two always agree. Takes the row's tone-or-severity, not the actor: the
name already says who that was.
The dot colour for one palette value — a :severity (:info/:warn/:error), a content-change
:tone (:created/:updated/:destroyed), or an action filter's raw value (create/update/
destroy, which resolve to their tone's colour). The node is a tinted disc (node_class/1) around
this solid dot; the filter switch reuses it for its per-option dots. An unknown value renders no
dot rather than guess. Accepts the atom or its string form.
The tinted-disc background the node draws around its dot_class/1 dot, for a :severity or a
content-change :tone. An unknown or nil value reads as the :info/:created green. Accepts
the atom or its string form.
Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_bulk_actions/1.
Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_empty/1.
Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_error/1.
The filter bar: a short :select renders as a segmented switch, a long one as a dropdown, a
:text filter as the search box and a :date_range as a pair of date inputs. The
phx-change="filter" form and the input names are Gervaz's contract — only the look is ours.
Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_header/1.
Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_loading/1.
The footer: a centred load-more, driven straight from the ui_adapter so it can carry the design's
classes (Shared.render_pagination/1 hardcodes its own).
Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_template_switcher/1.
Functions
The bg-/text- pair an actor avatar carries for a row of this palette value — the same tint the
node beside it uses, so the two always agree. Takes the row's tone-or-severity, not the actor: the
name already says who that was.
For a resource's :actor column render; a content-change :tone (:created/:updated/
:destroyed) colours by action, any other value by severity, and an unknown one reads green.
Accepts the atom or its string form.
The dot colour for one palette value — a :severity (:info/:warn/:error), a content-change
:tone (:created/:updated/:destroyed), or an action filter's raw value (create/update/
destroy, which resolve to their tone's colour). The node is a tinted disc (node_class/1) around
this solid dot; the filter switch reuses it for its per-option dots. An unknown value renders no
dot rather than guess. Accepts the atom or its string form.
The tinted-disc background the node draws around its dot_class/1 dot, for a :severity or a
content-change :tone. An unknown or nil value reads as the :info/:created green. Accepts
the atom or its string form.
Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_bulk_actions/1.
Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_empty/1.
Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_error/1.
The filter bar: a short :select renders as a segmented switch, a long one as a dropdown, a
:text filter as the search box and a :date_range as a pair of date inputs. The
phx-change="filter" form and the input names are Gervaz's contract — only the look is ours.
Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_header/1.
Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_loading/1.
The footer: a centred load-more, driven straight from the ui_adapter so it can carry the design's
classes (Shared.render_pagination/1 hardcodes its own).
Callback implementation for MishkaGervaz.Table.Behaviours.Template.render_template_switcher/1.