@centreon/ui 25.3.3 → 25.4.0-MON-191119-npm-develop.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 (187) hide show
  1. package/package.json +25 -11
  2. package/public/mockServiceWorker.js +8 -31
  3. package/src/ActionsList/index.tsx +1 -0
  4. package/src/Button/Icon/index.tsx +3 -1
  5. package/src/Button/Save/index.stories.tsx +1 -0
  6. package/src/Checkbox/Checkbox.tsx +3 -1
  7. package/src/Checkbox/CheckboxGroup/index.tsx +6 -1
  8. package/src/Colors/index.tsx +1 -1
  9. package/src/Dashboard/Dashboard.styles.ts +1 -1
  10. package/src/Dashboard/Layout.tsx +1 -1
  11. package/src/Dialog/UnsavedChanges/index.stories.tsx +1 -0
  12. package/src/Form/CollapsibleGroup.tsx +13 -13
  13. package/src/Form/Form.cypress.spec.tsx +137 -2
  14. package/src/Form/Form.stories.tsx +11 -31
  15. package/src/Form/Form.tsx +2 -0
  16. package/src/Form/Inputs/Checkbox.tsx +3 -2
  17. package/src/Form/Inputs/ConnectedAutocomplete.tsx +6 -1
  18. package/src/Form/Inputs/Grid.tsx +18 -29
  19. package/src/Form/Inputs/SubGroupDivider.tsx +7 -0
  20. package/src/Form/Inputs/Text.tsx +1 -0
  21. package/src/Form/Inputs/index.tsx +31 -24
  22. package/src/Form/Inputs/models.ts +8 -1
  23. package/src/Form/Section/FormSection.tsx +34 -0
  24. package/src/Form/Section/PanelTabs.tsx +13 -0
  25. package/src/Form/Section/navigateToSection.ts +9 -0
  26. package/src/Form/storiesData.tsx +14 -4
  27. package/src/Graph/BarChart/BarChart.cypress.spec.tsx +46 -6
  28. package/src/Graph/BarChart/BarChart.stories.tsx +60 -0
  29. package/src/Graph/BarChart/BarChart.tsx +56 -32
  30. package/src/Graph/BarChart/BarGroup.tsx +22 -32
  31. package/src/Graph/BarChart/MemoizedGroup.tsx +8 -11
  32. package/src/Graph/BarChart/ResponsiveBarChart.tsx +145 -32
  33. package/src/Graph/BarChart/Tooltip/BarChartTooltip.tsx +2 -2
  34. package/src/Graph/Chart/BasicComponents/Lines/StackedLines/index.tsx +7 -1
  35. package/src/Graph/Chart/BasicComponents/Lines/StackedLines/useStackedLines.ts +18 -45
  36. package/src/Graph/Chart/BasicComponents/Lines/index.tsx +42 -28
  37. package/src/Graph/Chart/Chart.cypress.spec.tsx +85 -15
  38. package/src/Graph/Chart/Chart.stories.tsx +84 -1
  39. package/src/Graph/Chart/Chart.tsx +17 -4
  40. package/src/Graph/Chart/InteractiveComponents/AnchorPoint/RegularAnchorPoint.tsx +8 -2
  41. package/src/Graph/Chart/InteractiveComponents/AnchorPoint/StackedAnchorPoint.tsx +10 -3
  42. package/src/Graph/Chart/InteractiveComponents/AnchorPoint/useTickGraph.ts +19 -2
  43. package/src/Graph/Chart/InteractiveComponents/Annotations/Annotation/index.tsx +1 -1
  44. package/src/Graph/Chart/InteractiveComponents/GraphValueTooltip/useGraphValueTooltip.ts +2 -4
  45. package/src/Graph/Chart/InteractiveComponents/ZoomPreview/index.tsx +14 -3
  46. package/src/Graph/Chart/InteractiveComponents/ZoomPreview/models.ts +3 -0
  47. package/src/Graph/Chart/InteractiveComponents/ZoomPreview/useZoomPreview.ts +12 -10
  48. package/src/Graph/Chart/InteractiveComponents/index.tsx +63 -5
  49. package/src/Graph/Chart/Legend/index.tsx +26 -2
  50. package/src/Graph/Chart/helpers/index.ts +4 -3
  51. package/src/Graph/Chart/index.tsx +45 -45
  52. package/src/Graph/Chart/models.ts +8 -0
  53. package/src/Graph/Chart/useChartData.ts +14 -2
  54. package/src/Graph/Gauge/Gauge.tsx +18 -14
  55. package/src/Graph/Gauge/ResponsiveGauge.tsx +10 -6
  56. package/src/Graph/Gauge/useResizeObserver.ts +68 -0
  57. package/src/Graph/SingleBar/ResponsiveSingleBar.tsx +18 -16
  58. package/src/Graph/SingleBar/ThresholdLine.tsx +4 -4
  59. package/src/Graph/SingleBar/models.ts +1 -0
  60. package/src/Graph/Text/Text.styles.ts +2 -2
  61. package/src/Graph/Text/Text.tsx +23 -10
  62. package/src/Graph/Timeline/ResponsiveTimeline.tsx +4 -0
  63. package/src/Graph/Timeline/Timeline.tsx +21 -4
  64. package/src/Graph/Tree/Links.tsx +2 -2
  65. package/src/Graph/Tree/Tree.tsx +2 -2
  66. package/src/Graph/Tree/constants.ts +1 -1
  67. package/src/Graph/common/BaseChart/BaseChart.tsx +6 -1
  68. package/src/Graph/common/BaseChart/ChartSvgWrapper.tsx +5 -4
  69. package/src/Graph/common/BaseChart/Header/index.tsx +3 -1
  70. package/src/Graph/common/BaseChart/useComputeBaseChartDimensions.ts +13 -9
  71. package/src/Graph/common/timeSeries/index.test.ts +20 -0
  72. package/src/Graph/common/timeSeries/index.ts +225 -44
  73. package/src/Graph/common/timeSeries/models.ts +6 -2
  74. package/src/Graph/common/utils.ts +45 -12
  75. package/src/Graph/index.ts +3 -1
  76. package/src/Graph/mockedData/dataWithMissingPoint.json +74 -0
  77. package/src/Graph/mockedData/pingServiceWithStackedKeys.json +205 -0
  78. package/src/Icon/RegexIcon.tsx +20 -0
  79. package/src/Icon/index.ts +1 -0
  80. package/src/InputField/Select/Autocomplete/Connected/Multi/MultiConnectedAutocompleteField.cypress.spec.tsx +68 -14
  81. package/src/InputField/Select/Autocomplete/Connected/index.tsx +49 -14
  82. package/src/InputField/Select/Autocomplete/Multi/Listbox.tsx +78 -0
  83. package/src/InputField/Select/Autocomplete/Multi/Multi.styles.ts +26 -0
  84. package/src/InputField/Select/Autocomplete/Multi/Multi.tsx +124 -0
  85. package/src/InputField/Select/Autocomplete/Multi/index.tsx +1 -117
  86. package/src/InputField/Select/Autocomplete/index.tsx +28 -17
  87. package/src/InputField/Select/Option.tsx +3 -3
  88. package/src/InputField/Select/index.tsx +4 -0
  89. package/src/InputField/Text/index.tsx +4 -2
  90. package/src/InputField/translatedLabels.ts +4 -0
  91. package/src/Listing/ActionBar/Pagination.tsx +10 -23
  92. package/src/Listing/ActionBar/PaginationActions.tsx +1 -10
  93. package/src/Listing/ActionBar/index.tsx +1 -1
  94. package/src/Listing/Cell/DataCell.tsx +6 -6
  95. package/src/Listing/Cell/EllipsisTypography.tsx +10 -32
  96. package/src/Listing/Cell/index.tsx +57 -89
  97. package/src/Listing/Checkbox.tsx +8 -20
  98. package/src/Listing/Header/Cell/ListingHeaderCell.tsx +17 -14
  99. package/src/Listing/Header/Cell/SelectActionListingHeaderCell.tsx +5 -9
  100. package/src/Listing/Header/ListingHeader.tsx +2 -5
  101. package/src/Listing/Header/_internals/Label.tsx +1 -17
  102. package/src/Listing/Row/EmptyRow.tsx +2 -6
  103. package/src/Listing/Row/Row.tsx +7 -36
  104. package/src/Listing/index.stories.tsx +1 -0
  105. package/src/Listing/index.tsx +26 -26
  106. package/src/Listing/useStyleTable.ts +58 -32
  107. package/src/ListingPage/index.stories.tsx +1 -0
  108. package/src/Module/index.tsx +8 -2
  109. package/src/MultiSelectEntries/index.stories.tsx +1 -0
  110. package/src/MultiSelectEntries/index.tsx +1 -1
  111. package/src/Pagination/Pagination.cypress.spec.tsx +137 -0
  112. package/src/Pagination/Pagination.stories.tsx +46 -0
  113. package/src/Pagination/Pagination.styles.ts +56 -0
  114. package/src/Pagination/Pagination.tsx +146 -0
  115. package/src/Pagination/index.ts +3 -0
  116. package/src/Pagination/utils.ts +7 -0
  117. package/src/SortableItems/index.stories.tsx +2 -2
  118. package/src/StoryBookThemeProvider/index.tsx +3 -1
  119. package/src/ThemeProvider/base.css +49 -0
  120. package/src/ThemeProvider/index.tsx +21 -47
  121. package/src/ThemeProvider/palettes.ts +5 -3
  122. package/src/ThemeProvider/tailwindcss.css +230 -0
  123. package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/PickersStartEndDate.tsx +9 -11
  124. package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/models.ts +1 -0
  125. package/src/TimePeriods/DateTimePickerInput.tsx +3 -1
  126. package/src/api/customFetch.ts +0 -9
  127. package/src/api/models.ts +9 -0
  128. package/src/api/useBulkResponse.ts +58 -0
  129. package/src/api/useGraphQuery/index.ts +108 -12
  130. package/src/components/Avatar/Avatar.stories.tsx +1 -0
  131. package/src/components/Button/Button.module.css +38 -0
  132. package/src/components/Button/Button.stories.tsx +25 -0
  133. package/src/components/Button/Button.tsx +2 -5
  134. package/src/components/CrudPage/Actions/Actions.styles.ts +15 -1
  135. package/src/components/CrudPage/Actions/Actions.tsx +7 -4
  136. package/src/components/CrudPage/Actions/Search.tsx +15 -14
  137. package/src/components/CrudPage/CrudPage.stories.tsx +1 -0
  138. package/src/components/CrudPage/CrudPageRoot.tsx +1 -1
  139. package/src/components/DataTable/DataTable.stories.tsx +1 -0
  140. package/src/components/DataTable/EmptyState/DataTableEmptyState.stories.tsx +1 -0
  141. package/src/components/DataTable/EmptyState/DataTableEmptyState.styles.ts +3 -1
  142. package/src/components/DataTable/EmptyState/DataTableEmptyState.tsx +4 -1
  143. package/src/components/DataTable/Item/DataTableItem.stories.tsx +1 -0
  144. package/src/components/Form/AccessRights/AccessRights.stories.tsx +1 -0
  145. package/src/components/Form/AccessRights/ShareInput/ShareInput.tsx +4 -3
  146. package/src/components/Form/AccessRights/ShareInput/useShareInput.tsx +15 -10
  147. package/src/components/Form/FormActions.tsx +21 -12
  148. package/src/components/Header/PageHeader/PageHeader.styles.ts +5 -5
  149. package/src/components/Layout/AreaIndicator.tsx +4 -6
  150. package/src/components/Layout/PageLayout/PageLayout.stories.tsx +1 -0
  151. package/src/components/Layout/PageLayout/PageLayout.styles.ts +1 -1
  152. package/src/components/Layout/PageLayout/PageLayout.tsx +9 -3
  153. package/src/components/Layout/PageLayout/PageLayoutActions.tsx +5 -3
  154. package/src/components/Layout/PageLayout/PageLayoutBody.tsx +5 -3
  155. package/src/components/Layout/PageLayout/PageLayoutHeader.tsx +5 -3
  156. package/src/components/Layout/PageLayout/PageQuickAccess.tsx +17 -17
  157. package/src/components/Menu/Button/MenuButton.tsx +6 -6
  158. package/src/components/Menu/MenuDivider.tsx +1 -5
  159. package/src/components/Menu/MenuItem.tsx +1 -5
  160. package/src/components/Menu/MenuItems.tsx +5 -4
  161. package/src/components/Modal/ConfirmationModal/ConfirmationModal.stories.tsx +1 -0
  162. package/src/components/Modal/ConfirmationModal/ConfirmationModal.tsx +4 -1
  163. package/src/components/Modal/Modal.stories.tsx +21 -0
  164. package/src/components/Modal/Modal.styles.ts +1 -19
  165. package/src/components/Modal/Modal.tsx +1 -1
  166. package/src/components/Modal/ModalBody.tsx +6 -4
  167. package/src/components/Modal/ModalHeader.tsx +9 -5
  168. package/src/components/Modal/modal.module.css +16 -0
  169. package/src/components/Tabs/Tab.styles.ts +0 -6
  170. package/src/components/Tabs/Tabs.tsx +37 -15
  171. package/src/index.ts +4 -0
  172. package/src/queryParameters/url/index.ts +7 -2
  173. package/src/utils/index.ts +1 -0
  174. package/src/utils/useLocale/index.ts +9 -0
  175. package/src/utils/useLocale/useLocale.cypress.spec.tsx +38 -0
  176. package/src/utils/useLocaleDateTimeFormat/index.ts +4 -2
  177. package/src/utils/usePluralizedTranslation.ts +2 -3
  178. package/src/Listing/Cell/DataCell.styles.ts +0 -27
  179. package/src/Listing/Header/Cell/ListingHeaderCell.styles.ts +0 -71
  180. package/src/Listing/Header/Cell/SelectActionListingHeaderCell.styles.ts +0 -26
  181. package/src/Listing/Header/ListingHeader.styles.ts +0 -16
  182. package/src/Listing/Listing.styles.ts +0 -78
  183. package/src/Listing/Row/EmptyRow.styles.ts +0 -14
  184. package/src/components/Button/Button.styles.ts +0 -44
  185. package/src/components/Layout/AreaIndicator.styles.ts +0 -33
  186. package/src/components/Menu/Button/MenuButton.styles.ts +0 -27
  187. package/src/components/Menu/Menu.styles.ts +0 -68
@@ -20,13 +20,13 @@ import {
20
20
  includes,
21
21
  isEmpty,
22
22
  isNil,
23
- isNotNil,
24
23
  keys,
25
24
  last,
26
25
  lt,
27
26
  map,
28
27
  negate,
29
28
  pipe,
29
+ pluck,
30
30
  prop,
31
31
  propEq,
32
32
  reduce,
@@ -73,7 +73,7 @@ const toTimeTickValue = (
73
73
  const getMetricsForIndex = (): Omit<TimeValue, 'timeTick'> => {
74
74
  const addMetricForTimeIndex = (acc, { metric_id, data }): TimeValue => ({
75
75
  ...acc,
76
- [metric_id]: data[timeIndex]
76
+ [metric_id]: data[timeIndex] === undefined ? null : data[timeIndex]
77
77
  });
78
78
 
79
79
  return reduce(addMetricForTimeIndex, {} as TimeValue, metrics);
@@ -140,6 +140,7 @@ const toLine = ({
140
140
  equals(ds_data.ds_stack, '1') || equals(ds_data.ds_stack, true)
141
141
  ? Number.parseInt(ds_data.ds_order || '0', 10)
142
142
  : null,
143
+ stackKey: ds_data.ds_stack_key || null,
143
144
  transparency: ds_data.ds_transparency,
144
145
  unit
145
146
  });
@@ -241,7 +242,10 @@ const getStackedMetricValues = ({
241
242
  timeSeries
242
243
  }: LinesTimeSeries): Array<number> => {
243
244
  const getTimeSeriesValuesForMetric = (metric_id): Array<number> =>
244
- map((timeValue) => getValueForMetric(timeValue)(metric_id), timeSeries);
245
+ map(
246
+ (timeValue) => getValueForMetric(timeValue)(metric_id) || 0,
247
+ timeSeries
248
+ );
245
249
 
246
250
  const metricsValues = pipe(
247
251
  map(prop('metric_id')) as (metric) => Array<number>,
@@ -353,6 +357,19 @@ const getScaleType = (
353
357
  const hasOnlyZeroesHasValue = (graphValues: Array<number>): boolean =>
354
358
  graphValues.every((value) => equals(value, 0) || equals(value, null));
355
359
 
360
+ const getSanitizedValues = reject(
361
+ (
362
+ value:
363
+ | number
364
+ | boolean
365
+ | typeof Number.POSITIVE_INFINITY
366
+ | typeof Number.NEGATIVE_INFINITY
367
+ ) =>
368
+ equals(value, false) ||
369
+ equals(value, Number.POSITIVE_INFINITY) ||
370
+ equals(value, Number.NEGATIVE_INFINITY)
371
+ );
372
+
356
373
  const getScale = ({
357
374
  graphValues,
358
375
  height,
@@ -363,23 +380,39 @@ const getScale = ({
363
380
  scaleLogarithmicBase,
364
381
  isHorizontal,
365
382
  invert,
366
- hasDisplayAsBar
383
+ hasDisplayAsBar,
384
+ hasLineFilled,
385
+ min,
386
+ max
367
387
  }): ScaleLinear<number, number> => {
368
388
  const isLogScale = equals(scale, 'logarithmic');
369
- const minValue = Math.min(
370
- hasDisplayAsBar && 0,
371
- invert && graphValues.every(lt(0))
372
- ? negate(getMax(graphValues))
373
- : getMin(graphValues),
374
- getMin(stackedValues),
375
- Math.min(...thresholds)
376
- );
377
- const maxValue = Math.max(
378
- getMax(graphValues),
379
- getMax(stackedValues),
380
- hasOnlyZeroesHasValue(graphValues) ? 1 : 0,
381
- Math.max(...thresholds)
382
- );
389
+ const sanitizedValuesForMinimum = min
390
+ ? [min]
391
+ : getSanitizedValues([
392
+ invert && graphValues.every(lt(0))
393
+ ? negate(getMax(graphValues))
394
+ : getMin(graphValues),
395
+ !isEmpty(stackedValues) &&
396
+ !equals(stackedValues, [0]) &&
397
+ getMin(stackedValues),
398
+ Math.min(...thresholds)
399
+ ]);
400
+ const minValue = Math.min(...sanitizedValuesForMinimum);
401
+ const minValueWithMargin =
402
+ (hasDisplayAsBar || hasLineFilled) && minValue > 0 && !min
403
+ ? 0
404
+ : minValue - Math.abs(minValue) * 0.05;
405
+
406
+ const sanitizedValuesForMaximum = max
407
+ ? [max]
408
+ : getSanitizedValues([
409
+ getMax(graphValues),
410
+ getMax(stackedValues),
411
+ hasOnlyZeroesHasValue(graphValues) ? 1 : 0,
412
+ Math.max(...thresholds)
413
+ ]);
414
+ const maxValue = Math.max(...sanitizedValuesForMaximum);
415
+ const maxValueWithMargin = maxValue + Math.abs(maxValue) * 0.05;
383
416
 
384
417
  const scaleType = getScaleType(scale);
385
418
 
@@ -387,21 +420,26 @@ const getScale = ({
387
420
  const range = [height, upperRangeValue];
388
421
 
389
422
  if (isCenteredZero) {
390
- const greatestValue = Math.max(Math.abs(maxValue), Math.abs(minValue));
423
+ const greatestValue = Math.max(
424
+ Math.abs(maxValueWithMargin),
425
+ Math.abs(minValueWithMargin)
426
+ );
391
427
 
392
428
  return scaleType<number>({
393
429
  base: scaleLogarithmicBase || 2,
394
430
  domain: [-greatestValue, greatestValue],
395
- range: isHorizontal ? range : range.reverse()
431
+ range: isHorizontal ? range : range.reverse(),
432
+ clamp: min || max
396
433
  });
397
434
  }
398
435
 
399
- const domain = [isLogScale ? 0.001 : minValue, maxValue];
436
+ const domain = [isLogScale ? 0.001 : minValueWithMargin, maxValueWithMargin];
400
437
 
401
438
  return scaleType<number>({
402
439
  base: scaleLogarithmicBase || 2,
403
440
  domain,
404
- range: isHorizontal ? range : range.reverse()
441
+ range: isHorizontal ? range : range.reverse(),
442
+ clamp: min || max
405
443
  });
406
444
  };
407
445
 
@@ -437,11 +475,19 @@ const getYScaleUnit = ({
437
475
  scaleLogarithmicBase,
438
476
  isHorizontal = true,
439
477
  unit,
440
- invert
441
- }: AxeScale & { invert?: boolean | string | null; unit: string }): ScaleLinear<
442
- number,
443
- number
444
- > => {
478
+ invert,
479
+ min,
480
+ max,
481
+ isBarChart,
482
+ boundariesUnit
483
+ }: AxeScale & {
484
+ invert?: boolean | string | null;
485
+ unit: string;
486
+ max?: number;
487
+ min?: number;
488
+ boundariesUnit?: string;
489
+ isBarChart?: boolean;
490
+ }): ScaleLinear<number, number> => {
445
491
  const [firstUnit] = getUnits(dataLines);
446
492
  const shouldApplyThresholds =
447
493
  equals(unit, thresholdUnit) || (!thresholdUnit && equals(firstUnit, unit));
@@ -468,11 +514,14 @@ const getYScaleUnit = ({
468
514
 
469
515
  return getScale({
470
516
  graphValues,
471
- hasDisplayAsBar: dataLines.some(
472
- ({ displayAs, unit: lineUnit, stackOrder }) =>
473
- equals(unit, lineUnit) &&
474
- equals(displayAs, 'bar') &&
475
- isNotNil(stackOrder)
517
+ hasDisplayAsBar:
518
+ isBarChart ||
519
+ dataLines.some(
520
+ ({ displayAs, unit: lineUnit }) =>
521
+ equals(unit, lineUnit) && equals(displayAs, 'bar')
522
+ ),
523
+ hasLineFilled: dataLines.some(
524
+ ({ unit: lineUnit, filled }) => equals(unit, lineUnit) && filled
476
525
  ),
477
526
  height: valueGraphHeight,
478
527
  invert,
@@ -481,10 +530,24 @@ const getYScaleUnit = ({
481
530
  scale,
482
531
  scaleLogarithmicBase,
483
532
  stackedValues,
484
- thresholds: shouldApplyThresholds ? thresholds : []
533
+ thresholds: shouldApplyThresholds ? thresholds : [],
534
+ min: boundaryToApplyToUnit({ unit, boundariesUnit, boundary: min }),
535
+ max: boundaryToApplyToUnit({ unit, boundariesUnit, boundary: max })
485
536
  });
486
537
  };
487
538
 
539
+ const boundaryToApplyToUnit = ({
540
+ boundary,
541
+ boundariesUnit,
542
+ unit
543
+ }): number | undefined => {
544
+ if (!boundariesUnit) {
545
+ return boundary;
546
+ }
547
+
548
+ return equals(boundariesUnit, unit) ? boundary : undefined;
549
+ };
550
+
488
551
  const getYScalePerUnit = ({
489
552
  dataLines,
490
553
  dataTimeSeries,
@@ -494,8 +557,17 @@ const getYScalePerUnit = ({
494
557
  isCenteredZero,
495
558
  scale,
496
559
  scaleLogarithmicBase,
497
- isHorizontal = true
498
- }: AxeScale): Record<string, ScaleLinear<number, number>> => {
560
+ isHorizontal = true,
561
+ isBarChart,
562
+ min,
563
+ max,
564
+ boundariesUnit
565
+ }: AxeScale & {
566
+ min?: number;
567
+ max?: number;
568
+ isBarChart?: boolean;
569
+ boundariesUnit?: string;
570
+ }): Record<string, ScaleLinear<number, number>> => {
499
571
  const units = getUnits(dataLines);
500
572
 
501
573
  const scalePerUnit = units.reduce((acc, unit) => {
@@ -514,7 +586,11 @@ const getYScalePerUnit = ({
514
586
  thresholdUnit,
515
587
  thresholds,
516
588
  unit,
517
- valueGraphHeight
589
+ valueGraphHeight,
590
+ min,
591
+ max,
592
+ isBarChart,
593
+ boundariesUnit
518
594
  })
519
595
  };
520
596
  }, {});
@@ -522,15 +598,15 @@ const getYScalePerUnit = ({
522
598
  return scalePerUnit;
523
599
  };
524
600
 
525
- const formatTime = (value: number): string => {
526
- return `${numeral(value).format('0.[00]a')} ms`;
601
+ const formatTime = ({ value, unit }): string => {
602
+ return `${numeral(value).format('0.[00]a')} ${unit}`;
527
603
  };
528
604
 
529
605
  const registerMsUnitToNumeral = (): null => {
530
606
  try {
531
607
  numeral.register('format', 'milliseconds', {
532
608
  format: (value) => {
533
- return formatTime(value);
609
+ return formatTime({ value, unit: 'ms' });
534
610
  },
535
611
  regexps: {
536
612
  format: /(ms)/,
@@ -547,6 +623,27 @@ const registerMsUnitToNumeral = (): null => {
547
623
 
548
624
  registerMsUnitToNumeral();
549
625
 
626
+ const registerSecondsUnitToNumeral = (): null => {
627
+ try {
628
+ numeral.register('format', 'seconds', {
629
+ format: (value) => {
630
+ return formatTime({ value, unit: 's' });
631
+ },
632
+ regexps: {
633
+ format: /(s)/,
634
+ unformat: /(s)/
635
+ },
636
+ unformat: () => ''
637
+ });
638
+
639
+ return null;
640
+ } catch (_) {
641
+ return null;
642
+ }
643
+ };
644
+
645
+ registerSecondsUnitToNumeral();
646
+
550
647
  const getBase1024 = ({ unit, base }): boolean => {
551
648
  const base2Units = [
552
649
  'B',
@@ -576,6 +673,7 @@ const formatMetricValue = ({
576
673
 
577
674
  const formatSuffix = cond([
578
675
  [equals('ms'), always(' ms')],
676
+ [equals('s'), always(' s')],
579
677
  [T, always(base1024 ? ' ib' : 'a')]
580
678
  ])(unit);
581
679
 
@@ -600,8 +698,6 @@ const formatMetricValueWithUnit = ({
600
698
  return null;
601
699
  }
602
700
 
603
- const base1024 = getBase1024({ base, unit });
604
-
605
701
  if (isRaw) {
606
702
  const unitText = equals('%', unit) ? unit : ` ${unit}`;
607
703
 
@@ -614,9 +710,7 @@ const formatMetricValueWithUnit = ({
614
710
 
615
711
  const formattedMetricValue = formatMetricValue({ base, unit, value });
616
712
 
617
- return base1024 || !unit || equals(unit, 'ms')
618
- ? formattedMetricValue
619
- : `${formattedMetricValue} ${unit}`;
713
+ return formattedMetricValue;
620
714
  };
621
715
 
622
716
  const bisectDate = bisector(identity).center;
@@ -666,6 +760,93 @@ export const formatMetricName = ({
666
760
  return metricName;
667
761
  };
668
762
 
763
+ export const getStackedLinesTimeSeriesPerStackAndUnit = ({
764
+ stackedLines,
765
+ timeSeries,
766
+ invert
767
+ }: {
768
+ stackedLines: Array<Line>;
769
+ timeSeries: Array<TimeValue>;
770
+ invert?: boolean;
771
+ }): {
772
+ stackedLinesTimeSeriesPerStackKeyAndUnit: Record<
773
+ string,
774
+ { lines: Array<Line>; timeSeries: Array<TimeValue> }
775
+ >;
776
+ stackedKeys: Record<string, null>;
777
+ } => {
778
+ const stackedKeys = stackedLines.reduce(
779
+ (acc, { unit, stackKey }) => ({
780
+ ...acc,
781
+ [`stacked-${unit || ''}-${stackKey ? stackKey : ''}`]: null
782
+ }),
783
+ {}
784
+ );
785
+ const stackedKeysWithOnlyStackKey = Object.keys(stackedKeys).filter(
786
+ (stackKey: string) => stackKey.split('-')[2]
787
+ );
788
+ const stackedKeysWithOnlyUnit = Object.keys(stackedKeys).filter(
789
+ (stackKey: string) => !stackKey.split('-')[2]
790
+ );
791
+
792
+ const stackedLinesTimeSeriesPerStackKey = stackedKeysWithOnlyStackKey.reduce(
793
+ (acc, stackedKey: string) => {
794
+ const [, stackUnit, stackKey] = stackedKey.split('-');
795
+ const relatedLines = stackedLines.filter(({ unit, stackKey: key }) => {
796
+ return stackUnit === (unit || '') && stackKey === key;
797
+ });
798
+
799
+ return {
800
+ ...acc,
801
+ [stackedKey]: {
802
+ lines: relatedLines,
803
+ timeSeries: getTimeSeriesForLines({
804
+ invert,
805
+ lines: relatedLines,
806
+ timeSeries
807
+ })
808
+ }
809
+ };
810
+ },
811
+ {}
812
+ );
813
+ const affectedLinesPerStackKey = flatten(
814
+ pluck('lines', Object.values(stackedLinesTimeSeriesPerStackKey))
815
+ );
816
+ const stackedLinesTimeSeriesPerUnit = stackedKeysWithOnlyUnit.reduce(
817
+ (acc, stackedKey: string) => {
818
+ const [, stackUnit] = stackedKey.split('-');
819
+ const relatedLines = stackedLines.filter(
820
+ (line) =>
821
+ !affectedLinesPerStackKey.some(
822
+ (affectedLine) => line.metric_id === affectedLine.metric_id
823
+ ) && stackUnit === (line.unit || '')
824
+ );
825
+
826
+ return {
827
+ ...acc,
828
+ [stackedKey]: {
829
+ lines: relatedLines,
830
+ timeSeries: getTimeSeriesForLines({
831
+ lines: relatedLines,
832
+ timeSeries,
833
+ invert
834
+ })
835
+ }
836
+ };
837
+ },
838
+ {}
839
+ );
840
+
841
+ return {
842
+ stackedLinesTimeSeriesPerStackKeyAndUnit: {
843
+ ...stackedLinesTimeSeriesPerStackKey,
844
+ ...stackedLinesTimeSeriesPerUnit
845
+ },
846
+ stackedKeys
847
+ };
848
+ };
849
+
669
850
  export {
670
851
  getTimeSeries,
671
852
  getLineData,
@@ -9,7 +9,8 @@ interface DsData {
9
9
  ds_invert: string | null;
10
10
  ds_legend: string | null;
11
11
  ds_order: string | null;
12
- ds_stack: string | null;
12
+ ds_stack: string | boolean | null;
13
+ ds_stack_key?: string | null;
13
14
  ds_transparency: number;
14
15
  }
15
16
 
@@ -20,7 +21,7 @@ export interface Metric {
20
21
  critical_low_threshold: number | null;
21
22
  data: Array<number | null>;
22
23
  displayAs?: 'line' | 'bar';
23
- ds_data?: DsData;
24
+ ds_data: DsData;
24
25
  legend: string;
25
26
  maximum_value: number | null;
26
27
  metric: string;
@@ -29,6 +30,8 @@ export interface Metric {
29
30
  unit: string;
30
31
  warning_high_threshold: number | null;
31
32
  warning_low_threshold: number | null;
33
+ service_name: string | null;
34
+ host_name: string | null;
32
35
  }
33
36
 
34
37
  type TimeSeries = { timeTick: string };
@@ -54,6 +57,7 @@ export interface Line {
54
57
  minimum_value: number | null;
55
58
  name: string;
56
59
  stackOrder: number | null;
60
+ stackKey: string | null;
57
61
  transparency: number;
58
62
  unit: string;
59
63
  }
@@ -4,9 +4,11 @@ import {
4
4
  always,
5
5
  cond,
6
6
  equals,
7
+ flatten,
7
8
  gt,
8
9
  gte,
9
10
  head,
11
+ isEmpty,
10
12
  isNil,
11
13
  last,
12
14
  length,
@@ -18,10 +20,12 @@ import {
18
20
 
19
21
  import { Theme, darken, getLuminance, lighten } from '@mui/material';
20
22
 
23
+ import dayjs from 'dayjs';
21
24
  import { BarStyle } from '../BarChart/models';
25
+ import { margin } from '../Chart/common';
22
26
  import { LineStyle } from '../Chart/models';
23
27
  import { Threshold, Thresholds } from './models';
24
- import { formatMetricValue } from './timeSeries';
28
+ import { formatMetricValueWithUnit } from './timeSeries';
25
29
  import { Line, TimeValue } from './timeSeries/models';
26
30
 
27
31
  interface GetColorFromDataAndThresholdsProps {
@@ -220,23 +224,29 @@ export const getFormattedAxisValues = ({
220
224
  lines,
221
225
  threshold
222
226
  }: GetFormattedAxisValuesProps): Array<string> => {
223
- const metricId = (lines.find(({ unit }) => equals(unit, axisUnit)) as Line)
224
- ?.metric_id;
227
+ const filteredMetrics = lines.filter(({ unit }) => equals(unit, axisUnit));
225
228
 
226
- if (isNil(metricId)) {
229
+ if (isEmpty(filteredMetrics)) {
227
230
  return [];
228
231
  }
229
- const formattedData = timeSeries.map((data) =>
230
- formatMetricValue({
231
- value: data[metricId],
232
- unit: axisUnit,
233
- base
234
- })
232
+
233
+ const metricIds = pluck('metric_id', filteredMetrics);
234
+
235
+ const formattedData = metricIds.map((metricId) =>
236
+ timeSeries.map((data) =>
237
+ formatMetricValueWithUnit({
238
+ value: data[metricId],
239
+ unit: axisUnit,
240
+ base
241
+ })
242
+ )
235
243
  );
236
244
 
245
+ const flattenedFormattedData = flatten(formattedData);
246
+
237
247
  const formattedThresholdValues = equals(thresholdUnit, axisUnit)
238
248
  ? threshold.map(({ value }) =>
239
- formatMetricValue({
249
+ formatMetricValueWithUnit({
240
250
  value,
241
251
  unit: axisUnit,
242
252
  base
@@ -244,7 +254,30 @@ export const getFormattedAxisValues = ({
244
254
  ) || []
245
255
  : [];
246
256
 
247
- return formattedData
257
+ return flattenedFormattedData
248
258
  .concat(formattedThresholdValues)
249
259
  .filter((v) => v) as Array<string>;
250
260
  };
261
+
262
+ interface ComputeGElementMarginLeftProps {
263
+ maxCharacters: number;
264
+ hasSecondUnit?: boolean;
265
+ }
266
+
267
+ export const computeGElementMarginLeft = ({
268
+ maxCharacters,
269
+ hasSecondUnit
270
+ }: ComputeGElementMarginLeftProps): number =>
271
+ maxCharacters * 5 + (hasSecondUnit ? margin.top * 0.8 : margin.top * 0.6);
272
+
273
+ export const computPixelsToShiftMouse = (xScale): number => {
274
+ const domain = xScale.domain();
275
+
276
+ const hoursDiffInGraph = dayjs(domain[1]).diff(domain[0], 'h');
277
+
278
+ if (!hoursDiffInGraph) {
279
+ return 0;
280
+ }
281
+
282
+ return Math.round(8 / hoursDiffInGraph);
283
+ };
@@ -1,3 +1,4 @@
1
+ export type { ParentSizeProps } from '@visx/responsive/lib/components/ParentSize';
1
2
  export { default as LineChart } from './Chart';
2
3
  export { default as ThresholdLines } from './Chart/BasicComponents/Lines/Threshold';
3
4
  export { default as useLineChartData } from './Chart/useChartData';
@@ -5,13 +6,14 @@ export { default as BarChart } from './BarChart/BarChart';
5
6
  export { Gauge } from './Gauge';
6
7
  export { SingleBar } from './SingleBar';
7
8
  export { Text as GraphText } from './Text';
9
+ export { default as Header } from './common/BaseChart/Header';
8
10
 
9
11
  export { HeatMap } from './HeatMap';
10
12
  export { BarStack } from './BarStack';
11
13
  export { PieChart } from './PieChart';
12
14
  export { Timeline } from './Timeline';
13
15
  export * from './Tree';
14
- export type { LineChartData } from './common/models';
16
+ export type { LineChartData, Threshold, Thresholds } from './common/models';
15
17
  export * from './common/timeSeries';
16
18
  export type { Metric } from './common/timeSeries/models';
17
19
  export * from './Chart/models';
@@ -0,0 +1,74 @@
1
+ {
2
+ "global": {},
3
+ "metrics": [
4
+ {
5
+ "metric": "count",
6
+ "metric_id": 1,
7
+ "legend": "count",
8
+ "displayAs": "bar",
9
+ "ds_data": {
10
+ "ds_stack": true,
11
+ "ds_transparency": 0,
12
+ "ds_filled": false,
13
+ "ds_color_area": "#4269d0",
14
+ "ds_color_line": "#4269d0"
15
+ },
16
+ "datasourceOptions": {
17
+ "field": null,
18
+ "group_by": null,
19
+ "op": "count-doc",
20
+ "query": "severity_text:\"Fatal\" OR severity_text:\"Error\"",
21
+ "period": 3600
22
+ },
23
+ "data": [
24
+ 217, 270, 293, 300, 303, 295, 298, 283, 299, 299, 297, 285, 270, 248,
25
+ 274, 292, 284, 47
26
+ ]
27
+ },
28
+ {
29
+ "metric": "count",
30
+ "metric_id": 2,
31
+ "legend": "count",
32
+ "displayAs": "bar",
33
+ "ds_data": {
34
+ "ds_stack": true,
35
+ "ds_transparency": 0,
36
+ "ds_filled": false,
37
+ "ds_color_area": "#efb118",
38
+ "ds_color_line": "#efb118"
39
+ },
40
+ "datasourceOptions": {
41
+ "field": null,
42
+ "group_by": null,
43
+ "op": "count-doc",
44
+ "query": "",
45
+ "period": 3600
46
+ },
47
+ "data": [
48
+ 32, 825, 939, 922, 918, 939, 943, 947, 946, 909, 931, 939, 883, 907,
49
+ 928, 904, 923, 893, 139
50
+ ]
51
+ }
52
+ ],
53
+ "times": [
54
+ "2025-10-04T16:19:30.000Z",
55
+ "2025-10-04T16:20:00.000Z",
56
+ "2025-10-04T16:20:30.000Z",
57
+ "2025-10-04T16:21:00.000Z",
58
+ "2025-10-04T16:21:30.000Z",
59
+ "2025-10-04T16:22:00.000Z",
60
+ "2025-10-04T16:22:30.000Z",
61
+ "2025-10-04T16:23:00.000Z",
62
+ "2025-10-04T16:23:30.000Z",
63
+ "2025-10-04T16:24:00.000Z",
64
+ "2025-10-04T16:24:30.000Z",
65
+ "2025-10-04T16:25:00.000Z",
66
+ "2025-10-04T16:25:30.000Z",
67
+ "2025-10-04T16:26:00.000Z",
68
+ "2025-10-04T16:26:30.000Z",
69
+ "2025-10-04T16:27:00.000Z",
70
+ "2025-10-04T16:27:30.000Z",
71
+ "2025-10-04T16:28:00.000Z",
72
+ "2025-10-04T16:28:30.000Z"
73
+ ]
74
+ }