From b9a2be4860f3a7a420390a478066453780a4e026 Mon Sep 17 00:00:00 2001 From: DmitriyA Date: Mon, 28 Apr 2025 09:27:07 -0400 Subject: [PATCH] prepared the graph for refactoring and added an indicator --- src/Charts/Components/ChartSkeleton.jsx | 56 ++++++------ .../Components/hooks/useMetricsData.jsx | 0 .../Components/hooks/useTimeHandlers.jsx | 0 src/Charts/Components/hooks/useWebSocket.jsx | 0 src/Charts/PrometheusChart.jsx | 85 +++++++++++-------- src/Charts/WebSocketManager.jsx | 12 ++- src/Components/hooks/TabContent.jsx | 47 ++++++++++ 7 files changed, 129 insertions(+), 71 deletions(-) create mode 100644 src/Charts/Components/hooks/useMetricsData.jsx create mode 100644 src/Charts/Components/hooks/useTimeHandlers.jsx create mode 100644 src/Charts/Components/hooks/useWebSocket.jsx diff --git a/src/Charts/Components/ChartSkeleton.jsx b/src/Charts/Components/ChartSkeleton.jsx index 7500023..090f1e7 100644 --- a/src/Charts/Components/ChartSkeleton.jsx +++ b/src/Charts/Components/ChartSkeleton.jsx @@ -1,34 +1,26 @@ -import React from 'react'; -import { Box, Skeleton } from '@mui/material'; +const ChartSkeleton = () => ( + + + + -const ChartSkeleton = ({ count = 1 }) => { - return ( - <> - {Array.from({ length: count }).map((_, index) => ( - - - - - - - - {[1, 2, 3, 4].map((i) => ( - - ))} - - + + + + + + + + + {[1, 2, 3, 4].map((_, i) => ( + ))} - - ); -}; - -export default ChartSkeleton; \ No newline at end of file + + +); \ No newline at end of file diff --git a/src/Charts/Components/hooks/useMetricsData.jsx b/src/Charts/Components/hooks/useMetricsData.jsx new file mode 100644 index 0000000..e69de29 diff --git a/src/Charts/Components/hooks/useTimeHandlers.jsx b/src/Charts/Components/hooks/useTimeHandlers.jsx new file mode 100644 index 0000000..e69de29 diff --git a/src/Charts/Components/hooks/useWebSocket.jsx b/src/Charts/Components/hooks/useWebSocket.jsx new file mode 100644 index 0000000..e69de29 diff --git a/src/Charts/PrometheusChart.jsx b/src/Charts/PrometheusChart.jsx index 0b1ae11..1a8b20c 100755 --- a/src/Charts/PrometheusChart.jsx +++ b/src/Charts/PrometheusChart.jsx @@ -101,53 +101,63 @@ const PrometheusChart = ({ metricName }) => { }, []); - const processMetricsData = useCallback((response) => { + const processMetricsData = useCallback((response, replace = false) => { console.log('Processing metrics data:', response); if (response.metric !== metricName) return; const dataArray = Array.isArray(response.data) ? response.data : [response.data]; if (!dataArray.length) return; - setChartData(prev => { - const newData = { ...(prev || {}) }; - const rangeSeconds = useCustomRange - ? (endDate.getTime() - startDate.getTime()) / 1000 - : selectedRange.value; + const newData = {}; + const rangeSeconds = useCustomRange + ? (endDate.getTime() - startDate.getTime()) / 1000 + : selectedRange.value; - dataArray.forEach(item => { - const instance = item.instance || 'default'; - if (!newData[instance]) newData[instance] = []; + dataArray.forEach(item => { + const instance = item.instance || 'default'; + if (!newData[instance]) newData[instance] = []; - // Унифицированная конвертация timestamp - let timestamp; - if (typeof item.timestamp === 'number') { - // Определяем, в секундах или миллисекундах пришел timestamp - timestamp = item.timestamp > 1e12 ? item.timestamp : item.timestamp * 1000; - } else { - timestamp = Date.now(); - } + let timestamp; + if (typeof item.timestamp === 'number') { + timestamp = item.timestamp > 1e12 ? item.timestamp : item.timestamp * 1000; + } else { + timestamp = Date.now(); + } - const value = parseFloat(item.value); - const formattedTime = formatTime(timestamp, rangeSeconds); + const value = parseFloat(item.value); + const formattedTime = formatTime(timestamp, rangeSeconds); - newData[instance].push({ - time: formattedTime.display, - fullTime: formattedTime.fullDisplay, - value: value, - timestamp: timestamp - }); + newData[instance].push({ + time: formattedTime.display, + fullTime: formattedTime.fullDisplay, + value, + timestamp }); - - // Сортируем и ограничиваем данные - Object.keys(newData).forEach(instance => { - newData[instance] = newData[instance] - .sort((a, b) => a.timestamp - b.timestamp) - .slice(-1000); - }); - return newData; }); + + Object.keys(newData).forEach(instance => { + newData[instance] = newData[instance] + .sort((a, b) => a.timestamp - b.timestamp) + .slice(-1000); + }); + + if (replace) { + setChartData(newData); // Заменяем полностью + } else { + setChartData(prev => { + const merged = { ...(prev || {}) }; + Object.keys(newData).forEach(instance => { + if (!merged[instance]) merged[instance] = []; + merged[instance] = [...merged[instance], ...newData[instance]] + .sort((a, b) => a.timestamp - b.timestamp) + .slice(-1000); + }); + return merged; + }); + } }, [metricName, selectedRange.value, formatTime, useCustomRange, startDate, endDate]); + const fetchData = useCallback(() => { if (isSelectingRange) return; @@ -197,7 +207,7 @@ const PrometheusChart = ({ metricName }) => { processMetricsData({ metric: metricName, data: processedData - }); + }, true); } } catch (error) { console.error('Ошибка при получении кастомных данных:', error); @@ -340,7 +350,9 @@ const PrometheusChart = ({ metricName }) => { useEffect(() => { // Обработчик данных с сервера const handleMetricsData = (data) => { - processMetricsData({ metric: metricName, data }); + if (!useCustomRange) { + processMetricsData({ metric: metricName, data }); + } }; // Подписываемся на обновления метрики @@ -359,7 +371,8 @@ const PrometheusChart = ({ metricName }) => { clearInterval(intervalRef.current); } }; - }, [metricName, processMetricsData]); + }, [metricName, useCustomRange, processMetricsData]); + useEffect(() => { if (useCustomRange && !isSelectingRange) { diff --git a/src/Charts/WebSocketManager.jsx b/src/Charts/WebSocketManager.jsx index aa4a46b..ff542a0 100644 --- a/src/Charts/WebSocketManager.jsx +++ b/src/Charts/WebSocketManager.jsx @@ -1,4 +1,3 @@ -// src/services/WebSocketManager.js import { io } from 'socket.io-client'; class WebSocketManager { @@ -7,13 +6,16 @@ class WebSocketManager { this.subscribers = new Map(); this.connectionStatus = 'disconnected'; this.connectionCallbacks = new Set(); + this.connecting = false; } connect() { - if (this.socket && (this.socket.connected || this.socket.reconnecting)) { + if (this.socket?.connected || this.connecting) { return this.socket; } + this.connecting = true; + this.socket = io(`${import.meta.env.VITE_BACK_WS_URL}/api/metrics-ws`, { transports: ['websocket'], reconnection: true, @@ -24,11 +26,13 @@ class WebSocketManager { this.socket.on('connect', () => { this.connectionStatus = 'connected'; + this.connecting = false; this.notifyConnectionStatus(); }); this.socket.on('disconnect', (reason) => { this.connectionStatus = 'disconnected'; + this.connecting = false; this.notifyConnectionStatus(); if (reason === 'io server disconnect') this.socket.connect(); }); @@ -50,7 +54,9 @@ class WebSocketManager { } subscribe(metricName, callback) { - this.connect(); + if (!this.socket?.connected) { + this.connect(); + } if (!this.subscribers.has(metricName)) { this.subscribers.set(metricName, new Set()); diff --git a/src/Components/hooks/TabContent.jsx b/src/Components/hooks/TabContent.jsx index 3ab4279..a1c8102 100644 --- a/src/Components/hooks/TabContent.jsx +++ b/src/Components/hooks/TabContent.jsx @@ -1,9 +1,30 @@ import SystemStatusChart from "../../Charts/SystemStatusChart"; import TreeTable from "../UI/TreeTable"; import FlowChart from "../TreeChart/FlowChart"; +import { getStatusColor } from "../TreeChart/dataUtils"; + const TabContent = ({ activeTab, statusHistories, treeData1, tabContent, handleOpenTab }) => { + // Функция для подсчета количества элементов каждого статуса + const countStatuses = (data) => { + const counts = { green: 0, yellow: 0, orange: 0, red: 0 }; + + const countRecursive = (node) => { + if (node.status) { + counts[node.status]++; + } + if (node.items && node.items.length > 0) { + node.items.forEach(child => countRecursive(child)); + } + }; + + countRecursive(data); + return counts; + }; + if (activeTab === "Главная") { + const statusCounts = treeData1 ? countStatuses(treeData1) : { green: 0, yellow: 0, orange: 0, red: 0 }; + return (

Общий мониторинг состояния системы

@@ -17,6 +38,32 @@ const TabContent = ({ activeTab, statusHistories, treeData1, tabContent, handleO
+ + {/* Контейнер для индикаторов статусов */} +
+ {Object.entries(statusCounts).map(([status, count]) => ( +
+ {count} +
+ ))} +
+