This guide shows you how to put one execution's current state on a page of your own LiveView and keep it current while the execution moves. To put the shipped diagram and event log on a page instead, see How to embed the ops view in a host LiveView.
You start from a Phoenix host that declares :statifier_ui and
:phoenix_live_view as dependencies, with a loan's execution already started
as a Statifier.Session under trace: true and record: true. The examples
use the loan chart from the README's Basic usage (on_loan, due,
returned, lost) and a session id of loan_42; MyApp.Loans.fetch!/1
stands for however your host finds the compiled chart, the session pid and
the SCXML source.
Start a subscriber in
mount/3and attach it to the session with catch-up:defmodule MyAppWeb.LoanLive do use MyAppWeb, :live_view alias StatifierUI.Live.State alias StatifierUI.Trace.Message alias StatifierUI.Trace.Subscriber def mount(%{"loan_id" => loan_id}, _session, socket) do {chart, session, source} = MyApp.Loans.fetch!(loan_id) {:ok, subscriber} = Subscriber.start_link(machine: chart, source: source) :ok = Subscriber.attach(subscriber, session, catch_up: true) # step 2 continues here end endSubscriber.stats(subscriber)now showsstatus: :attached,session: "loan_42"anddiagnostics: []. Ifdiagnosticscarries a:not_recordedentry, start the session withrecord: true.Register the LiveView as a listener, then build the read model from what the subscriber already holds:
:ok = Subscriber.add_listener(subscriber, self()) trace = State.new(chart) |> State.sync(subscriber) {:ok, assign(socket, trace: trace, finished: false)}State.configuration_ids(trace)returns{:ok, ["<scxml>", "on_loan"]}for a loan still on loan. Listener first and snapshot second, so no message falls between the two calls.Fold every message the subscriber sends into the read model:
def handle_info({:statifier_ui, _session_id, %Message{} = message}, socket) do {:noreply, update(socket, :trace, &State.push(&1, message))} endAfter the session takes
loan.due,State.configuration_ids(socket.assigns.trace)returns{:ok, ["<scxml>", "due"]}.Render the current state on your page:
def render(assigns) do ~H""" <p id="loan-state">{current_state(@trace)}</p> <p :if={@finished}>This loan's execution has finished.</p> """ end defp current_state(trace) do case State.configuration_ids(trace) do {:ok, ids} -> Enum.join(ids, ", ") {:error, :no_manifest} -> "unknown" end endThe
#loan-stateparagraph reads<scxml>, due, and changes on the next event without a reload.Mark the page when the execution finishes, with a clause placed above the one from step 3:
def handle_info( {:statifier_ui, _session_id, %Message{type: "session.halted"} = message}, socket ) do {:noreply, socket |> update(:trace, &State.push(&1, message)) |> assign(:finished, true)} endAfter the session takes
loan.returned, the#loan-stateparagraph reads<scxml>, returnedand the "finished" line appears.
For every option Subscriber.start_link/1 and Subscriber.attach/3 take, see
StatifierUI.Trace.Subscriber; for every read the model answers, see
StatifierUI.Live.State.