diff --git a/src/App.css b/src/App.css
index 40842f6..9c7629a 100755
--- a/src/App.css
+++ b/src/App.css
@@ -42,34 +42,4 @@
.read-the-docs {
color: #888;
-}
-
-/* Глобальный стиль для WebKit-браузеров (Chrome, Edge, Safari) */
-::-webkit-scrollbar {
- width: 10px; /* Толщина вертикального скролла */
- height: 10px; /* Толщина горизонтального скролла */
-}
-
-/* Фон скроллбара */
-::-webkit-scrollbar-track {
- background: #f1f1f1; /* Цвет фона */
- border-radius: 10px; /* Скругление углов */
-}
-
-/* Ползунок */
-::-webkit-scrollbar-thumb {
- background: #3d74c7; /* Основной цвет */
- border-radius: 10px; /* Скругляем края */
- border: 2px solid #f1f1f1; /* Белая обводка */
-}
-
-/* Эффект при наведении */
-::-webkit-scrollbar-thumb:hover {
- background: #2b5aa5; /* Чуть темнее при наведении */
-}
-
-/* Глобальный стиль для Firefox */
-* {
- scrollbar-width: thin; /* Делаем тонким */
- scrollbar-color: #3d74c7 #f1f1f1; /* Ползунок + фон */
}
\ No newline at end of file
diff --git a/src/Charts/Components/LineChartComponent.jsx b/src/Charts/Components/LineChartComponent.jsx
index 23ae6da..f607307 100644
--- a/src/Charts/Components/LineChartComponent.jsx
+++ b/src/Charts/Components/LineChartComponent.jsx
@@ -1,12 +1,12 @@
import React from 'react';
-import { LineChart, XAxis, YAxis, CartesianGrid, Tooltip, Legend, Line, ResponsiveContainer, Brush } from 'recharts';
+import { LineChart, XAxis, YAxis, CartesianGrid, Tooltip, Legend, Line, ResponsiveContainer } from 'recharts';
-const LineChartComponent = ({ chartData, metricName, metricType, colors, description, isLongRange }) => {
+const LineChartComponent = ({ chartData, metricName, metricType, colors, description }) => {
// Создаем массив уникальных временных меток
const allTimes = Object.values(chartData)
.flat()
.map(point => point.time)
- .filter((time, index, self) => self.indexOf(time) === index); // Убираем дубликаты
+ .filter((time, index, self) => self.indexOf(time) === index);
// Формируем данные для графика
const data = allTimes.map(time => {
@@ -18,14 +18,17 @@ const LineChartComponent = ({ chartData, metricName, metricType, colors, descrip
return point;
});
- console.log('Processed Data:', data); // Логируем данные для графика
-
// Кастомный Tooltip для отображения значения
const CustomTooltip = ({ active, payload, label }) => {
if (active && payload && payload.length) {
return (
-
-
{`${payload[0].value}`}
+
+
{`Время: ${label}`}
{/* Время из label */}
+ {payload.map((entry, index) => (
+
+ {`Значение: ${entry.value}`} {/* Имя и значение из payload */}
+
+ ))}
);
}
@@ -41,7 +44,7 @@ const LineChartComponent = ({ chartData, metricName, metricType, colors, descrip
-
} />
+
} /> {/* Подключаем кастомный Tooltip */}
{Object.keys(chartData).map((key, index) => (
))}
- {isLongRange && ( // Добавляем Brush только для длительных периодов
-
- )}
diff --git a/src/Charts/PrometheusChart.jsx b/src/Charts/PrometheusChart.jsx
index f6ce9be..159afba 100644
--- a/src/Charts/PrometheusChart.jsx
+++ b/src/Charts/PrometheusChart.jsx
@@ -1,258 +1,141 @@
import React, { useEffect, useState, useRef } from 'react';
import axios from 'axios';
import LineChartComponent from './Components/LineChartComponent';
-import BarChartComponent from './Components/BarChartComponent';
-import ScatterChartComponent from './Components/ScatterChartComponent';
-import DatePicker from 'react-datepicker';
-import '../Style/DatePicker.css';
const MAX_POINTS = 20; // Ограничение точек на графике
const COLORS = ['#3e95cd', '#8e5ea2', '#3cba9f', '#e8c3b9', '#c45850']; // Фиксированные цвета для линий
-// Компонент для выбора временного диапазона
-const TimeRangeSelector = ({ onRangeChange }) => {
- return (
-
-
-
-
-
- );
-};
-
-// Компонент для выбора произвольного диапазона дат
-const DateRangeSelector = ({ onDateChange }) => {
- const [startDate, setStartDate] = useState(new Date());
- const [endDate, setEndDate] = useState(new Date());
-
- const handleDateChange = (dates) => {
- const [start, end] = dates;
- setStartDate(start);
- setEndDate(end);
- onDateChange({ start, end });
- };
-
- return (
-
-
-
- );
-};
+// Список временных диапазонов и интервалов обновления
+const TIME_RANGES = [
+ { label: '1 минута', value: 60, interval: 3000 },
+ { label: '5 минут', value: 300, interval: 15000 },
+ { label: '30 минут', value: 1800, interval: 90000 },
+ { label: '1 час', value: 3600, interval: 180000 },
+ { label: '3 часа', value: 10800, interval: 540000 },
+ { label: '6 часов', value: 21600, interval: 1080000 },
+ { label: '12 часов', value: 43200, interval: 2160000 },
+ { label: '24 часа', value: 86400, interval: 4320000 },
+ { label: '2 дня', value: 172800, interval: 8640000 },
+ { label: '7 дней', value: 604800, interval: 30240000 },
+ { label: '30 дней', value: 2592000, interval: 129600000 },
+ { label: '90 дней', value: 7776000, interval: 388800000 },
+ { label: '6 месяцев', value: 15552000, interval: 777600000 },
+ { label: '9 месяцев', value: 23328000, interval: 1166400000 },
+ { label: '1 год', value: 31536000, interval: 1576800000 },
+];
const PrometheusChart = ({ metricName }) => {
const [chartData, setChartData] = useState({});
const [metricType, setMetricType] = useState('');
const [metricDescription, setMetricDescription] = useState('');
- const [timeRange, setTimeRange] = useState('24h'); // По умолчанию выбран диапазон "24 часа"
- const [customRange, setCustomRange] = useState({ start: null, end: null });
+ const [selectedRange, setSelectedRange] = useState(TIME_RANGES[0]); // По умолчанию 1 минута
const intervalRef = useRef(null);
- const isLongRange = (range) => {
- return range === '2w' || range === 'custom'; // "2w" — две недели, "custom" — кастомный диапазон
- };
-
- const fetchData = async (range, customStart, customEnd) => {
+ const fetchData = async () => {
try {
- const end = customEnd ? Math.floor(customEnd.getTime() / 1000) : Math.floor(Date.now() / 1000);
- let start;
+ const end = Math.floor(Date.now() / 1000);
+ const start = end - selectedRange.value;
- if (customStart) {
- start = Math.floor(customStart.getTime() / 1000);
- } else {
- switch (range) {
- case '1h':
- start = end - 60 * 60; // 1 час назад
- break;
- case '24h':
- start = end - 24 * 60 * 60; // 24 часа назад
- break;
- case '2w':
- start = end - 14 * 24 * 60 * 60; // 2 недели назад
- break;
- default:
- start = end - 24 * 60 * 60; // По умолчанию 24 часа
- }
- }
+ // Динамический шаг (чем больше диапазон, тем больше шаг)
+ let step;
+ if (selectedRange.value <= 3600) step = 5; // 1 час и меньше → 5 сек
+ else if (selectedRange.value <= 21600) step = 30; // 1-6 часов → 30 сек
+ else if (selectedRange.value <= 86400) step = 120; // 6-24 часа → 2 минуты
+ else step = 300; // > 24 часов → 5 минут
- const step = range === '2w' ? 3600 : 60; // Для двух недель увеличиваем шаг до 1 часа
+ console.log(`Запрашиваем данные с шагом ${step} сек`);
const response = await axios.get(`http://192.168.2.39:3000/metrics`, {
- params: {
- metric: metricName,
- start,
- end,
- step,
- },
+ params: { metric: metricName, start, end, step },
});
const result = response.data;
-
- // Проверяем структуру данных
- let metrics;
- if (Array.isArray(result)) {
- metrics = result;
- } else if (result.data && Array.isArray(result.data)) {
- metrics = result.data;
- } else {
- throw new Error('Invalid data format');
- }
+ let metrics = Array.isArray(result) ? result : result.data || [];
if (!Array.isArray(metrics) || metrics.length === 0) {
- throw new Error('No metrics data available');
+ console.warn('No metrics data available, filling with empty values.');
+ metrics = [];
}
- const type = metrics[0].type;
- setMetricType(type);
+ // 1. Генерация временных точек с учетом диапазона
+ const timePoints = [];
+ for (let t = start; t <= end; t += step) {
+ const date = new Date(t * 1000);
+ const formattedTime = selectedRange.value > 86400
+ ? date.toLocaleString([], { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' })
+ : date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });
- // Устанавливаем описание метрики
- setMetricDescription(metrics[0].description);
-
- // Очищаем предыдущие данные
- setChartData({});
-
- if (type === 'summary') {
- // Обработка данных для summary
- const newData = metrics.map(m => ({
- instance: m.instance,
- quantile: m.quantile,
- value: m.value
- }));
-
- // Группируем данные по instance
- const groupedData = newData.reduce((acc, point) => {
- if (!acc[point.instance]) {
- acc[point.instance] = [];
- }
- acc[point.instance].push(point);
- return acc;
- }, {});
-
- setChartData(groupedData);
- } else {
- // Обработка данных для counter, gauge, unknown
- const newDataPoints = metrics.map(m => ({
- time: new Date(m.timestamp).toLocaleTimeString(),
- value: m.value,
- instance: m.instance,
- device: m.device || m.scrape_job, // Используем device или scrape_job
- }));
-
- // Группируем данные по instance и device/scrape_job
- const updatedData = {};
-
- newDataPoints.forEach(point => {
- const key = `${point.instance}-${point.device}`; // Уникальный ключ
- if (!updatedData[key]) {
- updatedData[key] = [];
- }
- updatedData[key].push({
- time: point.time,
- value: point.value,
- });
-
- // Ограничиваем количество точек до MAX_POINTS
- if (updatedData[key].length > MAX_POINTS) {
- updatedData[key] = updatedData[key].slice(-MAX_POINTS); // Оставляем последние MAX_POINTS точек
- }
- });
-
- setChartData(updatedData);
+ timePoints.push(formattedTime);
}
+
+ // 2. Обработка данных
+ const updatedData = {};
+ metrics.forEach(m => {
+ const date = new Date(m.timestamp);
+ const formattedTime = selectedRange.value > 86400
+ ? date.toLocaleString([], { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' })
+ : date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });
+
+ const key = `${m.instance}-${m.device || m.scrape_job}`;
+ if (!updatedData[key]) updatedData[key] = {};
+ updatedData[key][formattedTime] = m.value;
+ });
+
+ // 3. Заполнение пропусков
+ const chartData = {};
+ Object.keys(updatedData).forEach(key => {
+ chartData[key] = timePoints.map(time => ({
+ time,
+ value: updatedData[key][time] ?? null,
+ }));
+ });
+
+ setChartData(chartData);
} catch (error) {
- console.error('Error fetching metrics:', error);
+ console.error('Ошибка при загрузке метрик:', error);
}
};
- useEffect(() => {
- fetchData(timeRange, customRange.start, customRange.end); // Первоначальная загрузка данных
- if (!isLongRange(timeRange)) { // Обновляем только для коротких диапазонов
- intervalRef.current = setInterval(() => {
- fetchData(timeRange, customRange.start, customRange.end);
- }, 5000); // Обновляем каждые 5 секунд
- }
+ useEffect(() => {
+ fetchData(); // Первоначальная загрузка данных
+
+ intervalRef.current = setInterval(() => {
+ fetchData();
+ }, selectedRange.interval); // Обновляем с выбранным интервалом
return () => {
if (intervalRef.current) {
clearInterval(intervalRef.current); // Очищаем интервал при размонтировании
}
};
- }, [metricName, timeRange, customRange]);
+ }, [metricName, selectedRange]); // Зависимость от metricName и selectedRange
- const handleRangeChange = (range) => {
- setTimeRange(range);
- setCustomRange({ start: null, end: null });
-
- if (!isLongRange(range)) {
- clearInterval(intervalRef.current); // Останавливаем обновление
- }
- };
-
- const handleDateChange = ({ start, end }) => {
- setCustomRange({ start, end });
- setTimeRange('custom'); // Устанавливаем кастомный диапазон
+ const handleRangeChange = (event) => {
+ const selectedValue = event.target.value;
+ const range = TIME_RANGES.find(range => range.value === parseInt(selectedValue, 10));
+ setSelectedRange(range);
};
if (!Object.keys(chartData).length) return Loading...
;
- const renderChart = () => {
- switch (metricType) {
- case 'counter':
- case 'gauge':
- return (
-
- );
- case 'summary':
- return (
-
- );
- case 'unknown':
- return (
-
- );
- default:
- return Unsupported metric type
;
- }
- };
-
return (
-
-
- {renderChart()}
+
+
+
+
+
);
};
diff --git a/src/Components/TreeChart/tabContent.jsx b/src/Components/TreeChart/tabContent.jsx
index 26ab955..9c55909 100644
--- a/src/Components/TreeChart/tabContent.jsx
+++ b/src/Components/TreeChart/tabContent.jsx
@@ -7,6 +7,8 @@ const getMetricName = (id) => {
return `zvks_apiforsnmp_measure_${id}`;
};
+//!!!!!!!!!!Пофиксить вкладуи с eth4, во всех eth 1-4 открывается именно 4 !!!!!!!!!!!!!
+
// Функция для рекурсивного сбора всех id потомков
const getAllChildIds = (node) => {
let ids = [];