@centreon/ui 26.11.1 → 26.11.3

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": "26.11.1",
3
+ "version": "26.11.3",
4
4
  "description": "Centreon UI Components",
5
5
  "scripts": {
6
6
  "update:deps": "pnpx npm-check-updates -i --format group",
@@ -95,7 +95,7 @@ const CollapsibleGroup = ({
95
95
  <ContainerComponent>
96
96
  <div
97
97
  className={
98
- 'snap-y flex flex-row justify-between w-full pl-3 pr-1 text-white items-center'
98
+ 'snap-y flex flex-row justify-between w-full pl-3 pr-1 text-text-primary items-center'
99
99
  }
100
100
  data-testid={`${group?.name}-header`}
101
101
  >
@@ -76,15 +76,15 @@ const ListingHeaderCell = ({
76
76
  height: dataStyle.header.height
77
77
  }}
78
78
  >
79
- <div className="flex items-center h-full justify-between text-white p-0">
79
+ <div className="flex items-center h-full justify-between text-text-primary p-0">
80
80
  {column.sortable ? (
81
81
  <TableSortLabel
82
82
  active={sortField === columnSortField}
83
83
  aria-label={`Column ${column.label}`}
84
84
  classes={{
85
- icon: 'text-white'
85
+ icon: 'text-text-primary'
86
86
  }}
87
- className="text-white"
87
+ className="text-text-primary"
88
88
  direction={sortOrder || 'desc'}
89
89
  onClick={sort}
90
90
  >
@@ -99,7 +99,7 @@ const ListingHeaderCell = ({
99
99
  {columnConfiguration?.sortable && areColumnsEditable && (
100
100
  <DraggableIconButton
101
101
  {...props}
102
- className={`p-0 ${isDragging ? 'cursor-grabbing' : 'cursor-grab'} text-white opacity-0 hover:opacity-100 focus:opacity-100`}
102
+ className={`p-0 ${isDragging ? 'cursor-grabbing' : 'cursor-grab'} text-text-primary opacity-0 hover:opacity-100 focus:opacity-100`}
103
103
  columnLabel={columnLabel}
104
104
  />
105
105
  )}
@@ -35,7 +35,7 @@ const SelectActionListingHeaderCell = ({
35
35
  >
36
36
  <Checkbox
37
37
  checked={hasRows && selectedRowCount === rowCount}
38
- className="text-white"
38
+ className="text-text-primary"
39
39
  indeterminate={
40
40
  hasRows && selectedRowCount > 0 && selectedRowCount < rowCount
41
41
  }
@@ -44,7 +44,7 @@ const SelectActionListingHeaderCell = ({
44
44
  />
45
45
  {not(isEmpty(predefinedRowsSelection)) ? (
46
46
  <PopoverMenu
47
- className="text-white"
47
+ className="text-text-primary"
48
48
  icon={<ArrowDropDownIcon />}
49
49
  title={labelPredefinedRowsSelectionMenu}
50
50
  >
@@ -57,7 +57,7 @@ const SelectActionListingHeaderCell = ({
57
57
  )}
58
58
  </PopoverMenu>
59
59
  ) : (
60
- <div className="text-white" />
60
+ <div className="text-text-primary" />
61
61
  )}
62
62
  </TableCell>
63
63
  );
@@ -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 {
@@ -179,7 +187,7 @@ export const lightPalette: PaletteOptions = {
179
187
  },
180
188
  background: {
181
189
  default: '#F4F4F4',
182
- listingHeader: '#666666',
190
+ listingHeader: '#D9D9D9',
183
191
  panel: '#EDEDED',
184
192
  panelGroups: '#F5F5F5',
185
193
  paper: '#FFFFFF',
@@ -198,6 +206,8 @@ export const lightPalette: PaletteOptions = {
198
206
  divider: '#E3E3E3',
199
207
  error: {
200
208
  contrastText: '#000',
209
+ dark: '#B23333',
210
+ light: '#FF6E6E',
201
211
  main: '#FF4A4A'
202
212
  },
203
213
  header: {
@@ -267,9 +277,9 @@ export const lightPalette: PaletteOptions = {
267
277
  },
268
278
  primary: {
269
279
  contrastText: '#fff',
270
- dark: '#255891',
271
- light: '#cde7fc',
272
- main: '#2E68AA'
280
+ dark: '#2A3575',
281
+ light: '#D8DCE9',
282
+ main: '#131D5A'
273
283
  },
274
284
  secondary: {
275
285
  contrastText: '#fff',
@@ -278,15 +288,17 @@ export const lightPalette: PaletteOptions = {
278
288
  main: '#C772D6'
279
289
  },
280
290
  statusBackground: {
281
- error: '#FF6666',
291
+ error: '#FF6E6E',
282
292
  none: alpha('#2E68AA', 0.1),
283
293
  pending: '#1EBEB3',
284
- success: '#88B922',
294
+ success: '#9FC74E',
285
295
  unknown: '#E3E3E3',
286
- warning: '#FD9B27'
296
+ warning: '#FCC481'
287
297
  },
288
298
  success: {
289
299
  contrastText: '#000',
300
+ dark: '#5F8117',
301
+ light: '#9FC74E',
290
302
  main: '#88B922'
291
303
  },
292
304
  text: {
@@ -294,9 +306,14 @@ export const lightPalette: PaletteOptions = {
294
306
  primary: '#000000',
295
307
  secondary: '#666666'
296
308
  },
309
+ tile: {
310
+ background: '#FFFFFF',
311
+ border: '#E3E3E3',
312
+ borderHover: '#CCCCCC'
313
+ },
297
314
  warning: {
298
315
  contrastText: '#000',
299
- dark: '#FC7E00',
316
+ dark: '#B16C1B',
300
317
  light: '#FCC481',
301
318
  main: '#FD9B27'
302
319
  }
@@ -342,7 +359,9 @@ export const darkPalette: PaletteOptions = {
342
359
  divider: '#666666',
343
360
  error: {
344
361
  contrastText: '#fff',
345
- main: '#D60101'
362
+ dark: '#B23333',
363
+ light: '#FF6E6E',
364
+ main: '#FF4A4A'
346
365
  },
347
366
  header: {
348
367
  page: {
@@ -407,7 +426,7 @@ export const darkPalette: PaletteOptions = {
407
426
  mode: ThemeMode.dark,
408
427
  pending: {
409
428
  contrastText: '#fff',
410
- main: '#118077'
429
+ main: '#1EBEB3'
411
430
  },
412
431
  primary: {
413
432
  contrastText: '#000',
@@ -420,25 +439,34 @@ export const darkPalette: PaletteOptions = {
420
439
  main: '#7C1FA2'
421
440
  },
422
441
  statusBackground: {
423
- error: '#D60101',
442
+ error: '#FF4A4A',
424
443
  none: alpha('#2E68AA', 0.1),
425
- pending: '#118077',
426
- success: '#5F8118',
444
+ pending: '#1EBEB3',
445
+ success: '#88B922',
427
446
  unknown: '#666666',
428
- warning: '#C55400'
447
+ warning: '#FD9B27'
429
448
  },
430
449
  success: {
431
450
  contrastText: '#fff',
432
- main: '#5F8118'
451
+ dark: '#5F8117',
452
+ light: '#9FC74E',
453
+ main: '#88B922'
433
454
  },
434
455
  text: {
435
456
  disabled: '#666666',
436
457
  primary: '#FFFFFF',
437
458
  secondary: '#CCCCCC'
438
459
  },
460
+ tile: {
461
+ background: '#2E2E2E',
462
+ border: '#4A4A4A',
463
+ borderHover: '#6D6D6D'
464
+ },
439
465
  warning: {
440
466
  contrastText: '#fff',
441
- main: '#C55400'
467
+ dark: '#B16C1B',
468
+ light: '#FCC481',
469
+ main: '#FD9B27'
442
470
  }
443
471
  };
444
472
 
@@ -46,7 +46,7 @@
46
46
 
47
47
  /* Background colors */
48
48
  --color-background-default: #f4f4f4;
49
- --color-background-listing-header: #666666;
49
+ --color-background-listing-header: #d9d9d9;
50
50
  --color-background-panel: #ededed;
51
51
  --color-background-panel-groups: #f5f5f5;
52
52
  --color-background-paper: #ffffff;
@@ -63,6 +63,8 @@
63
63
  /* Utility colors */
64
64
  --color-divider: #e3e3e3;
65
65
  --color-error-main: #ff4a4a;
66
+ --color-error-light: #ff6e6e;
67
+ --color-error-dark: #b23333;
66
68
 
67
69
  /* Header colors */
68
70
  --color-header-page-action-background-active: #1975d10f;
@@ -95,22 +97,29 @@
95
97
  --color-pending-main: #1ebeb3;
96
98
 
97
99
  /* Primary & Secondary colors */
98
- --color-primary-main: #2e68aa;
99
- --color-primary-light: #cde7fc;
100
- --color-primary-dark: #255891;
100
+ --color-primary-main: #131d5a;
101
+ --color-primary-light: #d8dce9;
102
+ --color-primary-dark: #2a3575;
101
103
  --color-primary-contrastText: #fff;
102
104
  --color-secondary-main: #c772d6;
103
105
  --color-secondary-light: #e5a5f0;
104
106
  --color-secondary-dark: #ac28c1;
105
107
 
106
108
  /* Status colors */
107
- --color-status-background-error: #ff6666;
109
+ --color-status-background-error: #ff6e6e;
108
110
  --color-status-background-none: --alpha(#2e68aa / 10%);
109
111
  --color-status-background-pending: #1ebeb3;
110
- --color-status-background-success: #88b922;
112
+ --color-status-background-success: #9fc74e;
111
113
  --color-stauts-background-unknown: #e3e3e3;
112
- --color-status-background-warning: #fd9b27;
114
+ --color-status-background-warning: #fcc481;
113
115
  --color-success-main: #88b922;
116
+ --color-success-light: #9fc74e;
117
+ --color-success-dark: #5f8117;
118
+
119
+ /* Tile container colors */
120
+ --color-tile-background: #ffffff;
121
+ --color-tile-border: #e3e3e3;
122
+ --color-tile-border-hover: #cccccc;
114
123
 
115
124
  /* Text colors */
116
125
  --color-text-disabled: #999999;
@@ -118,7 +127,7 @@
118
127
  --color-text-secondary: #666666;
119
128
  --color-warning-main: #fd9b27;
120
129
  --color-warning-light: #fcc481;
121
- --color-warning-dark: #fc7e00;
130
+ --color-warning-dark: #b16c1b;
122
131
 
123
132
  /* Base colors */
124
133
  --color-white: #ffffff;
@@ -156,7 +165,9 @@
156
165
  --color-chip-success: #5f8118;
157
166
  --color-chip-warning: #c55400;
158
167
  --color-divider: #666666;
159
- --color-error-main: #d60101;
168
+ --color-error-main: #ff4a4a;
169
+ --color-error-light: #ff6e6e;
170
+ --color-error-dark: #b23333;
160
171
  --color-header-page-action-background-active: #1975d10f;
161
172
  --color-header-page-action-background-default: #ffffff00;
162
173
  --color-header-page-action-color-active: #1976d2;
@@ -182,23 +193,30 @@
182
193
  --color-header-menu-item-color-active: #3e85d5;
183
194
  --color-header-menu-item-color-default: #f9fafb;
184
195
  --color-header-menu-item-color-hover: #ffffff;
185
- --color-pending-main: #118077;
196
+ --color-pending-main: #1ebeb3;
186
197
  --color-primary-main: #6eaff8;
187
198
  --color-primary-light: #8bbff9;
188
199
  --color-primary-dark: #4974a5;
189
200
  --color-primary-contrastText: #000;
190
201
  --color-secondary-main: #7c1fa2;
191
- --color-status-background-error: #d60101;
202
+ --color-status-background-error: #ff4a4a;
192
203
  --color-status-background-none: --alpha(#2e68aa / 10%);
193
- --color-status-background-pending: #118077;
194
- --color-status-background-success: #5f8118;
204
+ --color-status-background-pending: #1ebeb3;
205
+ --color-status-background-success: #88b922;
195
206
  --color-stauts-background-unknown: #666666;
196
- --color-status-background-warning: #c55400;
197
- --color-success-main: #5f8118;
207
+ --color-status-background-warning: #fd9b27;
208
+ --color-success-main: #88b922;
209
+ --color-success-light: #9fc74e;
210
+ --color-success-dark: #5f8117;
211
+ --color-tile-background: #2e2e2e;
212
+ --color-tile-border: #4a4a4a;
213
+ --color-tile-border-hover: #6d6d6d;
198
214
  --color-text-disabled: #666666;
199
215
  --color-text-primary: #ffffff;
200
216
  --color-text-secondary: #cccccc;
201
- --color-warning-main: #c55400;
217
+ --color-warning-main: #fd9b27;
218
+ --color-warning-light: #fcc481;
219
+ --color-warning-dark: #b16c1b;
202
220
  }
203
221
  }
204
222
 
@@ -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
- display: 'inline-block',
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
- display: 'inline-block',
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 }, index) => (
54
- <Fragment key={to.toString().replace(/\W/g, '')}>
55
- {index === 2 && <li className={classes.splitter} />}
56
- <li className={classes.item}>
57
- <Link
58
- aria-label={ariaLabel}
59
- className={classes.link}
60
- onClick={onClick}
61
- to={to}
62
- >
63
- <StatusCounter count={count} severityCode={severityCode} />
64
- </Link>
65
- </li>
66
- </Fragment>
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 { Badge, Tooltip } from '@mui/material';
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
- badge: {
14
- background: severityCode
15
- ? getStatusColors({ severityCode, theme })?.backgroundColor
16
- : 'transparent',
17
- borderRadius: theme.spacing(1.25),
18
- color: theme.palette.common.black,
19
- cursor: 'pointer',
20
- fontSize: theme.typography.body2.fontSize,
21
- fontWeight: theme.typography.fontWeightBold,
22
- height: theme.spacing(2.125),
23
- lineHeight: theme.spacing(2.125),
24
- minWidth: theme.spacing(2.125),
25
- position: 'relative',
26
- right: 0,
27
- top: 0,
28
- transform: 'none'
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 shouldDisableTooltip = Number(count) < 1000;
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
- <Badge
54
- badgeContent={formattedCount}
55
- classes={{
56
- badge: cx(classes.badge, className)
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 { Badge, ClickAwayListener } from '@mui/material';
4
+ import { ClickAwayListener, Tooltip } from '@mui/material';
5
5
 
6
- import { ComponentType, useEffect, useState } from 'react';
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
- header: {
45
- [theme.breakpoints.down(1025)]: {
46
- display: 'flex',
47
- flexFlow: 'row no-wrap'
48
- }
49
- },
50
- iconWrapper: {
51
- [theme.breakpoints.up(1025)]: {
52
- position: 'absolute',
53
- top: '0'
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
- textWrapper: {
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
- flex: '100%',
90
- fontSize: theme.typography.body1.fontSize,
91
- fontWeight: theme.typography.fontWeightBold,
92
- lineHeight: '1',
93
- whiteSpace: 'nowrap',
94
- [theme.breakpoints.down(1025)]: {
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: (params: { closeSubMenu: () => void }) => JSX.Element;
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
- showPendingBadge
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
- <div className={classes.header}>
151
- <div className={classes.indicators}>{renderIndicators()}</div>
152
- <button
153
- aria-controls={`${subMenuId}-menu`}
154
- aria-expanded={toggled}
155
- aria-haspopup="true"
156
- aria-label={title}
157
- className={classes.button}
158
- id={`${subMenuId}-button`}
159
- onClick={(): void => setToggled(!toggled)}
160
- type="button"
161
- >
162
- <span className={classes.iconWrapper}>
163
- <Badge
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';
@@ -85,7 +85,7 @@ export const useCopyCommandStyle = makeStyles()((theme) => ({
85
85
  languageChip: {
86
86
  background: theme.palette.background.listingHeader,
87
87
  borderRadius: `0px ${theme.shape.borderRadius}px ${theme.shape.borderRadius}px ${theme.shape.borderRadius}px`,
88
- color: theme.palette.common.white,
88
+ color: theme.palette.text.primary,
89
89
  fontSize: theme.typography.body2.fontSize,
90
90
  padding: `0px ${theme.spacing(0.5)}`,
91
91
  position: 'absolute',
@@ -25,14 +25,20 @@ export const getStatusColors = ({
25
25
  }: StatusColorProps): Colors => {
26
26
  const { palette } = theme;
27
27
 
28
+ // Typography color for status chips: text action primary (#000000) in light
29
+ // mode, paper (#212121) in dark mode, so it stays readable on the bright
30
+ // status backgrounds in both modes.
31
+ const chipTextColor =
32
+ palette.mode === 'dark' ? palette.background.paper : palette.text.primary;
33
+
28
34
  const colorMapping = {
29
35
  [SeverityCode.High]: {
30
36
  backgroundColor: theme.palette.statusBackground.error,
31
- color: palette.error.contrastText
37
+ color: chipTextColor
32
38
  },
33
39
  [SeverityCode.Medium]: {
34
40
  backgroundColor: theme.palette.statusBackground.warning,
35
- color: palette.warning.contrastText
41
+ color: chipTextColor
36
42
  },
37
43
  [SeverityCode.Low]: {
38
44
  backgroundColor: theme.palette.statusBackground.unknown,
@@ -40,11 +46,11 @@ export const getStatusColors = ({
40
46
  },
41
47
  [SeverityCode.Pending]: {
42
48
  backgroundColor: theme.palette.statusBackground.pending,
43
- color: palette.text.primary
49
+ color: chipTextColor
44
50
  },
45
51
  [SeverityCode.OK]: {
46
52
  backgroundColor: theme.palette.statusBackground.success,
47
- color: palette.text.primary
53
+ color: chipTextColor
48
54
  },
49
55
  [SeverityCode.None]: {
50
56
  backgroundColor: theme.palette.statusBackground.none,
@@ -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;