@centreon/ui 25.5.4 → 25.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@centreon/ui",
3
- "version": "25.5.4",
3
+ "version": "25.5.5",
4
4
  "description": "Centreon UI Components",
5
5
  "scripts": {
6
6
  "update:deps": "pnpx npm-check-updates -i --format group",
@@ -1,23 +1,28 @@
1
- import { ParentSize } from '../..';
1
+ import { Box } from '@mui/material';
2
2
  import { LineChartData, Thresholds } from '../common/models';
3
3
  import { getMetricWithLatestData } from '../common/timeSeries';
4
4
  import { Metric } from '../common/timeSeries/models';
5
5
 
6
6
  import ResponsiveGauge from './ResponsiveGauge';
7
+ import { useResizeObserver } from './useResizeObserver';
7
8
 
8
9
  export interface Props {
9
10
  baseColor?: string;
10
11
  data?: LineChartData;
11
12
  displayAsRaw?: boolean;
12
13
  thresholds: Thresholds;
14
+ max?: number;
13
15
  }
14
16
 
15
17
  export const Gauge = ({
16
18
  thresholds,
17
19
  data,
18
20
  displayAsRaw,
19
- baseColor
21
+ baseColor,
22
+ max
20
23
  }: Props): JSX.Element | null => {
24
+ const { width, height, ref } = useResizeObserver();
25
+
21
26
  if (!data) {
22
27
  return null;
23
28
  }
@@ -25,17 +30,16 @@ export const Gauge = ({
25
30
  const metric = getMetricWithLatestData(data) as Metric;
26
31
 
27
32
  return (
28
- <ParentSize>
29
- {({ width, height }) => (
30
- <ResponsiveGauge
31
- baseColor={baseColor}
32
- displayAsRaw={displayAsRaw}
33
- height={height}
34
- metric={metric}
35
- thresholds={thresholds}
36
- width={width}
37
- />
38
- )}
39
- </ParentSize>
33
+ <Box sx={{ width: '100%', height: '100%' }} ref={ref}>
34
+ <ResponsiveGauge
35
+ baseColor={baseColor}
36
+ displayAsRaw={displayAsRaw}
37
+ height={height}
38
+ metric={metric}
39
+ thresholds={thresholds}
40
+ width={width}
41
+ max={max}
42
+ />
43
+ </Box>
40
44
  );
41
45
  };
@@ -22,6 +22,7 @@ interface Props extends Pick<GaugeProps, 'thresholds' | 'baseColor'> {
22
22
  height: number;
23
23
  metric: Metric;
24
24
  width: number;
25
+ max?: number;
25
26
  }
26
27
 
27
28
  const ResponsiveGauge = ({
@@ -30,7 +31,8 @@ const ResponsiveGauge = ({
30
31
  thresholds,
31
32
  metric,
32
33
  displayAsRaw,
33
- baseColor
34
+ baseColor,
35
+ max
34
36
  }: Props): JSX.Element => {
35
37
  const { classes } = useTooltipStyles();
36
38
  const svgRef = useRef<SVGSVGElement>(null);
@@ -53,11 +55,13 @@ const ResponsiveGauge = ({
53
55
  pluck('value', thresholds.critical)
54
56
  ])
55
57
  : [0];
56
- const adaptedMaxValue = Math.max(
57
- metric.maximum_value || 0,
58
- Math.max(...thresholdValues) * 1.1,
59
- head(metric.data) as number
60
- );
58
+ const adaptedMaxValue =
59
+ max ||
60
+ Math.max(
61
+ metric.maximum_value || 0,
62
+ Math.max(...thresholdValues) * 1.1,
63
+ head(metric.data) as number
64
+ );
61
65
 
62
66
  const pieColor = getColorFromDataAndTresholds({
63
67
  baseColor,
@@ -0,0 +1,68 @@
1
+ import {
2
+ type RefObject,
3
+ useCallback,
4
+ useEffect,
5
+ useRef,
6
+ useState
7
+ } from 'react';
8
+
9
+ interface UseResizeObserverState {
10
+ width: number;
11
+ height: number;
12
+ ref: RefObject<HTMLDivElement | null>;
13
+ }
14
+
15
+ export const useResizeObserver = (): UseResizeObserverState => {
16
+ const [elementResolved, setElementResolved] = useState(false);
17
+ const [size, setSize] = useState([0, 0]);
18
+ const targetRef = useRef<HTMLDivElement | null>(null);
19
+ const observerRef = useRef<ResizeObserver | null>(null);
20
+
21
+ const resize = useCallback((entries: Array<ResizeObserverEntry>): void => {
22
+ setSize([entries[0].contentRect.width, entries[0].contentRect.height]);
23
+ }, []);
24
+
25
+ const observeElement = useCallback(() => {
26
+ if (!targetRef.current) {
27
+ return;
28
+ }
29
+
30
+ observerRef.current = new ResizeObserver(resize);
31
+ observerRef.current?.observe(targetRef.current);
32
+ }, [resize, targetRef.current]);
33
+
34
+ const unobserveElement = useCallback((): void => {
35
+ if (!targetRef.current) {
36
+ return;
37
+ }
38
+
39
+ observerRef.current?.unobserve(targetRef.current);
40
+ observerRef.current = null;
41
+ setElementResolved(false);
42
+ }, []);
43
+
44
+ useEffect(() => {
45
+ if (elementResolved) {
46
+ return;
47
+ }
48
+ setElementResolved(!!targetRef.current?.tagName);
49
+ });
50
+
51
+ useEffect(() => {
52
+ if (!elementResolved) {
53
+ return;
54
+ }
55
+
56
+ observeElement();
57
+
58
+ return () => {
59
+ unobserveElement();
60
+ };
61
+ }, [elementResolved]);
62
+
63
+ return {
64
+ width: size[0],
65
+ height: size[1],
66
+ ref: targetRef
67
+ };
68
+ };
@@ -4,7 +4,7 @@ import { animated, useSpring } from '@react-spring/web';
4
4
  import { scaleLinear } from '@visx/scale';
5
5
  import { Bar } from '@visx/shape';
6
6
  import { Group, Tooltip } from '@visx/visx';
7
- import { equals, flatten, head, lt, pluck } from 'ramda';
7
+ import { clamp, equals, flatten, head, lt, pluck } from 'ramda';
8
8
 
9
9
  import { Box, alpha, useTheme } from '@mui/material';
10
10
 
@@ -35,7 +35,8 @@ const ResponsiveSingleBar = ({
35
35
  displayAsRaw,
36
36
  baseColor,
37
37
  size = 'medium',
38
- showLabels = true
38
+ showLabels = true,
39
+ max
39
40
  }: Props): JSX.Element => {
40
41
  const { classes } = useTooltipStyles();
41
42
  const theme = useTheme();
@@ -51,11 +52,13 @@ const ResponsiveSingleBar = ({
51
52
  ])
52
53
  : [0];
53
54
 
54
- const adaptedMaxValue = Math.max(
55
- metric.maximum_value || 0,
56
- Math.max(...thresholdValues) * 1.1,
57
- head(metric.data) as number
58
- );
55
+ const adaptedMaxValue =
56
+ max ||
57
+ Math.max(
58
+ metric.maximum_value || 0,
59
+ Math.max(...thresholdValues) * 1.1,
60
+ head(metric.data) as number
61
+ );
59
62
 
60
63
  const { showTooltip, hideTooltip, tooltipOpen, tooltipData } =
61
64
  Tooltip.useTooltip();
@@ -72,7 +75,7 @@ const ResponsiveSingleBar = ({
72
75
  [latestMetricData, thresholds, theme]
73
76
  );
74
77
 
75
- const isSmall = equals(size, 'small') || isSmallHeight;
78
+ const isSmall = equals(size, 'small');
76
79
 
77
80
  const textStyle = isSmall ? theme.typography.h6 : theme.typography.h4;
78
81
 
@@ -118,14 +121,15 @@ const ResponsiveSingleBar = ({
118
121
 
119
122
  const springStyle = useSpring({ width: metricBarWidth });
120
123
 
121
- const barHeight = isSmallHeight ? barHeights.small : barHeights[size];
122
-
123
124
  const barY = groupMargin + (isSmall ? 0 : 2 * margins.top);
124
125
 
125
- const realBarHeight =
126
- !isSmall && textHeight + barHeight > height
127
- ? height - textHeight - 2 * margins.top
128
- : barHeight;
126
+ const realBarHeight = !isSmall
127
+ ? clamp(
128
+ barHeights.small,
129
+ barHeights.medium,
130
+ height - textHeight - 2 * margins.top
131
+ )
132
+ : barHeights.small;
129
133
 
130
134
  return (
131
135
  <div
@@ -66,12 +66,12 @@ export const ThresholdLine = ({
66
66
  x2={scaledValue + 1}
67
67
  y1={
68
68
  isSmall
69
- ? groupMargin - lineMargin + 6
69
+ ? groupMargin - lineMargin
70
70
  : groupMargin + lineMargin + margins.top
71
71
  }
72
72
  y2={
73
73
  isSmall
74
- ? barHeight + groupMargin - lineMargin + margins.top - 2
74
+ ? barHeight + groupMargin - lineMargin + margins.top - 6
75
75
  : barHeight + groupMargin + lineMargin + 2 * margins.top
76
76
  }
77
77
  />
@@ -83,12 +83,12 @@ export const ThresholdLine = ({
83
83
  x2={scaledValue + 1}
84
84
  y1={
85
85
  isSmall
86
- ? groupMargin - lineMargin + 5
86
+ ? groupMargin - lineMargin
87
87
  : groupMargin + lineMargin + margins.top
88
88
  }
89
89
  y2={
90
90
  isSmall
91
- ? barHeight + groupMargin - lineMargin + margins.top + 5
91
+ ? barHeight + groupMargin - lineMargin + margins.top - 6
92
92
  : barHeight + groupMargin + lineMargin + 2 * margins.top
93
93
  }
94
94
  onMouseEnter={onMouseEnter}
@@ -7,4 +7,5 @@ export interface SingleBarProps {
7
7
  showLabels?: boolean;
8
8
  size?: 'medium' | 'small';
9
9
  thresholds: Thresholds;
10
+ max?: number;
10
11
  }
@@ -11,8 +11,11 @@ export const useTextStyles = makeStyles()((theme) => ({
11
11
  gap: theme.spacing(1),
12
12
  justifyContent: 'center'
13
13
  },
14
- threshold: {
15
- textAlign: 'center'
14
+ thresholdRight: {
15
+ textAlign: 'start'
16
+ },
17
+ thresholdLeft: {
18
+ textAlign: 'end'
16
19
  },
17
20
  thresholds: {
18
21
  display: 'flex',
@@ -21,6 +21,7 @@ export interface Props {
21
21
  warning: string;
22
22
  };
23
23
  thresholds: Thresholds;
24
+ prefThresholds?: number;
24
25
  }
25
26
 
26
27
  export const Text = ({
@@ -28,7 +29,8 @@ export const Text = ({
28
29
  data,
29
30
  displayAsRaw,
30
31
  labels,
31
- baseColor
32
+ baseColor,
33
+ prefThresholds = 14
32
34
  }: Props): JSX.Element | null => {
33
35
  const theme = useTheme();
34
36
  const { classes, cx } = useTextStyles();
@@ -66,7 +68,7 @@ export const Text = ({
66
68
  <div className={classes.graphText}>
67
69
  <FluidTypography
68
70
  max="40px"
69
- pref={16}
71
+ pref={14}
70
72
  sx={{ color, fontWeight: 'bold', textAlign: 'center' }}
71
73
  text={
72
74
  formatMetricValueWithUnit({
@@ -80,16 +82,16 @@ export const Text = ({
80
82
  {thresholds.enabled && (
81
83
  <div className={classes.thresholds}>
82
84
  <FluidTypography
83
- containerClassName={cx(classes.threshold, classes.warning)}
85
+ containerClassName={cx(classes.thresholdLeft, classes.warning)}
84
86
  max="30px"
85
- pref={14}
87
+ pref={prefThresholds}
86
88
  text={`${labels.warning}: ${warningThresholdLabels.join(' - ')}`}
87
89
  variant="h5"
88
90
  />
89
91
  <FluidTypography
90
- containerClassName={cx(classes.threshold, classes.critical)}
92
+ containerClassName={cx(classes.thresholdRight, classes.critical)}
91
93
  max="30px"
92
- pref={14}
94
+ pref={prefThresholds}
93
95
  text={`${labels.critical}: ${criticalThresholdLabels.join(' - ')}`}
94
96
  variant="h5"
95
97
  />