feat(network-map): enhance ping and speed request handling with options for specific connections and loading states
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 2m1s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 2m1s
This commit is contained in:
@@ -195,14 +195,21 @@ export default function NetworkMapDashboard() {
|
|||||||
/** Один ключ пинга на ребро (маршруты статичны — одна сторона) */
|
/** Один ключ пинга на ребро (маршруты статичны — одна сторона) */
|
||||||
const edgePingKey = (a, b) => [String(a), String(b)].sort().join(':');
|
const edgePingKey = (a, b) => [String(a), String(b)].sort().join(':');
|
||||||
|
|
||||||
const requestPings = useCallback(async () => {
|
/**
|
||||||
if (connections.length === 0) return;
|
* Запросить пинг для всех соединений или для конкретного подмножества.
|
||||||
|
* Если передать force=true, игнорирует TTL кеша по пингу.
|
||||||
|
*/
|
||||||
|
const requestPings = useCallback(async (options = {}) => {
|
||||||
|
const { connections: targetConnections, force = false } = options;
|
||||||
|
const sourceConnections =
|
||||||
|
Array.isArray(targetConnections) && targetConnections.length > 0 ? targetConnections : connections;
|
||||||
|
if (sourceConnections.length === 0) return;
|
||||||
pingAbortRef.current = false;
|
pingAbortRef.current = false;
|
||||||
setPingLoading(true);
|
setPingLoading(true);
|
||||||
const ttlMs = Math.max(0, (pingCacheSeconds || 0) * 1000);
|
const ttlMs = Math.max(0, (pingCacheSeconds || 0) * 1000);
|
||||||
|
|
||||||
const tasks = [];
|
const tasks = [];
|
||||||
connections.forEach((c) => {
|
sourceConnections.forEach((c) => {
|
||||||
const from = String(c.from);
|
const from = String(c.from);
|
||||||
const to = String(c.to);
|
const to = String(c.to);
|
||||||
if (!from || !to || from === to) return;
|
if (!from || !to || from === to) return;
|
||||||
@@ -214,7 +221,7 @@ export default function NetworkMapDashboard() {
|
|||||||
srcTo && ['jumphost', 'home'].includes(String(srcTo.type || '').toLowerCase()) && c.internalToFrom;
|
srcTo && ['jumphost', 'home'].includes(String(srcTo.type || '').toLowerCase()) && c.internalToFrom;
|
||||||
|
|
||||||
const ekey = edgePingKey(from, to);
|
const ekey = edgePingKey(from, to);
|
||||||
if (ttlMs > 0 && pingTimestampsRef.current[ekey] && Date.now() - pingTimestampsRef.current[ekey] < ttlMs) {
|
if (!force && ttlMs > 0 && pingTimestampsRef.current[ekey] && Date.now() - pingTimestampsRef.current[ekey] < ttlMs) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,8 +298,14 @@ export default function NetworkMapDashboard() {
|
|||||||
const speedKey = (key1, key2) =>
|
const speedKey = (key1, key2) =>
|
||||||
[String(key1), String(key2)].sort().join(':');
|
[String(key1), String(key2)].sort().join(':');
|
||||||
|
|
||||||
const requestSpeeds = useCallback(async () => {
|
/**
|
||||||
const withSpeed = connections.filter(
|
* Запросить скорость для всех соединений или подмножества.
|
||||||
|
*/
|
||||||
|
const requestSpeeds = useCallback(async (options = {}) => {
|
||||||
|
const { connections: targetConnections } = options;
|
||||||
|
const sourceConnections =
|
||||||
|
Array.isArray(targetConnections) && targetConnections.length > 0 ? targetConnections : connections;
|
||||||
|
const withSpeed = sourceConnections.filter(
|
||||||
(c) => c.speedTestServerId && c.interfaceName
|
(c) => c.speedTestServerId && c.interfaceName
|
||||||
);
|
);
|
||||||
if (withSpeed.length === 0) return;
|
if (withSpeed.length === 0) return;
|
||||||
@@ -343,6 +356,22 @@ export default function NetworkMapDashboard() {
|
|||||||
setSpeedLoading(false);
|
setSpeedLoading(false);
|
||||||
}, [connections]);
|
}, [connections]);
|
||||||
|
|
||||||
|
const handleRefreshPingForConnection = useCallback(
|
||||||
|
(connection) => {
|
||||||
|
if (!connection) return;
|
||||||
|
requestPings({ connections: [connection], force: true });
|
||||||
|
},
|
||||||
|
[requestPings]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleRefreshSpeedForConnection = useCallback(
|
||||||
|
(connection) => {
|
||||||
|
if (!connection) return;
|
||||||
|
requestSpeeds({ connections: [connection] });
|
||||||
|
},
|
||||||
|
[requestSpeeds]
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
fetchData(controller.signal);
|
fetchData(controller.signal);
|
||||||
@@ -427,6 +456,10 @@ export default function NetworkMapDashboard() {
|
|||||||
speedMap={speedMap}
|
speedMap={speedMap}
|
||||||
pingStaleMap={pingStaleMap}
|
pingStaleMap={pingStaleMap}
|
||||||
speedStaleMap={speedStaleMap}
|
speedStaleMap={speedStaleMap}
|
||||||
|
onRefreshPingForConnection={handleRefreshPingForConnection}
|
||||||
|
onRefreshSpeedForConnection={handleRefreshSpeedForConnection}
|
||||||
|
pingLoading={pingLoading}
|
||||||
|
speedLoading={speedLoading}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -86,7 +86,18 @@ function speedKey(key1, key2) {
|
|||||||
return [String(key1), String(key2)].sort().join(':');
|
return [String(key1), String(key2)].sort().join(':');
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function NetworkMapUnifi({ servers = [], connections = [], pingMap = {}, speedMap = {}, pingStaleMap = {}, speedStaleMap = {} }) {
|
export default function NetworkMapUnifi({
|
||||||
|
servers = [],
|
||||||
|
connections = [],
|
||||||
|
pingMap = {},
|
||||||
|
speedMap = {},
|
||||||
|
pingStaleMap = {},
|
||||||
|
speedStaleMap = {},
|
||||||
|
onRefreshPingForConnection,
|
||||||
|
onRefreshSpeedForConnection,
|
||||||
|
pingLoading = false,
|
||||||
|
speedLoading = false,
|
||||||
|
}) {
|
||||||
const containerRef = useRef(null);
|
const containerRef = useRef(null);
|
||||||
const svgRef = useRef(null);
|
const svgRef = useRef(null);
|
||||||
const [size, setSize] = useState({ w: 800, h: 520 });
|
const [size, setSize] = useState({ w: 800, h: 520 });
|
||||||
@@ -514,6 +525,17 @@ export default function NetworkMapUnifi({ servers = [], connections = [], pingMa
|
|||||||
const sk = speedKey(selectedEdge.raw?.fromKey, selectedEdge.raw?.toKey);
|
const sk = speedKey(selectedEdge.raw?.fromKey, selectedEdge.raw?.toKey);
|
||||||
const speed = speedMap[sk] ?? selectedEdge.speed;
|
const speed = speedMap[sk] ?? selectedEdge.speed;
|
||||||
const speedStale = speedStaleMap[sk] === true;
|
const speedStale = speedStaleMap[sk] === true;
|
||||||
|
const canPingFrom =
|
||||||
|
fromServer &&
|
||||||
|
['jumphost', 'home'].includes(String(fromServer.type || '').toLowerCase()) &&
|
||||||
|
selectedEdge.raw?.internalFromTo;
|
||||||
|
const canPingTo =
|
||||||
|
toServer &&
|
||||||
|
['jumphost', 'home'].includes(String(toServer.type || '').toLowerCase()) &&
|
||||||
|
selectedEdge.raw?.internalToFrom;
|
||||||
|
const canPing = Boolean(canPingFrom || canPingTo);
|
||||||
|
const canSpeed =
|
||||||
|
Boolean(selectedEdge.raw?.speedTestServerId && selectedEdge.raw?.interfaceName);
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="network-map-edge-modal-backdrop"
|
className="network-map-edge-modal-backdrop"
|
||||||
@@ -635,6 +657,32 @@ export default function NetworkMapUnifi({ servers = [], connections = [], pingMa
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
<div className="mt-3 d-flex flex-wrap gap-2 justify-content-end">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn btn-outline-primary btn-sm"
|
||||||
|
disabled={!canPing || pingLoading || !onRefreshPingForConnection}
|
||||||
|
onClick={() => onRefreshPingForConnection && onRefreshPingForConnection(selectedEdge.raw)}
|
||||||
|
>
|
||||||
|
<IconRefresh
|
||||||
|
size={14}
|
||||||
|
className={pingLoading ? 'spin me-1' : 'me-1'}
|
||||||
|
/>
|
||||||
|
{pingLoading ? 'Пинг…' : 'Проверить пинг'}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn btn-outline-primary btn-sm"
|
||||||
|
disabled={!canSpeed || speedLoading || !onRefreshSpeedForConnection}
|
||||||
|
onClick={() => onRefreshSpeedForConnection && onRefreshSpeedForConnection(selectedEdge.raw)}
|
||||||
|
>
|
||||||
|
<IconRefresh
|
||||||
|
size={14}
|
||||||
|
className={speedLoading ? 'spin me-1' : 'me-1'}
|
||||||
|
/>
|
||||||
|
{speedLoading ? 'Скорость…' : 'Проверить скорость'}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user