@centreon/ui 23.10.47 → 23.10.49
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 +7 -6
- package/src/ActionsList/index.tsx +17 -10
- package/src/Dashboard/Dashboard.styles.ts +21 -18
- package/src/Dashboard/Item.tsx +2 -2
- package/src/RichTextEditor/ContentEditable.tsx +1 -1
- package/src/RichTextEditor/RichTextEditor.cypress.spec.tsx +30 -1
- package/src/RichTextEditor/RichTextEditor.tsx +8 -2
- package/src/RichTextEditor/index.stories.tsx +5 -0
- package/src/RichTextEditor/plugins/FloatingLinkEditorPlugin.tsx +6 -1
- package/src/RichTextEditor/plugins/ToolbarPlugin/MacrosButton.tsx +87 -0
- package/src/RichTextEditor/plugins/ToolbarPlugin/index.tsx +20 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@centreon/ui",
|
|
3
|
-
"version": "23.10.
|
|
3
|
+
"version": "23.10.49",
|
|
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",
|
|
@@ -100,10 +101,10 @@
|
|
|
100
101
|
"vite-plugin-turbosnap": "^1.0.2"
|
|
101
102
|
},
|
|
102
103
|
"dependencies": {
|
|
103
|
-
"@lexical/link": "0.
|
|
104
|
-
"@lexical/react": "0.
|
|
105
|
-
"@lexical/selection": "0.
|
|
106
|
-
"@lexical/utils": "0.
|
|
104
|
+
"@lexical/link": "0.11.3",
|
|
105
|
+
"@lexical/react": "0.11.3",
|
|
106
|
+
"@lexical/selection": "0.11.3",
|
|
107
|
+
"@lexical/utils": "0.11.3",
|
|
107
108
|
"@visx/curve": "^2.1.0",
|
|
108
109
|
"@visx/pattern": "^3.0.0",
|
|
109
110
|
"@visx/scale": "^3.0.0",
|
|
@@ -113,7 +114,7 @@
|
|
|
113
114
|
"anylogger": "^1.0.11",
|
|
114
115
|
"d3-array": "3.2.0",
|
|
115
116
|
"humanize-duration": "^3.27.3",
|
|
116
|
-
"lexical": "0.
|
|
117
|
+
"lexical": "0.11.3",
|
|
117
118
|
"notistack": "^2.0.8",
|
|
118
119
|
"react-grid-layout": "^1.3.4",
|
|
119
120
|
"react-html-parser": "^2.0.2",
|
|
@@ -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
|
|
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 = ({
|
|
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
|
-
|
|
50
|
-
<
|
|
51
|
-
|
|
52
|
-
|
|
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
|
})}
|
|
@@ -66,22 +66,25 @@ export const useDashboardLayoutStyles = makeStyles<boolean>()(
|
|
|
66
66
|
})
|
|
67
67
|
);
|
|
68
68
|
|
|
69
|
-
export const useDashboardItemStyles = makeStyles()(
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
widgetContent: {
|
|
75
|
-
height: '100%'
|
|
76
|
-
},
|
|
77
|
-
widgetHeader: {
|
|
78
|
-
'&:hover': {
|
|
79
|
-
backgroundColor: theme.palette.action.hover
|
|
69
|
+
export const useDashboardItemStyles = makeStyles<{ hasHeader: boolean }>()(
|
|
70
|
+
(theme, { hasHeader }) => ({
|
|
71
|
+
widgetContainer: {
|
|
72
|
+
height: '100%',
|
|
73
|
+
width: '100%'
|
|
80
74
|
},
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
75
|
+
widgetContent: {
|
|
76
|
+
height: '100%'
|
|
77
|
+
},
|
|
78
|
+
widgetHeader: {
|
|
79
|
+
'&:hover': {
|
|
80
|
+
backgroundColor: theme.palette.action.hover
|
|
81
|
+
},
|
|
82
|
+
cursor: 'move',
|
|
83
|
+
padding: theme.spacing(0.5, 2)
|
|
84
|
+
},
|
|
85
|
+
widgetPadding: {
|
|
86
|
+
overflowX: 'auto',
|
|
87
|
+
padding: hasHeader ? theme.spacing(1, 2, 2) : theme.spacing(1, 2)
|
|
88
|
+
}
|
|
89
|
+
})
|
|
90
|
+
);
|
package/src/Dashboard/Item.tsx
CHANGED
|
@@ -41,10 +41,10 @@ const Item = forwardRef(
|
|
|
41
41
|
}: DashboardItemProps,
|
|
42
42
|
ref: ForwardedRef<HTMLDivElement>
|
|
43
43
|
): ReactElement => {
|
|
44
|
-
const { classes, cx } = useDashboardItemStyles();
|
|
45
|
-
|
|
46
44
|
const hasHeader = !isNil(header);
|
|
47
45
|
|
|
46
|
+
const { classes, cx } = useDashboardItemStyles({ hasHeader });
|
|
47
|
+
|
|
48
48
|
const listeners = {
|
|
49
49
|
onMouseDown,
|
|
50
50
|
onMouseUp,
|
|
@@ -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;
|
|
@@ -120,7 +121,7 @@ describe('Rich Text Editor', () => {
|
|
|
120
121
|
|
|
121
122
|
cy.wrap(element)
|
|
122
123
|
.should('have.attr', 'rel')
|
|
123
|
-
.and('match', /^
|
|
124
|
+
.and('match', /^noreferrer/);
|
|
124
125
|
|
|
125
126
|
cy.wrap(element)
|
|
126
127
|
.should('have.attr', 'target')
|
|
@@ -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
|
|
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,
|
|
@@ -106,7 +106,12 @@ const FloatingLinkEditor = ({
|
|
|
106
106
|
const yOffset = tooltipPosition.y - rootElementY + 30;
|
|
107
107
|
|
|
108
108
|
return (
|
|
109
|
-
<Popper
|
|
109
|
+
<Popper
|
|
110
|
+
open
|
|
111
|
+
anchorEl={rootElement}
|
|
112
|
+
placement="top-start"
|
|
113
|
+
sx={{ zIndex: 'tooltip' }}
|
|
114
|
+
>
|
|
110
115
|
<Paper
|
|
111
116
|
sx={{
|
|
112
117
|
transform: `translate3d(${xOffset}px, ${
|
|
@@ -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
|
};
|