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 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;
|
||||
setPingLoading(true);
|
||||
const ttlMs = Math.max(0, (pingCacheSeconds || 0) * 1000);
|
||||
|
||||
const tasks = [];
|
||||
connections.forEach((c) => {
|
||||
sourceConnections.forEach((c) => {
|
||||
const from = String(c.from);
|
||||
const to = String(c.to);
|
||||
if (!from || !to || from === to) return;
|
||||
@@ -214,7 +221,7 @@ export default function NetworkMapDashboard() {
|
||||
srcTo && ['jumphost', 'home'].includes(String(srcTo.type || '').toLowerCase()) && c.internalToFrom;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -291,8 +298,14 @@ export default function NetworkMapDashboard() {
|
||||
const speedKey = (key1, key2) =>
|
||||
[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
|
||||
);
|
||||
if (withSpeed.length === 0) return;
|
||||
@@ -343,6 +356,22 @@ export default function NetworkMapDashboard() {
|
||||
setSpeedLoading(false);
|
||||
}, [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(() => {
|
||||
const controller = new AbortController();
|
||||
fetchData(controller.signal);
|
||||
@@ -427,6 +456,10 @@ export default function NetworkMapDashboard() {
|
||||
speedMap={speedMap}
|
||||
pingStaleMap={pingStaleMap}
|
||||
speedStaleMap={speedStaleMap}
|
||||
onRefreshPingForConnection={handleRefreshPingForConnection}
|
||||
onRefreshSpeedForConnection={handleRefreshSpeedForConnection}
|
||||
pingLoading={pingLoading}
|
||||
speedLoading={speedLoading}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -86,7 +86,18 @@ function speedKey(key1, key2) {
|
||||
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 svgRef = useRef(null);
|
||||
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 speed = speedMap[sk] ?? selectedEdge.speed;
|
||||
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 (
|
||||
<div
|
||||
className="network-map-edge-modal-backdrop"
|
||||
@@ -635,6 +657,32 @@ export default function NetworkMapUnifi({ servers = [], connections = [], pingMa
|
||||
</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>
|
||||
|
||||
Reference in New Issue
Block a user