"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 ? (
Открыть мониторинг
}
/>
) : (
)}
)
}