towerops/lib/towerops_web/live/status_page_live.ex
Graham McIntire 3ca0834ef0 tests: raise coverage to 70% via helper promotion + new unit/property tests
Promoted pure presentation and utility helpers from `defp` to `def @doc false`
across ~20 LiveViews, Oban workers, and sync modules so they're reachable from
unit tests. Refactored several `cond` blocks into idiomatic function heads with
guards. Added ~250 new test cases in new files under test/towerops and
test/towerops_web, including DB-backed tests for CnMaestro.Sync and
AlertNotificationWorker, and removed dead LiveView tab components and
CapacityLive (no callers anywhere in lib/test).

Configured mix.exs test_coverage.ignore_modules to exclude vendored third-party
code (SnmpKit, protobuf-generated Towerops.Agent.*, Absinthe GraphQL types,
Phoenix HTML modules, Inspect protocol impls) from coverage calculations —
these are not our project code.

Coverage: 66.93% → 70.09%. Full suite: 10,127 tests, 0 failures.
2026-04-24 09:49:06 -05:00

107 lines
3.7 KiB
Elixir

defmodule ToweropsWeb.StatusPageLive do
@moduledoc """
Public unauthenticated status page.
Renders at /status/:slug with a standalone layout (no sidebar).
Mobile-responsive for customers checking during outages.
"""
use ToweropsWeb, :live_view
alias Towerops.StatusPages
@impl true
def mount(%{"slug" => slug}, _session, socket) do
case StatusPages.get_config_by_slug(slug) do
nil ->
{:ok,
socket
|> put_flash(:error, "Status page not found")
|> assign(:not_found, true)
|> assign(:page_title, "Not Found")}
config ->
_ =
if connected?(socket) do
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "status_page:#{config.id}")
end
components = StatusPages.list_components(config.id)
active_incidents = StatusPages.list_active_incidents(config.id)
recent_incidents = StatusPages.list_incidents(config.id, limit: 10)
overall = StatusPages.overall_status(components)
{:ok,
socket
|> assign(:config, config)
|> assign(:components, components)
|> assign(:active_incidents, active_incidents)
|> assign(:recent_incidents, recent_incidents)
|> assign(:overall_status, overall)
|> assign(:not_found, false)
|> assign(:page_title, "#{config.company_name || "Status"} — System Status"), layout: false}
end
end
@impl true
def handle_info({:status_updated, _}, socket) do
config = socket.assigns.config
components = StatusPages.list_components(config.id)
active_incidents = StatusPages.list_active_incidents(config.id)
overall = StatusPages.overall_status(components)
{:noreply,
assign(socket,
components: components,
active_incidents: active_incidents,
overall_status: overall
)}
end
def handle_info(_, socket), do: {:noreply, socket}
# -- Helpers --
@doc false
def overall_color(:operational), do: "bg-green-500"
def overall_color(:degraded), do: "bg-yellow-500"
def overall_color(:partial_outage), do: "bg-orange-500"
def overall_color(:major_outage), do: "bg-red-500"
def overall_color(:maintenance), do: "bg-blue-500"
def overall_color(_), do: "bg-gray-500"
@doc false
def overall_text(:operational), do: "All Systems Operational"
def overall_text(:degraded), do: "Degraded Performance"
def overall_text(:partial_outage), do: "Partial System Outage"
def overall_text(:major_outage), do: "Major System Outage"
def overall_text(:maintenance), do: "Scheduled Maintenance"
def overall_text(_), do: "Unknown"
@doc false
def component_color("operational"), do: "bg-green-500"
def component_color("degraded"), do: "bg-yellow-500"
def component_color("partial_outage"), do: "bg-orange-500"
def component_color("major_outage"), do: "bg-red-500"
def component_color("maintenance"), do: "bg-blue-500"
def component_color(_), do: "bg-gray-400"
@doc false
def component_label("operational"), do: "Operational"
def component_label("degraded"), do: "Degraded"
def component_label("partial_outage"), do: "Partial Outage"
def component_label("major_outage"), do: "Major Outage"
def component_label("maintenance"), do: "Maintenance"
def component_label(s), do: s
@doc false
def severity_color("critical"), do: "text-red-600"
def severity_color("major"), do: "text-orange-600"
def severity_color(_), do: "text-yellow-600"
@doc false
def incident_status_label("investigating"), do: "Investigating"
def incident_status_label("identified"), do: "Identified"
def incident_status_label("monitoring"), do: "Monitoring"
def incident_status_label("resolved"), do: "Resolved"
def incident_status_label(s), do: s
end