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}
+
+ ))}
+
+