@centreon/ui 25.5.3 → 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 +1 -1
- package/src/Graph/Gauge/Gauge.tsx +18 -14
- package/src/Graph/Gauge/ResponsiveGauge.tsx +10 -6
- package/src/Graph/Gauge/useResizeObserver.ts +68 -0
- package/src/Graph/SingleBar/ResponsiveSingleBar.tsx +18 -14
- package/src/Graph/SingleBar/ThresholdLine.tsx +4 -4
- package/src/Graph/SingleBar/models.ts +1 -0
- package/src/Graph/Text/Text.styles.ts +5 -2
- package/src/Graph/Text/Text.tsx +8 -6
- package/src/components/Form/FormActions.tsx +7 -2
package/package.json
CHANGED
|
@@ -1,23 +1,28 @@
|
|
|
1
|
-
import {
|
|
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
|
-
<
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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 =
|
|
57
|
-
|
|
58
|
-
Math.max(
|
|
59
|
-
|
|
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 =
|
|
55
|
-
|
|
56
|
-
Math.max(
|
|
57
|
-
|
|
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')
|
|
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
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
|
69
|
+
? groupMargin - lineMargin
|
|
70
70
|
: groupMargin + lineMargin + margins.top
|
|
71
71
|
}
|
|
72
72
|
y2={
|
|
73
73
|
isSmall
|
|
74
|
-
? barHeight + groupMargin - lineMargin + margins.top -
|
|
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
|
|
86
|
+
? groupMargin - lineMargin
|
|
87
87
|
: groupMargin + lineMargin + margins.top
|
|
88
88
|
}
|
|
89
89
|
y2={
|
|
90
90
|
isSmall
|
|
91
|
-
? barHeight + groupMargin - lineMargin + margins.top
|
|
91
|
+
? barHeight + groupMargin - lineMargin + margins.top - 6
|
|
92
92
|
: barHeight + groupMargin + lineMargin + 2 * margins.top
|
|
93
93
|
}
|
|
94
94
|
onMouseEnter={onMouseEnter}
|
|
@@ -11,8 +11,11 @@ export const useTextStyles = makeStyles()((theme) => ({
|
|
|
11
11
|
gap: theme.spacing(1),
|
|
12
12
|
justifyContent: 'center'
|
|
13
13
|
},
|
|
14
|
-
|
|
15
|
-
textAlign: '
|
|
14
|
+
thresholdRight: {
|
|
15
|
+
textAlign: 'start'
|
|
16
|
+
},
|
|
17
|
+
thresholdLeft: {
|
|
18
|
+
textAlign: 'end'
|
|
16
19
|
},
|
|
17
20
|
thresholds: {
|
|
18
21
|
display: 'flex',
|
package/src/Graph/Text/Text.tsx
CHANGED
|
@@ -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={
|
|
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.
|
|
85
|
+
containerClassName={cx(classes.thresholdLeft, classes.warning)}
|
|
84
86
|
max="30px"
|
|
85
|
-
pref={
|
|
87
|
+
pref={prefThresholds}
|
|
86
88
|
text={`${labels.warning}: ${warningThresholdLabels.join(' - ')}`}
|
|
87
89
|
variant="h5"
|
|
88
90
|
/>
|
|
89
91
|
<FluidTypography
|
|
90
|
-
containerClassName={cx(classes.
|
|
92
|
+
containerClassName={cx(classes.thresholdRight, classes.critical)}
|
|
91
93
|
max="30px"
|
|
92
|
-
pref={
|
|
94
|
+
pref={prefThresholds}
|
|
93
95
|
text={`${labels.critical}: ${criticalThresholdLabels.join(' - ')}`}
|
|
94
96
|
variant="h5"
|
|
95
97
|
/>
|
|
@@ -13,6 +13,7 @@ export type FormActionsProps = {
|
|
|
13
13
|
onCancel: () => void;
|
|
14
14
|
variant: FormVariant;
|
|
15
15
|
isCancelButtonVisible?: boolean;
|
|
16
|
+
disableSubmit?: boolean;
|
|
16
17
|
};
|
|
17
18
|
|
|
18
19
|
export type FormActionsLabels = {
|
|
@@ -25,14 +26,18 @@ const FormActions = <TResource extends object>({
|
|
|
25
26
|
onCancel,
|
|
26
27
|
variant,
|
|
27
28
|
enableSubmitWhenNotDirty,
|
|
28
|
-
isCancelButtonVisible = true
|
|
29
|
+
isCancelButtonVisible = true,
|
|
30
|
+
disableSubmit = false
|
|
29
31
|
}: FormActionsProps): ReactElement => {
|
|
30
32
|
const { classes } = useStyles();
|
|
31
33
|
const { isSubmitting, dirty, isValid, submitForm } =
|
|
32
34
|
useFormikContext<TResource>();
|
|
33
35
|
|
|
34
36
|
const isSubmitDisabled =
|
|
35
|
-
|
|
37
|
+
disableSubmit ||
|
|
38
|
+
isSubmitting ||
|
|
39
|
+
(!dirty && !enableSubmitWhenNotDirty) ||
|
|
40
|
+
!isValid;
|
|
36
41
|
|
|
37
42
|
return (
|
|
38
43
|
<div className={classes.actions}>
|