@centreon/ui 23.10.30-MON-19324-dashboard-section-navigation.3 → 23.10.30

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.
Files changed (205) hide show
  1. package/package.json +9 -12
  2. package/src/@assets/icons/downtime.icon.svg +1 -0
  3. package/src/Dashboard/DashboardLayout.stories.tsx +5 -3
  4. package/src/Dashboard/Layout.tsx +4 -4
  5. package/src/Dashboard/utils.ts +28 -28
  6. package/src/Graph/BasicComponents/Axes/UnitLabel.tsx +20 -0
  7. package/src/Graph/BasicComponents/Axes/index.tsx +88 -0
  8. package/src/Graph/BasicComponents/Axes/models.ts +26 -0
  9. package/src/Graph/BasicComponents/Axes/useAxisY.ts +100 -0
  10. package/src/Graph/BasicComponents/Grids/index.tsx +20 -0
  11. package/src/Graph/BasicComponents/Lines/RegularLines/index.tsx +91 -0
  12. package/src/Graph/BasicComponents/Lines/RegularLines/useRegularLines.ts +15 -0
  13. package/src/Graph/BasicComponents/Lines/StackedLines/index.tsx +76 -0
  14. package/src/Graph/BasicComponents/Lines/StackedLines/useStackedLines.ts +39 -0
  15. package/src/Graph/BasicComponents/Lines/Threshold/BasicThreshold.tsx +51 -0
  16. package/src/Graph/BasicComponents/Lines/Threshold/Circle.tsx +43 -0
  17. package/src/Graph/BasicComponents/Lines/Threshold/ThresholdWithPatternLines.tsx +73 -0
  18. package/src/Graph/BasicComponents/Lines/Threshold/ThresholdWithVariation.tsx +59 -0
  19. package/src/Graph/BasicComponents/Lines/Threshold/helpers/index.ts +69 -0
  20. package/src/Graph/BasicComponents/Lines/Threshold/index.tsx +138 -0
  21. package/src/Graph/BasicComponents/Lines/Threshold/models.ts +105 -0
  22. package/src/Graph/BasicComponents/Lines/Threshold/useCoordinateCircle.ts +46 -0
  23. package/src/Graph/BasicComponents/Lines/Threshold/useScaleThreshold.ts +171 -0
  24. package/src/Graph/BasicComponents/Lines/index.tsx +180 -0
  25. package/src/Graph/BasicComponents/Lines/models.ts +42 -0
  26. package/src/Graph/BasicComponents/LoadingProgress.tsx +46 -0
  27. package/src/Graph/BasicComponents/useFilterLines.ts +60 -0
  28. package/src/Graph/Graph.styles.ts +45 -0
  29. package/src/Graph/Graph.tsx +217 -0
  30. package/src/Graph/Header/index.tsx +65 -0
  31. package/src/Graph/Icons/Downtime.tsx +9 -0
  32. package/src/Graph/InteractiveComponents/AnchorPoint/AnchorPoint.styles.ts +58 -0
  33. package/src/Graph/InteractiveComponents/AnchorPoint/GuidingLines.tsx +45 -0
  34. package/src/Graph/InteractiveComponents/AnchorPoint/RegularAnchorPoint.tsx +66 -0
  35. package/src/Graph/InteractiveComponents/AnchorPoint/StackedAnchorPoint.tsx +76 -0
  36. package/src/Graph/InteractiveComponents/AnchorPoint/TooltipAnchorPoint.tsx +70 -0
  37. package/src/Graph/InteractiveComponents/AnchorPoint/index.tsx +20 -0
  38. package/src/Graph/InteractiveComponents/AnchorPoint/models.ts +62 -0
  39. package/src/Graph/InteractiveComponents/AnchorPoint/useTickGraph.ts +94 -0
  40. package/src/Graph/InteractiveComponents/AnchorPoint/useTooltipAnchorPoint.ts +107 -0
  41. package/src/Graph/InteractiveComponents/Annotations/Annotation/Area.tsx +114 -0
  42. package/src/Graph/InteractiveComponents/Annotations/Annotation/Line.tsx +103 -0
  43. package/src/Graph/InteractiveComponents/Annotations/Annotation/index.tsx +81 -0
  44. package/src/Graph/InteractiveComponents/Annotations/Area/Downtime.tsx +27 -0
  45. package/src/Graph/InteractiveComponents/Annotations/EventAnnotations.tsx +61 -0
  46. package/src/Graph/InteractiveComponents/Annotations/Line/Acknowledgement.tsx +27 -0
  47. package/src/Graph/InteractiveComponents/Annotations/Line/Comments.tsx +25 -0
  48. package/src/Graph/InteractiveComponents/Annotations/annotationsAtoms.ts +183 -0
  49. package/src/Graph/InteractiveComponents/Annotations/index.tsx +49 -0
  50. package/src/Graph/InteractiveComponents/Annotations/models.ts +25 -0
  51. package/src/Graph/InteractiveComponents/Annotations/useAnnotation.ts +56 -0
  52. package/src/Graph/InteractiveComponents/Bar.tsx +21 -0
  53. package/src/Graph/InteractiveComponents/TimeShiftZones/TimeShiftIcon.tsx +62 -0
  54. package/src/Graph/InteractiveComponents/TimeShiftZones/TimeShiftZone.tsx +74 -0
  55. package/src/Graph/InteractiveComponents/TimeShiftZones/index.tsx +85 -0
  56. package/src/Graph/InteractiveComponents/TimeShiftZones/models.ts +12 -0
  57. package/src/Graph/InteractiveComponents/TimeShiftZones/useTimeShiftZones.ts +72 -0
  58. package/src/Graph/InteractiveComponents/Tooltip/index.tsx +59 -0
  59. package/src/Graph/InteractiveComponents/Tooltip/models.ts +9 -0
  60. package/src/Graph/InteractiveComponents/Tooltip/useGraphTooltip.ts +67 -0
  61. package/src/Graph/InteractiveComponents/ZoomPreview/index.tsx +38 -0
  62. package/src/Graph/InteractiveComponents/ZoomPreview/models.ts +9 -0
  63. package/src/Graph/InteractiveComponents/ZoomPreview/useZoomPreview.ts +107 -0
  64. package/src/Graph/InteractiveComponents/ZoomPreview/zoomPreviewAtoms.ts +3 -0
  65. package/src/Graph/InteractiveComponents/index.tsx +168 -0
  66. package/src/Graph/InteractiveComponents/interactionWithGraphAtoms.ts +51 -0
  67. package/src/Graph/Legend/InteractiveValue.tsx +22 -0
  68. package/src/Graph/Legend/Legend.styles.ts +71 -0
  69. package/src/Graph/Legend/LegendContent.tsx +27 -0
  70. package/src/Graph/Legend/LegendHeader.tsx +45 -0
  71. package/src/Graph/Legend/Marker.tsx +43 -0
  72. package/src/Graph/Legend/index.tsx +166 -0
  73. package/src/Graph/Legend/models.ts +11 -0
  74. package/src/Graph/Legend/useInteractiveValues.ts +86 -0
  75. package/src/Graph/Legend/useLegend.ts +114 -0
  76. package/src/Graph/LoadingSkeleton.tsx +44 -0
  77. package/src/Graph/common/index.ts +35 -0
  78. package/src/Graph/graphAtoms.ts +6 -0
  79. package/src/Graph/helpers/doc.ts +560 -0
  80. package/src/Graph/helpers/index.ts +58 -0
  81. package/src/Graph/index.stories.tsx +372 -0
  82. package/src/Graph/index.tsx +90 -0
  83. package/src/Graph/mockedData/annotationData.json +326 -0
  84. package/src/Graph/mockedData/exclusionPeriodFirstPeriod.json +588 -0
  85. package/src/Graph/mockedData/exclusionPeriodSecondPeriod.json +588 -0
  86. package/src/Graph/mockedData/exclusionPeriodThirdPeriod.json +581 -0
  87. package/src/Graph/mockedData/lastDay.json +1326 -0
  88. package/src/Graph/mockedData/lastDayAreaStack.json +3106 -0
  89. package/src/Graph/mockedData/lastDayForward.json +1338 -0
  90. package/src/Graph/mockedData/lastDayThreshold.json +2352 -0
  91. package/src/Graph/mockedData/lastMonth.json +1674 -0
  92. package/src/Graph/mockedData/lastWeek.json +2202 -0
  93. package/src/Graph/mockedData/zoomPreview.json +742 -0
  94. package/src/Graph/models.ts +150 -0
  95. package/src/Graph/timeSeries/index.test.ts +506 -0
  96. package/src/Graph/timeSeries/index.ts +512 -0
  97. package/src/Graph/timeSeries/models.ts +120 -0
  98. package/src/Graph/translatedLabels.ts +9 -0
  99. package/src/Graph/useGraphData.ts +47 -0
  100. package/src/Graph/useGraphIntersection.ts +36 -0
  101. package/src/ThemeProvider/index.tsx +5 -6
  102. package/src/ThemeProvider/palettes.ts +215 -385
  103. package/src/TimePeriods/CustomTimePeriod/CompactCustomTimePeriod.styles.ts +51 -0
  104. package/src/TimePeriods/CustomTimePeriod/CompactCustomTimePeriod.tsx +95 -0
  105. package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/ErrorText.tsx +14 -0
  106. package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/PickersStartEndDate.tsx +163 -0
  107. package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/index.tsx +76 -0
  108. package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/models.ts +61 -0
  109. package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/usePickersStartEndDate.ts +82 -0
  110. package/src/TimePeriods/CustomTimePeriod/index.tsx +66 -0
  111. package/src/TimePeriods/DateTimePickerInput.tsx +49 -0
  112. package/src/TimePeriods/ResolutionTimePeriod.cypress.spec.tsx +65 -0
  113. package/src/TimePeriods/SelectedTimePeriod.tsx +102 -0
  114. package/src/TimePeriods/TimePeriods.cypress.spec.tsx +510 -0
  115. package/src/TimePeriods/TimePeriods.styles.ts +22 -0
  116. package/src/TimePeriods/helpers/index.ts +26 -0
  117. package/src/TimePeriods/index.stories.tsx +98 -0
  118. package/src/TimePeriods/index.tsx +78 -0
  119. package/src/TimePeriods/mockedData.ts +12 -0
  120. package/src/TimePeriods/models.ts +97 -0
  121. package/src/TimePeriods/timePeriodsAtoms.ts +102 -0
  122. package/src/TimePeriods/translatedLabels.ts +9 -0
  123. package/src/TimePeriods/useSortTimePeriods.ts +31 -0
  124. package/src/TimePeriods/useTimePeriod.ts +49 -0
  125. package/src/api/TestQueryProvider.tsx +1 -2
  126. package/src/api/useFetchQuery/index.ts +7 -8
  127. package/src/api/useMutationQuery/index.ts +10 -11
  128. package/src/components/Button/Button.styles.ts +3 -17
  129. package/src/components/Button/Button.tsx +3 -6
  130. package/src/components/Button/Icon/IconButton.styles.ts +2 -9
  131. package/src/components/DataTable/DataTable.stories.tsx +0 -9
  132. package/src/components/DataTable/DataTable.styles.ts +0 -5
  133. package/src/components/DataTable/DataTable.tsx +6 -8
  134. package/src/components/DataTable/EmptyState/DataTableEmptyState.tsx +1 -4
  135. package/src/components/DataTable/Item/DataTableItem.styles.ts +2 -5
  136. package/src/components/DataTable/Item/DataTableItem.tsx +18 -36
  137. package/src/components/Header/Header.stories.tsx +27 -0
  138. package/src/components/Header/Header.styles.ts +27 -0
  139. package/src/components/Header/Header.tsx +23 -0
  140. package/src/components/Header/index.ts +1 -1
  141. package/src/components/Modal/index.ts +0 -2
  142. package/src/components/index.ts +0 -3
  143. package/src/index.ts +2 -0
  144. package/src/layout/TiledListingPage/TiledListingActions.tsx +15 -0
  145. package/src/layout/TiledListingPage/TiledListingContent.tsx +21 -0
  146. package/src/layout/TiledListingPage/TiledListingList.tsx +11 -0
  147. package/src/layout/TiledListingPage/TiledListingPage.styles.ts +16 -0
  148. package/src/layout/TiledListingPage/TiledListingPage.tsx +15 -0
  149. package/src/layout/TiledListingPage/index.ts +4 -0
  150. package/src/screens/dashboard/DashboardsOverview.stories.tsx +102 -110
  151. package/src/utils/index.ts +1 -1
  152. package/src/utils/sanitizedHTML.ts +1 -1
  153. package/test/setupTests.js +0 -3
  154. package/src/base/tokens/README.md +0 -3
  155. package/src/base/tokens/source/$metadata.json +0 -5
  156. package/src/base/tokens/source/base.json +0 -142
  157. package/src/base/tokens/themes/base.tokens.d.ts +0 -38
  158. package/src/base/tokens/themes/base.tokens.json +0 -695
  159. package/src/base/tokens/themes/base.tokens.ts +0 -38
  160. package/src/base/tokens/themes/ui-dark.tokens.d.ts +0 -38
  161. package/src/base/tokens/themes/ui-dark.tokens.json +0 -695
  162. package/src/base/tokens/themes/ui-dark.tokens.ts +0 -38
  163. package/src/base/tokens/themes/ui-light.tokens.d.ts +0 -38
  164. package/src/base/tokens/themes/ui-light.tokens.json +0 -695
  165. package/src/base/tokens/themes/ui-light.tokens.ts +0 -38
  166. package/src/components/Header/PageHeader/PageHeader.stories.tsx +0 -88
  167. package/src/components/Header/PageHeader/PageHeader.styles.ts +0 -99
  168. package/src/components/Header/PageHeader/PageHeader.tsx +0 -15
  169. package/src/components/Header/PageHeader/PageHeaderActions.tsx +0 -17
  170. package/src/components/Header/PageHeader/PageHeaderMain.tsx +0 -15
  171. package/src/components/Header/PageHeader/PageHeaderMenu.tsx +0 -15
  172. package/src/components/Header/PageHeader/PageHeaderTitle.tsx +0 -47
  173. package/src/components/Header/PageHeader/index.ts +0 -12
  174. package/src/components/Layout/AreaIndicator.styles.ts +0 -33
  175. package/src/components/Layout/AreaIndicator.tsx +0 -35
  176. package/src/components/Layout/PageLayout/PageLayout.stories.tsx +0 -81
  177. package/src/components/Layout/PageLayout/PageLayout.styles.ts +0 -40
  178. package/src/components/Layout/PageLayout/PageLayout.tsx +0 -21
  179. package/src/components/Layout/PageLayout/PageLayoutActions.tsx +0 -15
  180. package/src/components/Layout/PageLayout/PageLayoutBody.tsx +0 -24
  181. package/src/components/Layout/PageLayout/PageLayoutHeader.tsx +0 -15
  182. package/src/components/Layout/PageLayout/index.ts +0 -10
  183. package/src/components/Layout/index.ts +0 -1
  184. package/src/components/Menu/Button/MenuButton.stories.tsx +0 -16
  185. package/src/components/Menu/Button/MenuButton.styles.ts +0 -27
  186. package/src/components/Menu/Button/MenuButton.tsx +0 -59
  187. package/src/components/Menu/Button/index.ts +0 -1
  188. package/src/components/Menu/Menu.stories.tsx +0 -71
  189. package/src/components/Menu/Menu.styles.ts +0 -70
  190. package/src/components/Menu/Menu.tsx +0 -25
  191. package/src/components/Menu/MenuDivider.tsx +0 -13
  192. package/src/components/Menu/MenuItem.tsx +0 -36
  193. package/src/components/Menu/MenuItems.tsx +0 -35
  194. package/src/components/Menu/index.ts +0 -12
  195. package/src/components/Menu/useMenu.tsx +0 -79
  196. package/src/components/Tooltip/TextOverflowTooltip/TextOverflowTooltip.stories.tsx +0 -71
  197. package/src/components/Tooltip/TextOverflowTooltip/TextOverflowTooltip.styles.ts +0 -5
  198. package/src/components/Tooltip/TextOverflowTooltip/TextOverflowTooltip.tsx +0 -115
  199. package/src/components/Tooltip/TextOverflowTooltip/index.tsx +0 -1
  200. package/src/components/Tooltip/Tooltip.stories.tsx +0 -41
  201. package/src/components/Tooltip/Tooltip.styles.ts +0 -5
  202. package/src/components/Tooltip/Tooltip.tsx +0 -46
  203. package/src/components/Tooltip/index.ts +0 -1
  204. package/src/screens/dashboard/DashboardsDetail.stories.tsx +0 -108
  205. package/src/utils/useResizeObserver.ts +0 -6
@@ -0,0 +1,9 @@
1
+ export interface GraphTooltip {
2
+ hideTooltip: () => void;
3
+ tooltipData: Date;
4
+ tooltipLeft: number;
5
+ tooltipOpen: boolean;
6
+ tooltipTop: number;
7
+ }
8
+
9
+ export const width = 165;
@@ -0,0 +1,67 @@
1
+ import { useEffect } from 'react';
2
+
3
+ import { Event, Tooltip } from '@visx/visx';
4
+ import { ScaleLinear } from 'd3-scale';
5
+ import { useAtomValue } from 'jotai';
6
+
7
+ import { getDate } from '../../helpers/index';
8
+ import { TimeValue } from '../../timeSeries/models';
9
+ import { applyingZoomAtomAtom } from '../ZoomPreview/zoomPreviewAtoms';
10
+ import { eventMouseUpAtom } from '../interactionWithGraphAtoms';
11
+
12
+ import { GraphTooltip, width } from './models';
13
+
14
+ interface Props {
15
+ graphWidth: number;
16
+ timeSeries: Array<TimeValue>;
17
+ tooltipWidth?: number;
18
+ xScale: ScaleLinear<number, number>;
19
+ }
20
+
21
+ const useGraphTooltip = ({
22
+ graphWidth,
23
+ tooltipWidth = width,
24
+ timeSeries,
25
+ xScale
26
+ }: Props): GraphTooltip => {
27
+ const {
28
+ tooltipLeft,
29
+ tooltipTop,
30
+ tooltipOpen,
31
+ showTooltip,
32
+ hideTooltip,
33
+ tooltipData
34
+ } = Tooltip.useTooltip();
35
+
36
+ const mouseUpEvent = useAtomValue(eventMouseUpAtom);
37
+ const isZoomApplied = useAtomValue(applyingZoomAtomAtom);
38
+
39
+ useEffect(() => {
40
+ if (!mouseUpEvent || isZoomApplied) {
41
+ return;
42
+ }
43
+
44
+ const { x, y } = Event.localPoint(mouseUpEvent) || {
45
+ x: 0,
46
+ y: 0
47
+ };
48
+
49
+ const displayLeft = graphWidth - x < tooltipWidth;
50
+
51
+ showTooltip({
52
+ tooltipData: getDate({ positionX: x, timeSeries, xScale }),
53
+ tooltipLeft: displayLeft ? x - tooltipWidth : x,
54
+ tooltipTop: y
55
+ });
56
+ }, [mouseUpEvent]);
57
+
58
+ return {
59
+ hideTooltip,
60
+ tooltipData,
61
+ tooltipLeft,
62
+ tooltipOpen,
63
+ tooltipTop
64
+ } as GraphTooltip;
65
+ };
66
+
67
+ export default useGraphTooltip;
@@ -0,0 +1,38 @@
1
+ import { omit } from 'ramda';
2
+
3
+ import { alpha, useTheme } from '@mui/system';
4
+
5
+ import Bar from '../Bar';
6
+
7
+ import { ZoomPreviewData } from './models';
8
+ import useZoomPreview from './useZoomPreview';
9
+
10
+ const ZoomPreview = (data: ZoomPreviewData): JSX.Element => {
11
+ const theme = useTheme();
12
+
13
+ const { graphHeight, xScale, graphWidth, getInterval, ...rest } = data;
14
+
15
+ const { zoomBarWidth, zoomBoundaries } = useZoomPreview({
16
+ getInterval,
17
+ graphWidth,
18
+ xScale
19
+ });
20
+
21
+ const restData = omit(['enable'], { ...rest });
22
+
23
+ return (
24
+ <g>
25
+ <Bar
26
+ fill={alpha(theme.palette.primary.main, 0.2)}
27
+ height={graphHeight}
28
+ stroke={alpha(theme.palette.primary.main, 0.5)}
29
+ width={zoomBarWidth}
30
+ x={zoomBoundaries?.start || 0}
31
+ y={0}
32
+ {...restData}
33
+ />
34
+ </g>
35
+ );
36
+ };
37
+
38
+ export default ZoomPreview;
@@ -0,0 +1,9 @@
1
+ import { ScaleTime } from 'd3-scale';
2
+
3
+ import { InteractedZone } from '../../models';
4
+
5
+ export interface ZoomPreviewData extends InteractedZone {
6
+ graphHeight: number;
7
+ graphWidth: number;
8
+ xScale: ScaleTime<number, number>;
9
+ }
@@ -0,0 +1,107 @@
1
+ import { useEffect, useState } from 'react';
2
+
3
+ import { Event } from '@visx/visx';
4
+ import { ScaleTime } from 'd3-scale';
5
+ import { useAtomValue, useSetAtom } from 'jotai';
6
+ import { equals, gte, isNil, lt } from 'ramda';
7
+
8
+ import { margin } from '../../common';
9
+ import { Interval } from '../../models';
10
+ import {
11
+ eventMouseDownAtom,
12
+ eventMouseUpAtom,
13
+ mousePositionAtom
14
+ } from '../interactionWithGraphAtoms';
15
+
16
+ import { applyingZoomAtomAtom } from './zoomPreviewAtoms';
17
+
18
+ interface Boundaries {
19
+ end: number;
20
+ start: number;
21
+ }
22
+ interface ZoomPreview {
23
+ zoomBarWidth: number;
24
+ zoomBoundaries: Boundaries | null;
25
+ }
26
+
27
+ interface Props {
28
+ getInterval?: (args: Interval) => void;
29
+ graphWidth: number;
30
+ xScale: ScaleTime<number, number>;
31
+ }
32
+
33
+ const useZoomPreview = ({
34
+ xScale,
35
+ graphWidth,
36
+ getInterval
37
+ }: Props): ZoomPreview => {
38
+ const [zoomBoundaries, setZoomBoundaries] = useState<Boundaries | null>(null);
39
+ const eventMouseDown = useAtomValue(eventMouseDownAtom);
40
+ const eventMouseUp = useAtomValue(eventMouseUpAtom);
41
+ const mousePosition = useAtomValue(mousePositionAtom);
42
+ const setApplyingZoom = useSetAtom(applyingZoomAtomAtom);
43
+
44
+ const mousePointDown = eventMouseDown
45
+ ? Event.localPoint(eventMouseDown)
46
+ : null;
47
+
48
+ const mouseDownPositionX = mousePointDown
49
+ ? mousePointDown.x - margin.left
50
+ : null;
51
+
52
+ const movingMousePositionX = mousePosition
53
+ ? mousePosition[0] - margin.left
54
+ : null;
55
+
56
+ const applyZoom = (): void => {
57
+ getInterval?.({
58
+ end: xScale?.invert(zoomBoundaries?.end || graphWidth),
59
+ start: xScale?.invert(zoomBoundaries?.start || 0)
60
+ });
61
+ };
62
+
63
+ useEffect(() => {
64
+ if (isNil(mouseDownPositionX) || isNil(movingMousePositionX)) {
65
+ return;
66
+ }
67
+
68
+ setZoomBoundaries({
69
+ end: gte(movingMousePositionX, mouseDownPositionX)
70
+ ? movingMousePositionX
71
+ : mouseDownPositionX,
72
+ start: lt(movingMousePositionX, mouseDownPositionX)
73
+ ? movingMousePositionX
74
+ : mouseDownPositionX
75
+ });
76
+ }, [movingMousePositionX, mouseDownPositionX]);
77
+
78
+ useEffect(() => {
79
+ if (isNil(eventMouseUp) || isNil(zoomBoundaries)) {
80
+ return;
81
+ }
82
+ if (equals(zoomBoundaries.start, zoomBoundaries.end)) {
83
+ return;
84
+ }
85
+ applyZoom();
86
+ setApplyingZoom(false);
87
+ setZoomBoundaries(null);
88
+ }, [eventMouseUp]);
89
+
90
+ useEffect(() => {
91
+ if (isNil(zoomBoundaries)) {
92
+ return;
93
+ }
94
+ if (equals(zoomBoundaries.start, zoomBoundaries.end)) {
95
+ return;
96
+ }
97
+ setApplyingZoom(true);
98
+ }, [zoomBoundaries]);
99
+
100
+ const zoomBarWidth = Math.abs(
101
+ (zoomBoundaries?.end || 0) - (zoomBoundaries?.start || 0)
102
+ );
103
+
104
+ return { zoomBarWidth, zoomBoundaries };
105
+ };
106
+
107
+ export default useZoomPreview;
@@ -0,0 +1,3 @@
1
+ import { atom } from 'jotai';
2
+
3
+ export const applyingZoomAtomAtom = atom<boolean>(false);
@@ -0,0 +1,168 @@
1
+ import { MutableRefObject } from 'react';
2
+
3
+ import { Event } from '@visx/visx';
4
+ import { ScaleTime } from 'd3-scale';
5
+ import { useSetAtom } from 'jotai';
6
+ import { isEmpty, isNil } from 'ramda';
7
+ import { makeStyles } from 'tss-react/mui';
8
+
9
+ import {
10
+ AnnotationEvent,
11
+ GraphInterval,
12
+ InteractedZone,
13
+ InteractedZone as ZoomPreviewModel
14
+ } from '../models';
15
+ import { getTimeValue } from '../timeSeries';
16
+ import { TimeValue } from '../timeSeries/models';
17
+
18
+ import Annotations from './Annotations';
19
+ import { TimelineEvent } from './Annotations/models';
20
+ import Bar from './Bar';
21
+ import TimeShiftZones from './TimeShiftZones';
22
+ import ZoomPreview from './ZoomPreview';
23
+ import {
24
+ MousePosition,
25
+ changeMousePositionAndTimeValueDerivedAtom,
26
+ eventMouseDownAtom,
27
+ eventMouseLeaveAtom,
28
+ eventMouseUpAtom
29
+ } from './interactionWithGraphAtoms';
30
+
31
+ const useStyles = makeStyles()(() => ({
32
+ overlay: {
33
+ cursor: 'crosshair'
34
+ }
35
+ }));
36
+
37
+ interface CommonData {
38
+ graphHeight: number;
39
+ graphSvgRef: MutableRefObject<SVGSVGElement | null>;
40
+ graphWidth: number;
41
+ timeSeries: Array<TimeValue>;
42
+ xScale: ScaleTime<number, number>;
43
+ }
44
+
45
+ interface TimeShiftZonesData extends InteractedZone {
46
+ graphInterval: GraphInterval;
47
+ loading: boolean;
48
+ }
49
+
50
+ interface Props {
51
+ annotationData?: AnnotationEvent;
52
+ commonData: CommonData;
53
+ timeShiftZonesData: TimeShiftZonesData;
54
+ zoomData: ZoomPreviewModel;
55
+ }
56
+
57
+ const InteractionWithGraph = ({
58
+ zoomData,
59
+ commonData,
60
+ annotationData,
61
+ timeShiftZonesData
62
+ }: Props): JSX.Element => {
63
+ const { classes } = useStyles();
64
+
65
+ const setEventMouseDown = useSetAtom(eventMouseDownAtom);
66
+ const setEventMouseUp = useSetAtom(eventMouseUpAtom);
67
+ const setEventMouseLeave = useSetAtom(eventMouseLeaveAtom);
68
+
69
+ const changeMousePositionAndTimeValue = useSetAtom(
70
+ changeMousePositionAndTimeValueDerivedAtom
71
+ );
72
+
73
+ const { graphHeight, graphWidth, graphSvgRef, xScale, timeSeries } =
74
+ commonData;
75
+
76
+ const displayZoomPreview = zoomData?.enable ?? true;
77
+
78
+ const displayEventAnnotations =
79
+ !isNil(annotationData?.data) && !isEmpty(annotationData?.data);
80
+ const displayTimeShiftZones = timeShiftZonesData?.enable ?? true;
81
+
82
+ const mouseLeave = (event): void => {
83
+ setEventMouseLeave(event);
84
+ setEventMouseDown(null);
85
+ updateMousePosition(null);
86
+ };
87
+
88
+ const mouseUp = (event): void => {
89
+ setEventMouseUp(event);
90
+ setEventMouseDown(null);
91
+ };
92
+
93
+ const mouseMove = (event): void => {
94
+ const mousePoint = Event.localPoint(
95
+ graphSvgRef?.current as SVGSVGElement,
96
+ event
97
+ );
98
+ if (!mousePoint) {
99
+ return;
100
+ }
101
+ updateMousePosition([mousePoint.x, mousePoint.y]);
102
+ };
103
+
104
+ const mouseDown = (event): void => {
105
+ setEventMouseDown(event);
106
+ };
107
+
108
+ const updateMousePosition = (pointPosition: MousePosition): void => {
109
+ if (isNil(pointPosition)) {
110
+ changeMousePositionAndTimeValue({
111
+ position: null,
112
+ timeValue: null
113
+ });
114
+
115
+ return;
116
+ }
117
+ const timeValue = getTimeValue({
118
+ timeSeries,
119
+ x: pointPosition[0],
120
+ xScale
121
+ });
122
+
123
+ changeMousePositionAndTimeValue({ position: pointPosition, timeValue });
124
+ };
125
+
126
+ return (
127
+ <g>
128
+ {displayZoomPreview && (
129
+ <ZoomPreview
130
+ {...zoomData}
131
+ graphHeight={graphHeight}
132
+ graphWidth={graphWidth}
133
+ xScale={xScale}
134
+ />
135
+ )}
136
+ {displayEventAnnotations && (
137
+ <Annotations
138
+ data={annotationData?.data as Array<TimelineEvent>}
139
+ graphHeight={graphHeight}
140
+ graphSvgRef={graphSvgRef}
141
+ graphWidth={graphWidth}
142
+ xScale={xScale}
143
+ />
144
+ )}
145
+ {displayTimeShiftZones && (
146
+ <TimeShiftZones
147
+ graphHeight={graphHeight}
148
+ graphWidth={graphWidth}
149
+ {...timeShiftZonesData}
150
+ />
151
+ )}
152
+ <Bar
153
+ className={classes.overlay}
154
+ fill="transparent"
155
+ height={graphHeight}
156
+ width={graphWidth}
157
+ x={0}
158
+ y={0}
159
+ onMouseDown={mouseDown}
160
+ onMouseLeave={mouseLeave}
161
+ onMouseMove={mouseMove}
162
+ onMouseUp={mouseUp}
163
+ />
164
+ </g>
165
+ );
166
+ };
167
+
168
+ export default InteractionWithGraph;
@@ -0,0 +1,51 @@
1
+ import { atom } from 'jotai';
2
+ import { not, isNil } from 'ramda';
3
+
4
+ import { TimeValue } from '../timeSeries/models';
5
+
6
+ export const eventMouseDownAtom = atom<null | MouseEvent>(null);
7
+ export const eventMouseUpAtom = atom<null | MouseEvent>(null);
8
+ export const eventMouseLeaveAtom = atom<null | MouseEvent>(null);
9
+
10
+ export const timeValueAtom = atom<TimeValue | null>(null);
11
+ export const mousePositionAtom = atom<MousePosition>(null);
12
+ export const isListingGraphOpenAtom = atom(false);
13
+ export type MousePosition = [number, number] | null;
14
+
15
+ interface PositionTimeValue {
16
+ position: MousePosition;
17
+ timeValue: TimeValue | null;
18
+ }
19
+
20
+ interface NewTimeValueInViewportState {
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(
39
+ null,
40
+ (_, set, { position, timeValue }: PositionTimeValue): void => {
41
+ if (isNil(position) || isNil(timeValue)) {
42
+ set(mousePositionAtom, null);
43
+ set(timeValueAtom, null);
44
+
45
+ return;
46
+ }
47
+ set(mousePositionAtom, position);
48
+
49
+ set(timeValueAtom, timeValue);
50
+ }
51
+ );
@@ -0,0 +1,22 @@
1
+ import { Typography } from '@mui/material';
2
+
3
+ import { useStyles } from './Legend.styles';
4
+
5
+ interface Props {
6
+ value?: string | null;
7
+ }
8
+
9
+ const InteractiveValue = ({ value }: Props): JSX.Element | null => {
10
+ const { classes } = useStyles({});
11
+ if (!value) {
12
+ return null;
13
+ }
14
+
15
+ return (
16
+ <Typography className={classes.legendValue} variant="h6">
17
+ {value}
18
+ </Typography>
19
+ );
20
+ };
21
+
22
+ export default InteractiveValue;
@@ -0,0 +1,71 @@
1
+ import { makeStyles } from 'tss-react/mui';
2
+
3
+ import { margin } from '../common';
4
+
5
+ interface MakeStylesProps {
6
+ limitLegendRows?: boolean;
7
+ }
8
+
9
+ export const useStyles = makeStyles<MakeStylesProps>()(
10
+ (theme, { limitLegendRows }) => ({
11
+ highlight: {
12
+ color: theme.typography.body1.color
13
+ },
14
+ item: {
15
+ display: 'grid',
16
+ gridTemplateColumns: 'min-content minmax(50px, 1fr)',
17
+ marginBottom: theme.spacing(1)
18
+ },
19
+ items: {
20
+ display: 'grid',
21
+ gridTemplateColumns: 'repeat(auto-fit, minmax(150px, 1fr))',
22
+ justifyContent: 'center',
23
+ marginLeft: theme.spacing(0.5),
24
+ maxHeight: limitLegendRows ? theme.spacing(19) : 'unset',
25
+ overflowY: 'auto',
26
+ width: '100%'
27
+ },
28
+ legend: {
29
+ marginLeft: margin.left,
30
+ marginRight: margin.right,
31
+ maxHeight: theme.spacing(24),
32
+ overflowX: 'hidden',
33
+ overflowY: 'auto'
34
+ },
35
+ legendData: {
36
+ display: 'flex',
37
+ flexDirection: 'column'
38
+ },
39
+ legendName: {
40
+ display: 'flex',
41
+ flexDirection: 'row',
42
+ justifyContent: 'start',
43
+ overflow: 'hidden',
44
+ textOverflow: 'ellipsis'
45
+ },
46
+ legendUnit: {
47
+ justifyContent: 'start',
48
+ marginLeft: 'auto',
49
+ marginRight: theme.spacing(0.5),
50
+ overflow: 'hidden',
51
+ textOverflow: 'ellipsis'
52
+ },
53
+ legendValue: {
54
+ fontWeight: theme.typography.body1.fontWeight
55
+ },
56
+ minMaxAvgContainer: {
57
+ columnGap: theme.spacing(0.5),
58
+ display: 'grid',
59
+ gridAutoRows: theme.spacing(2),
60
+ gridTemplateColumns: 'repeat(2, min-content)',
61
+ whiteSpace: 'nowrap'
62
+ },
63
+ minMaxAvgValue: { fontWeight: 600 },
64
+ normal: {
65
+ color: theme.palette.text.primary
66
+ },
67
+ toggable: {
68
+ cursor: 'pointer'
69
+ }
70
+ })
71
+ );
@@ -0,0 +1,27 @@
1
+ import { useTranslation } from 'react-i18next';
2
+
3
+ import { Typography } from '@mui/material';
4
+
5
+ import { useStyles } from './Legend.styles';
6
+
7
+ interface Props {
8
+ data: string;
9
+ label: string;
10
+ }
11
+
12
+ const LegendContent = ({ data, label }: Props): JSX.Element => {
13
+ const { classes } = useStyles({});
14
+
15
+ const { t } = useTranslation();
16
+
17
+ return (
18
+ <div data-testid={label}>
19
+ <Typography variant="caption">{t(label)}: </Typography>
20
+ <Typography className={classes.minMaxAvgValue} variant="caption">
21
+ {data}
22
+ </Typography>
23
+ </div>
24
+ );
25
+ };
26
+
27
+ export default LegendContent;
@@ -0,0 +1,45 @@
1
+ import { includes, isEmpty, split } from 'ramda';
2
+
3
+ import { Tooltip, Typography } from '@mui/material';
4
+
5
+ import { Line } from '../timeSeries/models';
6
+
7
+ import { useStyles } from './Legend.styles';
8
+
9
+ interface Props {
10
+ line: Line;
11
+ }
12
+
13
+ const LegendHeader = ({ line }: Props): JSX.Element => {
14
+ const { classes } = useStyles({});
15
+ const { unit, name, legend } = line;
16
+
17
+ const legendName = legend || name;
18
+ const unitName = ` (${unit})`;
19
+ const metricName = includes('#', legendName)
20
+ ? split('#')(legendName)[1]
21
+ : legendName;
22
+
23
+ return (
24
+ <div className={classes.legendName}>
25
+ <Tooltip placement="top" title={legendName + unitName}>
26
+ <Typography
27
+ className={classes.legendName}
28
+ component="p"
29
+ variant="caption"
30
+ >
31
+ {metricName}
32
+ </Typography>
33
+ </Tooltip>
34
+ <Typography
35
+ className={classes.legendUnit}
36
+ component="p"
37
+ variant="caption"
38
+ >
39
+ {!isEmpty(line?.unit) && `(${line.unit})`}
40
+ </Typography>
41
+ </div>
42
+ );
43
+ };
44
+
45
+ export default LegendHeader;
@@ -0,0 +1,43 @@
1
+ import { equals } from 'ramda';
2
+ import { makeStyles } from 'tss-react/mui';
3
+
4
+ export enum LegendMarkerVariant {
5
+ 'dot',
6
+ 'bar'
7
+ }
8
+
9
+ interface StylesProps {
10
+ color?: string;
11
+ variant: LegendMarkerVariant;
12
+ }
13
+
14
+ const useStyles = makeStyles<StylesProps>()((theme, { color, variant }) => ({
15
+ disabled: {
16
+ color: theme.palette.text.disabled
17
+ },
18
+ icon: {
19
+ backgroundColor: color,
20
+ borderRadius: equals(LegendMarkerVariant.dot, variant) ? '50%' : 0,
21
+ height: equals(LegendMarkerVariant.dot, variant) ? 9 : '100%',
22
+ marginRight: theme.spacing(0.5),
23
+ width: 9
24
+ }
25
+ }));
26
+
27
+ interface Props {
28
+ color: string;
29
+ disabled?: boolean;
30
+ variant?: LegendMarkerVariant;
31
+ }
32
+
33
+ const LegendMarker = ({
34
+ disabled,
35
+ color,
36
+ variant = LegendMarkerVariant.bar
37
+ }: Props): JSX.Element => {
38
+ const { classes, cx } = useStyles({ color, variant });
39
+
40
+ return <div className={cx(classes.icon, { [classes.disabled]: disabled })} />;
41
+ };
42
+
43
+ export default LegendMarker;