SquatchMail.Web.Live.TrailLog (SquatchMail v0.1.0)

Copy Markdown View Source

The Trail Log — SquatchMail's default landing page (squatch_mail_dashboard mounted at /), showing the live activity feed: stat strip, filters, and the sent-email activity table.

One LiveView, four pages

This module also serves the sidebar's three archive pages, distinguished by live_action (see @pages):

  • :index — the Trail Log itself (/): recent activity, 7-day default range, stat strip.
  • :sightings — the Sightings archive (/sightings): every email on record, all-time default range.
  • :bounces / :complaints — the same table locked to status "bounced" / "complained" (/bounces, /complaints). The status filter is forced and its select hidden; a hand-typed ?status= param can't unlock it.

They share everything that matters — the URL-driven filters, the telemetry-driven refresh, pagination, and the activity table — so they're per-action page configs rather than three near-identical modules.

Filters live in the URL

Every filter (status, search, date range) is a query param, patched via push_patch/2 from handle_event/3 and re-read in handle_params/3 — the same pattern SquatchMail.Web.Live.Suppressions uses. This is what lets SquatchMail.Web.ActivityExportController's CSV export and the "back to Trail Log" link from the Sighting inspector both reconstruct the exact filter set a user was looking at, just from the URL.

Live updates

Rather than push every new email/event straight into the assigns from a telemetry handler (telemetry handlers run in the emitting process, not this LiveView's — attaching a handler here would execute in the wrong process and race with everything else), mount/3 attaches a handler that simply forwards [:squatch_mail, :email, :recorded] telemetry events to this LiveView's own process via send/2, debounced so a burst of events collapses into a single reload. A 30s poll (:timer.send_interval/2) is the fallback for whatever telemetry might miss (host restarts the handler attachment, a handler exception detaches it, etc.) The handler is detached in terminate/2 — leaving it attached would leak a reference to a dead LiveView process on every mount.

Summary

Functions

Builds Tracker.list_emails/1-shaped filters from Trail Log's query params. Public and shared with SquatchMail.Web.ActivityExportController so the CSV export always matches whatever's on screen — the archive pages' "Export CSV" links spell their locked status and effective range out as explicit query params (see export_query/2), so this 1-arity form (Trail Log defaults) is all the controller ever needs.

Functions

filters_from_params(params)

@spec filters_from_params(map()) :: map()

Builds Tracker.list_emails/1-shaped filters from Trail Log's query params. Public and shared with SquatchMail.Web.ActivityExportController so the CSV export always matches whatever's on screen — the archive pages' "Export CSV" links spell their locked status and effective range out as explicit query params (see export_query/2), so this 1-arity form (Trail Log defaults) is all the controller ever needs.