@centreon/ui 23.10.1-MON-20803-RS-add-basic-filter.21 → 23.10.1-MON-22436-cloud-notification-fix-wording.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@centreon/ui",
3
- "version": "23.10.1-MON-20803-RS-add-basic-filter.21",
3
+ "version": "23.10.1-MON-22436-cloud-notification-fix-wording.2",
4
4
  "description": "Centreon UI Components",
5
5
  "scripts": {
6
6
  "eslint": "eslint ./src --ext .js,.jsx,.ts,.tsx --max-warnings 0",
@@ -2,13 +2,16 @@ import { makeStyles } from 'tss-react/mui';
2
2
  import { T, always, cond, equals } from 'ramda';
3
3
 
4
4
  import { SvgIconComponent } from '@mui/icons-material';
5
- import Typography, { TypographyTypeMap } from '@mui/material/Typography';
6
- import { FormControlLabel, Checkbox as MuiCheckbox, Box } from '@mui/material';
5
+ import {
6
+ FormControlLabel,
7
+ Checkbox as MuiCheckbox,
8
+ Box,
9
+ Typography
10
+ } from '@mui/material';
7
11
 
8
12
  export type LabelPlacement = 'bottom' | 'top' | 'end' | 'start' | undefined;
9
13
 
10
14
  interface StyleProps {
11
- disabled: boolean;
12
15
  hasIcon: boolean;
13
16
  labelPlacement: LabelPlacement;
14
17
  }
@@ -22,7 +25,13 @@ const getLabelSpacing = (labelPlacement, theme): string => {
22
25
  };
23
26
 
24
27
  const useStyles = makeStyles<StyleProps>()(
25
- (theme, { disabled, hasIcon, labelPlacement }) => ({
28
+ (theme, { hasIcon, labelPlacement }) => ({
29
+ checkbox: {
30
+ '&.Mui-checked': {
31
+ color: theme.palette.primary.main
32
+ },
33
+ color: theme.palette.primary.main
34
+ },
26
35
  container: hasIcon
27
36
  ? {
28
37
  alignItems: 'center',
@@ -36,13 +45,8 @@ const useStyles = makeStyles<StyleProps>()(
36
45
  fontSize: theme.spacing(10)
37
46
  },
38
47
  label: {
39
- color: disabled
40
- ? theme.palette.action.disabled
41
- : theme.palette.text.secondary,
42
- fontSize: theme.typography.body1.fontSize,
43
- fontWeight: equals(labelPlacement, 'top')
44
- ? theme.typography.fontWeightBold
45
- : theme.typography.fontWeightMedium,
48
+ fontSize: theme.typography.body2.fontSize,
49
+ fontWeight: theme.typography.fontWeightMedium,
46
50
  padding: getLabelSpacing(labelPlacement, theme)
47
51
  }
48
52
  })
@@ -56,7 +60,6 @@ interface Props {
56
60
  disabled?: boolean;
57
61
  label: string;
58
62
  labelPlacement?: LabelPlacement;
59
- labelProps?: TypographyTypeMap['props'];
60
63
  onChange?: (e) => void;
61
64
  }
62
65
 
@@ -68,11 +71,9 @@ const Checkbox = ({
68
71
  className,
69
72
  disabled = false,
70
73
  labelPlacement = 'end',
71
- dataTestId,
72
- labelProps
74
+ dataTestId
73
75
  }: Props): JSX.Element => {
74
76
  const { classes, cx } = useStyles({
75
- disabled,
76
77
  hasIcon: !!Icon,
77
78
  labelPlacement
78
79
  });
@@ -84,6 +85,7 @@ const Checkbox = ({
84
85
  control={
85
86
  <MuiCheckbox
86
87
  checked={checked}
88
+ className={classes.checkbox}
87
89
  color="primary"
88
90
  disabled={disabled}
89
91
  id={label}
@@ -94,11 +96,7 @@ const Checkbox = ({
94
96
  }
95
97
  data-testid={dataTestId || ''}
96
98
  key={label}
97
- label={
98
- <Typography classes={{ root: classes.label }} {...labelProps}>
99
- {label}
100
- </Typography>
101
- }
99
+ label={<Typography className={classes.label}>{label}</Typography>}
102
100
  labelPlacement={labelPlacement}
103
101
  sx={{ margin: 0, padding: 0 }}
104
102
  />
@@ -1,19 +1,15 @@
1
1
  import { equals, includes } from 'ramda';
2
2
  import { makeStyles } from 'tss-react/mui';
3
3
 
4
- import FormGroup, { FormGroupProps } from '@mui/material/FormGroup';
5
- import { TypographyTypeMap } from '@mui/material/Typography';
4
+ import { FormGroup } from '@mui/material';
6
5
 
7
6
  import Checkbox, { LabelPlacement } from '../Checkbox';
8
7
 
9
8
  interface Props {
10
- className?: string;
11
9
  dataTestId?: string;
12
10
  direction?: 'horizontal' | 'vertical';
13
11
  disabled?: boolean;
14
- formGroupProps?: FormGroupProps;
15
12
  labelPlacement?: LabelPlacement;
16
- labelProps?: TypographyTypeMap['props'];
17
13
  onChange?: (e) => void;
18
14
  options: Array<string>;
19
15
  values: Array<string>;
@@ -38,32 +34,27 @@ const CheckboxGroup = ({
38
34
  onChange,
39
35
  labelPlacement = 'end',
40
36
  disabled = false,
41
- dataTestId,
42
- className,
43
- labelProps,
44
- formGroupProps
37
+ dataTestId
45
38
  }: Props): JSX.Element => {
46
- const { classes, cx } = useStyles();
39
+ const { classes } = useStyles();
47
40
 
48
41
  const row = !equals(direction, 'vertical');
49
42
 
50
43
  return (
51
44
  <FormGroup
52
- classes={{ root: classes.container }}
45
+ className={classes.container}
53
46
  data-testid={dataTestId || ''}
54
47
  row={row}
55
- {...formGroupProps}
56
48
  >
57
49
  {options.map((value) => {
58
50
  return (
59
51
  <Checkbox
60
52
  checked={includes(value, values)}
61
- className={cx(classes.checkbox, className)}
53
+ className={classes.checkbox}
62
54
  disabled={disabled}
63
55
  key={value}
64
56
  label={value}
65
57
  labelPlacement={labelPlacement}
66
- labelProps={labelProps}
67
58
  onChange={onChange}
68
59
  />
69
60
  );
@@ -1,4 +1,4 @@
1
- import { Dispatch, SetStateAction, useEffect, useState } from 'react';
1
+ import { useState, useEffect } from 'react';
2
2
 
3
3
  import { makeStyles } from 'tss-react/mui';
4
4
 
@@ -9,7 +9,6 @@ import {
9
9
  PopperPlacementType,
10
10
  useTheme
11
11
  } from '@mui/material';
12
- import { PopperProps } from '@mui/material/Popper';
13
12
 
14
13
  import { IconButton } from '..';
15
14
 
@@ -20,22 +19,15 @@ const useStyles = makeStyles()(() => ({
20
19
  }
21
20
  }));
22
21
 
23
- interface PopoverData {
24
- anchorEl: HTMLElement | undefined;
25
- setAnchorEl: Dispatch<SetStateAction<HTMLElement | undefined>>;
26
- }
27
-
28
22
  interface Props {
29
23
  canOpen?: boolean;
30
24
  children: (props?) => JSX.Element;
31
25
  className?: string;
32
26
  dataTestId?: string;
33
- getPopoverData?: (data: PopoverData) => void;
34
27
  icon: JSX.Element;
35
28
  onClose?: () => void;
36
29
  onOpen?: () => void;
37
30
  popperPlacement?: PopperPlacementType;
38
- popperProps?: Partial<PopperProps>;
39
31
  title?: string;
40
32
  }
41
33
 
@@ -48,21 +40,20 @@ const PopoverMenu = ({
48
40
  onClose,
49
41
  canOpen = true,
50
42
  className,
51
- dataTestId,
52
- getPopoverData,
53
- popperProps
43
+ dataTestId
54
44
  }: Props): JSX.Element => {
55
45
  const theme = useTheme();
56
46
  const { classes, cx } = useStyles();
57
47
  const [anchorEl, setAnchorEl] = useState<HTMLElement | undefined>();
48
+
58
49
  const isOpen = Boolean(anchorEl);
59
50
 
60
51
  const close = (reason?): void => {
61
52
  const isClosedByInputClick = reason?.type === 'mousedown';
53
+
62
54
  if (isClosedByInputClick) {
63
55
  return;
64
56
  }
65
-
66
57
  onClose?.();
67
58
  setAnchorEl(undefined);
68
59
  };
@@ -84,10 +75,6 @@ const PopoverMenu = ({
84
75
  }
85
76
  }, [canOpen]);
86
77
 
87
- useEffect(() => {
88
- getPopoverData?.({ anchorEl, setAnchorEl });
89
- }, [anchorEl]);
90
-
91
78
  return (
92
79
  <>
93
80
  <IconButton
@@ -110,7 +97,6 @@ const PopoverMenu = ({
110
97
  style={{ zIndex: theme.zIndex.tooltip }}
111
98
  onResize={(): undefined => undefined}
112
99
  onResizeCapture={(): undefined => undefined}
113
- {...popperProps}
114
100
  >
115
101
  <Paper>{children({ close })}</Paper>
116
102
  </Popper>
@@ -331,6 +331,29 @@ describe('Rich Text Editor', () => {
331
331
  cy.findByText(blockType).click();
332
332
 
333
333
  cy.get('[data-testid="RichTextEditor"]').find(tag).should('be.visible');
334
+
335
+ cy.makeSnapshot();
336
+ });
337
+ });
338
+ });
339
+
340
+ describe('Aligns', () => {
341
+ beforeEach(() => {
342
+ cy.mount({
343
+ Component: <RichTextEditor editable />
344
+ });
345
+ });
346
+
347
+ const testCases = ['Center', 'Right'];
348
+
349
+ testCases.forEach((label) => {
350
+ it(`aligns the text to the ${label} when the corresponding button is clicked`, () => {
351
+ cy.get('[data-testid="RichTextEditor"]').type('Example');
352
+
353
+ cy.findByLabelText('left').click();
354
+ cy.contains(label).click();
355
+
356
+ cy.makeSnapshot();
334
357
  });
335
358
  });
336
359
  });
@@ -63,7 +63,8 @@ withMacrosPlugin.args = {
63
63
 
64
64
  export const withEditableFalse = Template.bind({});
65
65
  withEditableFalse.args = {
66
- editable: false,
66
+ editable: true,
67
+ editorState: JSON.stringify(initialEditorState),
67
68
  initialEditorState: JSON.stringify(initialEditorState)
68
69
  };
69
70
 
@@ -71,7 +72,8 @@ export const Disabled = Template.bind({});
71
72
  Disabled.args = {
72
73
  disabled: true,
73
74
  editable: false,
74
- editorState: JSON.stringify(initialEditorState)
75
+ editorState: JSON.stringify(initialEditorState),
76
+ initialEditorState: JSON.stringify(initialEditorState)
75
77
  };
76
78
 
77
79
  const StoryWithEditableFalseLikePreview = (): JSX.Element => {
@@ -0,0 +1,115 @@
1
+ import { useCallback, useEffect, useState } from 'react';
2
+
3
+ import {
4
+ $getSelection,
5
+ $isElementNode,
6
+ $isRangeSelection,
7
+ ElementFormatType,
8
+ FORMAT_ELEMENT_COMMAND
9
+ } from 'lexical';
10
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
11
+ import { equals } from 'ramda';
12
+
13
+ import FormatAlignLeftIcon from '@mui/icons-material/FormatAlignLeft';
14
+ import FormatAlignCenterIcon from '@mui/icons-material/FormatAlignCenter';
15
+ import FormatAlignRightIcon from '@mui/icons-material/FormatAlignRight';
16
+ import { OverridableComponent } from '@mui/material/OverridableComponent';
17
+ import { SvgIconTypeMap } from '@mui/material';
18
+
19
+ import { Menu } from '../../../components';
20
+ import { getSelectedNode } from '../../utils/getSelectedNode';
21
+
22
+ import { useAlignPickerStyles } from './ToolbarPlugin.styles';
23
+
24
+ const formatOptions: Array<{
25
+ Icon: OverridableComponent<SvgIconTypeMap<object, 'svg'>>;
26
+ label: string;
27
+ value: ElementFormatType;
28
+ }> = [
29
+ {
30
+ Icon: FormatAlignLeftIcon,
31
+ label: 'Left',
32
+ value: 'left'
33
+ },
34
+ {
35
+ Icon: FormatAlignCenterIcon,
36
+ label: 'Center',
37
+ value: 'center'
38
+ },
39
+ {
40
+ Icon: FormatAlignRightIcon,
41
+ label: 'Right',
42
+ value: 'right'
43
+ }
44
+ ];
45
+
46
+ interface Props {
47
+ disabled: boolean;
48
+ }
49
+
50
+ const AlignPicker = ({ disabled }: Props): JSX.Element => {
51
+ const { classes } = useAlignPickerStyles();
52
+
53
+ const [elementFormat, setElementFormat] = useState<ElementFormatType>('left');
54
+
55
+ const [editor] = useLexicalComposerContext();
56
+
57
+ const dispatchAlignment = (alignment: ElementFormatType) => () => {
58
+ editor.dispatchCommand(FORMAT_ELEMENT_COMMAND, alignment);
59
+ };
60
+
61
+ const updateElementFormat = useCallback(() => {
62
+ const selection = $getSelection();
63
+
64
+ if (!$isRangeSelection(selection)) {
65
+ return;
66
+ }
67
+
68
+ const node = getSelectedNode(selection);
69
+ const parent = node.getParent();
70
+
71
+ setElementFormat(
72
+ ($isElementNode(node) ? node.getFormatType() : parent?.getFormatType()) ||
73
+ 'left'
74
+ );
75
+ }, [editor]);
76
+
77
+ const selectedFormat = formatOptions.find(({ value }) =>
78
+ equals(value, elementFormat)
79
+ );
80
+
81
+ useEffect(() => {
82
+ return editor.registerUpdateListener(({ editorState }) => {
83
+ editorState.read(() => {
84
+ updateElementFormat();
85
+ });
86
+ });
87
+ }, [editor, updateElementFormat]);
88
+
89
+ return (
90
+ <Menu>
91
+ <Menu.Button ariaLabel={elementFormat} disabled={disabled}>
92
+ {selectedFormat && (
93
+ <div className={classes.button}>
94
+ <selectedFormat.Icon /> {selectedFormat.label}
95
+ </div>
96
+ )}
97
+ </Menu.Button>
98
+ <Menu.Items>
99
+ {formatOptions.map(({ Icon, label, value }) => (
100
+ <Menu.Item
101
+ isActive={equals(value, elementFormat)}
102
+ key={value}
103
+ onClick={dispatchAlignment(value)}
104
+ >
105
+ <div className={classes.option}>
106
+ <Icon /> {label}
107
+ </div>
108
+ </Menu.Item>
109
+ ))}
110
+ </Menu.Items>
111
+ </Menu>
112
+ );
113
+ };
114
+
115
+ export default AlignPicker;
@@ -5,3 +5,18 @@ export const useBlockButtonsStyles = makeStyles()((theme) => ({
5
5
  width: theme.spacing(17)
6
6
  }
7
7
  }));
8
+
9
+ export const useAlignPickerStyles = makeStyles()((theme) => ({
10
+ button: {
11
+ alignItems: 'center',
12
+ display: 'flex',
13
+ flexDirection: 'row',
14
+ gap: theme.spacing(1)
15
+ },
16
+ option: {
17
+ alignItems: 'center',
18
+ display: 'flex',
19
+ flexDirection: 'row',
20
+ gap: theme.spacing(2)
21
+ }
22
+ }));
@@ -6,6 +6,7 @@ import FormatButtons from './FormatButtons';
6
6
  import UndoRedoButtons from './UndoRedoButtons';
7
7
  import MacrosButton from './MacrosButton';
8
8
  import BlockButtons from './BlockButtons';
9
+ import AlignPicker from './AlignPicker';
9
10
 
10
11
  interface Props {
11
12
  disabled: boolean;
@@ -56,6 +57,7 @@ const ToolbarPlugin = ({
56
57
  <MacrosButton disabled={disabled} />
57
58
  </>
58
59
  )}
60
+ <AlignPicker disabled={disabled} />
59
61
  </div>
60
62
  ) : null;
61
63
  };
@@ -21,7 +21,7 @@ import {
21
21
  GetConditionsSearchQueryParameterValueState
22
22
  } from './models';
23
23
 
24
- export const getFoundFields = ({
24
+ const getFoundFields = ({
25
25
  value,
26
26
  fields
27
27
  }: RegexSearchParameter): Array<SearchMatch> => {
@@ -108,7 +108,7 @@ const getConditionsSearchQueryParameterValue = (
108
108
  };
109
109
  };
110
110
 
111
- export const getSearchQueryParameterValue = (
111
+ const getSearchQueryParameterValue = (
112
112
  search: SearchParameter | undefined
113
113
  ): SearchQueryParameterValue => {
114
114
  if (search === undefined) {
@@ -134,3 +134,5 @@ export const getSearchQueryParameterValue = (
134
134
 
135
135
  return { $and: result };
136
136
  };
137
+
138
+ export default getSearchQueryParameterValue;
@@ -1,7 +1,7 @@
1
1
  import toRawQueryParameters from '../../queryParameters';
2
2
  import { QueryParameter } from '../../queryParameters/models';
3
3
 
4
- import { getSearchQueryParameterValue } from './getSearchQueryParameterValue';
4
+ import getSearchQueryParameterValue from './getSearchQueryParameterValue';
5
5
  import { Parameters, BuildListingEndpointParameters } from './models';
6
6
 
7
7
  const getQueryParameters = ({
@@ -13,6 +13,7 @@ import { useMenu } from '../useMenu';
13
13
  import { useStyles } from './MenuButton.styles';
14
14
 
15
15
  type MenuButtonProps = {
16
+ ariaLabel?: string;
16
17
  children?: ReactNode;
17
18
  hasArrow?: boolean;
18
19
  isOpen?: boolean;
@@ -27,6 +28,7 @@ const MenuButton = ({
27
28
  hasArrow = true,
28
29
  size = 'small',
29
30
  variant = 'ghost',
31
+ ariaLabel,
30
32
  ...attr
31
33
  }: MenuButtonProps): ReactElement => {
32
34
  const { classes } = useStyles();
@@ -47,6 +49,7 @@ const MenuButton = ({
47
49
  return (
48
50
  <Button
49
51
  {...attr}
52
+ aria-label={ariaLabel}
50
53
  className={classes.menuButton}
51
54
  data-is-active={isMenuOpen}
52
55
  size={size}
package/src/index.ts CHANGED
@@ -75,10 +75,7 @@ export { default as useCancelTokenSource } from './api/useCancelTokenSource';
75
75
  export { getData, patchData, postData, putData, deleteData } from './api';
76
76
  export { default as useRequest } from './api/useRequest';
77
77
  export { default as buildListingEndpoint } from './api/buildListingEndpoint';
78
- export {
79
- getSearchQueryParameterValue,
80
- getFoundFields
81
- } from './api/buildListingEndpoint/getSearchQueryParameterValue';
78
+ export { default as getSearchQueryParameterValue } from './api/buildListingEndpoint/getSearchQueryParameterValue';
82
79
  export type {
83
80
  Parameters as ListingParameters,
84
81
  BuildListingEndpointParameters,
@@ -1,4 +1,4 @@
1
- import { useRef, useCallback, useEffect } from 'react';
1
+ import { useRef, useCallback } from 'react';
2
2
 
3
3
  interface Props {
4
4
  functionToDebounce: (...args) => void;
@@ -12,11 +12,6 @@ export const useDebounce = ({
12
12
  memoProps = []
13
13
  }: Props): ((...args) => void) => {
14
14
  const timeoutRef = useRef<number | null>(null);
15
- const ref = useRef();
16
-
17
- useEffect(() => {
18
- ref.current = functionToDebounce;
19
- }, [functionToDebounce]);
20
15
 
21
16
  return useCallback((...args): void => {
22
17
  if (timeoutRef.current) {
@@ -24,7 +19,7 @@ export const useDebounce = ({
24
19
  }
25
20
 
26
21
  timeoutRef.current = setTimeout(() => {
27
- ref.current?.(...args);
22
+ functionToDebounce(...args);
28
23
  }, wait);
29
24
  }, memoProps);
30
25
  };