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
/>