redesign of graphs and visualizations
test-org/trust-module-frontend/pipeline/pr-rc There was a failure building this commit
Details
test-org/trust-module-frontend/pipeline/pr-rc There was a failure building this commit
Details
parent
c077449b2c
commit
fc1db66288
|
|
@ -1,17 +1,15 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { LineChart, XAxis, YAxis, CartesianGrid, Tooltip, Legend, Line, ResponsiveContainer } from 'recharts';
|
import { LineChart, XAxis, YAxis, CartesianGrid, Tooltip, Line, ResponsiveContainer } from 'recharts';
|
||||||
|
|
||||||
const LineChartComponent = ({ chartData, metricName, colors, description, onRangeSelect, filteredData }) => {
|
const LineChartComponent = ({ chartData, metricName, colors, description, onRangeSelect, filteredData }) => {
|
||||||
const [selectionStart, setSelectionStart] = useState(null);
|
const [selectionStart, setSelectionStart] = useState(null);
|
||||||
const [selectionEnd, setSelectionEnd] = useState(null);
|
const [selectionEnd, setSelectionEnd] = useState(null);
|
||||||
|
|
||||||
// Создаем массив уникальных временных меток
|
|
||||||
const allTimes = Object.values(chartData)
|
const allTimes = Object.values(chartData)
|
||||||
.flat()
|
.flat()
|
||||||
.map(point => point.time)
|
.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 => {
|
const data = allTimes.map(time => {
|
||||||
const point = { time };
|
const point = { time };
|
||||||
Object.keys(chartData).forEach(key => {
|
Object.keys(chartData).forEach(key => {
|
||||||
|
|
@ -21,10 +19,8 @@ const LineChartComponent = ({ chartData, metricName, colors, description, onRang
|
||||||
return point;
|
return point;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Используем отфильтрованные данные, если они есть
|
|
||||||
const displayData = filteredData || data;
|
const displayData = filteredData || data;
|
||||||
|
|
||||||
// Обработчик клика на графике
|
|
||||||
const handleClick = (e) => {
|
const handleClick = (e) => {
|
||||||
if (!e || !e.activeLabel) return;
|
if (!e || !e.activeLabel) return;
|
||||||
|
|
||||||
|
|
@ -45,40 +41,57 @@ const LineChartComponent = ({ chartData, metricName, colors, description, onRang
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Кастомный Tooltip для отображения значения
|
// Упрощенный Tooltip без указания instance
|
||||||
const CustomTooltip = ({ active, payload, label }) => {
|
const CustomTooltip = ({ active, payload, label }) => {
|
||||||
if (active && payload && payload.length) {
|
if (active && payload && payload.length) {
|
||||||
return (
|
return (
|
||||||
<div className="custom-tooltip" style={{ padding: '10px' }}>
|
<div className="custom-tooltip" style={{
|
||||||
<p>{`Время: ${label}`}</p>
|
backgroundColor: '#fff',
|
||||||
{payload.map((entry, index) => (
|
padding: '10px',
|
||||||
<p key={index} style={{}}>
|
border: '1px solid #ccc',
|
||||||
{`Значение: ${entry.value}`}
|
borderRadius: '4px'
|
||||||
</p>
|
}}>
|
||||||
))}
|
<p style={{ fontWeight: 'bold', marginBottom: '5px' }}>{`Время: ${label}`}</p>
|
||||||
|
<p>{`Значение: ${payload[0].value}`}</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<ResponsiveContainer width="100%" height={400}>
|
<ResponsiveContainer width="100%" height={400}>
|
||||||
<LineChart data={displayData} onClick={handleClick}>
|
<LineChart
|
||||||
<CartesianGrid strokeDasharray="3 3" />
|
data={displayData}
|
||||||
<XAxis dataKey="time" />
|
onClick={handleClick}
|
||||||
<YAxis />
|
margin={{ top: 5, right: 30, left: 20, bottom: 5 }}
|
||||||
<Tooltip content={<CustomTooltip />} />
|
>
|
||||||
<Legend />
|
<CartesianGrid strokeDasharray="3 3" stroke="#f0f0f0" />
|
||||||
|
<XAxis
|
||||||
|
dataKey="time"
|
||||||
|
tick={{ fill: '#666' }}
|
||||||
|
tickMargin={10}
|
||||||
|
/>
|
||||||
|
<YAxis
|
||||||
|
tick={{ fill: '#666' }}
|
||||||
|
tickMargin={10}
|
||||||
|
/>
|
||||||
|
<Tooltip
|
||||||
|
content={<CustomTooltip />}
|
||||||
|
cursor={{ stroke: '#ccc', strokeWidth: 1 }}
|
||||||
|
/>
|
||||||
|
{/* Убрали <Legend /> чтобы скрыть имена instance */}
|
||||||
{Object.keys(chartData).map((key, index) => (
|
{Object.keys(chartData).map((key, index) => (
|
||||||
<Line
|
<Line
|
||||||
key={key}
|
key={key}
|
||||||
type="monotone"
|
type="monotone"
|
||||||
dataKey={key}
|
dataKey={key}
|
||||||
stroke={colors[index % colors.length]}
|
stroke={colors[index % colors.length]}
|
||||||
name={key}
|
strokeWidth={2}
|
||||||
|
dot={false}
|
||||||
|
activeDot={{ r: 6 }}
|
||||||
|
// Убрали name чтобы не отображалось в tooltip
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</LineChart>
|
</LineChart>
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,7 @@ const PrometheusChart = ({ metricName }) => {
|
||||||
? date.toLocaleString([], { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' })
|
? 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' });
|
: date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });
|
||||||
|
|
||||||
const key = `${m.instance}-${m.device || m.scrape_job}`;
|
const key = m.instance;
|
||||||
if (!updatedData[key]) updatedData[key] = {};
|
if (!updatedData[key]) updatedData[key] = {};
|
||||||
updatedData[key][formattedTime] = m.value;
|
updatedData[key][formattedTime] = m.value;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
.range-selector {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 10px;
|
|
||||||
padding: 15px;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
border-radius: 8px;
|
|
||||||
background-color: #f9f9f9;
|
|
||||||
max-width: 500px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.range-selector label {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.range-selector select,
|
|
||||||
.range-selector button {
|
|
||||||
padding: 8px;
|
|
||||||
border: 1px solid #aaa;
|
|
||||||
border-radius: 5px;
|
|
||||||
background-color: white;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-range {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 10px;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-range div {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.date-picker {
|
|
||||||
width: 180px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.apply-button {
|
|
||||||
background-color: #007bff;
|
|
||||||
color: white;
|
|
||||||
padding: 8px 12px;
|
|
||||||
border: none;
|
|
||||||
border-radius: 5px;
|
|
||||||
cursor: pointer;
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.apply-button:hover {
|
|
||||||
background-color: #0056b3;
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue