@centreon/ui 25.3.3 → 25.4.0

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": "25.3.3",
3
+ "version": "25.4.0",
4
4
  "description": "Centreon UI Components",
5
5
  "scripts": {
6
6
  "update:deps": "pnpx npm-check-updates -i --format group",
@@ -59,6 +59,7 @@ const ActionsList = ({
59
59
  return (
60
60
  <MenuItem
61
61
  aria-label={label}
62
+ data-testid={label}
62
63
  className={classes.item}
63
64
  data-variant={variant}
64
65
  id={label}
@@ -19,6 +19,7 @@ const useStyles = makeStyles()((theme) => ({
19
19
 
20
20
  type Props = {
21
21
  ariaLabel?: string;
22
+ dataTestid?: string;
22
23
  className?: string;
23
24
  onClick: (event) => void;
24
25
  title?: string | JSX.Element;
@@ -42,6 +43,7 @@ export const IconButton = ({
42
43
  title = '',
43
44
  ariaLabel,
44
45
  className,
46
+ dataTestid,
45
47
  tooltipPlacement,
46
48
  tooltipClassName,
47
49
  ...props
@@ -59,7 +61,7 @@ export const IconButton = ({
59
61
  aria-label={ariaLabel}
60
62
  className={cx(classes.button, className)}
61
63
  color="primary"
62
- data-testid={ariaLabel}
64
+ data-testid={dataTestid || ariaLabel}
63
65
  id={getNormalizedId(ariaLabel || '')}
64
66
  {...props}
65
67
  />
@@ -43,7 +43,7 @@ const Annotation = ({
43
43
 
44
44
  const setAnnotationHovered = useSetAtom(annotationHoveredAtom);
45
45
 
46
- const content = `${truncate(event.content)} (${t(labelBy)} ${
46
+ const content = `${truncate({ content: event.content })} (${t(labelBy)} ${
47
47
  event.contact?.name
48
48
  })`;
49
49
 
@@ -38,9 +38,10 @@ export const getXAxisTickFormat = (graphInterval: GraphInterval): string => {
38
38
  return gte(numberDays, 2) ? dateFormat : timeFormat;
39
39
  };
40
40
 
41
- export const truncate = (content?: string): string => {
42
- const maxLength = 180;
43
-
41
+ export const truncate = ({
42
+ content,
43
+ maxLength = 180
44
+ }: { content?: string; maxLength?: number }): string => {
44
45
  if (isNil(content)) {
45
46
  return '';
46
47
  }
@@ -25,6 +25,18 @@ interface GetBackgroundColorProps extends Omit<Props, 'isRowHighlighted'> {
25
25
  theme: Theme;
26
26
  }
27
27
 
28
+ interface StylesProps extends Props {
29
+ isRowHighlighted?: boolean;
30
+ listingVariant?: ListingVariant;
31
+ }
32
+
33
+ interface GetRowHighlightStyleProps {
34
+ isRowHighlighted?: boolean;
35
+ theme: Theme;
36
+ disableRowCondition;
37
+ row;
38
+ }
39
+
28
40
  const getBackgroundColor = ({
29
41
  isRowHovered,
30
42
  row,
@@ -51,25 +63,20 @@ const getBackgroundColor = ({
51
63
  return 'unset';
52
64
  };
53
65
 
54
- interface StylesProps extends Props {
55
- isRowHighlighted?: boolean;
56
- listingVariant?: ListingVariant;
57
- }
58
-
59
- interface GetRowHighlightStyleProps {
60
- isRowHighlighted?: boolean;
61
- theme: Theme;
62
- }
63
-
64
- const getRowHighlightStyle = ({
66
+ const getRowTextColor = ({
65
67
  isRowHighlighted,
66
- theme
67
- }: GetRowHighlightStyleProps): CSSObject | undefined =>
68
- isRowHighlighted
69
- ? {
70
- color: theme.palette.text.primary
71
- }
72
- : undefined;
68
+ theme,
69
+ disableRowCondition,
70
+ row
71
+ }: GetRowHighlightStyleProps): CSSObject | undefined => {
72
+ if (isRowHighlighted) {
73
+ return { color: theme.palette.text.primary };
74
+ }
75
+
76
+ if (disableRowCondition(row)) {
77
+ return { color: alpha(theme.palette.text.secondary, 0.5) };
78
+ }
79
+ };
73
80
 
74
81
  const useStyles = makeStyles<StylesProps>()(
75
82
  (
@@ -112,7 +119,7 @@ const useStyles = makeStyles<StylesProps>()(
112
119
  height: '100%',
113
120
  overflow: 'hidden',
114
121
  ...getTextStyleByViewMode({ listingVariant, theme }),
115
- p: getRowHighlightStyle({ isRowHighlighted, theme }),
122
+ p: getRowTextColor({ isRowHighlighted, disableRowCondition, row, theme }),
116
123
  padding: theme.spacing(0, 1),
117
124
  whiteSpace: 'nowrap'
118
125
  }
@@ -211,7 +211,7 @@ export const lightPalette: PaletteOptions = {
211
211
  default: '#696969'
212
212
  }
213
213
  },
214
- border: '#4A4A4A',
214
+ border: '#EDEDED',
215
215
  description: '#4A4A4A',
216
216
  title: '#000000'
217
217
  }
@@ -353,7 +353,7 @@ export const darkPalette: PaletteOptions = {
353
353
  default: '#696969'
354
354
  }
355
355
  },
356
- border: '#bdbdbd',
356
+ border: '#666666',
357
357
  description: '#bdbdbd',
358
358
  title: '#fff'
359
359
  }
@@ -95,15 +95,6 @@ export const customFetch = <T>({
95
95
  };
96
96
  }
97
97
 
98
- if (equals(response.status, 207)) {
99
- return {
100
- data: data.results,
101
- isError: false,
102
- message: '',
103
- statusCode: response.status
104
- };
105
- }
106
-
107
98
  if (decoder) {
108
99
  return decoder.decodeToPromise(data).catch((error: string) => {
109
100
  catchError({
@@ -0,0 +1,58 @@
1
+ import {
2
+ complement,
3
+ includes,
4
+ isEmpty,
5
+ isNil,
6
+ last,
7
+ length,
8
+ prop,
9
+ propEq,
10
+ split
11
+ } from 'ramda';
12
+ import useSnackbar from '../Snackbar/useSnackbar';
13
+
14
+ const useBulkResponse = () => {
15
+ const { showSuccessMessage, showErrorMessage, showWarningMessage } =
16
+ useSnackbar();
17
+
18
+ const handleBulkResponse = ({
19
+ data,
20
+ labelSuccess,
21
+ labelWarning,
22
+ labelFailed,
23
+ items
24
+ }) => {
25
+ const successfullResponses =
26
+ data?.filter(propEq(204, 'status')) || isNil(data);
27
+
28
+ const failedResponses = data?.filter(complement(propEq(204, 'status')));
29
+
30
+ const failedResponsesIds = failedResponses
31
+ ?.map(prop('href'))
32
+ ?.map((item: string) =>
33
+ Number.parseInt(last(split('/', item || '')) as string, 10)
34
+ );
35
+
36
+ if (isEmpty(successfullResponses)) {
37
+ showErrorMessage(labelFailed);
38
+
39
+ return;
40
+ }
41
+
42
+ if (length(successfullResponses) < length(data)) {
43
+ const failedResponsesNames = items
44
+ ?.filter((item) => includes(item.id, failedResponsesIds))
45
+ .map((item) => item.name);
46
+
47
+ showWarningMessage(`${labelWarning}: ${failedResponsesNames.join(', ')}`);
48
+
49
+ return;
50
+ }
51
+
52
+ showSuccessMessage(labelSuccess);
53
+ };
54
+
55
+ return handleBulkResponse;
56
+ };
57
+
58
+ export default useBulkResponse;
@@ -2,7 +2,21 @@ import { makeStyles } from 'tss-react/mui';
2
2
 
3
3
  export const useActionsStyles = makeStyles()((theme) => ({
4
4
  search: {
5
- maxWidth: theme.spacing(50)
5
+ maxWidth: theme.spacing(60),
6
+ minWidth: theme.spacing(20),
7
+ width: '100%'
8
+ },
9
+ filters: {
10
+ width: '100%',
11
+ paddingInline: theme.spacing(1),
12
+ display: 'flex',
13
+ alignItems: 'center',
14
+ justifyContent: 'center'
15
+ },
16
+ actions: {
17
+ display: 'grid',
18
+ gridTemplateColumns: 'min-content auto',
19
+ gap: theme.spacing(1)
6
20
  },
7
21
  clearButton: {
8
22
  alignSelf: 'flex-start'
@@ -1,4 +1,5 @@
1
1
  import { Box } from '@mui/material';
2
+ import { useActionsStyles } from './Actions.styles';
2
3
  import AddButton from './AddButton';
3
4
  import Search from './Search';
4
5
 
@@ -11,12 +12,14 @@ interface Props {
11
12
  }
12
13
 
13
14
  const Actions = ({ labels, filters }: Props): JSX.Element => {
15
+ const { classes } = useActionsStyles();
16
+
14
17
  return (
15
- <Box
16
- sx={{ display: 'grid', gridTemplateColumns: 'min-content auto', gap: 2 }}
17
- >
18
+ <Box className={classes.actions}>
18
19
  <AddButton label={labels.add} />
19
- <Search label={labels.search} filters={filters} />
20
+ <div className={classes.filters}>
21
+ <Search label={labels.search} filters={filters} />
22
+ </div>
20
23
  </Box>
21
24
  );
22
25
  };
@@ -14,21 +14,22 @@ const Search = ({ label, filters }: Props): JSX.Element => {
14
14
  const { change } = useSearch();
15
15
 
16
16
  return (
17
- <SearchField
18
- className={classes.search}
19
- debounced
20
- fullWidth
21
- dataTestId={label}
22
- placeholder={label}
23
- onChange={change}
24
- textFieldSlotsAndSlotProps={{
25
- slotProps: {
26
- input: {
27
- endAdornment: <Filters label="filters" filters={filters} />
17
+ <div className={classes.search}>
18
+ <SearchField
19
+ debounced
20
+ fullWidth
21
+ dataTestId={label}
22
+ placeholder={label}
23
+ onChange={change}
24
+ textFieldSlotsAndSlotProps={{
25
+ slotProps: {
26
+ input: {
27
+ endAdornment: <Filters label="filters" filters={filters} />
28
+ }
28
29
  }
29
- }
30
- }}
31
- />
30
+ }}
31
+ />
32
+ </div>
32
33
  );
33
34
  };
34
35
 
@@ -25,9 +25,10 @@ const useStyles = makeStyles()((theme) => ({
25
25
  },
26
26
  pageHeader: {
27
27
  alignItems: 'center',
28
- borderBottom: `1px solid ${theme.palette.header.page.border}`,
28
+ borderBottom: `2px solid ${theme.palette.header.page.border}`,
29
29
  display: 'flex',
30
- gap: theme.spacing(4)
30
+ gap: theme.spacing(4),
31
+ paddingBottom: theme.spacing(0.5)
31
32
  },
32
33
  pageHeaderActions: {
33
34
  '& > button': {
@@ -46,8 +47,7 @@ const useStyles = makeStyles()((theme) => ({
46
47
  pageHeaderMain: {
47
48
  display: 'flex',
48
49
  flexGrow: 1,
49
- gap: theme.spacing(1),
50
- minHeight: theme.spacing(4.5)
50
+ gap: theme.spacing(1)
51
51
  },
52
52
  pageHeaderMenu: {
53
53
  alignItems: 'flex-start',
@@ -96,7 +96,7 @@ const useStyles = makeStyles()((theme) => ({
96
96
  alignSelf: 'flex-start',
97
97
  h1: {
98
98
  ...theme.typography.h5,
99
- fontWeight: theme.typography.fontWeightMedium,
99
+ fontWeight: theme.typography.fontWeightBold,
100
100
  margin: theme.spacing(0),
101
101
  lineHeight: '1'
102
102
  }
@@ -29,7 +29,7 @@ export const useStyles = makeStyles()((theme) => ({
29
29
  display: 'grid',
30
30
  gridTemplateRows: 'auto',
31
31
  overflow: 'hidden',
32
- padding: theme.spacing(1.5, 3, 1.5)
32
+ padding: theme.spacing(0, 3, 1.5)
33
33
  },
34
34
  pageLayoutHeader: {
35
35
  '[data-variant="fixed-header"] &': {
package/src/index.ts CHANGED
@@ -133,6 +133,7 @@ export {
133
133
  } from './api/useGraphQuery';
134
134
  export { WidgetResourceType as ResourceType } from './api/useGraphQuery/models';
135
135
  export { default as QueryProvider, client } from './api/QueryProvider';
136
+ export { default as useBulkResponse } from './api/useBulkResponse';
136
137
  export {
137
138
  default as FileDropZone,
138
139
  transformFileListToArray