From fdc39060a186925d59e816930d9b31f7bd06c353 Mon Sep 17 00:00:00 2001 From: shats Date: Wed, 18 Feb 2026 13:36:26 +0700 Subject: [PATCH] feat(NetworkMapUnifi): add short speed formatting and country flag display to network edges --- frontend/src/NetworkMapUnifi.jsx | 58 +++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/frontend/src/NetworkMapUnifi.jsx b/frontend/src/NetworkMapUnifi.jsx index 9e30152..9c3c74a 100644 --- a/frontend/src/NetworkMapUnifi.jsx +++ b/frontend/src/NetworkMapUnifi.jsx @@ -1,5 +1,6 @@ import { useMemo, useCallback, useState, useRef, useEffect } from 'react'; import { IconRefresh, IconMaximize, IconMinimize } from '@tabler/icons-react'; +import { countryToFlag } from './utils/serverUtils.js'; const UNIFI_BG = '#0f172a'; const UNIFI_CARD_BG = '#1e293b'; @@ -64,6 +65,22 @@ function formatMbps(bps) { return `${mbps.toFixed(1)} Мбит/с`; } +/** Короткий формат скорости для подписи на ребре: "↓287 ↑170 Мбит/с" */ +function formatSpeedShort(downloadBps, uploadBps) { + const fmt = (v) => { + if (v == null || Number.isNaN(v)) return '—'; + const mbps = v / 1_000_000; + if (!Number.isFinite(mbps)) return '—'; + return mbps >= 10 ? Math.round(mbps) : mbps.toFixed(1); + }; + const down = fmt(downloadBps); + const up = fmt(uploadBps); + if (down === '—' && up === '—') return null; + if (down === '—') return `↑${up} Мбит/с`; + if (up === '—') return `↓${down} Мбит/с`; + return `↓${down} ↑${up} Мбит/с`; +} + function speedKey(key1, key2) { return [String(key1), String(key2)].sort().join(':'); } @@ -197,7 +214,7 @@ export default function NetworkMapUnifi({ servers = [], connections = [], pingMa const speed = speedMap[sk]; const speedLabel = speed && (speed.tcpDownloadBps != null || speed.tcpUploadBps != null) - ? `↓ ${formatMbps(speed.tcpDownloadBps)} ↑ ${formatMbps(speed.tcpUploadBps)}` + ? formatSpeedShort(speed.tcpDownloadBps, speed.tcpUploadBps) : null; return { edgeKey: `${from}-${to}-${c.tunnelType || ''}`, @@ -299,9 +316,9 @@ export default function NetworkMapUnifi({ servers = [], connections = [], pingMa {(() => { const used = []; - const LABEL_W = 64; - const LABEL_H = 20; - const LABEL_GAP = 4; + const LABEL_W = 100; + const LABEL_H = 18; + const LABEL_GAP = 6; return edgesWithPing.map((e, idx) => { const dimFactor = hoveredEdgeKey && hoveredEdgeKey !== e.edgeKey ? 0.25 : 1; @@ -331,39 +348,40 @@ export default function NetworkMapUnifi({ servers = [], connections = [], pingMa const labels = [e.pingLabel, e.speedLabel].filter(Boolean); if (labels.length === 0) return null; let level = 0; + const totalH = labels.length * LABEL_H + (labels.length - 1) * LABEL_GAP; while ( level < 10 && used.some( (p) => Math.abs(p.x - x) < LABEL_W && - Math.abs(p.y - (y + level * (LABEL_H + LABEL_GAP))) < (labels.length * (LABEL_H + LABEL_GAP)) + Math.abs(p.y - (y + level * (totalH + 8))) < totalH + 16 ) ) { level += 1; } - y = y + level * (LABEL_H + LABEL_GAP); + y = y + level * (totalH + 8); used.push({ x, y }); - const pad = 6; + const pad = 8; return ( {labels.map((text, i) => { - const yy = y + i * (LABEL_H + LABEL_GAP); - const w = Math.min(text.length * 5.5 + pad * 2, 140); - const h = 18; + const yy = y + i * (LABEL_H + LABEL_GAP) + LABEL_H / 2; + const w = Math.max(LABEL_W, Math.min(text.length * 6 + pad * 2, 160)); + const h = LABEL_H + 4; return ( - + - {text.length > 24 ? text.slice(0, 22) + '…' : text} + {text} ); @@ -400,6 +418,20 @@ export default function NetworkMapUnifi({ servers = [], connections = [], pingMa strokeWidth={1} /> + {/* Флаг страны в левом верхнем углу карточки */} + {s.country && ( + + {countryToFlag(s.country)} + + )} {/* Иконка сервера в стиле UNIFI: прямоугольник с «портами» */}