@centreon/ui 26.11.0 → 26.11.2
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/Chart/Chart.cypress.spec.tsx +6 -11
- package/src/Graph/common/BaseChart/useComputeYAxisMaxCharacters.ts +3 -3
- 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
package/package.json
CHANGED
|
@@ -154,7 +154,7 @@ const checkGraphWidth = (): void => {
|
|
|
154
154
|
.and('equal', '392');
|
|
155
155
|
|
|
156
156
|
cy.findByTestId('graph-interaction-zone').then((graph) => {
|
|
157
|
-
expect(Number(graph[0].attributes.width.value)).to.be.greaterThan(
|
|
157
|
+
expect(Number(graph[0].attributes.width.value)).to.be.greaterThan(1149);
|
|
158
158
|
});
|
|
159
159
|
};
|
|
160
160
|
|
|
@@ -177,9 +177,6 @@ describe('Line chart', () => {
|
|
|
177
177
|
|
|
178
178
|
cy.contains('06/18/2023').should('be.visible');
|
|
179
179
|
|
|
180
|
-
cy.contains('0.56 s').should('be.visible');
|
|
181
|
-
cy.contains('73.25%').should('be.visible');
|
|
182
|
-
|
|
183
180
|
cy.makeSnapshot();
|
|
184
181
|
});
|
|
185
182
|
|
|
@@ -291,7 +288,7 @@ describe('Line chart', () => {
|
|
|
291
288
|
|
|
292
289
|
cy.findByTestId('graph-interaction-zone')
|
|
293
290
|
.should('have.attr', 'width')
|
|
294
|
-
.and('equal', '
|
|
291
|
+
.and('equal', '1220');
|
|
295
292
|
|
|
296
293
|
cy.get('[data-icon="true"]')
|
|
297
294
|
.eq(0)
|
|
@@ -743,12 +740,10 @@ describe('Lines and bars', () => {
|
|
|
743
740
|
|
|
744
741
|
checkGraphWidth();
|
|
745
742
|
|
|
746
|
-
cy.get(
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
'path[d="M23.953168044077135,235.36727985204413 h23.305785123966935 a17.479338842975203,17.479338842975203 0 0 1 17.479338842975203,17.479338842975203 v19.598028628005196 v17.479338842975203h-17.479338842975203 h-23.305785123966935 h-17.479338842975203v-17.479338842975203 v-19.598028628005196 a17.479338842975203,17.479338842975203 0 0 1 17.479338842975203,-17.479338842975203z"]'
|
|
751
|
-
).should('be.visible');
|
|
743
|
+
cy.get('[data-testid="stacked-bar-2-0-1243"]').should('be.visible');
|
|
744
|
+
cy.get('[data-testid="stacked-bar-10-0-8520.53622137828"]').should(
|
|
745
|
+
'be.visible'
|
|
746
|
+
);
|
|
752
747
|
|
|
753
748
|
cy.makeSnapshot();
|
|
754
749
|
});
|
|
@@ -44,7 +44,7 @@ export const useComputeYAxisMaxCharacters = ({
|
|
|
44
44
|
isHorizontal
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
-
// Always add a
|
|
47
|
+
// Always add a space in case the algorithm does not compute the displayed value in axis.
|
|
48
48
|
const maxLeftAxisCharacters = useMemo(() => {
|
|
49
49
|
if (!leftScale) {
|
|
50
50
|
return 0;
|
|
@@ -55,7 +55,7 @@ export const useComputeYAxisMaxCharacters = ({
|
|
|
55
55
|
|
|
56
56
|
return isEmpty(formattedTicks)
|
|
57
57
|
? 2
|
|
58
|
-
: Math.max(...formattedTicks.map((value) => value.length), 2) +
|
|
58
|
+
: Math.max(...formattedTicks.map((value) => value.length), 2) + 3;
|
|
59
59
|
}, [leftScale, axisLeft]);
|
|
60
60
|
|
|
61
61
|
const maxRightAxisCharacters = useMemo(() => {
|
|
@@ -68,7 +68,7 @@ export const useComputeYAxisMaxCharacters = ({
|
|
|
68
68
|
|
|
69
69
|
return isEmpty(formattedTicks)
|
|
70
70
|
? 2
|
|
71
|
-
: Math.max(...formattedTicks.map((value) => value.length), 2) +
|
|
71
|
+
: Math.max(...formattedTicks.map((value) => value.length), 2) + 3;
|
|
72
72
|
}, [rightScale, axisRight]);
|
|
73
73
|
|
|
74
74
|
return {
|
|
@@ -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
|
};
|
|
@@ -1,79 +1,48 @@
|
|
|
1
1
|
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
|
|
2
2
|
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
|
3
3
|
import type { SvgIconProps } from '@mui/material';
|
|
4
|
-
import {
|
|
4
|
+
import { ClickAwayListener, Tooltip } from '@mui/material';
|
|
5
5
|
|
|
6
|
-
import { ComponentType,
|
|
6
|
+
import type { ComponentType, MouseEvent } from 'react';
|
|
7
|
+
import { useEffect, useState } from 'react';
|
|
8
|
+
import { Link } from 'react-router';
|
|
7
9
|
import { makeStyles } from 'tss-react/mui';
|
|
8
10
|
|
|
9
11
|
import useCloseOnLegacyPage from './useCloseOnLegacyPage';
|
|
10
12
|
|
|
11
13
|
const useStyles = makeStyles()((theme) => ({
|
|
12
|
-
button: {
|
|
13
|
-
'& > svg': {
|
|
14
|
-
height: '0.9em',
|
|
15
|
-
margin: `-${theme.spacing(0.5)}`,
|
|
16
|
-
[theme.breakpoints.down(1025)]: {
|
|
17
|
-
margin: `-${theme.spacing(0.5)}`
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
|
-
appearance: 'none',
|
|
21
|
-
background: 'none',
|
|
22
|
-
border: 0,
|
|
23
|
-
color: theme.palette.common.white,
|
|
24
|
-
cursor: 'pointer',
|
|
25
|
-
display: 'flex',
|
|
26
|
-
|
|
27
|
-
[theme.breakpoints.up(1025)]: {
|
|
28
|
-
alignItems: 'center',
|
|
29
|
-
flexFlow: 'row no-wrap',
|
|
30
|
-
marginTop: theme.spacing(0.5)
|
|
31
|
-
},
|
|
32
|
-
|
|
33
|
-
[theme.breakpoints.down(1025)]: {
|
|
34
|
-
alignItems: 'center',
|
|
35
|
-
flexFlow: 'column wrap',
|
|
36
|
-
order: 1
|
|
37
|
-
},
|
|
38
|
-
|
|
39
|
-
padding: '0'
|
|
40
|
-
},
|
|
41
14
|
container: {
|
|
15
|
+
alignItems: 'center',
|
|
16
|
+
display: 'flex',
|
|
42
17
|
position: 'relative'
|
|
43
18
|
},
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
display: '
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
19
|
+
icon: {
|
|
20
|
+
'& > svg': {
|
|
21
|
+
display: 'block',
|
|
22
|
+
height: '16px',
|
|
23
|
+
width: '16px'
|
|
24
|
+
},
|
|
25
|
+
alignItems: 'center',
|
|
26
|
+
color: 'inherit',
|
|
27
|
+
display: 'inline-flex',
|
|
28
|
+
textDecoration: 'none'
|
|
55
29
|
},
|
|
56
30
|
indicators: {
|
|
31
|
+
alignItems: 'center',
|
|
32
|
+
display: 'inline-flex',
|
|
57
33
|
lineHeight: 1,
|
|
58
34
|
[theme.breakpoints.down(600)]: {
|
|
59
35
|
display: 'none'
|
|
60
|
-
},
|
|
61
|
-
[theme.breakpoints.down(1025)]: {
|
|
62
|
-
flex: 'initial',
|
|
63
|
-
marginLeft: theme.spacing(0.5),
|
|
64
|
-
order: 2
|
|
65
|
-
},
|
|
66
|
-
[theme.breakpoints.up(1025)]: {
|
|
67
|
-
height: theme.spacing(2.5),
|
|
68
|
-
marginLeft: theme.spacing(3.75)
|
|
69
36
|
}
|
|
70
37
|
},
|
|
71
38
|
subMenu: {
|
|
72
39
|
backgroundColor: theme.palette.background.default,
|
|
40
|
+
borderRadius: theme.spacing(1),
|
|
73
41
|
boxShadow: theme.shadows[3],
|
|
74
42
|
boxSizing: 'border-box',
|
|
75
43
|
left: 0,
|
|
76
44
|
minWidth: theme.spacing(20),
|
|
45
|
+
overflow: 'hidden',
|
|
77
46
|
position: 'absolute',
|
|
78
47
|
textAlign: 'left',
|
|
79
48
|
top: `calc(100% + ${theme.spacing(1.25)})`,
|
|
@@ -83,38 +52,53 @@ const useStyles = makeStyles()((theme) => ({
|
|
|
83
52
|
subMenuOpen: {
|
|
84
53
|
visibility: 'visible'
|
|
85
54
|
},
|
|
86
|
-
|
|
55
|
+
tile: {
|
|
56
|
+
'& > svg': {
|
|
57
|
+
height: '16px',
|
|
58
|
+
width: '16px'
|
|
59
|
+
},
|
|
60
|
+
'&:hover': {
|
|
61
|
+
borderColor: theme.palette.tile.borderHover
|
|
62
|
+
},
|
|
87
63
|
alignItems: 'center',
|
|
64
|
+
appearance: 'none',
|
|
65
|
+
background: theme.palette.tile.background,
|
|
66
|
+
border: `1px solid ${theme.palette.tile.border}`,
|
|
67
|
+
borderRadius: theme.spacing(1),
|
|
68
|
+
color: theme.palette.text.primary,
|
|
88
69
|
display: 'inline-flex',
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
display: 'none'
|
|
96
|
-
}
|
|
70
|
+
flexFlow: 'row nowrap',
|
|
71
|
+
gap: theme.spacing(1),
|
|
72
|
+
padding: '5px 9px'
|
|
73
|
+
},
|
|
74
|
+
tileButton: {
|
|
75
|
+
cursor: 'pointer'
|
|
97
76
|
}
|
|
98
77
|
}));
|
|
99
78
|
|
|
100
79
|
interface TopCounterLayoutProps {
|
|
101
80
|
Icon: ComponentType<SvgIconProps>;
|
|
81
|
+
iconLink?: string;
|
|
82
|
+
iconOnClick?: (e: MouseEvent<HTMLAnchorElement>) => void;
|
|
102
83
|
renderIndicators: () => JSX.Element;
|
|
103
|
-
renderSubMenu
|
|
104
|
-
showPendingBadge?: boolean;
|
|
84
|
+
renderSubMenu?: (params: { closeSubMenu: () => void }) => JSX.Element;
|
|
105
85
|
title: string;
|
|
86
|
+
tooltipDescription?: string;
|
|
106
87
|
}
|
|
107
88
|
|
|
108
89
|
const TopCounterLayout = ({
|
|
109
90
|
Icon,
|
|
110
91
|
title,
|
|
92
|
+
iconLink,
|
|
93
|
+
iconOnClick,
|
|
111
94
|
renderIndicators,
|
|
112
95
|
renderSubMenu,
|
|
113
|
-
|
|
96
|
+
tooltipDescription
|
|
114
97
|
}: TopCounterLayoutProps): JSX.Element => {
|
|
115
98
|
const { classes, cx } = useStyles();
|
|
116
99
|
const [toggled, setToggled] = useState(false);
|
|
117
100
|
const subMenuId = title.replace(/[^A-Za-z]/, '-');
|
|
101
|
+
const isExpandable = Boolean(renderSubMenu);
|
|
118
102
|
useCloseOnLegacyPage({ setToggled });
|
|
119
103
|
|
|
120
104
|
useEffect(() => {
|
|
@@ -137,6 +121,38 @@ const TopCounterLayout = ({
|
|
|
137
121
|
};
|
|
138
122
|
}, [toggled]);
|
|
139
123
|
|
|
124
|
+
const iconWithTooltip = (
|
|
125
|
+
<Tooltip
|
|
126
|
+
disableInteractive
|
|
127
|
+
enterDelay={500}
|
|
128
|
+
enterNextDelay={500}
|
|
129
|
+
placement="bottom"
|
|
130
|
+
title={tooltipDescription ?? title}
|
|
131
|
+
>
|
|
132
|
+
<Icon />
|
|
133
|
+
</Tooltip>
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
if (!isExpandable) {
|
|
137
|
+
return (
|
|
138
|
+
<div className={classes.tile}>
|
|
139
|
+
{iconLink ? (
|
|
140
|
+
<Link
|
|
141
|
+
aria-label={title}
|
|
142
|
+
className={classes.icon}
|
|
143
|
+
onClick={iconOnClick}
|
|
144
|
+
to={iconLink}
|
|
145
|
+
>
|
|
146
|
+
{iconWithTooltip}
|
|
147
|
+
</Link>
|
|
148
|
+
) : (
|
|
149
|
+
<span className={classes.icon}>{iconWithTooltip}</span>
|
|
150
|
+
)}
|
|
151
|
+
<span className={classes.indicators}>{renderIndicators()}</span>
|
|
152
|
+
</div>
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
140
156
|
return (
|
|
141
157
|
<ClickAwayListener
|
|
142
158
|
onClickAway={(): void => {
|
|
@@ -147,40 +163,27 @@ const TopCounterLayout = ({
|
|
|
147
163
|
}}
|
|
148
164
|
>
|
|
149
165
|
<div className={classes.container}>
|
|
150
|
-
<
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
>
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
anchorOrigin={{ horizontal: 'right', vertical: 'top' }}
|
|
165
|
-
color="pending"
|
|
166
|
-
invisible={!showPendingBadge}
|
|
167
|
-
overlap="circular"
|
|
168
|
-
variant="dot"
|
|
169
|
-
>
|
|
170
|
-
<Icon />
|
|
171
|
-
</Badge>
|
|
172
|
-
</span>
|
|
173
|
-
<span className={classes.textWrapper}>{title}</span>
|
|
174
|
-
{toggled ? <ExpandLessIcon /> : <ExpandMoreIcon />}
|
|
175
|
-
</button>
|
|
176
|
-
</div>
|
|
166
|
+
<button
|
|
167
|
+
aria-controls={`${subMenuId}-menu`}
|
|
168
|
+
aria-expanded={toggled}
|
|
169
|
+
aria-haspopup="true"
|
|
170
|
+
aria-label={title}
|
|
171
|
+
className={cx(classes.tile, classes.tileButton)}
|
|
172
|
+
id={`${subMenuId}-button`}
|
|
173
|
+
onClick={(): void => setToggled(!toggled)}
|
|
174
|
+
type="button"
|
|
175
|
+
>
|
|
176
|
+
<span className={classes.icon}>{iconWithTooltip}</span>
|
|
177
|
+
<span className={classes.indicators}>{renderIndicators()}</span>
|
|
178
|
+
{toggled ? <ExpandLessIcon /> : <ExpandMoreIcon />}
|
|
179
|
+
</button>
|
|
177
180
|
<div
|
|
178
181
|
aria-labelledby={`${subMenuId}-button`}
|
|
179
182
|
className={cx(classes.subMenu, { [classes.subMenuOpen]: toggled })}
|
|
180
183
|
id={`${subMenuId}-menu`}
|
|
181
184
|
role="menu"
|
|
182
185
|
>
|
|
183
|
-
{renderSubMenu({ closeSubMenu: () => setToggled(false) })}
|
|
186
|
+
{renderSubMenu?.({ closeSubMenu: () => setToggled(false) })}
|
|
184
187
|
</div>
|
|
185
188
|
</div>
|
|
186
189
|
</ClickAwayListener>
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
export * from './formaters';
|
|
2
2
|
export type { CounterProps } from './ResourceCounters';
|
|
3
3
|
export { default as TopCounterResourceCounters } from './ResourceCounters';
|
|
4
|
-
export type { SubMenuProps } from './ResourceSubMenu';
|
|
5
|
-
export { default as TopCounterResourceSubMenu } from './ResourceSubMenu';
|
|
6
4
|
export { default as TopCounterLayout } from './TopCounterLayout';
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import { List, ListItem } from '@mui/material';
|
|
2
|
-
|
|
3
|
-
import { getStatusColors, type SeverityCode } from '@centreon/ui';
|
|
4
|
-
import { ThemeMode } from '@centreon/ui-context';
|
|
5
|
-
|
|
6
|
-
import { equals } from 'ramda';
|
|
7
|
-
import { Link } from 'react-router';
|
|
8
|
-
import { makeStyles } from 'tss-react/mui';
|
|
9
|
-
|
|
10
|
-
const useStyles = makeStyles()((theme) => ({
|
|
11
|
-
count: {
|
|
12
|
-
marginLeft: 'auto'
|
|
13
|
-
},
|
|
14
|
-
link: {
|
|
15
|
-
alignItems: 'center',
|
|
16
|
-
color: 'inherit',
|
|
17
|
-
display: 'flex',
|
|
18
|
-
flex: '100%',
|
|
19
|
-
padding: `0 ${theme.spacing(1)}`,
|
|
20
|
-
textDecoration: 'none'
|
|
21
|
-
},
|
|
22
|
-
status: {
|
|
23
|
-
alignItems: 'center',
|
|
24
|
-
display: 'flex'
|
|
25
|
-
},
|
|
26
|
-
statusCounter: {
|
|
27
|
-
borderRadius: '50%',
|
|
28
|
-
height: theme.spacing(1),
|
|
29
|
-
marginRight: theme.spacing(1),
|
|
30
|
-
width: theme.spacing(1)
|
|
31
|
-
},
|
|
32
|
-
submenu: {
|
|
33
|
-
fontSize: theme.typography.body2.fontSize,
|
|
34
|
-
padding: 0
|
|
35
|
-
},
|
|
36
|
-
submenuItem: {
|
|
37
|
-
'&:hover': {
|
|
38
|
-
background: equals(theme.palette.mode, ThemeMode.dark)
|
|
39
|
-
? theme.palette.primary.dark
|
|
40
|
-
: theme.palette.primary.light,
|
|
41
|
-
color: equals(theme.palette.mode, ThemeMode.dark)
|
|
42
|
-
? theme.palette.common.white
|
|
43
|
-
: theme.palette.primary.main
|
|
44
|
-
},
|
|
45
|
-
'&:not(:last-child)': {
|
|
46
|
-
borderBottom: `1px solid ${theme.palette.divider}`
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}));
|
|
50
|
-
|
|
51
|
-
export interface SubMenuProps {
|
|
52
|
-
items: Array<{
|
|
53
|
-
countTestId?: string;
|
|
54
|
-
onClick: (e: React.MouseEvent) => void;
|
|
55
|
-
severityCode: SeverityCode;
|
|
56
|
-
submenuCount: string | number;
|
|
57
|
-
submenuTitle: string;
|
|
58
|
-
to: string;
|
|
59
|
-
}>;
|
|
60
|
-
onClose?: () => void;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const SubMenu = ({ items, onClose }: SubMenuProps): JSX.Element => {
|
|
64
|
-
const { classes, theme } = useStyles();
|
|
65
|
-
|
|
66
|
-
return (
|
|
67
|
-
<List className={classes.submenu}>
|
|
68
|
-
{items.map(
|
|
69
|
-
({
|
|
70
|
-
onClick,
|
|
71
|
-
severityCode,
|
|
72
|
-
submenuTitle,
|
|
73
|
-
submenuCount,
|
|
74
|
-
countTestId,
|
|
75
|
-
to
|
|
76
|
-
}) => (
|
|
77
|
-
<ListItem
|
|
78
|
-
className={classes.submenuItem}
|
|
79
|
-
disableGutters
|
|
80
|
-
key={to}
|
|
81
|
-
onClick={onClose}
|
|
82
|
-
>
|
|
83
|
-
<Link
|
|
84
|
-
className={classes.link}
|
|
85
|
-
onClick={onClick}
|
|
86
|
-
role="menuitem"
|
|
87
|
-
to={to}
|
|
88
|
-
>
|
|
89
|
-
<span className={classes.status}>
|
|
90
|
-
<span
|
|
91
|
-
className={classes.statusCounter}
|
|
92
|
-
style={{
|
|
93
|
-
backgroundColor: getStatusColors({ severityCode, theme })
|
|
94
|
-
?.backgroundColor
|
|
95
|
-
}}
|
|
96
|
-
/>
|
|
97
|
-
<span>{submenuTitle}</span>
|
|
98
|
-
</span>
|
|
99
|
-
<span className={classes.count} data-testid={countTestId}>
|
|
100
|
-
{submenuCount}
|
|
101
|
-
</span>
|
|
102
|
-
</Link>
|
|
103
|
-
</ListItem>
|
|
104
|
-
)
|
|
105
|
-
)}
|
|
106
|
-
</List>
|
|
107
|
-
);
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
export default SubMenu;
|