lib/squid_sonar_web/live/page_live.ex

defmodule SquidSonarWeb.PageLive do
  use SquidSonarWeb, :live_view

  alias SquidSonar.Dashboard

  @impl true
  def mount(_params, _session, socket) do
    socket =
      socket
      |> assign_new(:prefix, fn -> "" end)
      |> assign(:page_title, "SquidSonar Runtime")
      |> assign(:theme, :system)
      |> assign_dashboard()

    {:ok, socket}
  end

  @impl true
  def handle_event("refresh", _params, socket) do
    dashboard = socket.assigns.dashboard

    {:noreply,
     assign_dashboard(socket,
       filters: dashboard.filters,
       page: dashboard.page,
       page_size: dashboard.page_size
     )}
  end

  @impl true
  def handle_event("filter", params, socket) do
    {:noreply,
     assign_dashboard(socket,
       filters: Map.get(params, "filters", %{}),
       page_size: Map.get(params, "page_size"),
       page: 1
     )}
  end

  @impl true
  def handle_event("paginate", %{"page" => page} = params, socket) do
    dashboard = socket.assigns.dashboard

    {:noreply,
     assign_dashboard(socket,
       filters: dashboard.filters,
       page_size:
         Map.get(params, "page_size") || Map.get(params, "page-size") || dashboard.page_size,
       page: page
     )}
  end

  @impl true
  def handle_event("set_theme", %{"theme" => theme}, socket) do
    {:noreply, assign(socket, :theme, normalize_theme(theme))}
  end

  @impl true
  def render(assigns) do
    ~H"""
    <main
      id="squid-sonar-page"
      phx-hook="SquidSonarTheme"
      class={["squid-sonar-shell", "squid-sonar-theme-#{@theme}"]}
    >
      <header class="squid-sonar-topbar">
        <.link navigate={@prefix <> "/"} class="squid-sonar-brand squid-sonar-brand-link">
          <div>
            <p class="squid-sonar-eyebrow">Runtime dashboard</p>
            <h1>SquidSonar</h1>
          </div>
        </.link>
        <div class="squid-sonar-topbar-actions">
          <.theme_switcher theme={@theme} />
        </div>
      </header>

      <%= if @dashboard.load_error do %>
        <.dashboard_error error={@dashboard.load_error} />
      <% else %>
        <div class="squid-sonar-content">
          <form phx-change="filter" phx-submit="filter">
            <section class="squid-sonar-workspace">
              <aside class="squid-sonar-sidebar" aria-label="Status inventory">
                <div class="squid-sonar-sidebar-heading">
                  <h2>Status</h2>
                </div>
                <.status_nav_item
                  status={:all}
                  count={@dashboard.loaded_count}
                  active={@dashboard.filters.status == :all}
                />
                <.status_nav_item
                  :for={status <- @dashboard.statuses}
                  status={status}
                  count={Map.fetch!(@dashboard.status_counts, status)}
                  active={@dashboard.filters.status == status}
                />
              </aside>

              <.runs_panel dashboard={@dashboard} prefix={@prefix} />
            </section>
          </form>
        </div>
      <% end %>
    </main>
    """
  end

  defp assign_dashboard(socket, opts \\ []) do
    assign(socket, :dashboard, Dashboard.load(opts))
  end

  defp normalize_theme("system"), do: :system
  defp normalize_theme("light"), do: :light
  defp normalize_theme("dark"), do: :dark
  defp normalize_theme(_theme), do: :system
end