diff --git a/frontend/src/FilterManager.jsx b/frontend/src/FilterManager.jsx index 1594ffd..79a90d7 100644 --- a/frontend/src/FilterManager.jsx +++ b/frontend/src/FilterManager.jsx @@ -331,7 +331,18 @@ function CommunityAutocomplete({ label, value, onChange, communities = [], requi } // Компонент выбора Gateway в виде карточек (вместо выпадающего списка) -function GatewayAutocomplete({ label, value, onChange, gateways = [], required = false, placeholder = 'Введите или выберите gateway...' }) { +function GatewayAutocomplete({ + label, + value, + onChange, + gateways = [], + required = false, + placeholder = 'Введите или выберите gateway...', + // Карта пингов, как на Easy Switch: ключ `${routerId}:${gatewayIp}` → avg RTT + pingMap = {}, + // Идентификатор роутера (id/dns/ip из inventory), как на Easy Switch + routerId = null, +}) { const [inputValue, setInputValue] = useState(value || ''); const [isOpen, setIsOpen] = useState(false); const [highlightedIndex, setHighlightedIndex] = useState(-1); @@ -478,6 +489,10 @@ function GatewayAutocomplete({ label, value, onChange, gateways = [], required = {filteredGateways.map((gw, idx) => { const isSelected = gw.name === value; const isHighlighted = highlightedIndex === idx; + const pingKey = routerId && gw.ip ? `${routerId}:${gw.ip}` : null; + const ping = pingKey && Object.prototype.hasOwnProperty.call(pingMap, pingKey) + ? pingMap[pingKey] + : null; return (
{gw.primary && ( @@ -764,17 +782,33 @@ function FilterManager() { const [inventoryServers, setInventoryServers] = useState([]); // Network config gateways (from /network-config endpoint) const [networkConfigGateways, setNetworkConfigGateways] = useState([]); + // Пинги по шлюзам: ключ `${routerId}:${gatewayIp}` → avg RTT в мс (как на Easy Switch) + const [pingMap, setPingMap] = useState({}); + + // Получить metadata сервера из inventory по имени (dns/hostName/ip) + const getInventoryMetaForServer = (serverName) => { + if (!serverName) return null; + return inventoryServers.find((srv) => + String(srv.dns || '').trim() === serverName || + String(srv.hostName || '').trim() === serverName || + String(srv.ip || '').trim() === serverName + ); + }; + + // Получить routerId для MikroTik (id/dns/ip), как на странице Easy Switch + const getRouterIdForServer = (server) => { + if (!server) return null; + const meta = getInventoryMetaForServer(server.name); + if (!meta) return null; + return meta.id || meta.dns || meta.ip || null; + }; // Собираем gateways только для выбранного сервера const selectedServerGateways = (() => { if (!selectedServer) return []; // Ищем соответствующий сервер в inventoryServers по имени - const matchedServer = inventoryServers.find(srv => - String(srv.dns || '').trim() === selectedServer.name || - String(srv.hostName || '').trim() === selectedServer.name || - String(srv.ip || '').trim() === selectedServer.name - ); + const matchedServer = getInventoryMetaForServer(selectedServer.name); const serverDns = matchedServer?.dns || matchedServer?.hostName || selectedServer.name || ''; const serverId = matchedServer?.id || matchedServer?.ip || selectedServer.id || selectedServer.name || ''; @@ -853,6 +887,55 @@ function FilterManager() { return a.name.localeCompare(b.name); }); })(); + + // Предзагружаем пинги для gateways выбранного сервера (как на Easy Switch, но только для одного сервера) + const prefetchPingsForSelectedServer = () => { + try { + if (!selectedServer) return; + const routerId = getRouterIdForServer(selectedServer); + if (!routerId) return; + if (!selectedServerGateways || selectedServerGateways.length === 0) return; + + const tasks = []; + const seen = new Set(); + + selectedServerGateways.forEach((gw) => { + const ip = gw.ip || ''; + if (!ip) return; + const key = `${routerId}:${ip}`; + if (seen.has(key) || Object.prototype.hasOwnProperty.call(pingMap, key)) return; + seen.add(key); + tasks.push({ routerId, ip, key }); + }); + + if (tasks.length === 0) return; + + tasks.forEach(({ routerId: rId, ip, key }) => { + api + .post('/mikrotik/ping', { + serverId: rId, + gatewayIp: ip, + count: 5, + }) + .then(({ data }) => { + const value = + typeof data?.avgMs === 'number' ? Math.round(data.avgMs) : null; + setPingMap((prev) => ({ ...prev, [key]: value })); + }) + .catch((e) => { + console.warn('Failed to fetch ping for', rId, ip, e?.message || e); + setPingMap((prev) => ({ ...prev, [key]: null })); + }); + }); + } catch (e) { + console.warn('prefetchPingsForSelectedServer error:', e?.message || e); + } + }; + + // Автоматически обновляем пинги при смене выбранного сервера или списка его gateways + useEffect(() => { + prefetchPingsForSelectedServer(); + }, [selectedServer, selectedServerGateways, inventoryServers]); useEffect(() => { // Загружаем базовую AS из настроек @@ -2278,6 +2361,8 @@ function FilterManager() { value={newFilter.gateway} onChange={(val) => setNewFilter({ ...newFilter, gateway: val })} gateways={selectedServerGateways} + pingMap={pingMap} + routerId={getRouterIdForServer(selectedServer)} required /> @@ -2319,6 +2404,8 @@ function FilterManager() { value={editingFilter.gateway} onChange={(val) => setEditingFilter({ ...editingFilter, gateway: val })} gateways={selectedServerGateways} + pingMap={pingMap} + routerId={getRouterIdForServer(selectedServer)} required />