redesign of graphs and visualizations
test-org/trust-module-frontend/pipeline/pr-rc There was a failure building this commit Details

pull/27/head
DmitriyA 2025-03-26 05:16:52 -04:00
parent c077449b2c
commit fc1db66288
3 changed files with 35 additions and 76 deletions

View File

@ -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>

View File

@ -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;
}); });

View File

@ -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;
}