@centreon/ui 26.9.1 → 26.10.1
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 +2 -2
- package/src/Graph/BarChart/BarChart.cypress.spec.tsx +23 -12
- package/src/Graph/BarChart/ResponsiveBarChart.tsx +13 -22
- package/src/Graph/Chart/BasicComponents/Lines/index.tsx +2 -0
- package/src/Graph/Chart/Chart.cypress.spec.tsx +9 -8
- package/src/Graph/Chart/Chart.tsx +14 -20
- package/src/Graph/Chart/InteractiveComponents/AnchorPoint/GuidingLines.tsx +2 -0
- package/src/Graph/Chart/InteractiveComponents/AnchorPoint/RegularAnchorPoint.tsx +4 -1
- package/src/Graph/Chart/InteractiveComponents/AnchorPoint/StackedAnchorPoint.tsx +3 -0
- package/src/Graph/Chart/InteractiveComponents/AnchorPoint/models.ts +1 -0
- package/src/Graph/Chart/InteractiveComponents/AnchorPoint/useTickGraph.ts +11 -2
- package/src/Graph/Chart/InteractiveComponents/index.tsx +7 -2
- package/src/Graph/common/Axes/index.tsx +1 -6
- package/src/Graph/common/BaseChart/ChartSvgWrapper.tsx +8 -3
- package/src/Graph/common/BaseChart/useComputeBaseChartDimensions.ts +6 -6
- package/src/Graph/common/BaseChart/useComputeYAxisMaxCharacters.ts +68 -52
- package/src/Graph/common/utils.ts +11 -2
- package/src/ThemeProvider/palettes.ts +18 -0
- package/src/ThemeProvider/tailwindcss.css +8 -0
- package/src/TopCounterElements/ResourceCounters.tsx +25 -30
- package/src/TopCounterElements/StatusCounter.tsx +39 -30
- package/src/TopCounterElements/TopCounterLayout.tsx +94 -91
- package/src/TopCounterElements/index.tsx +0 -2
- package/src/TopCounterElements/ResourceSubMenu.tsx +0 -110
|
@@ -1,21 +1,18 @@
|
|
|
1
|
-
import { getTicks } from '@visx/scale';
|
|
2
|
-
import { ScaleLinear } from 'd3-scale';
|
|
3
1
|
import { isEmpty } from 'ramda';
|
|
4
2
|
import { useMemo } from 'react';
|
|
5
3
|
|
|
6
4
|
import type { ChartAxis } from '../../Chart/models';
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
5
|
+
import type { Data } from '../Axes/models';
|
|
6
|
+
import type { Thresholds } from '../models';
|
|
7
|
+
import { getFormattedAxisValues } from '../utils';
|
|
9
8
|
|
|
10
9
|
interface UseComputeYAxisMaxCharactersProps {
|
|
10
|
+
firstUnit: string;
|
|
11
|
+
secondUnit: string;
|
|
12
|
+
thresholdUnit?: string;
|
|
13
|
+
thresholds?: Thresholds;
|
|
14
|
+
graphData: Data;
|
|
11
15
|
axis?: ChartAxis;
|
|
12
|
-
base: number;
|
|
13
|
-
displayedLines: Array<Line>;
|
|
14
|
-
graphWidth: number;
|
|
15
|
-
graphHeight: number;
|
|
16
|
-
isHorizontal: boolean;
|
|
17
|
-
leftScale: ScaleLinear<number, number, never>;
|
|
18
|
-
rightScale: ScaleLinear<number, number, never>;
|
|
19
16
|
}
|
|
20
17
|
|
|
21
18
|
interface UseComputteYAxisMaxCharactersState {
|
|
@@ -24,52 +21,71 @@ interface UseComputteYAxisMaxCharactersState {
|
|
|
24
21
|
}
|
|
25
22
|
|
|
26
23
|
export const useComputeYAxisMaxCharacters = ({
|
|
24
|
+
thresholds,
|
|
25
|
+
firstUnit,
|
|
26
|
+
secondUnit,
|
|
27
|
+
graphData,
|
|
27
28
|
axis,
|
|
28
|
-
|
|
29
|
-
displayedLines,
|
|
30
|
-
graphWidth,
|
|
31
|
-
graphHeight,
|
|
32
|
-
isHorizontal,
|
|
33
|
-
leftScale,
|
|
34
|
-
rightScale
|
|
29
|
+
thresholdUnit
|
|
35
30
|
}: UseComputeYAxisMaxCharactersProps): UseComputteYAxisMaxCharactersState => {
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
31
|
+
const maxLeftValue = useMemo(
|
|
32
|
+
() =>
|
|
33
|
+
getFormattedAxisValues({
|
|
34
|
+
axisUnit: axis?.axisYLeft?.unit ?? firstUnit,
|
|
35
|
+
base: graphData?.baseAxis,
|
|
36
|
+
lines: graphData?.lines ?? [],
|
|
37
|
+
threshold: thresholds?.critical ?? [],
|
|
38
|
+
thresholdUnit,
|
|
39
|
+
timeSeries: graphData?.timeSeries ?? []
|
|
40
|
+
}),
|
|
41
|
+
[
|
|
42
|
+
thresholds?.critical,
|
|
43
|
+
axis?.axisYLeft?.unit,
|
|
44
|
+
firstUnit,
|
|
45
|
+
graphData?.timeSeries,
|
|
46
|
+
thresholdUnit,
|
|
47
|
+
graphData?.lines,
|
|
48
|
+
graphData?.baseAxis
|
|
49
|
+
]
|
|
50
|
+
);
|
|
46
51
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
52
|
+
const maxRightValue = useMemo(
|
|
53
|
+
() =>
|
|
54
|
+
getFormattedAxisValues({
|
|
55
|
+
axisUnit: axis?.axisYRight?.unit ?? secondUnit,
|
|
56
|
+
base: graphData.baseAxis,
|
|
57
|
+
lines: graphData.lines ?? [],
|
|
58
|
+
threshold: thresholds?.critical ?? [],
|
|
59
|
+
thresholdUnit,
|
|
60
|
+
timeSeries: graphData.timeSeries ?? []
|
|
61
|
+
}),
|
|
62
|
+
[
|
|
63
|
+
thresholds?.critical,
|
|
64
|
+
axis?.axisYRight?.unit,
|
|
65
|
+
secondUnit,
|
|
66
|
+
graphData.timeSeries,
|
|
67
|
+
thresholdUnit,
|
|
68
|
+
graphData.lines,
|
|
69
|
+
graphData.baseAxis
|
|
70
|
+
]
|
|
71
|
+
);
|
|
60
72
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
73
|
+
// Always add a character space in case the algorithm does not compute the displayed value in axis.
|
|
74
|
+
const maxLeftAxisCharacters = useMemo(
|
|
75
|
+
() =>
|
|
76
|
+
isEmpty(maxLeftValue)
|
|
77
|
+
? 2
|
|
78
|
+
: Math.max(...maxLeftValue.map((value) => value.length), 2) + 1,
|
|
79
|
+
[maxLeftValue]
|
|
80
|
+
);
|
|
68
81
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
82
|
+
const maxRightAxisCharacters = useMemo(
|
|
83
|
+
() =>
|
|
84
|
+
isEmpty(maxRightValue)
|
|
85
|
+
? 5
|
|
86
|
+
: Math.max(...maxRightValue.map((value) => value.length), 5) + 1,
|
|
87
|
+
[maxRightValue]
|
|
88
|
+
);
|
|
73
89
|
|
|
74
90
|
return {
|
|
75
91
|
maxLeftAxisCharacters,
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
} from 'ramda';
|
|
23
23
|
|
|
24
24
|
import type { BarStyle } from '../BarChart/models';
|
|
25
|
+
import { margin } from '../Chart/common';
|
|
25
26
|
import type { LineStyle } from '../Chart/models';
|
|
26
27
|
import type { Threshold, Thresholds } from './models';
|
|
27
28
|
import { formatMetricValueWithUnit } from './timeSeries';
|
|
@@ -262,8 +263,16 @@ export const getFormattedAxisValues = ({
|
|
|
262
263
|
.filter((v) => v) as Array<string>;
|
|
263
264
|
};
|
|
264
265
|
|
|
265
|
-
|
|
266
|
-
|
|
266
|
+
interface ComputeGElementMarginLeftProps {
|
|
267
|
+
maxCharacters: number;
|
|
268
|
+
hasSecondUnit?: boolean;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export const computeGElementMarginLeft = ({
|
|
272
|
+
maxCharacters,
|
|
273
|
+
hasSecondUnit
|
|
274
|
+
}: ComputeGElementMarginLeftProps): number =>
|
|
275
|
+
maxCharacters * 5 + (hasSecondUnit ? margin.top * 0.8 : margin.top * 0.6);
|
|
267
276
|
|
|
268
277
|
export const computPixelsToShiftMouse = (
|
|
269
278
|
xScale: import('d3-scale').ScaleTime<number, number>
|
|
@@ -45,6 +45,7 @@ declare module '@mui/material/styles' {
|
|
|
45
45
|
main: string;
|
|
46
46
|
};
|
|
47
47
|
statusBackground: StatusBackground;
|
|
48
|
+
tile: TypeTile;
|
|
48
49
|
}
|
|
49
50
|
interface StatusBackground {
|
|
50
51
|
error: string;
|
|
@@ -64,6 +65,13 @@ declare module '@mui/material/styles' {
|
|
|
64
65
|
main: string;
|
|
65
66
|
};
|
|
66
67
|
statusBackground: StatusBackground;
|
|
68
|
+
tile: TypeTile;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
interface TypeTile {
|
|
72
|
+
background: string;
|
|
73
|
+
border: string;
|
|
74
|
+
borderHover: string;
|
|
67
75
|
}
|
|
68
76
|
|
|
69
77
|
interface TypeBackground {
|
|
@@ -294,6 +302,11 @@ export const lightPalette: PaletteOptions = {
|
|
|
294
302
|
primary: '#000000',
|
|
295
303
|
secondary: '#666666'
|
|
296
304
|
},
|
|
305
|
+
tile: {
|
|
306
|
+
background: '#FFFFFF',
|
|
307
|
+
border: '#E3E3E3',
|
|
308
|
+
borderHover: '#CCCCCC'
|
|
309
|
+
},
|
|
297
310
|
warning: {
|
|
298
311
|
contrastText: '#000',
|
|
299
312
|
dark: '#FC7E00',
|
|
@@ -436,6 +449,11 @@ export const darkPalette: PaletteOptions = {
|
|
|
436
449
|
primary: '#FFFFFF',
|
|
437
450
|
secondary: '#CCCCCC'
|
|
438
451
|
},
|
|
452
|
+
tile: {
|
|
453
|
+
background: '#2E2E2E',
|
|
454
|
+
border: '#4A4A4A',
|
|
455
|
+
borderHover: '#6D6D6D'
|
|
456
|
+
},
|
|
439
457
|
warning: {
|
|
440
458
|
contrastText: '#fff',
|
|
441
459
|
main: '#C55400'
|
|
@@ -112,6 +112,11 @@
|
|
|
112
112
|
--color-status-background-warning: #fd9b27;
|
|
113
113
|
--color-success-main: #88b922;
|
|
114
114
|
|
|
115
|
+
/* Tile container colors */
|
|
116
|
+
--color-tile-background: #ffffff;
|
|
117
|
+
--color-tile-border: #e3e3e3;
|
|
118
|
+
--color-tile-border-hover: #cccccc;
|
|
119
|
+
|
|
115
120
|
/* Text colors */
|
|
116
121
|
--color-text-disabled: #999999;
|
|
117
122
|
--color-text-primary: #000000;
|
|
@@ -195,6 +200,9 @@
|
|
|
195
200
|
--color-stauts-background-unknown: #666666;
|
|
196
201
|
--color-status-background-warning: #c55400;
|
|
197
202
|
--color-success-main: #5f8118;
|
|
203
|
+
--color-tile-background: #2e2e2e;
|
|
204
|
+
--color-tile-border: #4a4a4a;
|
|
205
|
+
--color-tile-border-hover: #6d6d6d;
|
|
198
206
|
--color-text-disabled: #666666;
|
|
199
207
|
--color-text-primary: #ffffff;
|
|
200
208
|
--color-text-secondary: #cccccc;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { SeverityCode } from '@centreon/ui';
|
|
2
2
|
|
|
3
|
-
import { Fragment } from 'react';
|
|
4
3
|
import { Link } from 'react-router';
|
|
5
4
|
import { makeStyles } from 'tss-react/mui';
|
|
6
5
|
|
|
@@ -8,29 +7,23 @@ import StatusCounter from './StatusCounter';
|
|
|
8
7
|
|
|
9
8
|
const useStyles = makeStyles()((theme) => ({
|
|
10
9
|
container: {
|
|
11
|
-
|
|
10
|
+
alignItems: 'center',
|
|
11
|
+
display: 'flex',
|
|
12
|
+
gap: theme.spacing(1),
|
|
12
13
|
listStyle: 'none',
|
|
13
14
|
margin: 0,
|
|
14
|
-
padding: 0
|
|
15
|
-
[theme.breakpoints.down(1025)]: {
|
|
16
|
-
flexFlow: 'row wrap'
|
|
17
|
-
}
|
|
15
|
+
padding: 0
|
|
18
16
|
},
|
|
19
17
|
item: {
|
|
20
|
-
|
|
18
|
+
alignItems: 'center',
|
|
19
|
+
display: 'flex',
|
|
21
20
|
margin: 0,
|
|
22
|
-
padding: 0
|
|
23
|
-
paddingRight: theme.spacing(0.25)
|
|
21
|
+
padding: 0
|
|
24
22
|
},
|
|
25
23
|
link: {
|
|
24
|
+
alignItems: 'center',
|
|
25
|
+
display: 'flex',
|
|
26
26
|
textDecoration: 'none'
|
|
27
|
-
},
|
|
28
|
-
splitter: {
|
|
29
|
-
display: 'none',
|
|
30
|
-
[theme.breakpoints.down(1025)]: {
|
|
31
|
-
display: 'block',
|
|
32
|
-
marginBottom: theme.spacing(0.25)
|
|
33
|
-
}
|
|
34
27
|
}
|
|
35
28
|
}));
|
|
36
29
|
|
|
@@ -38,6 +31,7 @@ export interface CounterProps {
|
|
|
38
31
|
counters: Array<{
|
|
39
32
|
ariaLabel: string;
|
|
40
33
|
count: string | number;
|
|
34
|
+
detail?: string | number;
|
|
41
35
|
onClick: (e: React.MouseEvent) => void;
|
|
42
36
|
severityCode: SeverityCode;
|
|
43
37
|
to: string;
|
|
@@ -50,20 +44,21 @@ export default ({ counters }: CounterProps): JSX.Element => {
|
|
|
50
44
|
return (
|
|
51
45
|
<ul className={classes.container}>
|
|
52
46
|
{counters.map(
|
|
53
|
-
({ to, ariaLabel, onClick, count, severityCode }
|
|
54
|
-
<
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
47
|
+
({ to, ariaLabel, onClick, count, detail, severityCode }) => (
|
|
48
|
+
<li className={classes.item} key={to.toString().replace(/\W/g, '')}>
|
|
49
|
+
<Link
|
|
50
|
+
aria-label={ariaLabel}
|
|
51
|
+
className={classes.link}
|
|
52
|
+
onClick={onClick}
|
|
53
|
+
to={to}
|
|
54
|
+
>
|
|
55
|
+
<StatusCounter
|
|
56
|
+
count={count}
|
|
57
|
+
detail={detail}
|
|
58
|
+
severityCode={severityCode}
|
|
59
|
+
/>
|
|
60
|
+
</Link>
|
|
61
|
+
</li>
|
|
67
62
|
)
|
|
68
63
|
)}
|
|
69
64
|
</ul>
|
|
@@ -1,63 +1,72 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Tooltip } from '@mui/material';
|
|
2
2
|
|
|
3
3
|
import { getStatusColors, type SeverityCode } from '@centreon/ui';
|
|
4
4
|
|
|
5
5
|
import numeral from 'numeral';
|
|
6
|
+
import { isNil } from 'ramda';
|
|
6
7
|
import { makeStyles } from 'tss-react/mui';
|
|
7
8
|
|
|
8
9
|
export interface StyleProps {
|
|
9
10
|
severityCode?: SeverityCode | null;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
const useStyles = makeStyles<StyleProps>()((theme, { severityCode }) =>
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
13
|
+
const useStyles = makeStyles<StyleProps>()((theme, { severityCode }) => {
|
|
14
|
+
const statusColors = severityCode
|
|
15
|
+
? getStatusColors({ severityCode, theme })
|
|
16
|
+
: null;
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
container: {
|
|
20
|
+
alignItems: 'center',
|
|
21
|
+
color: theme.palette.mode === 'dark' ? '#EAEEF7' : '#1B2233',
|
|
22
|
+
cursor: 'pointer',
|
|
23
|
+
display: 'inline-flex',
|
|
24
|
+
gap: '3px'
|
|
25
|
+
},
|
|
26
|
+
count: {
|
|
27
|
+
fontFamily: 'ui-monospace, "Roboto Mono", Menlo, monospace',
|
|
28
|
+
fontSize: '12px',
|
|
29
|
+
fontWeight: theme.typography.fontWeightMedium,
|
|
30
|
+
lineHeight: 1
|
|
31
|
+
},
|
|
32
|
+
dot: {
|
|
33
|
+
backgroundColor: statusColors?.backgroundColor ?? theme.palette.divider,
|
|
34
|
+
borderRadius: '50%',
|
|
35
|
+
flexShrink: 0,
|
|
36
|
+
height: '9px',
|
|
37
|
+
width: '9px'
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
});
|
|
31
41
|
|
|
32
42
|
export interface Props {
|
|
33
43
|
className?: string;
|
|
34
44
|
count: string | number;
|
|
45
|
+
detail?: string | number;
|
|
35
46
|
severityCode?: SeverityCode | null;
|
|
36
47
|
}
|
|
37
48
|
|
|
38
49
|
const StatusCounter = ({
|
|
39
50
|
severityCode = null,
|
|
40
51
|
count,
|
|
52
|
+
detail,
|
|
41
53
|
className
|
|
42
54
|
}: Props): JSX.Element => {
|
|
43
55
|
const { classes, cx } = useStyles({ severityCode });
|
|
44
|
-
const
|
|
56
|
+
const hasDetail = !isNil(detail);
|
|
57
|
+
const shouldDisableTooltip = !hasDetail && Number(count) < 1000;
|
|
45
58
|
const formattedCount = numeral(count).format('0.[0]a');
|
|
46
59
|
|
|
47
60
|
return (
|
|
48
61
|
<Tooltip
|
|
49
62
|
disableHoverListener={shouldDisableTooltip}
|
|
50
63
|
followCursor
|
|
51
|
-
title={count}
|
|
64
|
+
title={hasDetail ? detail : count}
|
|
52
65
|
>
|
|
53
|
-
<
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}}
|
|
58
|
-
max={Number.POSITIVE_INFINITY}
|
|
59
|
-
overlap="circular"
|
|
60
|
-
/>
|
|
66
|
+
<span className={cx(classes.container, className)}>
|
|
67
|
+
<span className={classes.dot} />
|
|
68
|
+
<span className={classes.count}>{formattedCount}</span>
|
|
69
|
+
</span>
|
|
61
70
|
</Tooltip>
|
|
62
71
|
);
|
|
63
72
|
};
|