@centreon/ui 24.10.12 → 24.10.13

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 (153) hide show
  1. package/package.json +3 -2
  2. package/public/mockServiceWorker.js +1 -1
  3. package/src/Button/Icon/index.tsx +3 -1
  4. package/src/Dashboard/Dashboard.styles.ts +3 -4
  5. package/src/Dashboard/DashboardLayout.stories.tsx +1 -1
  6. package/src/Dashboard/Grid.tsx +11 -17
  7. package/src/Dashboard/Layout.tsx +27 -56
  8. package/src/Dialog/UnsavedChanges/index.tsx +15 -13
  9. package/src/Dialog/UnsavedChanges/translatedLabels.ts +15 -13
  10. package/src/Form/Form.tsx +0 -1
  11. package/src/Form/Inputs/Autocomplete.tsx +1 -1
  12. package/src/Form/Inputs/ConnectedAutocomplete.tsx +5 -2
  13. package/src/Form/Inputs/Grid.tsx +7 -1
  14. package/src/Form/Inputs/Radio.tsx +1 -1
  15. package/src/Form/Inputs/Switch.tsx +1 -1
  16. package/src/Form/Inputs/Text.tsx +1 -1
  17. package/src/Form/Inputs/index.tsx +25 -24
  18. package/src/Form/Inputs/models.ts +2 -0
  19. package/src/Graph/BarChart/BarChart.cypress.spec.tsx +3 -3
  20. package/src/Graph/BarChart/BarChart.tsx +24 -31
  21. package/src/Graph/BarChart/BarGroup.tsx +32 -59
  22. package/src/Graph/BarChart/BarStack.tsx +64 -13
  23. package/src/Graph/BarChart/MemoizedGroup.tsx +123 -0
  24. package/src/Graph/BarChart/ResponsiveBarChart.tsx +21 -7
  25. package/src/Graph/BarStack/BarStack.cypress.spec.tsx +87 -9
  26. package/src/Graph/BarStack/BarStack.stories.tsx +13 -4
  27. package/src/Graph/BarStack/BarStack.styles.ts +57 -33
  28. package/src/Graph/BarStack/Graph.tsx +173 -0
  29. package/src/Graph/BarStack/GraphAndLegend.tsx +117 -0
  30. package/src/Graph/BarStack/ResponsiveBarStack.tsx +61 -168
  31. package/src/Graph/BarStack/constants.ts +5 -0
  32. package/src/Graph/BarStack/models.ts +0 -1
  33. package/src/Graph/BarStack/useGraphAndLegend.ts +84 -0
  34. package/src/Graph/BarStack/useResponsiveBarStack.ts +73 -97
  35. package/src/Graph/Chart/Chart.cypress.spec.tsx +14 -26
  36. package/src/Graph/Chart/Chart.stories.tsx +1 -1
  37. package/src/Graph/Chart/Chart.tsx +53 -37
  38. package/src/Graph/Chart/InteractiveComponents/AnchorPoint/GuidingLines.tsx +3 -3
  39. package/src/Graph/Chart/InteractiveComponents/AnchorPoint/useTickGraph.ts +19 -6
  40. package/src/Graph/Chart/Legend/Legend.styles.ts +25 -11
  41. package/src/Graph/Chart/Legend/index.tsx +6 -24
  42. package/src/Graph/Chart/index.tsx +34 -43
  43. package/src/Graph/Chart/models.ts +0 -1
  44. package/src/Graph/Chart/useChartData.ts +19 -1
  45. package/src/Graph/HeatMap/ResponsiveHeatMap.tsx +20 -2
  46. package/src/Graph/HeatMap/model.ts +6 -2
  47. package/src/Graph/Legend/Legend.styles.ts +10 -0
  48. package/src/Graph/Legend/Legend.tsx +6 -1
  49. package/src/Graph/SingleBar/ResponsiveSingleBar.tsx +9 -10
  50. package/src/Graph/SingleBar/ThresholdLine.tsx +6 -6
  51. package/src/Graph/Text/Text.styles.ts +2 -2
  52. package/src/Graph/Text/Text.tsx +23 -10
  53. package/src/Graph/Timeline/ResponsiveTimeline.tsx +152 -0
  54. package/src/Graph/Timeline/Timeline.cypress.spec.tsx +148 -0
  55. package/src/Graph/Timeline/Timeline.stories.tsx +91 -0
  56. package/src/Graph/Timeline/Timeline.tsx +28 -0
  57. package/src/Graph/Timeline/index.ts +1 -0
  58. package/src/Graph/Timeline/models.ts +20 -0
  59. package/src/Graph/Timeline/timeline.styles.ts +11 -0
  60. package/src/Graph/Timeline/translatedLabel.ts +6 -0
  61. package/src/Graph/Timeline/useTimeline.ts +90 -0
  62. package/src/Graph/Tree/Links.tsx +2 -2
  63. package/src/Graph/Tree/Tree.tsx +2 -2
  64. package/src/Graph/Tree/constants.ts +1 -1
  65. package/src/Graph/common/Axes/index.tsx +1 -1
  66. package/src/Graph/common/Axes/useAxisY.ts +8 -4
  67. package/src/Graph/common/BaseChart/BaseChart.tsx +3 -12
  68. package/src/Graph/common/BaseChart/ChartSvgWrapper.tsx +12 -4
  69. package/src/Graph/common/BaseChart/Header/index.tsx +3 -1
  70. package/src/Graph/common/BaseChart/useComputeBaseChartDimensions.ts +23 -11
  71. package/src/Graph/common/BaseChart/useComputeYAxisMaxCharacters.ts +92 -0
  72. package/src/Graph/common/models.ts +7 -8
  73. package/src/Graph/common/timeSeries/index.test.ts +1 -1
  74. package/src/Graph/common/timeSeries/index.ts +56 -29
  75. package/src/Graph/common/timeSeries/models.ts +2 -0
  76. package/src/Graph/common/utils.ts +51 -3
  77. package/src/Graph/index.ts +4 -1
  78. package/src/Graph/mockedData/lastDayWithNullValues.json +6 -6
  79. package/src/Graph/mockedData/pingServiceLinesBars.json +47 -47
  80. package/src/Icon/DowntimeIcon.tsx +8 -1
  81. package/src/Icon/FlappingIcon.tsx +22 -0
  82. package/src/Icon/index.ts +1 -0
  83. package/src/InputField/Select/Autocomplete/Connected/Multi/index.test.tsx +21 -1
  84. package/src/InputField/Select/Autocomplete/Connected/index.test.tsx +2 -2
  85. package/src/InputField/Select/Autocomplete/Connected/index.tsx +52 -15
  86. package/src/InputField/Select/Autocomplete/Multi/index.stories.tsx +19 -0
  87. package/src/InputField/Select/Autocomplete/Multi/index.tsx +8 -5
  88. package/src/InputField/Select/Autocomplete/index.tsx +79 -54
  89. package/src/InputField/Text/index.tsx +6 -4
  90. package/src/InputField/translatedLabels.ts +2 -0
  91. package/src/Listing/ActionBar/index.tsx +1 -1
  92. package/src/Listing/Listing.styles.ts +3 -3
  93. package/src/Listing/index.tsx +40 -37
  94. package/src/Listing/models.ts +0 -8
  95. package/src/Listing/useStyleTable.ts +58 -32
  96. package/src/MultiSelectEntries/index.tsx +2 -0
  97. package/src/PopoverMenu/index.tsx +2 -9
  98. package/src/SortableItems/index.tsx +0 -1
  99. package/src/ThemeProvider/index.tsx +1 -1
  100. package/src/ThemeProvider/palettes.ts +6 -0
  101. package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/PickersStartEndDate.tsx +2 -3
  102. package/src/TimePeriods/DateTimePickerInput.tsx +3 -1
  103. package/src/api/buildListingEndpoint/getSearchQueryParameterValue.ts +7 -1
  104. package/src/api/buildListingEndpoint/models.ts +1 -0
  105. package/src/api/customFetch.ts +4 -1
  106. package/src/api/models.ts +9 -0
  107. package/src/api/useGraphQuery/index.ts +117 -20
  108. package/src/api/useGraphQuery/models.ts +1 -0
  109. package/src/api/useMutationQuery/index.ts +1 -1
  110. package/src/components/DataTable/DataTable.styles.ts +1 -1
  111. package/src/components/DataTable/EmptyState/DataTableEmptyState.styles.ts +2 -1
  112. package/src/components/DataTable/EmptyState/DataTableEmptyState.tsx +4 -1
  113. package/src/components/DataTable/Item/DataTableItem.styles.ts +28 -2
  114. package/src/components/DataTable/Item/DataTableItem.tsx +19 -4
  115. package/src/components/Form/FormActions.tsx +21 -12
  116. package/src/components/Layout/AreaIndicator.tsx +1 -1
  117. package/src/components/Layout/PageLayout/PageLayout.styles.ts +2 -7
  118. package/src/components/Layout/PageLayout/PageLayoutBody.tsx +0 -1
  119. package/src/components/Zoom/Zoom.tsx +9 -2
  120. package/src/components/Zoom/ZoomContent.tsx +143 -136
  121. package/src/components/Zoom/models.ts +18 -15
  122. package/src/components/Zoom/useMinimap.ts +5 -8
  123. package/src/components/Zoom/useZoom.ts +3 -3
  124. package/src/index.ts +2 -0
  125. package/src/utils/index.ts +1 -0
  126. package/src/utils/useLocale/index.ts +9 -0
  127. package/src/utils/useLocale/useLocale.cypress.spec.tsx +38 -0
  128. package/src/utils/useLocaleDateTimeFormat/index.ts +4 -2
  129. package/src/utils/usePluralizedTranslation.ts +2 -3
  130. package/src/Graph/common/timeSeries/index.test.ts-E +0 -622
  131. package/src/components/CrudPage/Actions/Actions.styles.ts +0 -16
  132. package/src/components/CrudPage/Actions/Actions.tsx +0 -24
  133. package/src/components/CrudPage/Actions/AddButton.tsx +0 -23
  134. package/src/components/CrudPage/Actions/Filters.tsx +0 -25
  135. package/src/components/CrudPage/Actions/Search.tsx +0 -31
  136. package/src/components/CrudPage/Actions/useSearch.tsx +0 -24
  137. package/src/components/CrudPage/Columns/Actions.tsx +0 -88
  138. package/src/components/CrudPage/CrudPage.cypress.spec.tsx +0 -559
  139. package/src/components/CrudPage/CrudPage.stories.tsx +0 -278
  140. package/src/components/CrudPage/CrudPageRoot.tsx +0 -142
  141. package/src/components/CrudPage/DeleteModal.tsx +0 -77
  142. package/src/components/CrudPage/Form/AddModal.tsx +0 -35
  143. package/src/components/CrudPage/Form/Buttons.tsx +0 -98
  144. package/src/components/CrudPage/Form/UpdateModal.tsx +0 -60
  145. package/src/components/CrudPage/Listing.tsx +0 -63
  146. package/src/components/CrudPage/atoms.ts +0 -30
  147. package/src/components/CrudPage/hooks/useDeleteItem.ts +0 -53
  148. package/src/components/CrudPage/hooks/useGetItem.ts +0 -36
  149. package/src/components/CrudPage/hooks/useGetItems.ts +0 -67
  150. package/src/components/CrudPage/hooks/useListingQueryKey.ts +0 -31
  151. package/src/components/CrudPage/index.tsx +0 -7
  152. package/src/components/CrudPage/models.ts +0 -118
  153. package/src/components/CrudPage/utils.ts +0 -4
@@ -0,0 +1,91 @@
1
+ import { Meta, StoryObj } from '@storybook/react';
2
+
3
+ import { Typography } from '@mui/material';
4
+ import Timeline from './Timeline';
5
+
6
+ const data = [
7
+ {
8
+ start: '2024-09-25T21:00:42+01:00',
9
+ end: '2024-09-25T21:15:00+01:00',
10
+ color: 'gray'
11
+ },
12
+ {
13
+ start: '2024-09-25T21:15:00+01:00',
14
+ end: '2024-09-25T21:54:00+01:00',
15
+ color: 'green'
16
+ },
17
+ {
18
+ start: '2024-09-25T21:54:00+01:00',
19
+ end: '2024-09-25T22:30:00+01:00',
20
+ color: 'red'
21
+ }
22
+ ];
23
+
24
+ const startDate = '2024-09-25T21:00:42+01:00';
25
+ const endDate = '2024-09-25T22:30:00+01:00';
26
+
27
+ const Template = (args): JSX.Element => {
28
+ return (
29
+ <div style={{ width: '700px', height: '100px' }}>
30
+ <Timeline {...args} />
31
+ </div>
32
+ );
33
+ };
34
+
35
+ const meta: Meta<typeof Timeline> = {
36
+ component: Timeline,
37
+ parameters: {
38
+ chromatic: {
39
+ delay: 1000
40
+ }
41
+ },
42
+ render: Template
43
+ };
44
+
45
+ export default meta;
46
+ type Story = StoryObj<typeof Timeline>;
47
+
48
+ export const Normal: Story = {
49
+ args: {
50
+ data,
51
+ startDate,
52
+ endDate
53
+ }
54
+ };
55
+
56
+ export const WithoutData: Story = {
57
+ args: {
58
+ data: [],
59
+ startDate,
60
+ endDate
61
+ }
62
+ };
63
+
64
+ export const WithSmallerTimeRangeThanData: Story = {
65
+ args: {
66
+ data,
67
+ startDate,
68
+ endDate: '2024-09-25T22:00:00+01:00'
69
+ }
70
+ };
71
+
72
+ export const WithCustomTooltip: Story = {
73
+ args: {
74
+ data,
75
+ startDate,
76
+ endDate,
77
+ TooltipContent: ({ duration, color }) => (
78
+ <div style={{ display: 'flex', flexDirection: 'row', gap: '8px' }}>
79
+ <div
80
+ style={{
81
+ backgroundColor: color,
82
+ width: '20px',
83
+ height: '20px',
84
+ borderRadius: '4px'
85
+ }}
86
+ />
87
+ <Typography>{duration}</Typography>
88
+ </div>
89
+ )
90
+ }
91
+ };
@@ -0,0 +1,28 @@
1
+ import { ParentSize } from '../..';
2
+
3
+ import ResponsiveTimeline from './ResponsiveTimeline';
4
+
5
+ const Timeline = ({
6
+ data,
7
+ startDate,
8
+ endDate,
9
+ TooltipContent,
10
+ tooltipClassName,
11
+ ...rest
12
+ }): JSX.Element => (
13
+ <ParentSize {...rest}>
14
+ {({ width, height }) => (
15
+ <ResponsiveTimeline
16
+ data={data}
17
+ startDate={startDate}
18
+ endDate={endDate}
19
+ TooltipContent={TooltipContent}
20
+ tooltipClassName={tooltipClassName}
21
+ height={height}
22
+ width={width}
23
+ />
24
+ )}
25
+ </ParentSize>
26
+ );
27
+
28
+ export default Timeline;
@@ -0,0 +1 @@
1
+ export { default as Timeline } from './Timeline';
@@ -0,0 +1,20 @@
1
+ export interface Data {
2
+ start: string;
3
+ end: string;
4
+ color: string;
5
+ }
6
+
7
+ export interface Tooltip {
8
+ start: string;
9
+ end: string;
10
+ color: string;
11
+ duration: string;
12
+ }
13
+
14
+ export interface TimelineProps {
15
+ data: Array<Data>;
16
+ startDate: string;
17
+ endDate: string;
18
+ TooltipContent?: (props: Tooltip) => JSX.Element;
19
+ tooltipClassName?: string;
20
+ }
@@ -0,0 +1,11 @@
1
+ import { makeStyles } from 'tss-react/mui';
2
+
3
+ export const useStyles = makeStyles()((theme) => ({
4
+ tooltip: {
5
+ backgroundColor: theme.palette.background.paper,
6
+ color: theme.palette.text.primary,
7
+ padding: theme.spacing(1),
8
+ boxShadow: theme.shadows[3],
9
+ maxWidth: 'none'
10
+ }
11
+ }));
@@ -0,0 +1,6 @@
1
+ export const labelYear = 'year';
2
+ export const labelMonth = 'month';
3
+ export const labelDay = 'day';
4
+ export const labelHour = 'hour';
5
+ export const labelMinutes = 'minutes';
6
+ export const labelMinute = 'minute';
@@ -0,0 +1,90 @@
1
+ import dayjs, { Dayjs } from 'dayjs';
2
+
3
+ import { usePluralizedTranslation } from '@centreon/ui';
4
+ import { lt } from 'ramda';
5
+ import { useCallback } from 'react';
6
+ import {
7
+ labelDay,
8
+ labelHour,
9
+ labelMinute,
10
+ labelMonth,
11
+ labelYear
12
+ } from './translatedLabel';
13
+
14
+ interface StartEndProps {
15
+ start: Dayjs;
16
+ end: Dayjs;
17
+ }
18
+
19
+ interface GetWidthProps extends StartEndProps {
20
+ timezone: string;
21
+ xScale;
22
+ }
23
+
24
+ interface UseTimelineState {
25
+ getTimeDifference: (props: StartEndProps) => string;
26
+ getWidth: (props: GetWidthProps) => number;
27
+ }
28
+
29
+ export const useTimeline = (): UseTimelineState => {
30
+ const { pluralizedT } = usePluralizedTranslation();
31
+
32
+ const getTimeDifference = useCallback(
33
+ ({ start, end }: StartEndProps): string => {
34
+ const diffInMilliseconds = end.diff(start);
35
+ const diffDuration = dayjs.duration(diffInMilliseconds);
36
+
37
+ const timeUnits = [
38
+ {
39
+ value: diffDuration.years(),
40
+ unit: pluralizedT({ label: labelYear, count: diffDuration.years() })
41
+ },
42
+ {
43
+ value: diffDuration.months(),
44
+ unit: pluralizedT({ label: labelMonth, count: diffDuration.months() })
45
+ },
46
+ {
47
+ value: diffDuration.days(),
48
+ unit: pluralizedT({ label: labelDay, count: diffDuration.days() })
49
+ },
50
+ {
51
+ value: diffDuration.hours(),
52
+ unit: pluralizedT({ label: labelHour, count: diffDuration.hours() })
53
+ },
54
+ {
55
+ value: diffDuration.minutes(),
56
+ unit: pluralizedT({
57
+ label: labelMinute,
58
+ count: diffDuration.minutes()
59
+ })
60
+ }
61
+ ];
62
+
63
+ const readableUnits = timeUnits
64
+ .filter((unit) => unit.value > 0)
65
+ .map((unit) => `${unit.value} ${unit.unit}`);
66
+
67
+ return readableUnits.slice(0, 2).join(', ');
68
+ },
69
+ []
70
+ );
71
+
72
+ const getWidth = useCallback(
73
+ ({ start, end, timezone, xScale }: GetWidthProps): number => {
74
+ const baseWidth =
75
+ xScale(dayjs(end).tz(timezone)) - xScale(dayjs(start).tz(timezone));
76
+
77
+ if (Number.isNaN(baseWidth) || lt(baseWidth, 0)) {
78
+ return 0;
79
+ }
80
+
81
+ return baseWidth;
82
+ },
83
+ []
84
+ );
85
+
86
+ return {
87
+ getTimeDifference,
88
+ getWidth
89
+ };
90
+ };
@@ -26,7 +26,7 @@ const Links = <TData extends BaseProp>({
26
26
  }: Props<TData>): Array<JSX.Element> => {
27
27
  const theme = useTheme();
28
28
 
29
- return links.map((link) => {
29
+ return links.map((link, idx) => {
30
30
  const ancestorIds = link.target
31
31
  .ancestors()
32
32
  .map((ancestor) => ancestor.data.data.id);
@@ -37,7 +37,7 @@ const Links = <TData extends BaseProp>({
37
37
 
38
38
  const LinkComponent = getLinkComponent(treeLink?.type);
39
39
 
40
- const key = `${link.source.data.data.id}-${link.source.data.data.name}-${ancestorIds}_${link.target.data.data.id}-${link.target.data.data.name}-${descendantIds}`;
40
+ const key = `${link.source.data.data.id}-${link.source.data.data.name}-${ancestorIds}_${link.target.data.data.id}-${link.target.data.data.name}-${descendantIds}-${idx}`;
41
41
 
42
42
  return (
43
43
  <LinkComponent
@@ -84,10 +84,10 @@ export const Tree = <TData extends BaseProp>({
84
84
  );
85
85
 
86
86
  return (
87
- <Group left={node.width}>
87
+ <Group left={node.width / 2}>
88
88
  <VisxTree
89
89
  left={0}
90
- nodeSize={[node.width + nodeMargins.y, node.height + nodeMargins.x]}
90
+ nodeSize={[node.height + nodeMargins.x, node.height + node.width]}
91
91
  root={hierarchy(formattedTree, getExpanded)}
92
92
  separation={() => 1}
93
93
  size={[containerWidth, containerHeight]}
@@ -1,2 +1,2 @@
1
1
  export const margins = { bottom: 30, left: 30, right: 30, top: 30 };
2
- export const nodeMargins = { x: 90, y: 16 };
2
+ export const nodeMargins = { x: 2 };
@@ -97,7 +97,7 @@ const Axes = ({
97
97
  tickLabelProps={() => ({
98
98
  ...axisLeft.tickLabelProps(),
99
99
  angle: yAxisTickLabelRotation,
100
- dx: isHorizontal ? -8 : 4,
100
+ dx: isHorizontal ? -4 : 4,
101
101
  dy: isHorizontal ? 4 : -6
102
102
  })}
103
103
  tickLength={2}
@@ -1,14 +1,14 @@
1
1
  import { useMemo } from 'react';
2
2
 
3
- import { Axis } from '@visx/visx';
3
+ import type { Axis } from '@visx/visx';
4
4
  import { isNil } from 'ramda';
5
5
 
6
6
  import { useTheme } from '@mui/material';
7
7
 
8
- import { formatMetricValue, getUnits } from '../timeSeries';
8
+ import { formatMetricValueWithUnit, getUnits } from '../timeSeries';
9
9
  import { commonTickLabelProps } from '../utils';
10
10
 
11
- import { Data, LabelProps } from './models';
11
+ import type { Data, LabelProps } from './models';
12
12
 
13
13
  interface AxisYData {
14
14
  displayUnit: boolean;
@@ -69,7 +69,11 @@ const useAxisY = ({
69
69
  return '';
70
70
  }
71
71
 
72
- return formatMetricValue({ base: data.baseAxis, unit, value }) as string;
72
+ return formatMetricValueWithUnit({
73
+ base: data.baseAxis,
74
+ unit,
75
+ value
76
+ }) as string;
73
77
  };
74
78
 
75
79
  const labelProps = ({
@@ -1,10 +1,4 @@
1
- import {
2
- Dispatch,
3
- MutableRefObject,
4
- ReactNode,
5
- SetStateAction,
6
- useMemo
7
- } from 'react';
1
+ import { Dispatch, MutableRefObject, SetStateAction, useMemo } from 'react';
8
2
 
9
3
  import { equals, gt, isNil, lte, reduce } from 'ramda';
10
4
 
@@ -12,8 +6,8 @@ import { Stack } from '@mui/material';
12
6
 
13
7
  import Legend from '../../Chart/Legend';
14
8
  import { legendWidth } from '../../Chart/Legend/Legend.styles';
9
+ import { LegendModel } from '../../Chart/models';
15
10
  import { Line } from '../timeSeries/models';
16
-
17
11
  import Header from './Header';
18
12
  import { LineChartHeader } from './Header/models';
19
13
  import { useBaseChartStyles } from './useBaseChartStyles';
@@ -25,12 +19,9 @@ interface Props {
25
19
  header?: LineChartHeader;
26
20
  height: number | null;
27
21
  isHorizontal?: boolean;
28
- legend: {
22
+ legend: Pick<LegendModel, 'renderExtraComponent' | 'placement' | 'mode'> & {
29
23
  displayLegend: boolean;
30
24
  legendHeight?: number;
31
- mode?: 'grid' | 'list';
32
- placement?: 'left' | 'right' | 'bottom';
33
- renderExtraComponent?: ReactNode;
34
25
  };
35
26
  legendRef: MutableRefObject<HTMLDivElement | null>;
36
27
  limitLegend?: number | false;
@@ -9,8 +9,6 @@ import Axes from '../Axes';
9
9
  import Grids from '../Grids';
10
10
  import { Line, TimeValue } from '../timeSeries/models';
11
11
 
12
- import { extraMargin } from './useComputeBaseChartDimensions';
13
-
14
12
  interface Props {
15
13
  allUnits: Array<string>;
16
14
  axis?: ChartAxis;
@@ -27,6 +25,8 @@ interface Props {
27
25
  svgRef: MutableRefObject<SVGSVGElement | null>;
28
26
  timeSeries: Array<TimeValue>;
29
27
  xScale;
28
+ maxAxisCharacters?: number;
29
+ hasSecondUnit?: boolean;
30
30
  }
31
31
 
32
32
  const ChartSvgWrapper = ({
@@ -44,7 +44,9 @@ const ChartSvgWrapper = ({
44
44
  axis,
45
45
  children,
46
46
  orientation = 'horizontal',
47
- allUnits
47
+ allUnits,
48
+ maxAxisCharacters = 0,
49
+ hasSecondUnit
48
50
  }: Props): JSX.Element => {
49
51
  const isHorizontal = equals(orientation, 'horizontal');
50
52
 
@@ -55,7 +57,13 @@ const ChartSvgWrapper = ({
55
57
  ref={svgRef}
56
58
  width="100%"
57
59
  >
58
- <Group.Group left={margin.left + extraMargin / 2} top={margin.top}>
60
+ <Group.Group
61
+ left={
62
+ maxAxisCharacters * 5 +
63
+ (hasSecondUnit ? margin.top * 0.8 : margin.top * 0.6)
64
+ }
65
+ top={margin.top}
66
+ >
59
67
  {showGridLines && (
60
68
  <Grids
61
69
  gridLinesType={gridLinesType}
@@ -1,3 +1,5 @@
1
+ import { ReactElement } from 'react';
2
+
1
3
  import Typography from '@mui/material/Typography';
2
4
 
3
5
  import { useMemoComponent } from '@centreon/ui';
@@ -10,7 +12,7 @@ interface Props {
10
12
  title: string;
11
13
  }
12
14
 
13
- const Header = ({ title, header }: Props): JSX.Element => {
15
+ const Header = ({ title, header }: Props): ReactElement => {
14
16
  const { classes } = ussHeaderChartStyles();
15
17
 
16
18
  const displayTitle = header?.displayTitle ?? true;
@@ -1,8 +1,10 @@
1
- import { MutableRefObject, useRef } from 'react';
1
+ import { RefCallback } from 'react';
2
2
 
3
3
  import { equals, isNil } from 'ramda';
4
4
 
5
+ import useResizeObserver from 'use-resize-observer';
5
6
  import { margin } from '../../Chart/common';
7
+ import { margins } from '../margins';
6
8
 
7
9
  export const extraMargin = 10;
8
10
 
@@ -13,12 +15,14 @@ interface UseComputeBaseChartDimensionsProps {
13
15
  legendHeight?: number;
14
16
  legendPlacement?: string;
15
17
  width: number;
18
+ maxAxisCharacters: number;
16
19
  }
17
20
 
18
21
  interface UseComputeBaseChartDimensionsState {
19
22
  graphHeight: number;
20
23
  graphWidth: number;
21
- legendRef: MutableRefObject<HTMLDivElement | null>;
24
+ legendRef: RefCallback<Element>;
25
+ titleRef: RefCallback<Element>;
22
26
  }
23
27
 
24
28
  export const useComputeBaseChartDimensions = ({
@@ -27,12 +31,17 @@ export const useComputeBaseChartDimensions = ({
27
31
  legendDisplay,
28
32
  legendPlacement,
29
33
  hasSecondUnit,
30
- legendHeight
34
+ legendHeight,
35
+ maxAxisCharacters
31
36
  }: UseComputeBaseChartDimensionsProps): UseComputeBaseChartDimensionsState => {
32
- const legendRef = useRef<HTMLDivElement | null>(null);
37
+ const {
38
+ ref: legendRef,
39
+ width: legendRefWidth,
40
+ height: legendRefHeight
41
+ } = useResizeObserver();
42
+ const { height: titleRefHeight } = useResizeObserver();
33
43
 
34
- const currentLegendHeight =
35
- legendHeight ?? (legendRef.current?.getBoundingClientRect().height || 0);
44
+ const currentLegendHeight = legendHeight ?? (legendRefHeight || 0);
36
45
 
37
46
  const legendBoundingHeight =
38
47
  !equals(legendDisplay, false) &&
@@ -42,20 +51,23 @@ export const useComputeBaseChartDimensions = ({
42
51
  const legendBoundingWidth =
43
52
  !equals(legendDisplay, false) &&
44
53
  (equals(legendPlacement, 'left') || equals(legendPlacement, 'right'))
45
- ? legendRef.current?.getBoundingClientRect().width || 0
54
+ ? legendRefWidth || 0
46
55
  : 0;
47
56
 
48
57
  const graphWidth =
49
58
  width > 0
50
59
  ? width -
51
- margin.left -
52
- (hasSecondUnit ? margin.right : 8) -
53
- extraMargin -
60
+ (hasSecondUnit ? maxAxisCharacters * 2 : maxAxisCharacters) * 6 -
61
+ (hasSecondUnit ? margins.left * 0.8 : margin.left) -
54
62
  legendBoundingWidth
55
63
  : 0;
56
64
  const graphHeight =
57
65
  (height || 0) > 0
58
- ? (height || 0) - margin.top - 5 - legendBoundingHeight
66
+ ? (height || 0) -
67
+ margin.top -
68
+ legendBoundingHeight -
69
+ (titleRefHeight || 0) -
70
+ 5
59
71
  : 0;
60
72
 
61
73
  return {
@@ -0,0 +1,92 @@
1
+ import { isEmpty } from 'ramda';
2
+ import { useMemo } from 'react';
3
+ import { ChartAxis } from '../../Chart/models';
4
+ import { Data } from '../Axes/models';
5
+ import { Thresholds } from '../models';
6
+ import { getFormattedAxisValues } from '../utils';
7
+
8
+ interface UseComputeYAxisMaxCharactersProps {
9
+ firstUnit: string;
10
+ secondUnit: string;
11
+ thresholdUnit?: string;
12
+ thresholds?: Thresholds;
13
+ graphData: Data;
14
+ axis?: ChartAxis;
15
+ }
16
+
17
+ interface UseComputteYAxisMaxCharactersState {
18
+ maxLeftAxisCharacters: number;
19
+ maxRightAxisCharacters: number;
20
+ }
21
+
22
+ export const useComputeYAxisMaxCharacters = ({
23
+ thresholds,
24
+ firstUnit,
25
+ secondUnit,
26
+ graphData,
27
+ axis,
28
+ thresholdUnit
29
+ }: UseComputeYAxisMaxCharactersProps): UseComputteYAxisMaxCharactersState => {
30
+ const maxLeftValue = useMemo(
31
+ () =>
32
+ getFormattedAxisValues({
33
+ threshold: thresholds?.critical ?? [],
34
+ axisUnit: axis?.axisYLeft?.unit ?? firstUnit,
35
+ timeSeries: graphData?.timeSeries ?? [],
36
+ thresholdUnit,
37
+ lines: graphData?.lines ?? [],
38
+ base: graphData?.baseAxis
39
+ }),
40
+ [
41
+ thresholds?.critical,
42
+ axis?.axisYLeft?.unit,
43
+ firstUnit,
44
+ graphData?.timeSeries,
45
+ thresholdUnit,
46
+ graphData?.lines,
47
+ graphData?.baseAxis
48
+ ]
49
+ );
50
+
51
+ const maxRightValue = useMemo(
52
+ () =>
53
+ getFormattedAxisValues({
54
+ threshold: thresholds?.critical ?? [],
55
+ axisUnit: axis?.axisYRight?.unit ?? secondUnit,
56
+ timeSeries: graphData.timeSeries ?? [],
57
+ thresholdUnit,
58
+ lines: graphData.lines ?? [],
59
+ base: graphData.baseAxis
60
+ }),
61
+ [
62
+ thresholds?.critical,
63
+ axis?.axisYRight?.unit,
64
+ secondUnit,
65
+ graphData.timeSeries,
66
+ thresholdUnit,
67
+ graphData.lines,
68
+ graphData.baseAxis
69
+ ]
70
+ );
71
+
72
+ const maxLeftAxisCharacters = useMemo(
73
+ () =>
74
+ isEmpty(maxLeftValue)
75
+ ? 2
76
+ : Math.max(...maxLeftValue.map((value) => value.length), 2),
77
+ [maxLeftValue]
78
+ );
79
+
80
+ const maxRightAxisCharacters = useMemo(
81
+ () =>
82
+ isEmpty(maxRightValue)
83
+ ? 5
84
+ : Math.max(...maxRightValue.map((value) => value.length), 5),
85
+ [maxRightValue]
86
+ );
87
+
88
+ return {
89
+ maxLeftAxisCharacters,
90
+ maxRightAxisCharacters
91
+ };
92
+ };
@@ -6,14 +6,13 @@ export interface LineChartData {
6
6
  times: Array<string>;
7
7
  }
8
8
 
9
+ export interface Threshold {
10
+ label: string;
11
+ value: number;
12
+ }
13
+
9
14
  export interface Thresholds {
10
- critical: Array<{
11
- label: string;
12
- value: number;
13
- }>;
15
+ critical: Array<Threshold>;
14
16
  enabled: boolean;
15
- warning: Array<{
16
- label: string;
17
- value: number;
18
- }>;
17
+ warning: Array<Threshold>;
19
18
  }
@@ -567,7 +567,7 @@ describe('Format value with unit', () => {
567
567
 
568
568
  if (unit === 'ms') {
569
569
  return {
570
- expectedResult: '34.23 seconds',
570
+ expectedResult: '34.23k ms',
571
571
  unit,
572
572
  value: 34232
573
573
  };