@centreon/ui 23.10.46 → 23.10.48

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.46",
3
+ "version": "23.10.48",
4
4
  "description": "Centreon UI Components",
5
5
  "scripts": {
6
6
  "eslint": "eslint ./src --ext .js,.jsx,.ts,.tsx --max-warnings 0",
@@ -71,6 +71,7 @@
71
71
  "@testing-library/jest-dom": "^5.16.5",
72
72
  "@testing-library/react": "^13.4.0",
73
73
  "@testing-library/react-hooks": "^8.0.1",
74
+ "@types/cypress": "^1.1.3",
74
75
  "@types/jest": "^27.5.0",
75
76
  "@types/ramda": "^0.28.12",
76
77
  "@types/react": "^18.0.26",
@@ -1,6 +1,4 @@
1
1
  /* eslint-disable react/no-array-index-key */
2
- import * as React from 'react';
3
-
4
2
  import { makeStyles } from 'tss-react/mui';
5
3
  import { useTranslation } from 'react-i18next';
6
4
  import { equals } from 'ramda';
@@ -15,14 +13,15 @@ import {
15
13
  } from '@mui/material';
16
14
 
17
15
  interface ActionsType {
18
- Icon: (props: SvgIconProps) => JSX.Element;
16
+ Icon?: (props: SvgIconProps) => JSX.Element;
19
17
  label: string;
20
- onClick?: () => void;
18
+ onClick?: (e?) => void;
21
19
  }
22
20
 
23
21
  interface Props {
24
22
  actions: Array<ActionsType | 'divider'>;
25
23
  className?: string;
24
+ listItemClassName?: string;
26
25
  }
27
26
 
28
27
  const useStyles = makeStyles()({
@@ -31,7 +30,11 @@ const useStyles = makeStyles()({
31
30
  }
32
31
  });
33
32
 
34
- const ActionsList = ({ className, actions }: Props): JSX.Element => {
33
+ const ActionsList = ({
34
+ className,
35
+ listItemClassName,
36
+ actions
37
+ }: Props): JSX.Element => {
35
38
  const { cx, classes } = useStyles();
36
39
  const { t } = useTranslation();
37
40
 
@@ -45,11 +48,15 @@ const ActionsList = ({ className, actions }: Props): JSX.Element => {
45
48
  const { label, Icon, onClick } = action as ActionsType;
46
49
 
47
50
  return (
48
- <MenuItem aria-label={label} key={label} onClick={onClick}>
49
- <ListItemIcon>
50
- <Icon fontSize="small" />
51
- </ListItemIcon>
52
- <ListItemText>{t(label)}</ListItemText>
51
+ <MenuItem aria-label={label} id={label} key={label} onClick={onClick}>
52
+ {Icon && (
53
+ <ListItemIcon>
54
+ <Icon fontSize="small" />
55
+ </ListItemIcon>
56
+ )}
57
+ <ListItemText className={listItemClassName}>
58
+ {t(label)}
59
+ </ListItemText>
53
60
  </MenuItem>
54
61
  );
55
62
  })}
@@ -1,4 +1,5 @@
1
1
  import RichTextEditor from './RichTextEditor';
2
+ import { standardMacros } from './plugins/ToolbarPlugin/MacrosButton';
2
3
 
3
4
  interface CheckElementStyleOnRichTextEditorProps {
4
5
  check: boolean;
@@ -201,4 +202,32 @@ describe('Rich Text Editor', () => {
201
202
  );
202
203
  });
203
204
  });
205
+
206
+ describe('Rich Text Editor with Macros Plugin', () => {
207
+ beforeEach(() => {
208
+ cy.mount({
209
+ Component: <RichTextEditor displayMacrosButton editable />
210
+ });
211
+ });
212
+
213
+ it('displays the Macros button when the "displayMacrosButton" prop is set to true', () => {
214
+ cy.findByLabelText('Macros').should('be.visible');
215
+ cy.findByLabelText('Macros').click();
216
+
217
+ standardMacros.forEach((macro) => {
218
+ cy.findByText(macro).should('be.visible');
219
+ });
220
+ });
221
+
222
+ it('ensures that the selected macro is inserted into the RichTextEditor', () => {
223
+ cy.get('[data-testid="RichTextEditor"]').type('macro : ');
224
+
225
+ cy.findByLabelText('Macros').click({});
226
+
227
+ standardMacros.forEach((macro) => {
228
+ cy.findByText(macro).should('be.visible').click({ force: true });
229
+ cy.get('[data-testid="RichTextEditor"]').should('contain', macro);
230
+ });
231
+ });
232
+ });
204
233
  });
@@ -18,6 +18,7 @@ import FloatingLinkEditorPlugin from './plugins/FloatingLinkEditorPlugin';
18
18
 
19
19
  export interface RichTextEditorProps {
20
20
  contentClassName?: string;
21
+ displayMacrosButton?: boolean;
21
22
  editable: boolean;
22
23
  editorState?: string;
23
24
  error?: string;
@@ -92,7 +93,8 @@ const RichTextEditor = ({
92
93
  toolbarPositions = 'start',
93
94
  error,
94
95
  onBlur,
95
- contentClassName
96
+ contentClassName,
97
+ displayMacrosButton = false
96
98
  }: RichTextEditorProps): JSX.Element => {
97
99
  const { classes } = useStyles({ toolbarPositions });
98
100
 
@@ -122,7 +124,11 @@ const RichTextEditor = ({
122
124
  <LexicalComposer initialConfig={initialConfig}>
123
125
  <div className={classes.container}>
124
126
  <div className={classes.toolbar}>
125
- <ToolbarPlugin editable={editable} getEditorState={getEditorState} />
127
+ <ToolbarPlugin
128
+ displayMacrosButton={displayMacrosButton}
129
+ editable={editable}
130
+ getEditorState={getEditorState}
131
+ />
126
132
  </div>
127
133
  <div>
128
134
  <RichTextPlugin
@@ -56,6 +56,11 @@ withCustomPlaceholder.args = {
56
56
  placeholder: 'Custom placeholder...'
57
57
  };
58
58
 
59
+ export const withMacrosPlugin = Template.bind({});
60
+ withMacrosPlugin.args = {
61
+ displayMacrosButton: true
62
+ };
63
+
59
64
  export const withEditableFalse = Template.bind({});
60
65
  withEditableFalse.args = {
61
66
  editable: false,
@@ -0,0 +1,87 @@
1
+ import { useState } from 'react';
2
+
3
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
4
+ import { createCommand, LexicalCommand } from 'lexical';
5
+
6
+ import MacrosIcon from '@mui/icons-material/TerminalOutlined';
7
+
8
+ import { ActionsList, IconButton, PopoverMenu } from '../../..';
9
+
10
+ import { useStyles } from '.';
11
+
12
+ const LowPriority = 1;
13
+
14
+ export const standardMacros = [
15
+ '{{SHORTDATETIME}}',
16
+ '{{LONGDATETIME}}',
17
+ '{{ALIAS}}',
18
+ '{{ID}}',
19
+ '{{NAME}}',
20
+ '{{OUTPUT}}',
21
+ '{{STATE}}',
22
+ '{{STATETYPE}}'
23
+ ];
24
+
25
+ const MacrosButton = (): JSX.Element => {
26
+ const { classes } = useStyles();
27
+ const [arMacrosDiplayed, setAreMacrosDiplayed] = useState(false);
28
+
29
+ const [editor] = useLexicalComposerContext();
30
+
31
+ const INSERT_MACROS_COMMAND: LexicalCommand<string> = createCommand();
32
+
33
+ const onClick = (e): void => {
34
+ const macro = e.target.id || e.target.textContent.trim();
35
+
36
+ editor.dispatchCommand(INSERT_MACROS_COMMAND, macro);
37
+ };
38
+
39
+ editor.registerCommand(
40
+ INSERT_MACROS_COMMAND,
41
+ (payload: string) => {
42
+ if (!editor) {
43
+ return false;
44
+ }
45
+
46
+ document.execCommand('insertText', false, payload);
47
+
48
+ return true;
49
+ },
50
+ LowPriority
51
+ );
52
+
53
+ const displayMacros = (): void => {
54
+ setAreMacrosDiplayed(true);
55
+ };
56
+
57
+ const actions = standardMacros.map((macro) => ({
58
+ label: macro,
59
+ onClick
60
+ }));
61
+
62
+ return (
63
+ <PopoverMenu
64
+ icon={
65
+ <IconButton
66
+ ariaLabel="Macros"
67
+ className={classes.macrosButton}
68
+ title="Macros"
69
+ tooltipPlacement="top"
70
+ onClick={displayMacros}
71
+ >
72
+ <MacrosIcon />
73
+ </IconButton>
74
+ }
75
+ >
76
+ {(): JSX.Element => (
77
+ <div>
78
+ {arMacrosDiplayed && (
79
+ <ActionsList actions={actions} listItemClassName={classes.macros} />
80
+ )}
81
+ </div>
82
+ )}
83
+ </PopoverMenu>
84
+ );
85
+ };
86
+
87
+ export default MacrosButton;
@@ -5,23 +5,35 @@ import { Divider } from '@mui/material';
5
5
 
6
6
  import FormatButtons from './FormatButtons';
7
7
  import UndoRedoButtons from './UndoRedoButtons';
8
+ import MacrosButton from './MacrosButton';
8
9
 
9
10
  interface Props {
11
+ displayMacrosButton?: boolean;
10
12
  editable: boolean;
11
13
  getEditorState?: (editorState: EditorState) => void;
12
14
  }
13
15
 
14
- const useStyles = makeStyles()((theme) => ({
16
+ export const useStyles = makeStyles()((theme) => ({
15
17
  container: {
18
+ alignItems: 'center',
16
19
  columnGap: theme.spacing(1),
17
20
  display: 'flex',
18
21
  marginBottom: theme.spacing(1)
22
+ },
23
+ macros: {
24
+ '& span': {
25
+ fontSize: theme.typography.caption.fontSize
26
+ }
27
+ },
28
+ macrosButton: {
29
+ marginBottom: theme.spacing(0.5)
19
30
  }
20
31
  }));
21
32
 
22
33
  const ToolbarPlugin = ({
23
34
  getEditorState,
24
- editable
35
+ editable,
36
+ displayMacrosButton
25
37
  }: Props): JSX.Element | null => {
26
38
  const { classes } = useStyles();
27
39
 
@@ -30,6 +42,12 @@ const ToolbarPlugin = ({
30
42
  <UndoRedoButtons />
31
43
  <Divider flexItem orientation="vertical" />
32
44
  <FormatButtons getEditorState={getEditorState} />
45
+ {displayMacrosButton && (
46
+ <>
47
+ <Divider flexItem orientation="vertical" />
48
+ <MacrosButton />
49
+ </>
50
+ )}
33
51
  </div>
34
52
  ) : null;
35
53
  };
@@ -7,11 +7,10 @@ import { makeStyles } from 'tss-react/mui';
7
7
  import { WizardContentProps } from './models';
8
8
  import ActionsBar from './ActionsBar';
9
9
 
10
- const useStyles = makeStyles()((theme) => ({
10
+ const useStyles = makeStyles()(() => ({
11
11
  content: {
12
12
  height: '100%',
13
- overflow: 'auto',
14
- padding: theme.spacing(2, 3, 1, 3)
13
+ overflow: 'auto'
15
14
  },
16
15
  form: {
17
16
  display: 'flex',
@@ -38,7 +38,8 @@ const Wizard = ({
38
38
  onClose = undefined,
39
39
  confirmDialogLabels = undefined,
40
40
  actionsBarLabels = actionsBarLabelsDefaultValues,
41
- displayConfirmDialog
41
+ displayConfirmDialog,
42
+ ...rest
42
43
  }: WizardProps): JSX.Element => {
43
44
  const { classes } = useStyles();
44
45
  const [currentStep, setCurrentStep] = useState(0);
@@ -119,6 +120,7 @@ const Wizard = ({
119
120
  maxWidth={width}
120
121
  open={open}
121
122
  onClose={handleClose}
123
+ {...rest}
122
124
  >
123
125
  <Stepper currentStep={currentStep} steps={steps} />
124
126
  <Formik
@@ -1,5 +1,7 @@
1
1
  import { FormikValues, FormikErrors, FormikHelpers } from 'formik';
2
2
 
3
+ import { DialogProps } from '@mui/material';
4
+
3
5
  export interface StepComponentProps {
4
6
  disableNextOnSendingRequests: (sendingRequests: Array<boolean>) => void;
5
7
  }
@@ -38,7 +40,10 @@ interface ConfirmDialogLabels {
38
40
  labelTitle: string;
39
41
  }
40
42
 
43
+ type ValueOf<T> = T[keyof T];
44
+
41
45
  export interface WizardProps {
46
+ [key: string]: ValueOf<DialogProps>;
42
47
  actionsBarLabels?: ActionsBarLabels;
43
48
  confirmDialogLabels?: ConfirmDialogLabels;
44
49
  displayConfirmDialog?: boolean;