Add CapacityInsightWorker (every 15 min) that generates critical/warning insights when backhaul utilization exceeds 90%/75% and auto-resolves when it drops below 70%. Add capacity and utilization columns to the device ports tab with set/clear capacity controls. Add organization-level /capacity page with summary cards and per-site capacity table. Add capacity summary card to site show page. Add Capacity link to nav menu.
56 lines
2.4 KiB
Elixir
56 lines
2.4 KiB
Elixir
defmodule ToweropsWeb.CapacityLive do
|
|
@moduledoc false
|
|
use ToweropsWeb, :live_view
|
|
|
|
alias Towerops.Capacity
|
|
|
|
@impl true
|
|
def mount(_params, _session, socket) do
|
|
organization = socket.assigns.current_scope.organization
|
|
summaries = Capacity.get_organization_capacity_summary(organization.id)
|
|
|
|
total_capacity = Enum.reduce(summaries, 0, fn s, acc -> acc + s.total_capacity_bps end)
|
|
total_throughput = Enum.reduce(summaries, 0.0, fn s, acc -> acc + s.total_throughput_bps end)
|
|
|
|
overall_utilization =
|
|
if total_capacity > 0, do: Float.round(total_throughput / total_capacity * 100, 1), else: 0.0
|
|
|
|
sites_at_risk = Enum.count(summaries, fn s -> s.utilization_pct >= 75 end)
|
|
sites_with_headroom = Enum.count(summaries, fn s -> s.utilization_pct < 70 and s.total_capacity_bps > 0 end)
|
|
|
|
{:ok,
|
|
socket
|
|
|> assign(:page_title, "Capacity")
|
|
|> assign(:summaries, summaries)
|
|
|> assign(:total_capacity, total_capacity)
|
|
|> assign(:total_throughput, total_throughput)
|
|
|> assign(:overall_utilization, overall_utilization)
|
|
|> assign(:sites_at_risk, sites_at_risk)
|
|
|> assign(:sites_with_headroom, sites_with_headroom)}
|
|
end
|
|
|
|
defp format_capacity(bps) when is_number(bps) and bps >= 1_000_000_000,
|
|
do: "#{Float.round(bps / 1_000_000_000, 1)} Gbps"
|
|
|
|
defp format_capacity(bps) when is_number(bps) and bps >= 1_000_000, do: "#{Float.round(bps / 1_000_000, 1)} Mbps"
|
|
|
|
defp format_capacity(bps) when is_number(bps) and bps >= 1_000, do: "#{Float.round(bps / 1_000, 1)} Kbps"
|
|
|
|
defp format_capacity(bps) when is_number(bps), do: "#{bps} bps"
|
|
defp format_capacity(_), do: "-"
|
|
|
|
defp utilization_color(pct) when pct >= 90, do: "bg-red-500"
|
|
defp utilization_color(pct) when pct >= 70, do: "bg-yellow-500"
|
|
defp utilization_color(_pct), do: "bg-green-500"
|
|
|
|
defp utilization_text_color(pct) when pct >= 90, do: "text-red-600 dark:text-red-400"
|
|
defp utilization_text_color(pct) when pct >= 70, do: "text-yellow-600 dark:text-yellow-400"
|
|
defp utilization_text_color(_pct), do: "text-green-600 dark:text-green-400"
|
|
|
|
defp status_badge(pct) when pct >= 90, do: {"Critical", "bg-red-100 text-red-700 dark:bg-red-900/50 dark:text-red-300"}
|
|
|
|
defp status_badge(pct) when pct >= 70,
|
|
do: {"Warning", "bg-yellow-100 text-yellow-700 dark:bg-yellow-900/50 dark:text-yellow-300"}
|
|
|
|
defp status_badge(_pct), do: {"Healthy", "bg-green-100 text-green-700 dark:bg-green-900/50 dark:text-green-300"}
|
|
end
|