fix(ui): сохранить данные дашборда при сбоях и гонках запросов

This commit is contained in:
Denozordec committed 2026-09-20 00:58:58 +07:00
1 parent 0d418e2e39
commit 6a726b13b4
6 files changed
+316 -94

No files matched your search

+17 -27
View File
@@ -24,9 +24,9 @@ import { DashboardEventsTimeline } from "@/components/dashboard/dashboard-events
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 { DashboardDataStatus } from "@/components/dashboard/dashboard-data-status"
import { Badge } from "@/components/reui/badge"
import { Button, buttonVariants } from "@/components/ui/button"
import { 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"
@@ -69,17 +69,7 @@ export default function DashboardPage() {
<div className="flex-1 overflow-y-auto">
<div className="flex flex-col gap-4 px-4 py-4 md:gap-6 md:px-6 md:py-5">
{dash.error && !dash.loading ? (
<Alert variant="destructive">
<AlertTitle>Не удалось обновить дашборд</AlertTitle>
<AlertDescription className="flex flex-wrap items-center gap-2">
<span>{dash.error}</span>
<Button variant="outline" size="sm" onClick={dash.retry}>
Повторить
</Button>
</AlertDescription>
</Alert>
) : null}
{dash.isLive && <DashboardDataStatus sources={dash.sources} refreshing={dash.refreshing} onRefresh={dash.retry} />}
<KpiStatGrid
aria-label="Сводка дашборда"
@@ -88,8 +78,8 @@ export default function DashboardPage() {
{
id: "fleet",
label: "Флот",
value: `${dash.onlineCount} / ${dash.totalServers}`,
hint: !dash.isLive
value: dash.availability.servers ? `${dash.onlineCount} / ${dash.totalServers}` : "—",
hint: !dash.availability.servers ? "нет данных" : !dash.isLive
? "демо"
: offline > 0
? `${offline} offline`
@@ -104,8 +94,8 @@ export default function DashboardPage() {
{
id: "overlay",
label: "Оверлей",
value: String(dash.overlay.up),
hint: dash.overlay.total > 0 ? `${dash.overlay.down} down` : "нет туннелей",
value: dash.availability.overlay ? String(dash.overlay.up) : "—",
hint: !dash.availability.overlay ? "не все источники доступны" : dash.overlay.total > 0 ? `${dash.overlay.down} down` : "нет туннелей",
href: "/gre",
icon: <CableIcon />,
iconClassName: "text-info",
@@ -123,8 +113,8 @@ export default function DashboardPage() {
{
id: "health",
label: "Здоровье",
value: String(health),
hint: `${dash.probeDown} down · ${dash.probeWarn} warn`,
value: dash.availability.probes ? String(health) : "—",
hint: dash.availability.probes ? `${dash.probeDown} down · ${dash.probeWarn} warn` : "нет данных",
href: "/uptime",
icon: <BellIcon />,
iconClassName: health > 0 ? "text-destructive" : "text-muted-foreground",
@@ -268,8 +258,8 @@ export default function DashboardPage() {
icon: ServerIcon,
count: dash.attentionServers.length,
countVariant: "warning-light",
emptyTitle: "Все online",
emptyDescription: "Нет офлайн или degraded узлов.",
emptyTitle: dash.reliable.servers ? "Все online" : "Состояние не подтверждено",
emptyDescription: dash.reliable.servers ? "Нет офлайн или degraded узлов." : "Проверьте состояние источников выше.",
children: <AttentionRows rows={dash.attentionServers} />,
},
{
@@ -279,8 +269,8 @@ export default function DashboardPage() {
iconClassName: "text-info",
count: dash.attentionOverlay.length,
countVariant: "destructive-light",
emptyTitle: "Туннели up",
emptyDescription: "GRE и WireGuard в норме.",
emptyTitle: dash.reliable.overlay ? "Туннели up" : "Состояние не подтверждено",
emptyDescription: dash.reliable.overlay ? "GRE и WireGuard в норме." : "Проверьте состояние источников выше.",
children: <AttentionRows rows={dash.attentionOverlay} />,
},
{
@@ -290,8 +280,8 @@ export default function DashboardPage() {
iconClassName: "text-destructive",
count: dash.attentionProbes.length,
countVariant: "destructive-light",
emptyTitle: "Пробы up",
emptyDescription: "Нет down или warn.",
emptyTitle: dash.reliable.probes ? "Пробы up" : "Состояние не подтверждено",
emptyDescription: dash.reliable.probes ? "Нет down или warn." : "Проверьте состояние источников выше.",
children: <AttentionRows rows={dash.attentionProbes} />,
},
]}
@@ -319,8 +309,8 @@ export default function DashboardPage() {
{dash.activeProbes.length === 0 && !dash.probesLoading ? (
<EmptyState
className="py-10"
title="Нет проб на дашборде"
description="Включите пробу и отметьте ★ на странице мониторинга."
title={dash.availability.probes ? "Нет проб на дашборде" : "Данные проб недоступны"}
description={dash.availability.probes ? "Включите пробу и отметьте ★ на странице мониторинга." : "Повторите обновление данных."}
action={
<Link href="/uptime" className={cn(buttonVariants({ variant: "outline", size: "sm" }))}>
Открыть мониторинг