@centreon/ui 24.4.1-sync-release-34022.0 → 24.4.1-test-code-coverage.0

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 (220) hide show
  1. package/package.json +48 -40
  2. package/src/ActionsList/ActionsList.styles.ts +40 -71
  3. package/src/Button/Icon/index.stories.tsx +1 -1
  4. package/src/Button/Icon/index.tsx +1 -1
  5. package/src/Dashboard/Dashboard.styles.ts +6 -5
  6. package/src/Dialog/Confirm/index.tsx +10 -2
  7. package/src/Dialog/UnsavedChanges/index.tsx +21 -20
  8. package/src/Dialog/UnsavedChanges/translatedLabels.ts +4 -6
  9. package/src/Dialog/index.tsx +8 -1
  10. package/src/Form/Inputs/CheckboxGroup.tsx +4 -1
  11. package/src/Form/Inputs/Text.tsx +3 -1
  12. package/src/Form/Inputs/models.ts +1 -0
  13. package/src/Graph/BarStack/BarStack.cypress.spec.tsx +139 -0
  14. package/src/Graph/BarStack/BarStack.stories.tsx +123 -0
  15. package/src/Graph/BarStack/BarStack.styles.ts +37 -0
  16. package/src/Graph/BarStack/BarStack.tsx +14 -0
  17. package/src/Graph/BarStack/ResponsiveBarStack.tsx +209 -0
  18. package/src/Graph/BarStack/index.ts +1 -0
  19. package/src/Graph/BarStack/models.ts +19 -0
  20. package/src/Graph/BarStack/useResponsiveBarStack.ts +131 -0
  21. package/src/Graph/Gauge/Gauge.cypress.spec.tsx +102 -0
  22. package/src/Graph/Gauge/Gauge.tsx +1 -1
  23. package/src/Graph/HeatMap/HeatMap.cypress.spec.tsx +145 -0
  24. package/src/Graph/HeatMap/HeatMap.stories.tsx +0 -25
  25. package/src/Graph/HeatMap/ResponsiveHeatMap.tsx +8 -2
  26. package/src/Graph/Legend/Legend.tsx +21 -0
  27. package/src/Graph/Legend/index.ts +1 -0
  28. package/src/Graph/Legend/models.ts +11 -0
  29. package/src/Graph/LineChart/BasicComponents/Lines/Threshold/index.tsx +4 -5
  30. package/src/Graph/LineChart/BasicComponents/ThresholdLine.tsx +3 -1
  31. package/src/Graph/LineChart/Header/index.tsx +3 -31
  32. package/src/Graph/LineChart/InteractiveComponents/AnchorPoint/useTickGraph.ts +9 -11
  33. package/src/Graph/LineChart/InteractiveComponents/Annotations/Annotation/index.tsx +3 -2
  34. package/src/Graph/LineChart/InteractiveComponents/GraphValueTooltip/GraphValueTooltip.tsx +68 -0
  35. package/src/Graph/LineChart/InteractiveComponents/GraphValueTooltip/useGraphValueTooltip.ts +27 -0
  36. package/src/Graph/LineChart/InteractiveComponents/GraphValueTooltip/useGraphValueTooltipStyles.ts +31 -0
  37. package/src/Graph/LineChart/InteractiveComponents/index.tsx +132 -17
  38. package/src/Graph/LineChart/InteractiveComponents/interactionWithGraphAtoms.ts +7 -27
  39. package/src/Graph/LineChart/Legend/Legend.styles.ts +5 -9
  40. package/src/Graph/LineChart/Legend/LegendHeader.tsx +10 -22
  41. package/src/Graph/LineChart/Legend/index.tsx +17 -55
  42. package/src/Graph/LineChart/LineChart.cypress.spec.tsx +91 -0
  43. package/src/Graph/LineChart/LineChart.styles.ts +8 -0
  44. package/src/Graph/LineChart/LineChart.tsx +106 -116
  45. package/src/Graph/LineChart/LoadingSkeleton.tsx +2 -2
  46. package/src/Graph/LineChart/index.tsx +6 -7
  47. package/src/Graph/LineChart/mockedData/lastDayWithIncompleteValues.json +1320 -0
  48. package/src/Graph/LineChart/mockedData/lastDayWithNullValues.json +1314 -0
  49. package/src/Graph/LineChart/models.ts +12 -1
  50. package/src/Graph/PieChart/PieChart.cypress.spec.tsx +154 -0
  51. package/src/Graph/PieChart/PieChart.stories.tsx +194 -0
  52. package/src/Graph/PieChart/PieChart.styles.ts +39 -0
  53. package/src/Graph/PieChart/PieChart.tsx +14 -0
  54. package/src/Graph/PieChart/ResponsivePie.tsx +243 -0
  55. package/src/Graph/PieChart/index.ts +1 -0
  56. package/src/Graph/PieChart/models.ts +19 -0
  57. package/src/Graph/PieChart/useResponsivePie.ts +81 -0
  58. package/src/Graph/SingleBar/SingleBar.cypress.spec.tsx +121 -0
  59. package/src/Graph/Text/Text.cypress.spec.tsx +101 -0
  60. package/src/Graph/Text/Text.styles.ts +12 -1
  61. package/src/Graph/Text/Text.tsx +17 -12
  62. package/src/Graph/Tree/DescendantNodes.tsx +89 -0
  63. package/src/Graph/Tree/Links.tsx +77 -0
  64. package/src/Graph/Tree/StandaloneTree.tsx +32 -0
  65. package/src/Graph/Tree/Tree.cypress.spec.tsx +195 -0
  66. package/src/Graph/Tree/Tree.stories.tsx +160 -0
  67. package/src/Graph/Tree/Tree.tsx +116 -0
  68. package/src/Graph/Tree/constants.ts +2 -0
  69. package/src/Graph/Tree/index.ts +4 -0
  70. package/src/Graph/Tree/models.ts +55 -0
  71. package/src/Graph/Tree/stories/contents.tsx +164 -0
  72. package/src/Graph/Tree/stories/datas.ts +305 -0
  73. package/src/Graph/Tree/utils.ts +49 -0
  74. package/src/Graph/common/testUtils.ts +71 -0
  75. package/src/Graph/common/timeSeries/index.ts +50 -12
  76. package/src/Graph/common/utils.ts +19 -0
  77. package/src/Graph/index.ts +4 -0
  78. package/src/InputField/Number/Number.cypress.spec.tsx +85 -0
  79. package/src/InputField/Number/Number.stories.tsx +66 -0
  80. package/src/InputField/Number/Number.tsx +74 -0
  81. package/src/InputField/Search/index.tsx +2 -2
  82. package/src/InputField/Select/Autocomplete/Multi/index.tsx +4 -2
  83. package/src/InputField/Select/Autocomplete/index.tsx +10 -3
  84. package/src/InputField/Select/IconPopover/index.tsx +1 -1
  85. package/src/InputField/Select/index.tsx +14 -1
  86. package/src/InputField/Text/index.tsx +38 -38
  87. package/src/Listing/ActionBar/index.tsx +10 -10
  88. package/src/Listing/Cell/DataCell.styles.ts +3 -0
  89. package/src/Listing/Cell/DataCell.tsx +8 -4
  90. package/src/Listing/Listing.cypress.spec.tsx +217 -33
  91. package/src/Listing/Listing.styles.ts +3 -5
  92. package/src/Listing/Row/Row.tsx +7 -3
  93. package/src/Listing/index.stories.tsx +25 -2
  94. package/src/Listing/index.test.tsx +1 -1
  95. package/src/Listing/index.tsx +202 -143
  96. package/src/Listing/models.ts +1 -0
  97. package/src/Listing/useStyleTable.ts +1 -0
  98. package/src/Panel/index.tsx +1 -1
  99. package/src/PopoverMenu/index.tsx +6 -5
  100. package/src/ThemeProvider/index.tsx +3 -0
  101. package/src/TimePeriods/CustomTimePeriod/CompactCustomTimePeriod.styles.ts +6 -7
  102. package/src/TimePeriods/ResolutionTimePeriod.cypress.spec.tsx +12 -9
  103. package/src/Typography/FluidTypography/FluidTypography.cypress.spec.tsx +27 -0
  104. package/src/Typography/FluidTypography/index.stories.tsx +2 -2
  105. package/src/Typography/FluidTypography/index.tsx +21 -28
  106. package/src/api/index.ts +3 -3
  107. package/src/api/useGraphQuery/index.ts +26 -5
  108. package/src/api/useGraphQuery/models.ts +5 -0
  109. package/src/api/useMutationQuery/index.test.ts +4 -4
  110. package/src/api/useMutationQuery/index.ts +24 -13
  111. package/src/components/CollapsibleItem/CollapsibleItem.cypress.spec.tsx +76 -0
  112. package/src/components/CollapsibleItem/CollapsibleItem.stories.tsx +26 -0
  113. package/src/components/CollapsibleItem/CollapsibleItem.tsx +43 -14
  114. package/src/components/CollapsibleItem/useCollapsibleItemStyles.ts +24 -1
  115. package/src/components/DataTable/DataTable.cypress.spec.tsx +14 -33
  116. package/src/components/DataTable/Item/DataTableItem.tsx +4 -60
  117. package/src/components/Form/{AccessRightsV2 → AccessRights}/AccessRights.cypress.spec.tsx +36 -13
  118. package/src/components/Form/{AccessRightsV2 → AccessRights}/ShareInput/ContactSwitch.tsx +11 -3
  119. package/src/components/Form/{AccessRightsV2 → AccessRights}/ShareInput/ShareInput.styles.ts +8 -0
  120. package/src/components/Form/{AccessRightsV2 → AccessRights}/ShareInput/ShareInput.tsx +1 -0
  121. package/src/components/Form/{AccessRightsV2 → AccessRights}/ShareInput/useShareInput.tsx +4 -0
  122. package/src/components/Form/{AccessRightsV2 → AccessRights}/models.ts +1 -0
  123. package/src/components/Form/{AccessRightsV2 → AccessRights}/storiesData.ts +23 -22
  124. package/src/components/Form/Dashboard/DashboardDuplicationForm.tsx +85 -0
  125. package/src/components/Form/Dashboard/index.ts +1 -0
  126. package/src/components/Form/FormActions.tsx +7 -2
  127. package/src/components/Form/index.ts +2 -2
  128. package/src/components/ItemComposition/Item.tsx +1 -1
  129. package/src/components/ItemComposition/ItemComposition.cypress.spec.tsx +113 -0
  130. package/src/components/ItemComposition/ItemComposition.stories.tsx +14 -0
  131. package/src/components/ItemComposition/ItemComposition.styles.ts +36 -3
  132. package/src/components/ItemComposition/ItemComposition.tsx +41 -17
  133. package/src/components/List/Item/ListItem.tsx +3 -3
  134. package/src/components/Modal/ConfirmationModal/ConfirmationModal.cypress.spec.tsx +168 -0
  135. package/src/components/Modal/ConfirmationModal/ConfirmationModal.stories.tsx +62 -0
  136. package/src/components/Modal/ConfirmationModal/ConfirmationModal.tsx +87 -0
  137. package/src/components/Modal/Modal.styles.ts +8 -3
  138. package/src/components/Modal/index.ts +2 -0
  139. package/src/components/Tooltip/ConfirmationTooltip/ConfirmationTooltip.stories.tsx +3 -3
  140. package/src/components/Tooltip/ConfirmationTooltip/ConfirmationTooltip.tsx +1 -1
  141. package/src/components/Tooltip/ConfirmationTooltip/models.ts +1 -1
  142. package/src/components/Zoom/Minimap.tsx +129 -0
  143. package/src/components/Zoom/Zoom.cypress.spec.tsx +246 -0
  144. package/src/components/Zoom/Zoom.stories.tsx +115 -0
  145. package/src/components/Zoom/Zoom.styles.tsx +68 -0
  146. package/src/components/Zoom/Zoom.tsx +64 -0
  147. package/src/components/Zoom/ZoomContent.tsx +170 -0
  148. package/src/components/Zoom/constants.ts +2 -0
  149. package/src/components/Zoom/localPoint.ts +51 -0
  150. package/src/components/Zoom/models.ts +25 -0
  151. package/src/components/Zoom/useMinimap.ts +156 -0
  152. package/src/components/Zoom/useZoom.ts +70 -0
  153. package/src/components/Zoom/utils.ts +55 -0
  154. package/src/components/index.ts +1 -0
  155. package/src/index.ts +1 -0
  156. package/src/utils/index.ts +3 -0
  157. package/src/utils/resourcesStatusURL.ts +166 -0
  158. package/src/utils/useFullscreen/Fullscreen.cypress.spec.tsx +130 -0
  159. package/src/utils/useFullscreen/atoms.ts +3 -0
  160. package/src/utils/useFullscreen/index.ts +2 -0
  161. package/src/utils/useFullscreen/translatedLabels.ts +1 -0
  162. package/src/utils/useFullscreen/useFullscreen.ts +73 -0
  163. package/src/utils/useFullscreen/useFullscreenListener.ts +62 -0
  164. package/src/utils/useInfiniteScrollListing.ts +4 -1
  165. package/src/Graph/LineChart/BasicComponents/LoadingProgress.tsx +0 -46
  166. package/src/Graph/LineChart/InteractiveComponents/AnchorPoint/TooltipAnchorPoint.tsx +0 -96
  167. package/src/Graph/LineChart/InteractiveComponents/AnchorPoint/useTooltipAnchorPoint.ts +0 -107
  168. package/src/Graph/LineChart/Legend/InteractiveValue.tsx +0 -22
  169. package/src/Graph/LineChart/Legend/useInteractiveValues.ts +0 -99
  170. package/src/Typography/FluidTypography/useFluidResizeObserver.ts +0 -56
  171. package/src/components/Form/AccessRights/AccessRights.resource.ts +0 -45
  172. package/src/components/Form/AccessRights/AccessRightsForm.stories.tsx +0 -59
  173. package/src/components/Form/AccessRights/AccessRightsForm.styles.ts +0 -21
  174. package/src/components/Form/AccessRights/AccessRightsForm.tsx +0 -67
  175. package/src/components/Form/AccessRights/AccessRightsFormActions.tsx +0 -80
  176. package/src/components/Form/AccessRights/Input/AddAction.tsx +0 -31
  177. package/src/components/Form/AccessRights/Input/ContactAccessRightInput.stories.tsx +0 -54
  178. package/src/components/Form/AccessRights/Input/ContactAccessRightInput.tsx +0 -72
  179. package/src/components/Form/AccessRights/Input/ContactAccessRightsInput.styles.ts +0 -22
  180. package/src/components/Form/AccessRights/Input/ContactInputField.tsx +0 -105
  181. package/src/components/Form/AccessRights/Input/RoleInputField.tsx +0 -29
  182. package/src/components/Form/AccessRights/List/ContactAccessRightsList.stories.tsx +0 -97
  183. package/src/components/Form/AccessRights/List/ContactAccessRightsList.styles.ts +0 -71
  184. package/src/components/Form/AccessRights/List/ContactAccessRightsList.tsx +0 -51
  185. package/src/components/Form/AccessRights/List/ContactAccessRightsListItem.stories.tsx +0 -116
  186. package/src/components/Form/AccessRights/List/ContactAccessRightsListItem.tsx +0 -118
  187. package/src/components/Form/AccessRights/List/ContactAccessRightsListItemSkeleton.tsx +0 -26
  188. package/src/components/Form/AccessRights/List/ContactAccessRightsListSkeleton.tsx +0 -28
  189. package/src/components/Form/AccessRights/Stats/AccessRightsStats.styles.ts +0 -18
  190. package/src/components/Form/AccessRights/Stats/AccessRightsStats.tsx +0 -41
  191. package/src/components/Form/AccessRights/__fixtures__/contactAccessRight.mock.ts +0 -54
  192. package/src/components/Form/AccessRights/common/GroupLabel.styles.ts +0 -18
  193. package/src/components/Form/AccessRights/common/GroupLabel.tsx +0 -15
  194. package/src/components/Form/AccessRights/common/Input.styles.ts +0 -48
  195. package/src/components/Form/AccessRights/common/RoleInputSelect.styles.ts +0 -11
  196. package/src/components/Form/AccessRights/common/RoleInputSelect.tsx +0 -57
  197. package/src/components/Form/AccessRights/index.ts +0 -3
  198. package/src/components/Form/AccessRights/useAccessRightsForm.test.tsx +0 -531
  199. package/src/components/Form/AccessRights/useAccessRightsForm.tsx +0 -282
  200. package/src/components/Form/AccessRights/useAccessRightsForm.utils.ts +0 -41
  201. /package/src/components/Form/{AccessRightsV2 → AccessRights}/AccessRights.stories.tsx +0 -0
  202. /package/src/components/Form/{AccessRightsV2 → AccessRights}/AccessRights.styles.ts +0 -0
  203. /package/src/components/Form/{AccessRightsV2 → AccessRights}/AccessRights.tsx +0 -0
  204. /package/src/components/Form/{AccessRightsV2 → AccessRights}/Actions/Actions.styles.ts +0 -0
  205. /package/src/components/Form/{AccessRightsV2 → AccessRights}/Actions/Actions.tsx +0 -0
  206. /package/src/components/Form/{AccessRightsV2 → AccessRights}/Actions/useActions.ts +0 -0
  207. /package/src/components/Form/{AccessRightsV2 → AccessRights}/List/Item.tsx +0 -0
  208. /package/src/components/Form/{AccessRightsV2 → AccessRights}/List/List.styles.tsx +0 -0
  209. /package/src/components/Form/{AccessRightsV2 → AccessRights}/List/List.tsx +0 -0
  210. /package/src/components/Form/{AccessRightsV2 → AccessRights}/List/ListItemSkeleton.tsx +0 -0
  211. /package/src/components/Form/{AccessRightsV2 → AccessRights}/List/ListSkeleton.tsx +0 -0
  212. /package/src/components/Form/{AccessRightsV2 → AccessRights}/List/RemoveAccessRight.tsx +0 -0
  213. /package/src/components/Form/{AccessRightsV2 → AccessRights}/List/StateChip.tsx +0 -0
  214. /package/src/components/Form/{AccessRightsV2 → AccessRights}/List/useItem.ts +0 -0
  215. /package/src/components/Form/{AccessRightsV2 → AccessRights}/Provider.tsx +0 -0
  216. /package/src/components/Form/{AccessRightsV2 → AccessRights}/Stats/Stats.tsx +0 -0
  217. /package/src/components/Form/{AccessRightsV2 → AccessRights}/atoms.ts +0 -0
  218. /package/src/components/Form/{AccessRightsV2 → AccessRights}/common/RoleSelectField.styles.tsx +0 -0
  219. /package/src/components/Form/{AccessRightsV2 → AccessRights}/common/RoleSelectField.tsx +0 -0
  220. /package/src/components/Form/{AccessRightsV2 → AccessRights}/useAccessRightsInitValues.ts +0 -0
@@ -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 { isEmpty, isNil } from 'ramda';
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 { getTimeValue } from '../../common/timeSeries';
16
- import { TimeValue } from '../../common/timeSeries/models';
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
- changeMousePositionAndTimeValueDerivedAtom,
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,13 +61,15 @@ 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
  }
44
70
 
45
71
  interface TimeShiftZonesData extends InteractedZone {
46
72
  graphInterval: GraphInterval;
47
- loading: boolean;
48
73
  }
49
74
 
50
75
  interface Props {
@@ -65,13 +90,19 @@ const InteractionWithGraph = ({
65
90
  const setEventMouseDown = useSetAtom(eventMouseDownAtom);
66
91
  const setEventMouseUp = useSetAtom(eventMouseUpAtom);
67
92
  const setEventMouseLeave = useSetAtom(eventMouseLeaveAtom);
93
+ const changeMousePosition = useSetAtom(changeMousePositionDerivedAtom);
94
+ const setGraphTooltipData = useSetAtom(graphTooltipDataAtom);
68
95
 
69
- const changeMousePositionAndTimeValue = useSetAtom(
70
- changeMousePositionAndTimeValueDerivedAtom
71
- );
72
-
73
- const { graphHeight, graphWidth, graphSvgRef, xScale, timeSeries } =
74
- commonData;
96
+ const {
97
+ graphHeight,
98
+ graphWidth,
99
+ graphSvgRef,
100
+ xScale,
101
+ timeSeries,
102
+ leftScale,
103
+ rightScale,
104
+ lines
105
+ } = commonData;
75
106
 
76
107
  const displayZoomPreview = zoomData?.enable ?? true;
77
108
 
@@ -83,6 +114,7 @@ const InteractionWithGraph = ({
83
114
  setEventMouseLeave(event);
84
115
  setEventMouseDown(null);
85
116
  updateMousePosition(null);
117
+ setGraphTooltipData(null);
86
118
  };
87
119
 
88
120
  const mouseUp = (event): void => {
@@ -107,10 +139,10 @@ const InteractionWithGraph = ({
107
139
 
108
140
  const updateMousePosition = (pointPosition: MousePosition): void => {
109
141
  if (isNil(pointPosition)) {
110
- changeMousePositionAndTimeValue({
111
- position: null,
112
- timeValue: null
142
+ changeMousePosition({
143
+ position: null
113
144
  });
145
+ setGraphTooltipData(null);
114
146
 
115
147
  return;
116
148
  }
@@ -120,7 +152,89 @@ const InteractionWithGraph = ({
120
152
  xScale
121
153
  });
122
154
 
123
- changeMousePositionAndTimeValue({ position: pointPosition, timeValue });
155
+ if (isNil(timeValue)) {
156
+ changeMousePosition({
157
+ position: null
158
+ });
159
+ setGraphTooltipData(null);
160
+
161
+ return;
162
+ }
163
+
164
+ const date = timeValue.timeTick;
165
+ const displayedMetricIds = pluck('metric_id', lines);
166
+ const filteredMetricsValue = pick(displayedMetricIds, timeValue);
167
+ const [, secondUnit, thirdUnit] = getUnits(lines as Array<Line>);
168
+ const areAllValuesEmpty = pipe(values, all(isNil))(filteredMetricsValue);
169
+
170
+ const linesData = getLinesForMetrics({
171
+ lines,
172
+ metricIds: keys(filteredMetricsValue).map(Number)
173
+ });
174
+
175
+ if (areAllValuesEmpty) {
176
+ changeMousePosition({ position: pointPosition });
177
+ setGraphTooltipData(null);
178
+
179
+ return;
180
+ }
181
+
182
+ const distanceWithPointPositionPerMetric = reduce(
183
+ (acc, [metricId, value]) => {
184
+ if (isNil(value)) {
185
+ return acc;
186
+ }
187
+
188
+ const lineData = getLineForMetric({
189
+ lines,
190
+ metric_id: Number(metricId)
191
+ });
192
+ const yScale = getYScale({
193
+ hasMoreThanTwoUnits: Boolean(thirdUnit),
194
+ invert: (lineData as Line).invert,
195
+ leftScale,
196
+ rightScale,
197
+ secondUnit,
198
+ unit: (lineData as Line).unit
199
+ });
200
+
201
+ const y0 = yScale(value);
202
+
203
+ const diffBetweenY0AndPointPosition = Math.abs(
204
+ y0 + margin.top - pointPosition[1]
205
+ );
206
+
207
+ return {
208
+ ...acc,
209
+ [metricId]: diffBetweenY0AndPointPosition
210
+ };
211
+ },
212
+ {},
213
+ Object.entries(filteredMetricsValue)
214
+ );
215
+
216
+ const nearestY0 = Math.min(...values(distanceWithPointPositionPerMetric));
217
+
218
+ const nearestLine = pipe(
219
+ toPairs,
220
+ find(([, y0]) => equals(y0, nearestY0)) as () => [string, number]
221
+ )(distanceWithPointPositionPerMetric);
222
+
223
+ changeMousePosition({ position: pointPosition });
224
+ setGraphTooltipData({
225
+ date,
226
+ highlightedMetricId: Number(nearestLine[0]),
227
+ metrics: map(
228
+ ({ metric_id, color, unit, legend, name }) => ({
229
+ color,
230
+ id: metric_id,
231
+ name: formatMetricName({ legend, name }),
232
+ unit,
233
+ value: timeValue?.[metric_id]
234
+ }),
235
+ linesData
236
+ ).filter(({ value }) => !isNil(value))
237
+ });
124
238
  };
125
239
 
126
240
  return (
@@ -151,8 +265,9 @@ const InteractionWithGraph = ({
151
265
  )}
152
266
  <Bar
153
267
  className={classes.overlay}
268
+ data-testid="graph-interaction-zone"
154
269
  fill="transparent"
155
- height={graphHeight}
270
+ height={graphHeight - margin.bottom}
156
271
  width={graphWidth}
157
272
  x={0}
158
273
  y={0}
@@ -1,52 +1,32 @@
1
1
  import { atom } from 'jotai';
2
- import { not, isNil } from 'ramda';
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 PositionTimeValue {
17
+ interface Position {
16
18
  position: MousePosition;
17
- timeValue: TimeValue | null;
18
19
  }
19
20
 
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(
21
+ export const changeMousePositionDerivedAtom = atom(
39
22
  null,
40
- (_, set, { position, timeValue }: PositionTimeValue): void => {
41
- if (isNil(position) || isNil(timeValue)) {
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
  );
@@ -8,7 +8,7 @@ interface MakeStylesProps {
8
8
 
9
9
  export const legendWidth = 21;
10
10
  const legendItemHeight = 5.25;
11
- const legendItemHeightCompact = 1.75;
11
+ const legendItemHeightCompact = 2;
12
12
 
13
13
  export const useStyles = makeStyles<MakeStylesProps>()(
14
14
  (theme, { limitLegendRows }) => ({
@@ -28,10 +28,11 @@ export const useStyles = makeStyles<MakeStylesProps>()(
28
28
  columnGap: theme.spacing(3),
29
29
  display: 'grid',
30
30
  gridAutoRows: theme.spacing(legendItemHeight),
31
- gridTemplateColumns: `repeat(auto-fit, ${theme.spacing(legendWidth)})`,
31
+ gridTemplateColumns: `repeat(auto-fit, minmax(${theme.spacing(legendWidth)}, 1fr))`,
32
32
  maxHeight: limitLegendRows
33
33
  ? theme.spacing(legendItemHeight * 2 + 1)
34
34
  : 'unset',
35
+ overflowX: 'hidden',
35
36
  overflowY: 'auto',
36
37
  rowGap: theme.spacing(1),
37
38
  width: '100%'
@@ -63,9 +64,6 @@ interface StylesProps {
63
64
  export const useLegendHeaderStyles = makeStyles<StylesProps>()(
64
65
  (theme, { color }) => ({
65
66
  container: {
66
- display: 'flex',
67
- flexDirection: 'row',
68
- gap: theme.spacing(0.5),
69
67
  width: '100%'
70
68
  },
71
69
  disabled: {
@@ -79,10 +77,7 @@ export const useLegendHeaderStyles = makeStyles<StylesProps>()(
79
77
  width: theme.spacing(1.5)
80
78
  },
81
79
  legendName: {
82
- '&[data-mode="compact"]': {
83
- maxWidth: theme.spacing(legendWidth * 0.5)
84
- },
85
- maxWidth: theme.spacing(legendWidth * 0.75)
80
+ maxWidth: '95%'
86
81
  },
87
82
  markerAndLegendName: {
88
83
  alignItems: 'center',
@@ -97,6 +92,7 @@ export const useLegendHeaderStyles = makeStyles<StylesProps>()(
97
92
  whiteSpace: 'nowrap'
98
93
  },
99
94
  text: {
95
+ fontSize: '0.75rem',
100
96
  fontWeight: theme.typography.fontWeightMedium,
101
97
  lineHeight: 1
102
98
  }
@@ -1,8 +1,10 @@
1
- import { includes, isEmpty, split } from 'ramda';
2
-
3
1
  import { Typography } from '@mui/material';
4
2
 
5
- import { EllipsisTypography, formatMetricValue } from '../../..';
3
+ import {
4
+ EllipsisTypography,
5
+ formatMetricName,
6
+ formatMetricValue
7
+ } from '../../..';
6
8
  import { Line } from '../../common/timeSeries/models';
7
9
  import { Tooltip } from '../../../components';
8
10
 
@@ -27,22 +29,11 @@ const LegendHeader = ({
27
29
  }: Props): JSX.Element => {
28
30
  const { classes, cx } = useLegendHeaderStyles({ color });
29
31
 
30
- const { unit, name, legend } = line;
31
-
32
- const legendName = legend || name;
33
- const hasUnit = !isEmpty(unit);
34
- const unitName = `(${unit})`;
35
- const metricName = includes('#', legendName)
36
- ? split('#')(legendName)[1]
37
- : legendName;
32
+ const { name, legend } = line;
38
33
 
39
- const getEndText = (): string => {
40
- if (value) {
41
- return `${value}${hasUnit ? ` ${unit}` : ''}`;
42
- }
34
+ const metricName = formatMetricName({ legend, name });
43
35
 
44
- return hasUnit ? ` ${unitName}` : '';
45
- };
36
+ const legendName = legend || name;
46
37
 
47
38
  return (
48
39
  <div className={classes.container}>
@@ -51,7 +42,7 @@ const LegendHeader = ({
51
42
  label={
52
43
  minMaxAvg ? (
53
44
  <div>
54
- <Typography>{`${legendName} ${unitName}`}</Typography>
45
+ <Typography>{legendName}</Typography>
55
46
  <div className={classes.minMaxAvgContainer}>
56
47
  {minMaxAvg.map(({ label, value: subValue }) => (
57
48
  <LegendContent
@@ -66,7 +57,7 @@ const LegendHeader = ({
66
57
  </div>
67
58
  </div>
68
59
  ) : (
69
- `${legendName} ${unitName}`
60
+ legendName
70
61
  )
71
62
  }
72
63
  placement="top"
@@ -83,9 +74,6 @@ const LegendHeader = ({
83
74
  </EllipsisTypography>
84
75
  </div>
85
76
  </Tooltip>
86
- {hasUnit && (
87
- <Typography className={classes.text}>{getEndText()}</Typography>
88
- )}
89
77
  </div>
90
78
  );
91
79
  };
@@ -1,68 +1,50 @@
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
- import { maxLinesDisplayedLegend } from '../common';
11
9
  import { formatMetricValue } from '../../common/timeSeries';
12
- import { Line, TimeValue } from '../../common/timeSeries/models';
10
+ import { Line } from '../../common/timeSeries/models';
13
11
  import { labelAvg, labelMax, labelMin } from '../translatedLabels';
14
- import { timeValueAtom } from '../InteractiveComponents/interactionWithGraphAtoms';
15
12
 
16
- import InteractiveValue from './InteractiveValue';
17
13
  import { useStyles } from './Legend.styles';
18
14
  import LegendHeader from './LegendHeader';
19
15
  import { GetMetricValueProps, LegendDisplayMode } from './models';
20
- import useInteractiveValues from './useInteractiveValues';
21
16
  import useLegend from './useLegend';
22
17
  import LegendContent from './LegendContent';
23
18
 
24
19
  interface Props {
25
20
  base: number;
26
- displayAnchor?: boolean;
27
- limitLegendRows?: boolean;
21
+ limitLegend?: false | number;
28
22
  lines: Array<Line>;
29
23
  renderExtraComponent?: ReactNode;
30
24
  setLinesGraph: Dispatch<SetStateAction<Array<Line> | null>>;
31
25
  shouldDisplayLegendInCompactMode: boolean;
32
- timeSeries: Array<TimeValue>;
33
26
  toggable?: boolean;
34
- xScale;
35
27
  }
36
28
 
37
29
  const MainLegend = ({
38
30
  lines,
39
- timeSeries,
40
31
  base,
41
32
  toggable = true,
42
- limitLegendRows = true,
33
+ limitLegend = false,
43
34
  renderExtraComponent,
44
- displayAnchor = true,
45
35
  setLinesGraph,
46
- xScale,
47
36
  shouldDisplayLegendInCompactMode
48
37
  }: Props): JSX.Element => {
49
- const { classes, cx } = useStyles({ limitLegendRows });
38
+ const { classes, cx } = useStyles({ limitLegendRows: Boolean(limitLegend) });
50
39
  const theme = useTheme();
51
40
 
52
41
  const { selectMetricLine, clearHighlight, highlightLine, toggleMetricLine } =
53
42
  useLegend({ lines, setLinesGraph });
54
43
 
55
- const { getFormattedValue } = useInteractiveValues({
56
- base,
57
- lines,
58
- timeSeries,
59
- xScale
60
- });
61
-
62
44
  const sortedData = sortBy(prop('metric_id'), lines);
63
45
 
64
- const displayedLines = limitLegendRows
65
- ? slice(0, maxLinesDisplayedLegend, sortedData)
46
+ const displayedLines = limitLegend
47
+ ? slice(0, limitLegend, sortedData)
66
48
  : sortedData;
67
49
 
68
50
  const getMetricValue = ({ value, unit }: GetMetricValueProps): string =>
@@ -100,10 +82,6 @@ const MainLegend = ({
100
82
  ? color
101
83
  : alpha(theme.palette.text.disabled, 0.2);
102
84
 
103
- const interactiveValue = displayAnchor
104
- ? getFormattedValue(line)
105
- : null;
106
-
107
85
  const minMaxAvg = [
108
86
  {
109
87
  label: labelMin,
@@ -138,28 +116,18 @@ const MainLegend = ({
138
116
  minMaxAvg={
139
117
  shouldDisplayLegendInCompactMode ? minMaxAvg : undefined
140
118
  }
141
- value={
142
- shouldDisplayLegendInCompactMode
143
- ? interactiveValue
144
- : undefined
145
- }
146
119
  />
147
120
  {!shouldDisplayLegendInCompactMode && (
148
121
  <div>
149
- {displayAnchor && (
150
- <InteractiveValue value={interactiveValue} />
151
- )}
152
- {!interactiveValue && (
153
- <div className={classes.minMaxAvgContainer}>
154
- {minMaxAvg.map(({ label, value }) => (
155
- <LegendContent
156
- data={getMetricValue({ unit: line.unit, value })}
157
- key={label}
158
- label={label}
159
- />
160
- ))}
161
- </div>
162
- )}
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>
163
131
  </div>
164
132
  )}
165
133
  </Box>
@@ -174,25 +142,19 @@ const MainLegend = ({
174
142
  const Legend = (props: Props): JSX.Element => {
175
143
  const {
176
144
  toggable,
177
- limitLegendRows,
178
- timeSeries,
145
+ limitLegend,
179
146
  lines,
180
147
  base,
181
- displayAnchor,
182
148
  shouldDisplayLegendInCompactMode
183
149
  } = props;
184
- const timeValue = useAtomValue(timeValueAtom);
185
150
 
186
151
  return useMemoComponent({
187
152
  Component: <MainLegend {...props} />,
188
153
  memoProps: [
189
- timeValue,
190
- timeSeries,
191
154
  lines,
192
155
  base,
193
156
  toggable,
194
- limitLegendRows,
195
- displayAnchor,
157
+ limitLegend,
196
158
  shouldDisplayLegendInCompactMode
197
159
  ]
198
160
  });
@@ -0,0 +1,91 @@
1
+ import { LineChartData } from '../common/models';
2
+
3
+ import dataLastDay from './mockedData/lastDay.json';
4
+ import dataLastDayWithNullValues from './mockedData/lastDayWithNullValues.json';
5
+ import dataLastDayWithIncompleteValues from './mockedData/lastDayWithIncompleteValues.json';
6
+ import { args as argumentsData } from './helpers/doc';
7
+
8
+ import WrapperLineChart from '.';
9
+
10
+ const initialize = (data = dataLastDay): void => {
11
+ cy.mount({
12
+ Component: (
13
+ <WrapperLineChart
14
+ {...argumentsData}
15
+ data={data as unknown as LineChartData}
16
+ />
17
+ )
18
+ });
19
+ };
20
+
21
+ describe('Line chart', () => {
22
+ describe('Tooltip', () => {
23
+ it('displays a tooltip when the graph is hovered', () => {
24
+ initialize();
25
+
26
+ cy.contains('oracle-buffer-hit-ratio graph on srv-oracle-users').should(
27
+ 'be.visible'
28
+ );
29
+ cy.contains('hitratio').should('be.visible');
30
+ cy.contains('querytime').should('be.visible');
31
+ cy.contains('connTime').should('be.visible');
32
+ cy.contains('Min: 70.31').should('be.visible');
33
+
34
+ cy.findByTestId('graph-interaction-zone').realMouseMove(250, 70);
35
+
36
+ cy.contains('06/18/2023').should('be.visible');
37
+
38
+ cy.contains('0.45 s').should('be.visible');
39
+ cy.contains('75.93%').should('be.visible');
40
+ cy.contains('0.43 s').should('be.visible');
41
+
42
+ cy.makeSnapshot();
43
+ });
44
+
45
+ it('displays a metric highlighted when the graph is hovered and the metric is the nearest point', () => {
46
+ initialize();
47
+
48
+ cy.contains('Min: 70.31').should('be.visible');
49
+
50
+ cy.findByTestId('graph-interaction-zone').realMouseMove(452, 26);
51
+
52
+ cy.get('[data-metric="querytime"]').should(
53
+ 'have.attr',
54
+ 'data-highlight',
55
+ 'true'
56
+ );
57
+ cy.get('[data-metric="connTime"]').should(
58
+ 'have.attr',
59
+ 'data-highlight',
60
+ 'false'
61
+ );
62
+
63
+ cy.makeSnapshot();
64
+ });
65
+
66
+ it('does not display the tooltip when null values are hovered', () => {
67
+ initialize(dataLastDayWithNullValues);
68
+
69
+ cy.contains('Min: 70.31').should('be.visible');
70
+
71
+ cy.findByTestId('graph-interaction-zone').realMouseMove(1160, 100);
72
+
73
+ cy.get('[data-metric="querytime"]').should('not.exist');
74
+
75
+ cy.makeSnapshot();
76
+ });
77
+
78
+ it('displays the tooltip with defined values whent the graph is hovered', () => {
79
+ initialize(dataLastDayWithIncompleteValues);
80
+
81
+ cy.contains('Min: 70.31').should('be.visible');
82
+
83
+ cy.findByTestId('graph-interaction-zone').realMouseMove(1150, 100);
84
+
85
+ cy.get('[data-metric="querytime"]').should('be.visible');
86
+ cy.get('[data-metric="hitratio"]').should('not.exist');
87
+
88
+ cy.makeSnapshot();
89
+ });
90
+ });
91
+ });
@@ -35,6 +35,14 @@ const useStyles = makeStyles()((theme) => ({
35
35
  fill: theme.palette.text.primary,
36
36
  position: 'relative'
37
37
  },
38
+ graphValueTooltip: {
39
+ backgroundColor: theme.palette.background.paper,
40
+ borderRadius: theme.shape.borderRadius,
41
+ boxShadow: theme.shadows[3],
42
+ color: theme.palette.text.primary,
43
+ maxWidth: 'none',
44
+ padding: 0
45
+ },
38
46
  header: {
39
47
  display: 'grid',
40
48
  gridTemplateColumns: '0.4fr 1fr 0.4fr',