@centreon/ui 24.4.63 → 24.4.65
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 +8 -3
- 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/Tree/DescendantNodes.tsx +88 -0
- package/src/Graph/Tree/Links.tsx +64 -0
- package/src/Graph/Tree/StandaloneTree.tsx +32 -0
- package/src/Graph/Tree/Tree.cypress.spec.tsx +171 -0
- package/src/Graph/Tree/Tree.stories.tsx +144 -0
- package/src/Graph/Tree/Tree.tsx +116 -0
- package/src/Graph/Tree/constants.ts +2 -0
- package/src/Graph/Tree/index.ts +4 -0
- package/src/Graph/Tree/models.ts +52 -0
- package/src/Graph/Tree/stories/contents.tsx +164 -0
- package/src/Graph/Tree/stories/datas.ts +305 -0
- package/src/Graph/Tree/utils.ts +49 -0
- package/src/Graph/common/timeSeries/index.ts +31 -1
- package/src/Graph/index.ts +1 -0
- package/src/components/Zoom/Minimap.tsx +127 -0
- package/src/components/Zoom/Zoom.cypress.spec.tsx +246 -0
- package/src/components/Zoom/Zoom.stories.tsx +115 -0
- package/src/components/Zoom/Zoom.styles.tsx +68 -0
- package/src/components/Zoom/Zoom.tsx +61 -0
- package/src/components/Zoom/ZoomContent.tsx +167 -0
- package/src/components/Zoom/constants.ts +2 -0
- package/src/components/Zoom/localPoint.ts +51 -0
- package/src/components/Zoom/models.ts +25 -0
- package/src/components/Zoom/useMinimap.ts +156 -0
- package/src/components/Zoom/useZoom.ts +70 -0
- package/src/components/Zoom/utils.ts +55 -0
- package/src/components/index.ts +1 -0
- 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,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@centreon/ui",
|
|
3
|
-
"version": "24.4.
|
|
3
|
+
"version": "24.4.65",
|
|
4
4
|
"description": "Centreon UI Components",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"update:deps": "pnpx npm-check-updates -i --format group",
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"@vitejs/plugin-react": "^4.2.1",
|
|
83
83
|
"@vitejs/plugin-react-swc": "^3.6.0",
|
|
84
84
|
"axios-mock-adapter": "^1.22.0",
|
|
85
|
-
"cypress": "^13.7.
|
|
85
|
+
"cypress": "^13.7.1",
|
|
86
86
|
"identity-obj-proxy": "^3.0.0",
|
|
87
87
|
"jest-transform-stub": "^2.0.0",
|
|
88
88
|
"mochawesome": "^7.1.3",
|
|
@@ -114,15 +114,20 @@
|
|
|
114
114
|
"@lexical/selection": "^0.12.6",
|
|
115
115
|
"@lexical/utils": "^0.12.6",
|
|
116
116
|
"@react-spring/web": "^9.7.3",
|
|
117
|
+
"@visx/clip-path": "^3.3.0",
|
|
117
118
|
"@visx/curve": "^2.1.0",
|
|
119
|
+
"@visx/event": "^3.3.0",
|
|
118
120
|
"@visx/group": "^3.3.0",
|
|
121
|
+
"@visx/hierarchy": "^3.3.0",
|
|
119
122
|
"@visx/legend": "^3.5.0",
|
|
120
123
|
"@visx/pattern": "^3.3.0",
|
|
124
|
+
"@visx/point": "^3.3.0",
|
|
121
125
|
"@visx/scale": "^3.5.0",
|
|
122
|
-
"@visx/shape": "^2.
|
|
126
|
+
"@visx/shape": "^2.18.0",
|
|
123
127
|
"@visx/text": "^3.3.0",
|
|
124
128
|
"@visx/threshold": "^2.12.2",
|
|
125
129
|
"@visx/visx": "2.16.0",
|
|
130
|
+
"@visx/zoom": "^3.3.0",
|
|
126
131
|
"anylogger": "^1.0.11",
|
|
127
132
|
"d3-array": "3.2.4",
|
|
128
133
|
"humanize-duration": "^3.31.0",
|
|
@@ -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) {
|