diff --git a/app/(main)/network-map/page.tsx b/app/(main)/network-map/page.tsx index 5d72d59b..1bbbe5c7 100644 --- a/app/(main)/network-map/page.tsx +++ b/app/(main)/network-map/page.tsx @@ -1,6 +1,7 @@ "use client" import { useState, useRef, useEffect, useMemo, useCallback, Suspense } from "react" +import {fitNetworkMapCamera} from "@/lib/network-map-camera" import { useSearchParams } from "next/navigation" import {readNetworkMapUrl,patchNetworkMapUrl,type NetworkMapFilter} from "@/lib/network-map-url-state" import {Alert,AlertTitle,AlertDescription} from "@/components/ui/alert" @@ -441,9 +442,9 @@ function latencyColor(ms: number | null) { if (ms > 60) return "var(--status-degraded)" return "var(--status-online)" } -function shortName(name: string) { +function shortName(name: string, limit = 24) { const label = name.replace(/^(home|mt)-/, "").split("-").slice(0, 3).join("-") - return label.length > 24 ? label.slice(0, 23).trimEnd() + "…" : label + return label.length > limit ? label.slice(0, limit - 1).trimEnd() + "…" : label } function greStatusToServerStatus(s: "up" | "down" | "degraded"): ServerStatus { @@ -646,7 +647,7 @@ function SvgTooltip({ n }: { n: Server & { x: number; y: number } }) { const oy = n.y - 32 const lines = [ n.name, - `${TYPE_LABELS[n.type]} · ${n.site}`, + `${TYPE_LABELS[n.type]} · ${n.site || n.country?.toUpperCase() || "—"}`, n.latency != null ? `${n.latency} мс` : "Офлайн", n.model ?? "", ].filter(Boolean) @@ -670,8 +671,9 @@ function SvgTooltip({ n }: { n: Server & { x: number; y: number } }) { ) } -function ServerNode({ n, isSel, isVis, isDragged, hideCatalogLatency, onClick, onDblClick, onHoverChange, onContextMenu, onMouseDown }: { +function ServerNode({ labelScale = 1, n, isSel, isVis, isDragged, hideCatalogLatency, onClick, onDblClick, onHoverChange, onContextMenu, onMouseDown }: { n: Server & { x: number; y: number } + labelScale?: number isSel: boolean; isVis: boolean; isDragged: boolean /** Не дублировать «N мс» из каталога, если на карте уже показаны метрики GRE (оранжевые числа в круге). */ hideCatalogLatency?: boolean @@ -749,13 +751,13 @@ function ServerNode({ n, isSel, isVis, isDragged, hideCatalogLatency, onClick, o lineHeight: 1.25, }} > - {n.site} + {n.site || n.country?.toUpperCase() || "—"} ) : ( 32 ? "13" : "11"} fontWeight="700" - fill="var(--foreground)" fontFamily="ui-monospace,monospace">{n.site} + fill="var(--foreground)" fontFamily="ui-monospace,monospace">{n.site || n.country?.toUpperCase() || "—"} )} {!hideCatalogLatency && ( @@ -763,8 +765,8 @@ function ServerNode({ n, isSel, isVis, isDragged, hideCatalogLatency, onClick, o )} {(n.name && ( - {shortName(n.name)} + {shortName(n.name,labelScale>1?12:24)} ))} ) @@ -1005,7 +1007,8 @@ function ContextMenu({ menu, onClose }: { menu: CtxMenu; onClose: () => void }) const MM_W = 172, MM_H = 94 -function Minimap({ pan, zoom, nodes, greEdges, satPos, wanJhEdges, homeRouters, servicePos, onClose, onPan }: { +function Minimap({ viewportHeight, pan, zoom, nodes, greEdges, satPos, wanJhEdges, homeRouters, servicePos, onClose, onPan }: { + viewportHeight: number pan: { x: number; y: number }; zoom: number nodes: (Server & { x: number; y: number })[] greEdges: GreMapEdge[] @@ -1017,7 +1020,7 @@ function Minimap({ pan, zoom, nodes, greEdges, satPos, wanJhEdges, homeRouters, onPan: (x: number, y: number) => void }) { const vpW = Math.min(W, W / zoom) - const vpH = Math.min(H, H / zoom) + const vpH = Math.min(H, viewportHeight / zoom) function handleClick(e: React.MouseEvent) { e.stopPropagation() @@ -1070,7 +1073,7 @@ function Minimap({ pan, zoom, nodes, greEdges, satPos, wanJhEdges, homeRouters, fill="var(--card)" stroke="var(--chart-4)" strokeWidth="3" opacity="0.85" /> ))} {/* viewport rect */} -