# `MishkaCmsCoreWeb.Templates.HistoryTimeline`
[🔗](https://github.com/mishka-group/mishka_cms_core/blob/v0.0.1/lib/mishka_cms_core_web/templates/history_timeline.ex#L5)

The visual editor's history, drawn as a MishkaGervaz custom table template: a vertical rail with a
bucket-tinted node per change, the assistant's own words where it has them, and a Revert on every
row whose document was kept.

Backed by `MishkaCmsCore.Runtime.PageBuilderEvent` and opened from the builder's Record-history
sheet. It replaced a hand-rolled `<ol>` over the in-memory undo stack, which meant the sheet showed
one session's ops, called every author "You", and lost everything on reload.

## Why a second timeline template

`MishkaCmsCoreWeb.Templates.ActivityTimeline` draws a vertical timeline too, and is deliberately NOT
extended: it binds row content by column POSITION, and its `dot_class` / `node_class` helpers are
public API for `MishkaCmsCore.Activity.ActivityEntry` and `MishkaDocument.EventLog`. Reusing it
would couple three unrelated tables through a shared private vocabulary. This follows
`MishkaCmsCoreWeb.Templates.ReviewComments` instead — filter pills, per-row buttons, one static
column the template unpacks itself.

A template owns the whole table, so the filter bar and the footer are here. No UI adapter is
involved: everything this draws is either the template's own markup or a column's `render`.

## Two rules that are easy to get wrong

**`filter_values` is keyed by the filter's ATOM name** — gervaz builds it with
`Map.put(acc, filter.name, value)`. Reading it with a string key answers `nil` silently, and the
table then renders unfiltered with every pill unchecked, which looks like the pills are unwired.

**Author branches on `author_type` BEFORE the masking ladder.** Every row carries a human
`author_id`, including an assistant's — it is whoever's editor ran the prompt — so a ladder that
matches an email-bearing author first would print the operator's address under the assistant's
work. See `MishkaCmsCore.Runtime.PageBuilderEvent`.

# `render_bulk_actions`

# `render_empty`

# `render_error`

# `render_filters`

The four pills — All / Content / Style / Publish — as radios rather than a dropdown.

"All" is the empty value of the one `:select` filter, so switching to it clears rather than
filtering on a fourth thing.

# `render_header`

# `render_loading`

The timeline, before it knows what happened.

Three rows the shape of a real one — dot, connector, a title and a line of detail — so the sheet
settles into its content instead of replacing a centred spinner with a list.

# `render_template_switcher`

---

*Consult [api-reference.md](api-reference.md) for complete listing*
