@centreon/ui 26.10.0 → 26.10.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/Form/CollapsibleGroup.tsx +1 -1
- package/src/Listing/Header/Cell/ListingHeaderCell.tsx +4 -4
- package/src/Listing/Header/Cell/SelectActionListingHeaderCell.tsx +3 -3
- package/src/ThemeProvider/palettes.ts +44 -16
- package/src/ThemeProvider/tailwindcss.css +34 -16
- 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/components/CopyCommand/CopyCommand.styles.tsx +1 -1
- package/src/utils/statuses.ts +10 -4
- package/src/TopCounterElements/ResourceSubMenu.tsx +0 -110
package/package.json
CHANGED
|
@@ -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-
|
|
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-
|
|
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-
|
|
85
|
+
icon: 'text-text-primary'
|
|
86
86
|
}}
|
|
87
|
-
className="text-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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: '#
|
|
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: '#
|
|
271
|
-
light: '#
|
|
272
|
-
main: '#
|
|
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: '#
|
|
291
|
+
error: '#FF6E6E',
|
|
282
292
|
none: alpha('#2E68AA', 0.1),
|
|
283
293
|
pending: '#1EBEB3',
|
|
284
|
-
success: '#
|
|
294
|
+
success: '#9FC74E',
|
|
285
295
|
unknown: '#E3E3E3',
|
|
286
|
-
warning: '#
|
|
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: '#
|
|
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
|
-
|
|
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: '#
|
|
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: '#
|
|
442
|
+
error: '#FF4A4A',
|
|
424
443
|
none: alpha('#2E68AA', 0.1),
|
|
425
|
-
pending: '#
|
|
426
|
-
success: '#
|
|
444
|
+
pending: '#1EBEB3',
|
|
445
|
+
success: '#88B922',
|
|
427
446
|
unknown: '#666666',
|
|
428
|
-
warning: '#
|
|
447
|
+
warning: '#FD9B27'
|
|
429
448
|
},
|
|
430
449
|
success: {
|
|
431
450
|
contrastText: '#fff',
|
|
432
|
-
|
|
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
|
-
|
|
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: #
|
|
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: #
|
|
99
|
-
--color-primary-light: #
|
|
100
|
-
--color-primary-dark: #
|
|
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: #
|
|
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: #
|
|
112
|
+
--color-status-background-success: #9fc74e;
|
|
111
113
|
--color-stauts-background-unknown: #e3e3e3;
|
|
112
|
-
--color-status-background-warning: #
|
|
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: #
|
|
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: #
|
|
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: #
|
|
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: #
|
|
202
|
+
--color-status-background-error: #ff4a4a;
|
|
192
203
|
--color-status-background-none: --alpha(#2e68aa / 10%);
|
|
193
|
-
--color-status-background-pending: #
|
|
194
|
-
--color-status-background-success: #
|
|
204
|
+
--color-status-background-pending: #1ebeb3;
|
|
205
|
+
--color-status-background-success: #88b922;
|
|
195
206
|
--color-stauts-background-unknown: #666666;
|
|
196
|
-
--color-status-background-warning: #
|
|
197
|
-
--color-success-main: #
|
|
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: #
|
|
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
|
-
|
|
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';
|
|
@@ -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.
|
|
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',
|
package/src/utils/statuses.ts
CHANGED
|
@@ -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:
|
|
37
|
+
color: chipTextColor
|
|
32
38
|
},
|
|
33
39
|
[SeverityCode.Medium]: {
|
|
34
40
|
backgroundColor: theme.palette.statusBackground.warning,
|
|
35
|
-
color:
|
|
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:
|
|
49
|
+
color: chipTextColor
|
|
44
50
|
},
|
|
45
51
|
[SeverityCode.OK]: {
|
|
46
52
|
backgroundColor: theme.palette.statusBackground.success,
|
|
47
|
-
color:
|
|
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;
|