Merge pull request 'debugging' (#29) from debugging into redesign
test-org/trust-module-frontend/pipeline/pr-rc This commit looks good Details

Reviewed-on: http://git.enode/deployer3000/trust-module-frontend/pulls/29
pull/28/head
DmitriyA 2025-04-09 14:57:13 +03:00
commit 46484efdea
4 changed files with 358 additions and 181 deletions

View File

@ -11,28 +11,59 @@ const LineChartComponent = ({
const [selectionArea, setSelectionArea] = useState(null); const [selectionArea, setSelectionArea] = useState(null);
const [isSelecting, setIsSelecting] = useState(false); const [isSelecting, setIsSelecting] = useState(false);
const chartRef = useRef(null); const chartRef = useRef(null);
const containerRef = useRef(null);
const allTimes = Object.values(chartData) const allTimestamps = Object.values(chartData)
.flat() .flat()
.map(point => point.time) .map(point => point.timestamp)
.filter((time, index, self) => self.indexOf(time) === index); .filter((timestamp, index, self) => self.indexOf(timestamp) === index)
.sort((a, b) => a - b);
const data = allTimestamps.map(timestamp => {
const point = { timestamp };
const firstPoint = Object.values(chartData)
.flat()
.find(p => p.timestamp === timestamp);
if (firstPoint) {
point.time = firstPoint.time;
point.fullTime = firstPoint.fullTime;
}
const data = allTimes.map(time => {
const point = { time };
Object.keys(chartData).forEach(key => { Object.keys(chartData).forEach(key => {
const instanceData = chartData[key].find(p => p.time === time); const instanceData = chartData[key].find(p => p.timestamp === timestamp);
point[key] = instanceData ? instanceData.value : null; point[key] = instanceData ? instanceData.value : null;
}); });
return point; return point;
}).sort((a, b) => {
const timeA = chartData[Object.keys(chartData)[0]].find(d => d.time === a.time)?.timestamp;
const timeB = chartData[Object.keys(chartData)[0]].find(d => d.time === b.time)?.timestamp;
return timeA - timeB;
}); });
const displayData = filteredData || data; const displayData = filteredData || data;
const instanceKeys = displayData.length
? Object.keys(displayData[0]).filter(k => !['timestamp', 'time', 'fullTime'].includes(k))
: [];
// Функция для определения оптимального формата времени в зависимости от диапазона
const getTimeFormat = () => {
if (!data.length) return 'HH:mm:ss';
const first = data[0].timestamp;
const last = data[data.length - 1].timestamp;
const range = last - first;
// Если диапазон больше 24 часов - показываем дату
if (range > 86400000) {
return 'dd.MM HH:mm';
}
// Если больше 1 часа - показываем часы и минуты
if (range > 3600000) {
return 'HH:mm';
}
// Для коротких диапазонов - показываем время с секундами
return 'HH:mm:ss';
};
useEffect(() => { useEffect(() => {
const handleSelectStart = (e) => { const handleSelectStart = (e) => {
if (isSelecting) { if (isSelecting) {
@ -40,44 +71,66 @@ const LineChartComponent = ({
} }
}; };
document.addEventListener('selectstart', handleSelectStart); document.addEventListener('selectstart', handleSelectStart);
return () => document.removeEventListener('selectstart', handleSelectStart); return () => document.removeEventListener('selectstart', handleSelectStart);
}, [isSelecting]); }, [isSelecting]);
const handleMouseDown = (e) => { const handleMouseDown = (e) => {
if (!e || !e.activeLabel) return; if (!e) return;
// Получаем индекс точки по координатам
const activeIndex = e.activeTooltipIndex;
if (activeIndex === undefined || activeIndex < 0 || activeIndex >= data.length) return;
setIsSelecting(true); setIsSelecting(true);
setSelectionArea({ start: e.activeLabel, end: null }); setSelectionArea({
start: data[activeIndex].timestamp,
end: null,
startIndex: activeIndex,
endIndex: null
});
}; };
const handleMouseMove = (e) => { const handleMouseMove = (e) => {
if (!selectionArea?.start || !e?.activeLabel) return; if (!isSelecting || !selectionArea?.start || !e) return;
setSelectionArea(prev => ({ ...prev, end: e.activeLabel }));
const activeIndex = e.activeTooltipIndex;
if (activeIndex === undefined || activeIndex < 0 || activeIndex >= data.length) return;
setSelectionArea(prev => ({
...prev,
end: data[activeIndex].timestamp,
endIndex: activeIndex
}));
}; };
const handleMouseUp = () => { const handleMouseUp = () => {
if (!isSelecting || !selectionArea?.start || !selectionArea?.end) {
setIsSelecting(false); setIsSelecting(false);
if (!selectionArea?.start || !selectionArea?.end) {
setSelectionArea(null); setSelectionArea(null);
return; return;
} }
const startIndex = data.findIndex(point => point.time === selectionArea.start); const startIndex = Math.min(selectionArea.startIndex, selectionArea.endIndex);
const endIndex = data.findIndex(point => point.time === selectionArea.end); const endIndex = Math.max(selectionArea.startIndex, selectionArea.endIndex);
// Нормализуем индексы к диапазону [0, 1] для родительского компонента
const normalizedStart = startIndex / (data.length - 1);
const normalizedEnd = endIndex / (data.length - 1);
if (startIndex >= 0 && endIndex >= 0) {
onRangeSelect({ onRangeSelect({
startIndex: Math.min(startIndex, endIndex), startIndex: normalizedStart,
endIndex: Math.max(startIndex, endIndex) endIndex: normalizedEnd
}); });
}
setIsSelecting(false);
setSelectionArea(null); setSelectionArea(null);
}; };
const CustomTooltip = ({ active, payload, label }) => { const CustomTooltip = ({ active, payload, label }) => {
if (active && payload && payload.length) { if (active && payload && payload.length) {
const currentPoint = data.find(point => point.timestamp === label);
return ( return (
<div style={{ <div style={{
backgroundColor: '#fff', backgroundColor: '#fff',
@ -86,7 +139,9 @@ const LineChartComponent = ({
borderRadius: '4px', borderRadius: '4px',
boxShadow: '0 2px 5px rgba(0,0,0,0.1)' boxShadow: '0 2px 5px rgba(0,0,0,0.1)'
}}> }}>
<p style={{ fontWeight: 'bold', marginBottom: '5px' }}>{`${label}`}</p> <p style={{ fontWeight: 'bold', marginBottom: '5px' }}>
{currentPoint?.fullTime || new Date(label).toLocaleString('ru-RU')}
</p>
{payload.map((item, index) => ( {payload.map((item, index) => (
<p key={index} style={{ color: item.color }}> <p key={index} style={{ color: item.color }}>
{`Значение: ${item.value}`} {`Значение: ${item.value}`}
@ -103,20 +158,7 @@ const LineChartComponent = ({
} }
return ( return (
<div <div style={{ position: 'relative', height: '400px' }}>
style={{ position: 'relative', height: '400px' }}
ref={containerRef}
className={isSelecting ? 'no-selection' : ''}
>
<style>
{`
.no-selection {
user-select: none;
-webkit-user-select: none;
}
`}
</style>
<ResponsiveContainer width="100%" height="100%"> <ResponsiveContainer width="100%" height="100%">
<LineChart <LineChart
data={displayData} data={displayData}
@ -128,16 +170,44 @@ const LineChartComponent = ({
> >
<CartesianGrid strokeDasharray="3 3" stroke="#f0f0f0" /> <CartesianGrid strokeDasharray="3 3" stroke="#f0f0f0" />
<XAxis <XAxis
dataKey="time" dataKey="timestamp"
tick={{ fontSize: 12 }} height={75}
tick={{ fontSize: 12, angle: -45, textAnchor: 'end' }}
interval={Math.max(1, Math.floor(data.length / 10))}
tickFormatter={(timestamp) => {
const date = new Date(timestamp);
const format = getTimeFormat();
if (format === 'dd.MM HH:mm') {
return date.toLocaleString('ru-RU', {
day: '2-digit',
month: '2-digit',
hour: '2-digit',
minute: '2-digit'
});
} else if (format === 'HH:mm') {
return date.toLocaleString('ru-RU', {
hour: '2-digit',
minute: '2-digit'
});
} else {
return date.toLocaleString('ru-RU', {
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
}
}}
/> />
<YAxis tick={{ fontSize: 12 }} /> <YAxis tick={{ fontSize: 12 }} />
<Tooltip content={<CustomTooltip />} /> <Tooltip content={<CustomTooltip />} />
{Object.keys(chartData).map((instance, index) => ( {instanceKeys.map((instance, index) => (
<Line <Line
key={instance} key={instance}
type="monotone" type="monotone"
dataKey={instance} dataKey={instance}
name={instance}
stroke={colors[index % colors.length]} stroke={colors[index % colors.length]}
strokeWidth={2} strokeWidth={2}
dot={false} dot={false}

View File

@ -17,39 +17,57 @@ const PrometheusChart = ({ metricName }) => {
const [selectedGraphRange, setSelectedGraphRange] = useState(null); const [selectedGraphRange, setSelectedGraphRange] = useState(null);
const [filteredData, setFilteredData] = useState(null); const [filteredData, setFilteredData] = useState(null);
const [isSelectingRange, setIsSelectingRange] = useState(false); const [isSelectingRange, setIsSelectingRange] = useState(false);
const [lastCustomRange, setLastCustomRange] = useState(null);
const intervalRef = useRef(null); const intervalRef = useRef(null);
const socketRef = useRef(null); const socketRef = useRef(null);
const debounceRef = useRef(null);
const formatTime = useCallback((timestamp, rangeSeconds) => { const formatTime = useCallback((timestamp, rangeSeconds) => {
const date = new Date(timestamp); const ts = typeof timestamp === 'number' ? timestamp : Date.now();
if (rangeSeconds > 86400) { const date = new Date(ts);
return {
display: date.toLocaleString([], { // Определяем формат в зависимости от диапазона
day: '2-digit', const showFullDate = rangeSeconds > 86400; // больше суток
month: '2-digit',
year: '2-digit', const timeOptions = {
hour: '2-digit',
minute: '2-digit'
}),
timestamp: timestamp
};
}
return {
display: date.toLocaleTimeString([], {
hour: '2-digit', hour: '2-digit',
minute: '2-digit', minute: '2-digit',
second: '2-digit' second: '2-digit',
hour12: false
};
const dateOptions = showFullDate ? {
month: '2-digit',
day: '2-digit',
...timeOptions
} : timeOptions;
return {
display: date.toLocaleString('ru-RU', dateOptions),
fullDisplay: date.toLocaleString('ru-RU', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false
}), }),
timestamp: timestamp timestamp: ts
}; };
}, []); }, []);
const calculateStep = useCallback((start, end) => { const calculateStep = useCallback((start, end) => {
const range = end - start; const range = end - start;
if (range <= 3600) return 5; if (range <= 60) return 1; // 1 мин
if (range <= 21600) return 30; if (range <= 300) return 5; // 5 мин
if (range <= 86400) return 120; if (range <= 1800) return 15; // 30 мин
return 300; if (range <= 3600) return 30; // 1 час
if (range <= 10800) return 60; // 3 часа
if (range <= 21600) return 120; // 6 часов
if (range <= 43200) return 300; // 12 часов
if (range <= 86400) return 600; // 24 часа
return 1800; // > 24 часов
}, []); }, []);
const fetchData = useCallback(() => { const fetchData = useCallback(() => {
@ -72,26 +90,8 @@ const PrometheusChart = ({ metricName }) => {
} }
}, [metricName, selectedRange.value, isSelectingRange]); }, [metricName, selectedRange.value, isSelectingRange]);
const groupBySecond = (points) => {
const grouped = [];
const timeMap = {};
points.forEach(point => {
const timeKey = Math.floor(point.timestamp / 1000);
if (!timeMap[timeKey]) {
timeMap[timeKey] = { ...point, count: 1 };
grouped.push(timeMap[timeKey]);
} else {
timeMap[timeKey].value = (timeMap[timeKey].value * timeMap[timeKey].count + point.value) /
(timeMap[timeKey].count + 1);
timeMap[timeKey].count += 1;
}
});
return grouped;
};
const processMetricsData = useCallback((response) => { const processMetricsData = useCallback((response) => {
console.log('Processing metrics data:', response);
if (response.metric !== metricName) return; if (response.metric !== metricName) return;
const dataArray = Array.isArray(response.data) ? response.data : [response.data]; const dataArray = Array.isArray(response.data) ? response.data : [response.data];
@ -99,32 +99,43 @@ const PrometheusChart = ({ metricName }) => {
setChartData(prev => { setChartData(prev => {
const newData = { ...(prev || {}) }; const newData = { ...(prev || {}) };
const rangeSeconds = useCustomRange
? (endDate.getTime() - startDate.getTime()) / 1000
: selectedRange.value;
dataArray.forEach(item => { dataArray.forEach(item => {
const instance = item.instance || 'default'; const instance = item.instance || 'default';
if (!newData[instance]) newData[instance] = []; if (!newData[instance]) newData[instance] = [];
const timestamp = item.timestamp > 1e12 ? item.timestamp : item.timestamp * 1000; // Унифицированная конвертация timestamp
const value = parseFloat(item.value); let timestamp;
if (typeof item.timestamp === 'number') {
// Определяем, в секундах или миллисекундах пришел timestamp
timestamp = item.timestamp > 1e12 ? item.timestamp : item.timestamp * 1000;
} else {
timestamp = Date.now();
}
const value = parseFloat(item.value);
const formattedTime = formatTime(timestamp, rangeSeconds);
if (!newData[instance].some(p => p.timestamp === timestamp)) {
newData[instance].push({ newData[instance].push({
time: formatTime(timestamp, selectedRange.value).display, time: formattedTime.display,
fullTime: formattedTime.fullDisplay,
value: value, value: value,
timestamp: timestamp timestamp: timestamp
}); });
}
}); });
// Сортируем и ограничиваем данные
Object.keys(newData).forEach(instance => { Object.keys(newData).forEach(instance => {
newData[instance] = groupBySecond(newData[instance]) newData[instance] = newData[instance]
.sort((a, b) => a.timestamp - b.timestamp) .sort((a, b) => a.timestamp - b.timestamp)
.slice(-1000); .slice(-1000);
}); });
return newData;
return Object.keys(newData).length ? newData : prev;
}); });
}, [metricName, selectedRange.value, formatTime]); }, [metricName, selectedRange.value, formatTime, useCustomRange, startDate, endDate]);
const setupWebSocket = useCallback(() => { const setupWebSocket = useCallback(() => {
if (socketRef.current) { if (socketRef.current) {
@ -178,7 +189,7 @@ const PrometheusChart = ({ metricName }) => {
const fetchCustomRangeData = useCallback(async () => { const fetchCustomRangeData = useCallback(async () => {
const start = Math.floor(startDate.getTime() / 1000); const start = Math.floor(startDate.getTime() / 1000);
const end = Math.floor(endDate.getTime() / 1000); const end = Math.floor(endDate.getTime() / 1000);
const step = calculateStep(start, end); const rangeSeconds = end - start;
try { try {
const response = await axios.get(`${import.meta.env.VITE_BACK_URL}/metrics`, { const response = await axios.get(`${import.meta.env.VITE_BACK_URL}/metrics`, {
@ -186,18 +197,21 @@ const PrometheusChart = ({ metricName }) => {
metric: metricName, metric: metricName,
start, start,
end, end,
step step: calculateStep(start, end)
} }
}); });
if (response.data) { // Изменили условие, так как бэкенд возвращает массив напрямую if (response.data?.length) {
// Преобразуем данные перед передачей в processMetricsData
const processedData = response.data.map(item => ({
...item,
timestamp: item.timestamp, // оставляем в секундах - processMetricsData конвертирует
value: item.value.toString()
}));
processMetricsData({ processMetricsData({
metric: metricName, metric: metricName,
data: response.data.map(item => ({ data: processedData
...item,
timestamp: item.timestamp / 1000, // или item.timestamp если уже в секундах
value: item.value.toString() // преобразуем в строку, как ожидает processMetricsData
}))
}); });
} }
} catch (error) { } catch (error) {
@ -207,6 +221,12 @@ const PrometheusChart = ({ metricName }) => {
const handleRangeChange = useCallback((event) => { const handleRangeChange = useCallback((event) => {
// Очищаем текущий интервал
if (intervalRef.current) {
clearInterval(intervalRef.current);
intervalRef.current = null;
}
const selectedValue = event.target.value; const selectedValue = event.target.value;
const range = TIME_RANGES.find(r => r.value === parseInt(selectedValue, 10)); const range = TIME_RANGES.find(r => r.value === parseInt(selectedValue, 10));
@ -220,50 +240,131 @@ const PrometheusChart = ({ metricName }) => {
setEndDate(now); setEndDate(now);
setStartDate(new Date(now.getTime() - range.value * 1000)); setStartDate(new Date(now.getTime() - range.value * 1000));
// Переподключение сокета при возврате к стандартным диапазонам // Переподключение сокета
if (!socketRef.current?.connected) { if (!socketRef.current?.connected) {
socketRef.current?.connect(); socketRef.current?.connect();
} }
}, []); }, []);
const handleCustomRangeChange = useCallback(() => { const handleCustomRangeChange = useCallback(() => {
// Отключаем WebSocket соединение
if (socketRef.current?.connected) {
socketRef.current.disconnect();
setConnectionStatus('disconnected');
}
// Очищаем интервал обновления
if (intervalRef.current) {
clearInterval(intervalRef.current);
intervalRef.current = null;
}
setUseCustomRange(true); setUseCustomRange(true);
setChartData(null); setChartData(null);
setSelectedGraphRange(null); setSelectedGraphRange(null);
setFilteredData(null); setFilteredData(null);
}, []); fetchCustomRangeData();
}, [fetchCustomRangeData]);
const handleResetZoom = useCallback(() => { const handleResetZoom = useCallback(() => {
setSelectedGraphRange(null); setSelectedGraphRange(null);
setFilteredData(null); setFilteredData(null);
setIsSelectingRange(false); setIsSelectingRange(false);
if (useCustomRange) {
fetchCustomRangeData();
} else {
if (!socketRef.current?.connected) {
socketRef.current?.connect();
}
fetchData(); fetchData();
}, [fetchData]); }
if (lastCustomRange) {
handleRangeSelect(lastCustomRange);
return;
}
}, [fetchData, fetchCustomRangeData, useCustomRange]);
const interpolateData = useCallback((data, targetPointCount) => {
if (!data || data.length < 2) return data;
if (data.length >= targetPointCount) return data;
const interpolated = [];
const step = (data.length - 1) / (targetPointCount - 1);
for (let i = 0; i < targetPointCount; i++) {
const index = i * step;
const lowerIndex = Math.floor(index);
const upperIndex = Math.ceil(index);
if (lowerIndex === upperIndex) {
interpolated.push(data[lowerIndex]);
continue;
}
const fraction = index - lowerIndex;
const interpolatedPoint = {};
Object.keys(data[lowerIndex]).forEach(key => {
if (key === 'timestamp') {
interpolatedPoint[key] = data[lowerIndex][key] +
fraction * (data[upperIndex][key] - data[lowerIndex][key]);
// Добавляем отображаемое время
const { display, fullDisplay } = formatTime(interpolatedPoint[key],
(endDate - startDate) / 1000);
interpolatedPoint.time = display;
interpolatedPoint.fullTime = fullDisplay;
} else if (typeof data[lowerIndex][key] === 'number') {
interpolatedPoint[key] = data[lowerIndex][key] +
fraction * (data[upperIndex][key] - data[lowerIndex][key]);
} else {
interpolatedPoint[key] = data[lowerIndex][key];
}
});
interpolated.push(interpolatedPoint);
}
return interpolated;
}, []);
const handleRangeSelect = useCallback((range) => { const handleRangeSelect = useCallback((range) => {
if (range) { setLastCustomRange(range);
// Начало выделения - останавливаем обновления if (!range || !chartData) return;
setIsSelectingRange(true); setIsSelectingRange(true);
setSelectedGraphRange(range); setSelectedGraphRange(range);
// Отключаем сокет // Отключаем автоматические обновления
if (socketRef.current?.connected) { if (socketRef.current?.connected) {
socketRef.current.disconnect(); socketRef.current.disconnect();
} }
// Очищаем интервал
if (intervalRef.current) { if (intervalRef.current) {
clearInterval(intervalRef.current); clearInterval(intervalRef.current);
intervalRef.current = null; intervalRef.current = null;
} }
} else {
// Окончание выделения - возобновляем соединение
setIsSelectingRange(false);
if (!useCustomRange && socketRef.current && !socketRef.current.connected) { // Получаем все точки и сортируем по времени
socketRef.current.connect(); const allPoints = Object.values(chartData).flat();
} const sortedPoints = allPoints.sort((a, b) => a.timestamp - b.timestamp);
}
}, [useCustomRange]); // Вычисляем абсолютные индексы
const startIndex = Math.floor(range.startIndex * (sortedPoints.length - 1));
const endIndex = Math.floor(range.endIndex * (sortedPoints.length - 1));
// Фильтруем точки по выбранному диапазону
const filtered = sortedPoints.slice(startIndex, endIndex + 1);
// Применяем интерполяцию только если точек меньше 100
const interpolated = filtered.length < 100 ?
interpolateData(filtered, Math.min(100, filtered.length * 3)) :
filtered;
setFilteredData(interpolated);
setIsSelectingRange(false);
}, [chartData, interpolateData, formatTime]);
useEffect(() => { useEffect(() => {
const socket = setupWebSocket(); const socket = setupWebSocket();
@ -273,16 +374,29 @@ const PrometheusChart = ({ metricName }) => {
}; };
}, [setupWebSocket]); }, [setupWebSocket]);
// Обновим useEffect для кастомного диапазона
useEffect(() => { useEffect(() => {
if (useCustomRange) { if (useCustomRange && !isSelectingRange) {
if (socketRef.current?.connected) { // Очищаем предыдущий таймер
socketRef.current.disconnect(); if (debounceRef.current) {
} clearTimeout(debounceRef.current);
fetchCustomRangeData();
return;
} }
if (!socketRef.current?.connected || isSelectingRange) return; // Устанавливаем новый таймер с задержкой 500 мс
debounceRef.current = setTimeout(() => {
fetchCustomRangeData();
}, 500);
}
return () => {
if (debounceRef.current) {
clearTimeout(debounceRef.current);
}
};
}, [useCustomRange, isSelectingRange, startDate, endDate, fetchCustomRangeData]);
useEffect(() => {
if (useCustomRange || isSelectingRange) return;
const fetchDataWrapper = () => { const fetchDataWrapper = () => {
try { try {
@ -292,45 +406,41 @@ const PrometheusChart = ({ metricName }) => {
} }
}; };
// Очищаем предыдущий интервал
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
// Запускаем сразу и затем по интервалу
fetchDataWrapper(); fetchDataWrapper();
intervalRef.current = setInterval(fetchDataWrapper, selectedRange.interval); intervalRef.current = setInterval(fetchDataWrapper, selectedRange.interval);
return () => { return () => {
if (intervalRef.current) { if (intervalRef.current) {
clearInterval(intervalRef.current); clearInterval(intervalRef.current);
intervalRef.current = null;
} }
}; };
}, [fetchData, fetchCustomRangeData, selectedRange.interval, useCustomRange, isSelectingRange]); }, [fetchData, selectedRange.interval, useCustomRange, isSelectingRange]);
useEffect(() => { useEffect(() => {
if (!chartData || !selectedGraphRange) { if (!selectedGraphRange || !chartData) {
setFilteredData(null); setFilteredData(null);
return; return;
} }
const { startIndex, endIndex } = selectedGraphRange; const allPoints = Object.values(chartData).flat();
const allTimes = Object.values(chartData) const sortedPoints = allPoints.sort((a, b) => a.timestamp - b.timestamp);
.flat()
.map(point => point.time)
.filter((time, index, self) => self.indexOf(time) === index);
const data = allTimes.map(time => { const startIndex = Math.floor(selectedGraphRange.startIndex * (sortedPoints.length - 1));
const point = { time }; const endIndex = Math.floor(selectedGraphRange.endIndex * (sortedPoints.length - 1));
Object.keys(chartData).forEach(key => {
const instanceData = chartData[key].find(p => p.time === time);
point[key] = instanceData ? instanceData.value : null;
});
return point;
}).sort((a, b) => {
const timeA = chartData[Object.keys(chartData)[0]].find(d => d.time === a.time)?.timestamp;
const timeB = chartData[Object.keys(chartData)[0]].find(d => d.time === b.time)?.timestamp;
return timeA - timeB;
});
const filtered = data.slice(startIndex, endIndex + 1); const filtered = sortedPoints.slice(startIndex, endIndex + 1);
setFilteredData(filtered); const interpolated = filtered.length > 100 ?
}, [selectedGraphRange, chartData]); interpolateData(filtered, 100) :
filtered;
setFilteredData(interpolated);
}, [selectedGraphRange, chartData, interpolateData]);
if (chartData === null) { if (chartData === null) {
return <div style={{ padding: '20px', textAlign: 'center' }}>Loading data...</div>; return <div style={{ padding: '20px', textAlign: 'center' }}>Loading data...</div>;
@ -373,7 +483,7 @@ const PrometheusChart = ({ metricName }) => {
chartData={chartData} chartData={chartData}
metricName={metricName} metricName={metricName}
colors={COLORS} colors={COLORS}
onRangeSelect={handleRangeSelect} // Используем модифицированный обработчик onRangeSelect={handleRangeSelect}
filteredData={filteredData} filteredData={filteredData}
/> />
</div> </div>

View File

@ -7,8 +7,6 @@ const getMetricName = (id) => {
return `zvks_apiforsnmp_measure_${id}`; return `zvks_apiforsnmp_measure_${id}`;
}; };
//!!!!!!!!!!Пофиксить вкладуи с eth4, во всех eth 1-4 открывается именно 4 !!!!!!!!!!!!!
// Функция для рекурсивного сбора всех id потомков // Функция для рекурсивного сбора всех id потомков
const getAllChildIds = (node) => { const getAllChildIds = (node) => {
let ids = []; let ids = [];

View File

@ -1,6 +1,5 @@
import SystemStatusChart from "../../Charts/SystemStatusChart"; import SystemStatusChart from "../../Charts/SystemStatusChart";
import TreeTable from "../UI/TreeTable"; import TreeTable from "../UI/TreeTable";
import FlowChart from "../TreeChart/FlowChart"; import FlowChart from "../TreeChart/FlowChart";
const TabContent = ({ activeTab, statusHistories, treeData1, tabContent, handleOpenTab }) => { const TabContent = ({ activeTab, statusHistories, treeData1, tabContent, handleOpenTab }) => {