<%!-- Header --%>

{@current_scope.organization.name}

Network overview

<%= if assigns[:last_updated] do %>
Updated {ToweropsWeb.TimeHelpers.format_datetime(@last_updated, @timezone, @time_format)}
<% end %>
<%= if !assigns[:summary] do %> <.skeleton_dashboard /> <% end %> <%!-- Empty State --%> <%= if assigns[:summary] && @device_count == 0 do %>
<.icon name="hero-light-bulb" class="mx-auto h-14 w-14 text-blue-500 dark:text-blue-400" />

{t("Let's get started!")}

{t("Set up your network monitoring in a few steps.")}

<%= if @current_scope.organization.use_sites do %>
1

{t("Create a Site")}

{t("Sites represent your physical locations")}

2

{t("Add Devices")}

{t("Add routers, switches, and servers to your sites")}

<% else %>
1

{t("Add Devices")}

{t("Add network devices to monitor")}

<% end %>
{if @current_scope.organization.use_sites, do: "3", else: "2"}

{t("Monitor & Receive Alerts")}

{t("TowerOps automatically monitors your devices and alerts you of issues")}

<%= if @current_scope.organization.use_sites do %> <.button navigate={~p"/sites/new"} variant="primary"> <.icon name="hero-plus" class="h-5 w-5" /> Create Your First Site <% else %> <.button navigate={~p"/devices/new"} variant="primary"> <.icon name="hero-plus" class="h-5 w-5" /> Add Your First Device <% end %>
<% end %> <%= if assigns[:summary] && @device_count > 0 do %> <%!-- ═══════════════════════════════════════════════ STAT CARDS — compact row ═══════════════════════════════════════════════ --%>
<%!-- Health Score --%>
{t("Health")} 80 -> "bg-green-100 text-green-700 dark:bg-green-900/40 dark:text-green-400" @summary.health_score > 50 -> "bg-yellow-100 text-yellow-700 dark:bg-yellow-900/40 dark:text-yellow-400" true -> "bg-red-100 text-red-700 dark:bg-red-900/40 dark:text-red-400" end ]}> {cond do @summary.health_score > 80 -> "Good" @summary.health_score > 50 -> "Degraded" true -> "Critical" end}

{@summary.health_score}

<%!-- Uptime --%>
{t("Uptime")}

{if @uptime_percentage == 100.0, do: "100", else: :erlang.float_to_binary(@uptime_percentage, decimals: 1)}%

{@device_up}/{@device_count} up

<%!-- Devices --%> <.link navigate={~p"/devices"} class="rounded-lg border border-gray-200 bg-white px-4 py-3 transition hover:shadow-sm dark:border-white/10 dark:bg-gray-800/50" > {t("Devices")}

{@device_count}

{@device_up} up <%= if @device_down > 0 do %> {@device_down} down <% end %>
<%!-- Alerts --%> <.link navigate={~p"/alerts"} class="rounded-lg border border-gray-200 bg-white px-4 py-3 transition hover:shadow-sm dark:border-white/10 dark:bg-gray-800/50" > {t("Alerts")}

0, do: "text-red-600 dark:text-red-400", else: "text-green-600 dark:text-green-400" ) ]}> {if @total_alert_count == 0, do: "✓", else: @total_alert_count}

{if @total_alert_count == 0, do: "All clear", else: "View details →"}

<%!-- Secondary stats (only show if data exists) --%> <%= if @has_subscribers || (@current_scope.organization.use_sites && @sites_count > 0) do %>
<%= if @has_subscribers do %>
{t("Subscribers")}

{format_number(@summary.subscribers.total)}

{format_mrr(@summary.subscribers.total_mrr)}/mo

{t("MRR at Risk")}

{format_mrr(@impact_summary.mrr_at_risk)}

0} class="text-xs text-red-600 dark:text-red-400" > {format_number(@impact_summary.subscribers_affected)} affected

<% end %> <%= if @current_scope.organization.use_sites && @sites_count > 0 do %> <.link navigate={~p"/sites"} class="rounded-lg border border-gray-200 bg-white px-4 py-3 transition hover:shadow-sm dark:border-white/10 dark:bg-gray-800/50" > {t("Sites")}

{@sites_count}

<% end %> <.link navigate={~p"/insights"} class="rounded-lg border border-gray-200 bg-white px-4 py-3 transition hover:shadow-sm dark:border-white/10 dark:bg-gray-800/50" > {t("Insights")}

{@summary.insights.critical + @summary.insights.warning + @summary.insights.info}

0} class="inline-flex items-center rounded-full bg-red-100 px-1.5 py-0.5 text-[10px] font-medium text-red-700 dark:bg-red-900/30 dark:text-red-400" > {@summary.insights.critical} critical 0} class="inline-flex items-center rounded-full bg-yellow-100 px-1.5 py-0.5 text-[10px] font-medium text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400" > {@summary.insights.warning} warning
<% end %> <%!-- ═══════════════════════════════════════════════ {t("ACTIVE INCIDENTS (only when there ARE incidents)")} ═══════════════════════════════════════════════ --%> <%= if @active_incidents != [] do %>

{t("Active Incidents")}

{length(@active_incidents)}
<.link navigate={~p"/devices/#{incident.device_id}"} class="text-sm font-semibold text-gray-900 hover:text-blue-600 dark:text-white dark:hover:text-blue-400" > {incident.device_name} at {incident.site_name}
{format_duration(incident.duration_seconds)} <%= if incident.subscribers_affected > 0 do %> {format_number(incident.subscribers_affected)} subs <% end %> <%= if mrr_at_risk_positive?(incident.mrr_at_risk) do %> {format_mrr(incident.mrr_at_risk)}/mo <% end %>
<% end %> <%!-- ═══════════════════════════════════════════════ {t("MAIN CONTENT — full width stacked layout")} ═══════════════════════════════════════════════ --%> <%!-- Active Alerts (only show section when there ARE alerts) --%> <%= if @active_alerts != [] do %>

{t("Active Alerts")}

<.link navigate={~p"/alerts"} class="text-xs font-medium text-blue-600 hover:text-blue-700 dark:text-blue-400" > View all {@total_alert_count} →
{t("Device")} {t("Message")} {t("Impact")} {t("When")}
<.link navigate={~p"/devices/#{alert.device.id}"} class="text-sm font-medium text-gray-900 hover:text-blue-600 dark:text-white dark:hover:text-blue-400" > {alert.device.name}

{alert.device.site.name}

{alert.message} <%= if alert.gaiia_impact && alert.gaiia_impact["total_subscribers"] && alert.gaiia_impact["total_subscribers"] > 0 do %> {alert.gaiia_impact["total_subscribers"]} subs <% end %> <.timestamp datetime={alert.triggered_at} timezone={@timezone} /> <%= if is_nil(alert.acknowledged_at) && is_nil(alert.resolved_at) do %> <% else %> Ack'd <% end %>
<% end %> <%!-- Insights (compact grouped view) --%> <%= if @insights != [] do %>

{t("Insights")}

<.link patch={~p"/dashboard"} class={[ "rounded-full px-2 py-0.5 text-[10px] font-medium transition", if(is_nil(@insight_source), do: "bg-gray-900 text-white dark:bg-white dark:text-gray-900", else: "text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-white/10" ) ]} > {t("All")} <.link :for={source <- ~w(preseem snmp gaiia system)} patch={~p"/dashboard?insight_source=#{source}"} class={[ "rounded-full px-2 py-0.5 text-[10px] font-medium transition", if(@insight_source == source, do: "bg-gray-900 text-white dark:bg-white dark:text-gray-900", else: "text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-white/10" ) ]} > {source}
<.link navigate={~p"/insights"} class="text-xs font-medium text-blue-600 hover:text-blue-700 dark:text-blue-400" > View all →
{insight.urgency} {insight.source}

<.link navigate={~p"/insights?source=#{insight.source}"} class="hover:text-blue-600 dark:hover:text-blue-400" > {insight.title}

{insight.description}

<% end %> <%!-- Recent Config Changes --%> <%= if Enum.any?(@recent_config_changes) do %>

Config Changes (7d)

<.link navigate={~p"/insights"} class="text-xs font-medium text-blue-600 hover:text-blue-700 dark:text-blue-400" > View all →
<%= for change <- @recent_config_changes do %> <.link navigate={~p"/devices/#{change.device_id}/config-timeline"} class="flex items-center gap-3 px-4 py-2.5 bg-white hover:bg-gray-50 dark:bg-gray-800/50 dark:hover:bg-white/5 transition-colors" >
{if change.device, do: change.device.name, else: "Unknown"} {change.change_size} lines · {Enum.join( Enum.take(change.sections_changed, 2), ", " )}
{format_short_datetime(change.changed_at, @timezone)} <% end %>
<% end %> <%!-- Site Health Grid --%> <%= if @current_scope.organization.use_sites && @site_impact_summaries != [] do %>

{t("Site Health")}

<.link navigate={~p"/sites"} class="text-xs font-medium text-blue-600 hover:text-blue-700 dark:text-blue-400" > View all →
{t("Site")} {t("Devices")} {t("Down")} {t("QoE")} {t("Subscribers")}
<.link navigate={~p"/sites/#{site.site_id}"} class="flex items-center gap-2 text-sm font-medium text-gray-900 hover:text-blue-600 dark:text-white dark:hover:text-blue-400" > {site.name} {site.device_count} <%= if site.devices_down > 0 do %> {site.devices_down} <% else %> 0 <% end %> <%= if site.avg_qoe do %> "text-red-600 dark:text-red-400" site.avg_qoe < 4.0 -> "text-yellow-600 dark:text-yellow-400" true -> "text-green-600 dark:text-green-400" end }> {format_qoe(site.avg_qoe)} <% else %> <% end %> <%= if site.subscribers do %> {site.subscribers} <%= if site.subscribers_affected > 0 do %> ({format_number(site.subscribers_affected)} affected) <% end %> <% else %> <% end %>
<% end %> <%!-- Recent Activity (compact, only show meaningful entries) --%> <%= if assigns[:recent_activity] && @recent_activity != [] do %>

{t("Recent Activity")}

<.link navigate={~p"/activity"} class="text-xs font-medium text-blue-600 hover:text-blue-700 dark:text-blue-400" > View all →

{activity.summary}

{format_short_datetime(activity.timestamp, @timezone)}
<% end %> <%!-- Quick Actions --%>
<.link navigate={~p"/devices/new"} class="btn btn-outline btn-sm btn-xs gap-1"> <.icon name="hero-plus-circle" class="h-3.5 w-3.5" /> Add Device <.link navigate={~p"/alerts"} class="btn btn-outline btn-sm btn-xs gap-1"> <.icon name="hero-bell-alert" class="h-3.5 w-3.5" /> Alerts <.link navigate={~p"/trace"} class="btn btn-outline btn-sm btn-xs gap-1"> <.icon name="hero-signal" class="h-3.5 w-3.5" /> Trace <.link navigate={~p"/network-map"} class="btn btn-outline btn-sm btn-xs gap-1"> <.icon name="hero-globe-alt" class="h-3.5 w-3.5" /> Network Map
<% end %>