prepared the graph for refactoring and added an indicator
parent
d5aa312104
commit
b9a2be4860
|
|
@ -1,34 +1,26 @@
|
|||
import React from 'react';
|
||||
import { Box, Skeleton } from '@mui/material';
|
||||
|
||||
const ChartSkeleton = ({ count = 1 }) => {
|
||||
return (
|
||||
<>
|
||||
{Array.from({ length: count }).map((_, index) => (
|
||||
<Box
|
||||
key={index}
|
||||
sx={{
|
||||
const ChartSkeleton = () => (
|
||||
<Box sx={{
|
||||
backgroundColor: '#fff',
|
||||
borderRadius: '8px',
|
||||
padding: '20px',
|
||||
mb: 3,
|
||||
height: '400px'
|
||||
}}
|
||||
>
|
||||
marginBottom: '20px',
|
||||
position: 'relative'
|
||||
}}>
|
||||
<Box sx={{ position: 'absolute', right: '20px', top: '20px' }}>
|
||||
<Skeleton variant="circular" width={16} height={16} />
|
||||
</Box>
|
||||
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 2 }}>
|
||||
<Skeleton variant="text" width="40%" height={30} />
|
||||
<Skeleton variant="text" width="20%" height={30} />
|
||||
<Skeleton variant="text" width="30%" height={30} />
|
||||
</Box>
|
||||
<Skeleton variant="rectangular" width="100%" height="80%" />
|
||||
|
||||
<Skeleton variant="rectangular" width="100%" height={300} />
|
||||
|
||||
<Box sx={{ display: 'flex', justifyContent: 'center', mt: 2, gap: 2 }}>
|
||||
{[1, 2, 3, 4].map((i) => (
|
||||
{[1, 2, 3, 4].map((_, i) => (
|
||||
<Skeleton key={i} variant="rounded" width={80} height={36} />
|
||||
))}
|
||||
</Box>
|
||||
</Box>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChartSkeleton;
|
||||
|
|
@ -101,15 +101,14 @@ 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 newData = {};
|
||||
const rangeSeconds = useCustomRange
|
||||
? (endDate.getTime() - startDate.getTime()) / 1000
|
||||
: selectedRange.value;
|
||||
|
|
@ -118,10 +117,8 @@ const PrometheusChart = ({ metricName }) => {
|
|||
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();
|
||||
|
|
@ -133,21 +130,34 @@ const PrometheusChart = ({ metricName }) => {
|
|||
newData[instance].push({
|
||||
time: formattedTime.display,
|
||||
fullTime: formattedTime.fullDisplay,
|
||||
value: value,
|
||||
timestamp: timestamp
|
||||
value,
|
||||
timestamp
|
||||
});
|
||||
});
|
||||
|
||||
// Сортируем и ограничиваем данные
|
||||
Object.keys(newData).forEach(instance => {
|
||||
newData[instance] = newData[instance]
|
||||
.sort((a, b) => a.timestamp - b.timestamp)
|
||||
.slice(-1000);
|
||||
});
|
||||
return newData;
|
||||
|
||||
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) => {
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
if (!this.socket?.connected) {
|
||||
this.connect();
|
||||
}
|
||||
|
||||
if (!this.subscribers.has(metricName)) {
|
||||
this.subscribers.set(metricName, new Set());
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<div>
|
||||
<h2 style={{ textAlign: 'center' }}>Общий мониторинг состояния системы</h2>
|
||||
|
|
@ -17,6 +38,32 @@ const TabContent = ({ activeTab, statusHistories, treeData1, tabContent, handleO
|
|||
<SystemStatusChart data={statusHistories.history2} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Контейнер для индикаторов статусов */}
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end',
|
||||
marginTop: '20px',
|
||||
gap: '10px'
|
||||
}}>
|
||||
{Object.entries(statusCounts).map(([status, count]) => (
|
||||
<div key={status} style={{
|
||||
width: '30px',
|
||||
height: '30px',
|
||||
backgroundColor: getStatusColor(status),
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
color: 'white',
|
||||
fontWeight: 'bold',
|
||||
borderRadius: '5px',
|
||||
boxShadow: '0 2px 5px rgba(0,0,0,0.2)'
|
||||
}}>
|
||||
{count}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<label>Статус компонентов системы</label>
|
||||
<TreeTable data={treeData1} />
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue