MishkaCmsCore. Activity. Behaviours. Source behaviour
(Mishka CMS Core v0.0.1)
Copy Markdown
View Source
Behaviour for activity-feed data sources. Each adapter answers four questions:
topics/1— which PubSub topics the parent LiveView must subscribe to so the feed receives live updates.handles?/1— whether a given broadcast belongs to this source.to_entry/1— turn a live broadcast into a feed entry.initial_fetch/2— fetch the most recent entries for first render.in_scope?/2— (optional) whether a live broadcast belongs in a resource-scoped feed; only needed by sources on a global topic.
Adapters live under MishkaCmsCore.Activity.Sources.* (e.g.
PaperTrail, Oban). The ActivityFeed LiveComponent composes any
list of sources without knowing what each one does.
Summary
Types
One activity entry. Every key here is one a renderer reads, so a source that omits one hands a
template a map entry.that_key raises on — MishkaCmsCore.Activity.Helpers.complete_entry/1 fills
the gap at both seams, and entry_contract_test.exs fails the source that left it. The optional
tail is the pipeline's own: :actor_label and :site_label are resolved downstream by
MishkaCmsCore.Activity.ActivityEntry, :host by the dashboard's Recent activity widget.
Callbacks
Whether a live broadcast belongs in a feed of the given scope. Sources whose
topics/1 already encode the scope (per-resource topics, e.g. PaperTrail /
Oban) can omit it — the subscription alone filters them. A source on a GLOBAL
topic (e.g. EventLog's "event_log:created") implements it so a
resource-scoped feed drops out-of-scope broadcasts. A missing callback is
treated as always in scope.
Types
@type entry() :: %{ :id => String.t(), :resource_label => String.t(), :action => atom(), :severity => :info | :warn | :error, :tone => :created | :updated | :destroyed | nil, :badge_label => String.t() | nil, :badge_tone => atom() | nil, :inserted_at => DateTime.t(), :source_id => String.t() | nil, :site_id => String.t() | nil, :user_id => String.t() | nil, :message => String.t(), optional(atom()) => any() }
One activity entry. Every key here is one a renderer reads, so a source that omits one hands a
template a map entry.that_key raises on — MishkaCmsCore.Activity.Helpers.complete_entry/1 fills
the gap at both seams, and entry_contract_test.exs fails the source that left it. The optional
tail is the pipeline's own: :actor_label and :site_label are resolved downstream by
MishkaCmsCore.Activity.ActivityEntry, :host by the dashboard's Recent activity widget.
Callbacks
@callback handles?(Phoenix.Socket.Broadcast.t()) :: boolean()
@callback in_scope?(Phoenix.Socket.Broadcast.t(), scope()) :: boolean()
Whether a live broadcast belongs in a feed of the given scope. Sources whose
topics/1 already encode the scope (per-resource topics, e.g. PaperTrail /
Oban) can omit it — the subscription alone filters them. A source on a GLOBAL
topic (e.g. EventLog's "event_log:created") implements it so a
resource-scoped feed drops out-of-scope broadcasts. A missing callback is
treated as always in scope.
@callback initial_fetch(scope(), limit :: pos_integer()) :: [entry()]
@callback to_entry(Phoenix.Socket.Broadcast.t()) :: entry() | nil