fix(traffic): подтверждать свежесть статусов привязанных интерфейсов

This commit is contained in:
Denozordec committed 2026-10-12 22:35:17 +07:00
1 parent 2b3d583e3b
commit b4d0733cfa
27 files changed
+1463 -36

No files matched your search

+8 -4
View File
@@ -3,6 +3,7 @@
import { useState, useMemo, useEffect, type ReactNode } from "react"
import { Alert, AlertTitle, AlertDescription } from "@/components/reui/alert"
import { projectTrafficObservations, type TrafficObservationMeta } from "@/lib/traffic-observations"
import { projectTrafficBindingStatus } from "@/lib/traffic-binding-status"
import { TrafficObservationStatus } from "@/components/traffic/traffic-observation-status"
import { TrafficDataTime } from "@/components/traffic/traffic-data-time"
import { PageHeader } from "@/components/page-header"
@@ -86,6 +87,8 @@ function flowEmptyHint(stats: FlowStatsDto | null, collectorAlive?: boolean): st
// ─── data model ───────────────────────────────────────────────────────────────
interface BoundIfaceTraffic {
statusObservedAt?: string|null
statusExpiresAt?: string|null
volumeUnit?: "GiB"
observations?: TrafficObservationMeta
id: string
@@ -110,7 +113,7 @@ interface BoundIfaceTraffic {
txTotal: number | null
rxSeries: (number|null)[]
txSeries: (number|null)[]
status: "online" | "offline"
status: "online" | "offline" | "unknown"
}
interface ServerTraffic {
@@ -508,7 +511,7 @@ function IfaceRow({ c, showServer = false }: { c: BoundIfaceTraffic; showServer?
"shrink-0 text-[10px] px-1.5 py-0.5 rounded-full font-medium tabular-nums",
c.status === "online" ? "bg-success/10 text-success" : "bg-muted text-muted-foreground",
)}>
{c.status === "online" ? "online" : "offline"}
{c.status === "online" ? "Работает" : c.status === "unknown" ? "Нет данных" : "Неактивен"}
</span>
</div>
)
@@ -767,6 +770,7 @@ const toLiveBound = (c: BoundIfaceTraffic): BoundIfaceTraffic => ({
...c,
interfaceType: (["ether", "gre", "wg", "other"].includes(c.interfaceType) ? c.interfaceType : "other") as InterfaceType,
...projectTrafficObservations(c),
status: projectTrafficBindingStatus(c.status,c.statusObservedAt,c.statusExpiresAt),
})
const toLiveUser = (u: UserTraffic & { interfaces?: BoundIfaceTraffic[] }): UserTraffic => {
@@ -965,7 +969,7 @@ export default function TrafficPage() {
const activeServerTraffic = useMemo(() => isLive ? (trafficReady ? liveServers.map(s => ({ ...s, ...projectTrafficObservations(s, trafficClock) })) : []) : serverTraffic, [isLive, trafficReady, liveServers, trafficClock])
const activeUserTraffic = useMemo(() => isLive ? (trafficReady ? liveUsers.map(u => ({ ...u, ...projectTrafficObservations(u, trafficClock), interfaces: u.interfaces.map(toLiveBound) })) : []) : userTraffic, [isLive, trafficReady, liveUsers, trafficClock])
const activeBoundIfaces = useMemo(() => isLive ? (trafficReady ? liveBoundIfaces.map(c => ({ ...c, ...projectTrafficObservations(c, trafficClock) })) : []) : boundIfaces, [isLive, trafficReady, liveBoundIfaces, trafficClock])
const activeBoundIfaces = useMemo(() => isLive ? (trafficReady ? liveBoundIfaces.map(c => ({ ...c, ...projectTrafficObservations(c, trafficClock), status: projectTrafficBindingStatus(c.status,c.statusObservedAt,c.statusExpiresAt,trafficClock) })) : []) : boundIfaces, [isLive, trafficReady, liveBoundIfaces, trafficClock])
const visibleIfaces = useMemo(
() => hideDisabledIfaces ? serverIfaces.filter((i) => !i.disabled && i.running) : serverIfaces,
[serverIfaces, hideDisabledIfaces],
@@ -1099,7 +1103,7 @@ export default function TrafficPage() {
const displayedFlow = currentFlows && !liveError ? (flowLiveSample ?? currentAnalytics?.data ?? null) : null
const selServer = useMemo(() => activeServerTraffic.find(s => s.id === selectedId) ?? activeServerTraffic[0], [selectedId, activeServerTraffic])
const detailServer = isLive ? (currentDetail?.server ? { ...currentDetail.server, ...projectTrafficObservations(currentDetail.server, trafficClock) } : null) : selServer
const detailServer = isLive ? (currentDetail?.server ? { ...currentDetail.server, ...projectTrafficObservations(currentDetail.server, trafficClock), boundIfaces: currentDetail.server.boundIfaces.map(toLiveBound) } : null) : selServer
const selUser = useMemo(() => activeUserTraffic.find(u => u.id === selectedId) ?? activeUserTraffic[0], [selectedId, activeUserTraffic])
const selIface = useMemo(() => activeBoundIfaces.find(c => c.id === selectedId) ?? activeBoundIfaces[0], [selectedId, activeBoundIfaces])