@centreon/ui 24.4.63 → 24.4.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/Graph/LineChart/Header/index.tsx +3 -31
- package/src/Graph/LineChart/InteractiveComponents/AnchorPoint/useTickGraph.ts +9 -11
- package/src/Graph/LineChart/InteractiveComponents/GraphValueTooltip/GraphValueTooltip.tsx +68 -0
- package/src/Graph/LineChart/InteractiveComponents/GraphValueTooltip/useGraphValueTooltip.ts +27 -0
- package/src/Graph/LineChart/InteractiveComponents/GraphValueTooltip/useGraphValueTooltipStyles.ts +31 -0
- package/src/Graph/LineChart/InteractiveComponents/index.tsx +132 -16
- package/src/Graph/LineChart/InteractiveComponents/interactionWithGraphAtoms.ts +7 -27
- package/src/Graph/LineChart/Legend/LegendHeader.tsx +8 -5
- package/src/Graph/LineChart/Legend/index.tsx +10 -47
- package/src/Graph/LineChart/LineChart.cypress.spec.tsx +91 -0
- package/src/Graph/LineChart/LineChart.styles.ts +8 -0
- package/src/Graph/LineChart/LineChart.tsx +107 -109
- package/src/Graph/LineChart/mockedData/lastDayWithIncompleteValues.json +1320 -0
- package/src/Graph/LineChart/mockedData/lastDayWithNullValues.json +1314 -0
- package/src/Graph/LineChart/models.ts +12 -0
- package/src/Graph/common/timeSeries/index.ts +31 -1
- package/src/Graph/LineChart/InteractiveComponents/AnchorPoint/TooltipAnchorPoint.tsx +0 -96
- package/src/Graph/LineChart/InteractiveComponents/AnchorPoint/useTooltipAnchorPoint.ts +0 -107
- package/src/Graph/LineChart/Legend/InteractiveValue.tsx +0 -22
- package/src/Graph/LineChart/Legend/useInteractiveValues.ts +0 -99
package/package.json
CHANGED
|
@@ -1,41 +1,17 @@
|
|
|
1
|
-
import { ScaleLinear } from 'd3-scale';
|
|
2
|
-
import { isNil } from 'ramda';
|
|
3
|
-
|
|
4
1
|
import Typography from '@mui/material/Typography';
|
|
5
2
|
|
|
6
|
-
import {
|
|
3
|
+
import { useMemoComponent } from '@centreon/ui';
|
|
7
4
|
|
|
8
5
|
import { useStyles } from '../LineChart.styles';
|
|
9
|
-
import useTickGraph from '../InteractiveComponents/AnchorPoint/useTickGraph';
|
|
10
6
|
import { LineChartHeader } from '../models';
|
|
11
|
-
import { TimeValue } from '../../common/timeSeries/models';
|
|
12
7
|
|
|
13
8
|
interface Props {
|
|
14
|
-
displayTimeTick?: boolean;
|
|
15
9
|
header?: LineChartHeader;
|
|
16
|
-
timeSeries: Array<TimeValue>;
|
|
17
10
|
title: string;
|
|
18
|
-
xScale: ScaleLinear<number, number>;
|
|
19
11
|
}
|
|
20
12
|
|
|
21
|
-
const Header = ({
|
|
22
|
-
title,
|
|
23
|
-
displayTimeTick = true,
|
|
24
|
-
header,
|
|
25
|
-
timeSeries,
|
|
26
|
-
xScale
|
|
27
|
-
}: Props): JSX.Element => {
|
|
13
|
+
const Header = ({ title, header }: Props): JSX.Element => {
|
|
28
14
|
const { classes } = useStyles();
|
|
29
|
-
const { toDateTime } = useLocaleDateTimeFormat();
|
|
30
|
-
|
|
31
|
-
const { tickAxisBottom } = useTickGraph({
|
|
32
|
-
timeSeries,
|
|
33
|
-
xScale
|
|
34
|
-
});
|
|
35
|
-
const time =
|
|
36
|
-
displayTimeTick && !isNil(tickAxisBottom)
|
|
37
|
-
? toDateTime(tickAxisBottom)
|
|
38
|
-
: null;
|
|
39
15
|
|
|
40
16
|
const displayTitle = header?.displayTitle ?? true;
|
|
41
17
|
|
|
@@ -49,16 +25,12 @@ const Header = ({
|
|
|
49
25
|
{title}
|
|
50
26
|
</Typography>
|
|
51
27
|
)}
|
|
52
|
-
|
|
53
|
-
<Typography align="center" style={{ height: 20 }} variant="body1">
|
|
54
|
-
{time}
|
|
55
|
-
</Typography>
|
|
56
28
|
</div>
|
|
57
29
|
{header?.extraComponent}
|
|
58
30
|
</div>
|
|
59
31
|
),
|
|
60
32
|
|
|
61
|
-
memoProps: [
|
|
33
|
+
memoProps: [title, header]
|
|
62
34
|
});
|
|
63
35
|
};
|
|
64
36
|
|
|
@@ -2,13 +2,12 @@ import { useEffect, useState } from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { ScaleLinear } from 'd3-scale';
|
|
4
4
|
import { useAtomValue } from 'jotai';
|
|
5
|
-
import { isEmpty, isNil, not } from 'ramda';
|
|
6
5
|
|
|
7
6
|
import useAxisY from '../../BasicComponents/Axes/useAxisY';
|
|
8
7
|
import { margin } from '../../common';
|
|
9
|
-
import {
|
|
8
|
+
import { getTimeValue } from '../../../common/timeSeries';
|
|
10
9
|
import { Line, TimeValue } from '../../../common/timeSeries/models';
|
|
11
|
-
import { mousePositionAtom
|
|
10
|
+
import { mousePositionAtom } from '../interactionWithGraphAtoms';
|
|
12
11
|
|
|
13
12
|
interface AnchorPointResult {
|
|
14
13
|
positionX?: number;
|
|
@@ -42,14 +41,13 @@ const useTickGraph = ({
|
|
|
42
41
|
const { axisRight, axisLeft } = useAxisY({ data: { baseAxis, lines } });
|
|
43
42
|
|
|
44
43
|
const mousePosition = useAtomValue(mousePositionAtom);
|
|
45
|
-
const timeValueData = useAtomValue(timeValueAtom);
|
|
46
44
|
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
45
|
+
const positionX = mousePosition
|
|
46
|
+
? mousePosition[0] - margin.left - 4
|
|
47
|
+
: undefined;
|
|
48
|
+
const positionY = mousePosition
|
|
49
|
+
? mousePosition[1] - margin.top + 2
|
|
50
|
+
: undefined;
|
|
53
51
|
|
|
54
52
|
useEffect(() => {
|
|
55
53
|
if (!mousePosition) {
|
|
@@ -62,7 +60,7 @@ const useTickGraph = ({
|
|
|
62
60
|
const mousePositionTimeTick = mousePosition
|
|
63
61
|
? getTimeValue({ timeSeries, x: mousePosition[0], xScale }).timeTick
|
|
64
62
|
: 0;
|
|
65
|
-
const timeTickValue =
|
|
63
|
+
const timeTickValue = mousePosition
|
|
66
64
|
? new Date(mousePositionTimeTick)
|
|
67
65
|
: null;
|
|
68
66
|
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { useAtomValue } from 'jotai';
|
|
2
|
+
import { equals, isNil } from 'ramda';
|
|
3
|
+
|
|
4
|
+
import { Box, Typography } from '@mui/material';
|
|
5
|
+
|
|
6
|
+
import { mousePositionAtom } from '../interactionWithGraphAtoms';
|
|
7
|
+
import { formatMetricValueWithUnit } from '../../../common/timeSeries';
|
|
8
|
+
|
|
9
|
+
import { useGraphValueTooltip } from './useGraphValueTooltip';
|
|
10
|
+
import { useGraphValueTooltipStyles } from './useGraphValueTooltipStyles';
|
|
11
|
+
|
|
12
|
+
interface Props {
|
|
13
|
+
base: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const GraphValueTooltip = ({ base }: Props): JSX.Element | null => {
|
|
17
|
+
const { classes } = useGraphValueTooltipStyles();
|
|
18
|
+
const mousePosition = useAtomValue(mousePositionAtom);
|
|
19
|
+
|
|
20
|
+
const graphValue = useGraphValueTooltip();
|
|
21
|
+
|
|
22
|
+
if (isNil(graphValue) || isNil(mousePosition)) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<div className={classes.tooltipContainer}>
|
|
28
|
+
<Typography fontWeight="bold">{graphValue.dateTime}</Typography>
|
|
29
|
+
<div className={classes.metrics}>
|
|
30
|
+
{graphValue.metrics.map(({ unit, color, id, value, name }) => {
|
|
31
|
+
const isMetricHighlighted = equals(
|
|
32
|
+
id,
|
|
33
|
+
graphValue.highlightedMetricId
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<div
|
|
38
|
+
className={classes.metric}
|
|
39
|
+
data-highlight={isMetricHighlighted}
|
|
40
|
+
data-metric={name}
|
|
41
|
+
key={id}
|
|
42
|
+
>
|
|
43
|
+
<Box
|
|
44
|
+
className={classes.metricColorBox}
|
|
45
|
+
sx={{ backgroundColor: color }}
|
|
46
|
+
/>
|
|
47
|
+
<Typography
|
|
48
|
+
className={classes.metricName}
|
|
49
|
+
fontWeight={isMetricHighlighted ? 'bold' : undefined}
|
|
50
|
+
>
|
|
51
|
+
{name}
|
|
52
|
+
</Typography>
|
|
53
|
+
<Typography fontWeight={isMetricHighlighted ? 'bold' : undefined}>
|
|
54
|
+
{formatMetricValueWithUnit({
|
|
55
|
+
base,
|
|
56
|
+
unit,
|
|
57
|
+
value
|
|
58
|
+
})}
|
|
59
|
+
</Typography>
|
|
60
|
+
</div>
|
|
61
|
+
);
|
|
62
|
+
})}
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export default GraphValueTooltip;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { useAtomValue } from 'jotai';
|
|
2
|
+
import { isNil } from 'ramda';
|
|
3
|
+
|
|
4
|
+
import { graphTooltipDataAtom } from '../interactionWithGraphAtoms';
|
|
5
|
+
import { useLocaleDateTimeFormat } from '../../../../utils';
|
|
6
|
+
import { GraphTooltipData } from '../../models';
|
|
7
|
+
|
|
8
|
+
interface UseGraphValueTooltipState extends Omit<GraphTooltipData, 'date'> {
|
|
9
|
+
dateTime: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const useGraphValueTooltip = (): UseGraphValueTooltipState | null => {
|
|
13
|
+
const { toDate, toTime } = useLocaleDateTimeFormat();
|
|
14
|
+
const graphTooltipData = useAtomValue(graphTooltipDataAtom);
|
|
15
|
+
|
|
16
|
+
if (isNil(graphTooltipData)) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const formattedDateTime = `${toDate(graphTooltipData.date)} / ${toTime(graphTooltipData.date)}`;
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
dateTime: formattedDateTime,
|
|
24
|
+
highlightedMetricId: graphTooltipData.highlightedMetricId,
|
|
25
|
+
metrics: graphTooltipData.metrics
|
|
26
|
+
};
|
|
27
|
+
};
|
package/src/Graph/LineChart/InteractiveComponents/GraphValueTooltip/useGraphValueTooltipStyles.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { makeStyles } from 'tss-react/mui';
|
|
2
|
+
|
|
3
|
+
export const useGraphValueTooltipStyles = makeStyles()((theme) => ({
|
|
4
|
+
dateTimeLabel: {
|
|
5
|
+
fontSize: '1.1rem'
|
|
6
|
+
},
|
|
7
|
+
metric: {
|
|
8
|
+
alignItems: 'center',
|
|
9
|
+
display: 'flex',
|
|
10
|
+
gap: theme.spacing(1),
|
|
11
|
+
weidth: '100%'
|
|
12
|
+
},
|
|
13
|
+
metricColorBox: {
|
|
14
|
+
borderRadius: theme.shape.borderRadius,
|
|
15
|
+
flexShrink: 0,
|
|
16
|
+
height: theme.spacing(1.5),
|
|
17
|
+
width: theme.spacing(1.5)
|
|
18
|
+
},
|
|
19
|
+
metricName: {
|
|
20
|
+
flexGrow: 1
|
|
21
|
+
},
|
|
22
|
+
metrics: {
|
|
23
|
+
display: 'flex',
|
|
24
|
+
flexDirection: 'column',
|
|
25
|
+
marginTop: theme.spacing(0.5),
|
|
26
|
+
width: '100%'
|
|
27
|
+
},
|
|
28
|
+
tooltipContainer: {
|
|
29
|
+
padding: theme.spacing(1)
|
|
30
|
+
}
|
|
31
|
+
}));
|
|
@@ -3,7 +3,21 @@ import { MutableRefObject } from 'react';
|
|
|
3
3
|
import { Event } from '@visx/visx';
|
|
4
4
|
import { ScaleTime } from 'd3-scale';
|
|
5
5
|
import { useSetAtom } from 'jotai';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
all,
|
|
8
|
+
equals,
|
|
9
|
+
find,
|
|
10
|
+
isEmpty,
|
|
11
|
+
isNil,
|
|
12
|
+
keys,
|
|
13
|
+
map,
|
|
14
|
+
pick,
|
|
15
|
+
pipe,
|
|
16
|
+
pluck,
|
|
17
|
+
reduce,
|
|
18
|
+
toPairs,
|
|
19
|
+
values
|
|
20
|
+
} from 'ramda';
|
|
7
21
|
import { makeStyles } from 'tss-react/mui';
|
|
8
22
|
|
|
9
23
|
import {
|
|
@@ -12,8 +26,16 @@ import {
|
|
|
12
26
|
InteractedZone,
|
|
13
27
|
InteractedZone as ZoomPreviewModel
|
|
14
28
|
} from '../models';
|
|
15
|
-
import {
|
|
16
|
-
|
|
29
|
+
import {
|
|
30
|
+
formatMetricName,
|
|
31
|
+
getLineForMetric,
|
|
32
|
+
getLinesForMetrics,
|
|
33
|
+
getTimeValue,
|
|
34
|
+
getUnits,
|
|
35
|
+
getYScale
|
|
36
|
+
} from '../../common/timeSeries';
|
|
37
|
+
import { Line, TimeValue } from '../../common/timeSeries/models';
|
|
38
|
+
import { margin } from '../common';
|
|
17
39
|
|
|
18
40
|
import Annotations from './Annotations';
|
|
19
41
|
import { TimelineEvent } from './Annotations/models';
|
|
@@ -22,10 +44,11 @@ import TimeShiftZones from './TimeShiftZones';
|
|
|
22
44
|
import ZoomPreview from './ZoomPreview';
|
|
23
45
|
import {
|
|
24
46
|
MousePosition,
|
|
25
|
-
|
|
47
|
+
changeMousePositionDerivedAtom,
|
|
26
48
|
eventMouseDownAtom,
|
|
27
49
|
eventMouseLeaveAtom,
|
|
28
|
-
eventMouseUpAtom
|
|
50
|
+
eventMouseUpAtom,
|
|
51
|
+
graphTooltipDataAtom
|
|
29
52
|
} from './interactionWithGraphAtoms';
|
|
30
53
|
|
|
31
54
|
const useStyles = makeStyles()(() => ({
|
|
@@ -38,6 +61,9 @@ interface CommonData {
|
|
|
38
61
|
graphHeight: number;
|
|
39
62
|
graphSvgRef: MutableRefObject<SVGSVGElement | null>;
|
|
40
63
|
graphWidth: number;
|
|
64
|
+
leftScale;
|
|
65
|
+
lines;
|
|
66
|
+
rightScale;
|
|
41
67
|
timeSeries: Array<TimeValue>;
|
|
42
68
|
xScale: ScaleTime<number, number>;
|
|
43
69
|
}
|
|
@@ -65,13 +91,19 @@ const InteractionWithGraph = ({
|
|
|
65
91
|
const setEventMouseDown = useSetAtom(eventMouseDownAtom);
|
|
66
92
|
const setEventMouseUp = useSetAtom(eventMouseUpAtom);
|
|
67
93
|
const setEventMouseLeave = useSetAtom(eventMouseLeaveAtom);
|
|
94
|
+
const changeMousePosition = useSetAtom(changeMousePositionDerivedAtom);
|
|
95
|
+
const setGraphTooltipData = useSetAtom(graphTooltipDataAtom);
|
|
68
96
|
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
97
|
+
const {
|
|
98
|
+
graphHeight,
|
|
99
|
+
graphWidth,
|
|
100
|
+
graphSvgRef,
|
|
101
|
+
xScale,
|
|
102
|
+
timeSeries,
|
|
103
|
+
leftScale,
|
|
104
|
+
rightScale,
|
|
105
|
+
lines
|
|
106
|
+
} = commonData;
|
|
75
107
|
|
|
76
108
|
const displayZoomPreview = zoomData?.enable ?? true;
|
|
77
109
|
|
|
@@ -83,6 +115,7 @@ const InteractionWithGraph = ({
|
|
|
83
115
|
setEventMouseLeave(event);
|
|
84
116
|
setEventMouseDown(null);
|
|
85
117
|
updateMousePosition(null);
|
|
118
|
+
setGraphTooltipData(null);
|
|
86
119
|
};
|
|
87
120
|
|
|
88
121
|
const mouseUp = (event): void => {
|
|
@@ -107,10 +140,10 @@ const InteractionWithGraph = ({
|
|
|
107
140
|
|
|
108
141
|
const updateMousePosition = (pointPosition: MousePosition): void => {
|
|
109
142
|
if (isNil(pointPosition)) {
|
|
110
|
-
|
|
111
|
-
position: null
|
|
112
|
-
timeValue: null
|
|
143
|
+
changeMousePosition({
|
|
144
|
+
position: null
|
|
113
145
|
});
|
|
146
|
+
setGraphTooltipData(null);
|
|
114
147
|
|
|
115
148
|
return;
|
|
116
149
|
}
|
|
@@ -120,7 +153,89 @@ const InteractionWithGraph = ({
|
|
|
120
153
|
xScale
|
|
121
154
|
});
|
|
122
155
|
|
|
123
|
-
|
|
156
|
+
if (isNil(timeValue)) {
|
|
157
|
+
changeMousePosition({
|
|
158
|
+
position: null
|
|
159
|
+
});
|
|
160
|
+
setGraphTooltipData(null);
|
|
161
|
+
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const date = timeValue.timeTick;
|
|
166
|
+
const displayedMetricIds = pluck('metric_id', lines);
|
|
167
|
+
const filteredMetricsValue = pick(displayedMetricIds, timeValue);
|
|
168
|
+
const [, secondUnit, thirdUnit] = getUnits(lines as Array<Line>);
|
|
169
|
+
const areAllValuesEmpty = pipe(values, all(isNil))(filteredMetricsValue);
|
|
170
|
+
|
|
171
|
+
const linesData = getLinesForMetrics({
|
|
172
|
+
lines,
|
|
173
|
+
metricIds: keys(filteredMetricsValue).map(Number)
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
if (areAllValuesEmpty) {
|
|
177
|
+
changeMousePosition({ position: pointPosition });
|
|
178
|
+
setGraphTooltipData(null);
|
|
179
|
+
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const distanceWithPointPositionPerMetric = reduce(
|
|
184
|
+
(acc, [metricId, value]) => {
|
|
185
|
+
if (isNil(value)) {
|
|
186
|
+
return acc;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const lineData = getLineForMetric({
|
|
190
|
+
lines,
|
|
191
|
+
metric_id: Number(metricId)
|
|
192
|
+
});
|
|
193
|
+
const yScale = getYScale({
|
|
194
|
+
hasMoreThanTwoUnits: Boolean(thirdUnit),
|
|
195
|
+
invert: (lineData as Line).invert,
|
|
196
|
+
leftScale,
|
|
197
|
+
rightScale,
|
|
198
|
+
secondUnit,
|
|
199
|
+
unit: (lineData as Line).unit
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
const y0 = yScale(value);
|
|
203
|
+
|
|
204
|
+
const diffBetweenY0AndPointPosition = Math.abs(
|
|
205
|
+
y0 + margin.top - pointPosition[1]
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
...acc,
|
|
210
|
+
[metricId]: diffBetweenY0AndPointPosition
|
|
211
|
+
};
|
|
212
|
+
},
|
|
213
|
+
{},
|
|
214
|
+
Object.entries(filteredMetricsValue)
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
const nearestY0 = Math.min(...values(distanceWithPointPositionPerMetric));
|
|
218
|
+
|
|
219
|
+
const nearestLine = pipe(
|
|
220
|
+
toPairs,
|
|
221
|
+
find(([, y0]) => equals(y0, nearestY0)) as () => [string, number]
|
|
222
|
+
)(distanceWithPointPositionPerMetric);
|
|
223
|
+
|
|
224
|
+
changeMousePosition({ position: pointPosition });
|
|
225
|
+
setGraphTooltipData({
|
|
226
|
+
date,
|
|
227
|
+
highlightedMetricId: Number(nearestLine[0]),
|
|
228
|
+
metrics: map(
|
|
229
|
+
({ metric_id, color, unit, legend, name }) => ({
|
|
230
|
+
color,
|
|
231
|
+
id: metric_id,
|
|
232
|
+
name: formatMetricName({ legend, name }),
|
|
233
|
+
unit,
|
|
234
|
+
value: timeValue?.[metric_id]
|
|
235
|
+
}),
|
|
236
|
+
linesData
|
|
237
|
+
).filter(({ value }) => value)
|
|
238
|
+
});
|
|
124
239
|
};
|
|
125
240
|
|
|
126
241
|
return (
|
|
@@ -151,8 +266,9 @@ const InteractionWithGraph = ({
|
|
|
151
266
|
)}
|
|
152
267
|
<Bar
|
|
153
268
|
className={classes.overlay}
|
|
269
|
+
data-testid="graph-interaction-zone"
|
|
154
270
|
fill="transparent"
|
|
155
|
-
height={graphHeight}
|
|
271
|
+
height={graphHeight - margin.bottom}
|
|
156
272
|
width={graphWidth}
|
|
157
273
|
x={0}
|
|
158
274
|
y={0}
|
|
@@ -1,52 +1,32 @@
|
|
|
1
1
|
import { atom } from 'jotai';
|
|
2
|
-
import {
|
|
2
|
+
import { isNil } from 'ramda';
|
|
3
3
|
|
|
4
4
|
import { TimeValue } from '../../common/timeSeries/models';
|
|
5
|
+
import { GraphTooltipData } from '../models';
|
|
5
6
|
|
|
6
7
|
export const eventMouseDownAtom = atom<null | MouseEvent>(null);
|
|
7
8
|
export const eventMouseUpAtom = atom<null | MouseEvent>(null);
|
|
8
9
|
export const eventMouseLeaveAtom = atom<null | MouseEvent>(null);
|
|
10
|
+
export const graphTooltipDataAtom = atom<GraphTooltipData | null>(null);
|
|
9
11
|
|
|
10
12
|
export const timeValueAtom = atom<TimeValue | null>(null);
|
|
11
13
|
export const mousePositionAtom = atom<MousePosition>(null);
|
|
12
14
|
export const isListingGraphOpenAtom = atom(false);
|
|
13
15
|
export type MousePosition = [number, number] | null;
|
|
14
16
|
|
|
15
|
-
interface
|
|
17
|
+
interface Position {
|
|
16
18
|
position: MousePosition;
|
|
17
|
-
timeValue: TimeValue | null;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
isInViewport?: boolean;
|
|
22
|
-
newTimeValue: TimeValue | null;
|
|
23
|
-
}
|
|
24
|
-
export const changeTimeValueDerivedAtom = atom(
|
|
25
|
-
null,
|
|
26
|
-
(
|
|
27
|
-
_,
|
|
28
|
-
set,
|
|
29
|
-
{ newTimeValue, isInViewport }: NewTimeValueInViewportState
|
|
30
|
-
): void => {
|
|
31
|
-
if (not(isInViewport)) {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
set(timeValueAtom, newTimeValue);
|
|
35
|
-
}
|
|
36
|
-
);
|
|
37
|
-
|
|
38
|
-
export const changeMousePositionAndTimeValueDerivedAtom = atom(
|
|
21
|
+
export const changeMousePositionDerivedAtom = atom(
|
|
39
22
|
null,
|
|
40
|
-
(_, set, { position
|
|
41
|
-
if (isNil(position)
|
|
23
|
+
(_, set, { position }: Position): void => {
|
|
24
|
+
if (isNil(position)) {
|
|
42
25
|
set(mousePositionAtom, null);
|
|
43
|
-
set(timeValueAtom, null);
|
|
44
26
|
|
|
45
27
|
return;
|
|
46
28
|
}
|
|
47
29
|
|
|
48
30
|
set(mousePositionAtom, position);
|
|
49
|
-
|
|
50
|
-
set(timeValueAtom, timeValue);
|
|
51
31
|
}
|
|
52
32
|
);
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isEmpty } from 'ramda';
|
|
2
2
|
|
|
3
3
|
import { Typography } from '@mui/material';
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
EllipsisTypography,
|
|
7
|
+
formatMetricName,
|
|
8
|
+
formatMetricValue
|
|
9
|
+
} from '../../..';
|
|
6
10
|
import { Line } from '../../common/timeSeries/models';
|
|
7
11
|
import { Tooltip } from '../../../components';
|
|
8
12
|
|
|
@@ -29,12 +33,11 @@ const LegendHeader = ({
|
|
|
29
33
|
|
|
30
34
|
const { unit, name, legend } = line;
|
|
31
35
|
|
|
36
|
+
const metricName = formatMetricName({ legend, name });
|
|
37
|
+
|
|
32
38
|
const legendName = legend || name;
|
|
33
39
|
const hasUnit = !isEmpty(unit);
|
|
34
40
|
const unitName = `(${unit})`;
|
|
35
|
-
const metricName = includes('#', legendName)
|
|
36
|
-
? split('#')(legendName)[1]
|
|
37
|
-
: legendName;
|
|
38
41
|
|
|
39
42
|
const getEndText = (): string => {
|
|
40
43
|
if (value) {
|
|
@@ -1,48 +1,38 @@
|
|
|
1
1
|
import { Dispatch, ReactNode, SetStateAction } from 'react';
|
|
2
2
|
|
|
3
3
|
import { prop, slice, sortBy } from 'ramda';
|
|
4
|
-
import { useAtomValue } from 'jotai';
|
|
5
4
|
|
|
6
5
|
import { Box, alpha, useTheme } from '@mui/material';
|
|
7
6
|
|
|
8
7
|
import { useMemoComponent } from '@centreon/ui';
|
|
9
8
|
|
|
10
9
|
import { formatMetricValue } from '../../common/timeSeries';
|
|
11
|
-
import { Line
|
|
10
|
+
import { Line } from '../../common/timeSeries/models';
|
|
12
11
|
import { labelAvg, labelMax, labelMin } from '../translatedLabels';
|
|
13
|
-
import { timeValueAtom } from '../InteractiveComponents/interactionWithGraphAtoms';
|
|
14
12
|
|
|
15
|
-
import InteractiveValue from './InteractiveValue';
|
|
16
13
|
import { useStyles } from './Legend.styles';
|
|
17
14
|
import LegendHeader from './LegendHeader';
|
|
18
15
|
import { GetMetricValueProps, LegendDisplayMode } from './models';
|
|
19
|
-
import useInteractiveValues from './useInteractiveValues';
|
|
20
16
|
import useLegend from './useLegend';
|
|
21
17
|
import LegendContent from './LegendContent';
|
|
22
18
|
|
|
23
19
|
interface Props {
|
|
24
20
|
base: number;
|
|
25
|
-
displayAnchor?: boolean;
|
|
26
21
|
limitLegend?: false | number;
|
|
27
22
|
lines: Array<Line>;
|
|
28
23
|
renderExtraComponent?: ReactNode;
|
|
29
24
|
setLinesGraph: Dispatch<SetStateAction<Array<Line> | null>>;
|
|
30
25
|
shouldDisplayLegendInCompactMode: boolean;
|
|
31
|
-
timeSeries: Array<TimeValue>;
|
|
32
26
|
toggable?: boolean;
|
|
33
|
-
xScale;
|
|
34
27
|
}
|
|
35
28
|
|
|
36
29
|
const MainLegend = ({
|
|
37
30
|
lines,
|
|
38
|
-
timeSeries,
|
|
39
31
|
base,
|
|
40
32
|
toggable = true,
|
|
41
33
|
limitLegend = false,
|
|
42
34
|
renderExtraComponent,
|
|
43
|
-
displayAnchor = true,
|
|
44
35
|
setLinesGraph,
|
|
45
|
-
xScale,
|
|
46
36
|
shouldDisplayLegendInCompactMode
|
|
47
37
|
}: Props): JSX.Element => {
|
|
48
38
|
const { classes, cx } = useStyles({ limitLegendRows: Boolean(limitLegend) });
|
|
@@ -51,13 +41,6 @@ const MainLegend = ({
|
|
|
51
41
|
const { selectMetricLine, clearHighlight, highlightLine, toggleMetricLine } =
|
|
52
42
|
useLegend({ lines, setLinesGraph });
|
|
53
43
|
|
|
54
|
-
const { getFormattedValue } = useInteractiveValues({
|
|
55
|
-
base,
|
|
56
|
-
lines,
|
|
57
|
-
timeSeries,
|
|
58
|
-
xScale
|
|
59
|
-
});
|
|
60
|
-
|
|
61
44
|
const sortedData = sortBy(prop('metric_id'), lines);
|
|
62
45
|
|
|
63
46
|
const displayedLines = limitLegend
|
|
@@ -99,10 +82,6 @@ const MainLegend = ({
|
|
|
99
82
|
? color
|
|
100
83
|
: alpha(theme.palette.text.disabled, 0.2);
|
|
101
84
|
|
|
102
|
-
const interactiveValue = displayAnchor
|
|
103
|
-
? getFormattedValue(line)
|
|
104
|
-
: null;
|
|
105
|
-
|
|
106
85
|
const minMaxAvg = [
|
|
107
86
|
{
|
|
108
87
|
label: labelMin,
|
|
@@ -137,28 +116,18 @@ const MainLegend = ({
|
|
|
137
116
|
minMaxAvg={
|
|
138
117
|
shouldDisplayLegendInCompactMode ? minMaxAvg : undefined
|
|
139
118
|
}
|
|
140
|
-
value={
|
|
141
|
-
shouldDisplayLegendInCompactMode
|
|
142
|
-
? interactiveValue
|
|
143
|
-
: undefined
|
|
144
|
-
}
|
|
145
119
|
/>
|
|
146
120
|
{!shouldDisplayLegendInCompactMode && (
|
|
147
121
|
<div>
|
|
148
|
-
{
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
label={label}
|
|
158
|
-
/>
|
|
159
|
-
))}
|
|
160
|
-
</div>
|
|
161
|
-
)}
|
|
122
|
+
<div className={classes.minMaxAvgContainer}>
|
|
123
|
+
{minMaxAvg.map(({ label, value }) => (
|
|
124
|
+
<LegendContent
|
|
125
|
+
data={getMetricValue({ unit: line.unit, value })}
|
|
126
|
+
key={label}
|
|
127
|
+
label={label}
|
|
128
|
+
/>
|
|
129
|
+
))}
|
|
130
|
+
</div>
|
|
162
131
|
</div>
|
|
163
132
|
)}
|
|
164
133
|
</Box>
|
|
@@ -174,24 +143,18 @@ const Legend = (props: Props): JSX.Element => {
|
|
|
174
143
|
const {
|
|
175
144
|
toggable,
|
|
176
145
|
limitLegend,
|
|
177
|
-
timeSeries,
|
|
178
146
|
lines,
|
|
179
147
|
base,
|
|
180
|
-
displayAnchor,
|
|
181
148
|
shouldDisplayLegendInCompactMode
|
|
182
149
|
} = props;
|
|
183
|
-
const timeValue = useAtomValue(timeValueAtom);
|
|
184
150
|
|
|
185
151
|
return useMemoComponent({
|
|
186
152
|
Component: <MainLegend {...props} />,
|
|
187
153
|
memoProps: [
|
|
188
|
-
timeValue,
|
|
189
|
-
timeSeries,
|
|
190
154
|
lines,
|
|
191
155
|
base,
|
|
192
156
|
toggable,
|
|
193
157
|
limitLegend,
|
|
194
|
-
displayAnchor,
|
|
195
158
|
shouldDisplayLegendInCompactMode
|
|
196
159
|
]
|
|
197
160
|
});
|