"use client" import Link from "next/link" import { ActivityIcon, BellIcon, CableIcon, FilterIcon, GitMergeIcon, HardDriveIcon, HeartPulseIcon, MapIcon, ServerIcon, ShieldIcon, } from "lucide-react" import { PageHeader } from "@/components/page-header" import { OpsPanel } from "@/components/ops-panel" import { KpiStatGrid } from "@/components/reui-kit/kpi-stat-grid" import { QuickActionGrid } from "@/components/reui-kit/quick-action-grid" import { AttentionQueue } from "@/components/reui-kit/attention-queue" import { TrafficRxTxChart } from "@/components/reui-kit/traffic-rx-tx-chart" import { LatencyChart } from "@/components/dashboard/latency-chart" import { DashboardEventsTimeline } from "@/components/dashboard/dashboard-events-timeline" import { InternetPathPanel } from "@/components/dashboard/internet-path-panel" import { DashboardActiveProbesDataGrid } from "@/components/data-grids/dashboard-active-probes-data-grid" import { EmptyState } from "@/components/empty-state" import { Alert, AlertDescription, AlertTitle } from "@/components/reui/alert" import { Badge } from "@/components/reui/badge" import { Button, buttonVariants } from "@/components/ui/button" import { cn } from "@/lib/utils" import { fmtRate } from "@/lib/fmt-rate" import { useDashboardLive, type AttentionRow } from "@/hooks/use-dashboard-live" function fmtIntRu(n: number): string { return n.toLocaleString("ru-RU") } function AttentionRows({ rows }: { rows: AttentionRow[] }) { return (
{rows.map((row) => ( {row.title} {row.hint} ))}
) } export default function DashboardPage() { const dash = useDashboardLive() const offline = Math.max(0, dash.totalServers - dash.onlineCount) const health = dash.probeDown + dash.probeWarn return (
{dash.error && !dash.loading ? ( Не удалось обновить дашборд {dash.error} ) : null} 0 ? `${offline} offline` : dash.totalServers > 0 ? "все online" : "нет узлов", href: "/servers", icon: , iconClassName: "text-muted-foreground", variant: offline > 0 ? "warning" : "default", }, { id: "overlay", label: "Оверлей", value: String(dash.overlay.up), hint: dash.overlay.total > 0 ? `${dash.overlay.down} down` : "нет туннелей", href: "/gre", icon: , iconClassName: "text-info", variant: dash.overlay.down > 0 ? "warning" : "default", }, { id: "bgp", label: "BGP Rx", value: dash.bgp ? fmtIntRu(dash.bgp.prefixSum) : "—", hint: dash.bgp ? `${dash.bgp.establishedCount} Established` : "нет данных", href: "/bgp", icon: , iconClassName: "text-primary", }, { id: "health", label: "Здоровье", value: String(health), hint: `${dash.probeDown} down · ${dash.probeWarn} warn`, href: "/uptime", icon: , iconClassName: health > 0 ? "text-destructive" : "text-muted-foreground", variant: health > 0 ? "destructive" : "default", }, ]} /> , iconClassName: "text-info", }, { id: "map", title: "Карта сети", description: "Топология GRE и WAN", href: "/network-map", icon: , iconClassName: "text-primary", }, { id: "filters", title: "Фильтры", description: "Правила обхода и списки", href: "/filters", icon: , iconClassName: "text-info", }, { id: "firewall", title: "Firewall", description: "Цепочки filter / nat", href: "/firewall", icon: , iconClassName: "text-warning", }, { id: "backups", title: "Бэкапы", description: "Снапшоты и расписание", href: "/backups", icon: , iconClassName: "text-muted-foreground", }, { id: "bgp", title: "BGP", description: "Сессии и префиксы", href: "/bgp", icon: , iconClassName: "text-primary", }, ]} />
{dash.latency.kind === "loading" && (
)} {dash.latency.kind === "empty" && (

{dash.latency.message}

)} {(dash.latency.kind === "mock" || dash.latency.kind === "live") && ( )} Все → } >
{dash.traffic.demo ? демо : null} RX {fmtRate(dash.traffic.rxNow)} TX {fmtRate(dash.traffic.txNow)} Трафик →
) : null } contentClassName="px-3 pb-3" > {dash.loading && !dash.traffic ? (
) : !dash.traffic ? (

Нет данных трафика за последний час.{" "} Открыть трафик

) : ( )} , }, { id: "overlay", title: "Оверлей", icon: CableIcon, iconClassName: "text-info", count: dash.attentionOverlay.length, countVariant: "destructive-light", emptyTitle: "Туннели up", emptyDescription: "GRE и WireGuard в норме.", children: , }, { id: "probes", title: "Пробы", icon: HeartPulseIcon, iconClassName: "text-destructive", count: dash.attentionProbes.length, countVariant: "destructive-light", emptyTitle: "Пробы up", emptyDescription: "Нет down или warn.", children: , }, ]} />
{dash.probesSubtitle} } headerRight={ Мониторинг → } contentClassName="px-0 pb-0" > {dash.activeProbes.length === 0 && !dash.probesLoading ? ( Открыть мониторинг } /> ) : ( )}
) }