feat(FilterManager): enhance GatewayAutocomplete with ping functionality and prefetching for selected server
Publish Fast Tabler Docker image / build-and-push-fast (push) Failing after 3m5s
Publish Fast Tabler Docker image / build-and-push-fast (push) Failing after 3m5s
This commit is contained in:
@@ -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 (
|
||||
<div className="col" key={gw.name || idx}>
|
||||
<button
|
||||
@@ -511,12 +526,15 @@ function GatewayAutocomplete({ label, value, onChange, gateways = [], required =
|
||||
{gw.serverDns}
|
||||
</div>
|
||||
)}
|
||||
{(gw.country || gw.provider) && (
|
||||
<div className={`small text-truncate ${isSelected ? 'text-white-75' : 'text-muted'}`}>
|
||||
{gw.country && <span className="me-1">{countryToFlag(gw.country)}</span>}
|
||||
{gw.provider}
|
||||
</div>
|
||||
)}
|
||||
{/* Пинг шлюза (вместо строки с провайдером/страной), как на странице Easy Switch */}
|
||||
<div
|
||||
className={`fw-bold mt-1 ${
|
||||
isSelected ? 'text-white' : 'text-success'
|
||||
}`}
|
||||
style={{ fontSize: '1.05rem' }}
|
||||
>
|
||||
{ping != null ? ping : '—'}
|
||||
</div>
|
||||
</div>
|
||||
{gw.primary && (
|
||||
<span className={`badge ${isSelected ? 'bg-white text-primary' : 'bg-green-lt text-green'}`}>
|
||||
@@ -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
|
||||
/>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user