@centreon/ui 24.4.1-MON-21276-Create-a-basic-token.0 → 24.4.1-MON-32982-migrate-playlists-front-code.3
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/Button/Save/Content.tsx +9 -26
- package/src/Button/Save/index.tsx +3 -10
- package/src/Checkbox/Checkbox.tsx +2 -2
- package/src/Checkbox/CheckboxGroup/index.tsx +2 -2
- package/src/Dialog/index.tsx +1 -1
- package/src/FallbackPage/FallbackPage.tsx +3 -3
- package/src/InputField/Select/Autocomplete/index.tsx +115 -121
- package/src/Listing/Cell/DataCell.tsx +15 -1
- package/src/Module/LicensedModule/LicenseCheck/index.tsx +25 -10
- package/src/Module/LicensedModule/index.tsx +7 -1
- package/src/Module/Module.cypress.spec.tsx +129 -0
- package/src/Module/index.tsx +2 -4
- package/src/TimePeriods/DateTimePickerInput.tsx +3 -12
- package/src/index.ts +0 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@centreon/ui",
|
|
3
|
-
"version": "24.4.1-MON-
|
|
3
|
+
"version": "24.4.1-MON-32982-migrate-playlists-front-code.3",
|
|
4
4
|
"description": "Centreon UI Components",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"eslint": "eslint ./src --ext .js,.jsx,.ts,.tsx --max-warnings 0",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { useTranslation } from 'react-i18next';
|
|
2
|
+
|
|
1
3
|
import CheckIcon from '@mui/icons-material/Check';
|
|
2
4
|
import SaveIcon from '@mui/icons-material/Save';
|
|
3
|
-
import { Typography, TypographyProps } from '@mui/material';
|
|
4
5
|
|
|
5
6
|
interface Props {
|
|
6
7
|
labelLoading: string;
|
|
@@ -10,42 +11,24 @@ interface Props {
|
|
|
10
11
|
succeeded: boolean;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
interface WrapperLabelProps {
|
|
14
|
-
label: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const WrapperLabel = ({
|
|
18
|
-
label,
|
|
19
|
-
...rest
|
|
20
|
-
}: WrapperLabelProps & TypographyProps): JSX.Element => {
|
|
21
|
-
return <Typography {...rest}>{label}</Typography>;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
14
|
const Content = ({
|
|
25
15
|
succeeded,
|
|
26
16
|
labelSucceeded,
|
|
27
17
|
labelSave,
|
|
28
18
|
loading,
|
|
29
|
-
labelLoading
|
|
30
|
-
|
|
31
|
-
|
|
19
|
+
labelLoading
|
|
20
|
+
}: Props): JSX.Element | string | null => {
|
|
21
|
+
const { t } = useTranslation();
|
|
22
|
+
|
|
32
23
|
if (loading) {
|
|
33
|
-
return
|
|
24
|
+
return t(labelLoading);
|
|
34
25
|
}
|
|
35
26
|
|
|
36
27
|
if (succeeded) {
|
|
37
|
-
return labelSucceeded ? (
|
|
38
|
-
<WrapperLabel label={labelSucceeded} {...rest} />
|
|
39
|
-
) : (
|
|
40
|
-
<CheckIcon />
|
|
41
|
-
);
|
|
28
|
+
return labelSucceeded ? t(labelSucceeded) : <CheckIcon />;
|
|
42
29
|
}
|
|
43
30
|
|
|
44
|
-
return labelSave ? (
|
|
45
|
-
<WrapperLabel label={labelSave} {...rest} />
|
|
46
|
-
) : (
|
|
47
|
-
<SaveIcon />
|
|
48
|
-
);
|
|
31
|
+
return labelSave ? t(labelSave) : <SaveIcon />;
|
|
49
32
|
};
|
|
50
33
|
|
|
51
34
|
export default Content;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { any, isEmpty, isNil, not, or, pipe } from 'ramda';
|
|
2
2
|
import { makeStyles } from 'tss-react/mui';
|
|
3
3
|
|
|
4
|
-
import { Theme, Tooltip
|
|
4
|
+
import { Theme, Tooltip } from '@mui/material';
|
|
5
5
|
import { LoadingButton } from '@mui/lab';
|
|
6
6
|
|
|
7
7
|
import { getNormalizedId } from '../../utils';
|
|
@@ -18,12 +18,10 @@ const useStyles = makeStyles()((theme: Theme) => ({
|
|
|
18
18
|
interface Props extends Record<string, unknown> {
|
|
19
19
|
className?: string;
|
|
20
20
|
labelLoading?: string;
|
|
21
|
-
labelProps?: TypographyProps;
|
|
22
21
|
labelSave?: string;
|
|
23
22
|
labelSucceeded?: string;
|
|
24
23
|
loading?: boolean;
|
|
25
24
|
size?: 'small' | 'medium' | 'large';
|
|
26
|
-
startIcon?: boolean;
|
|
27
25
|
succeeded?: boolean;
|
|
28
26
|
tooltip?: string;
|
|
29
27
|
tooltipLabel?: string;
|
|
@@ -47,8 +45,6 @@ const SaveButton = ({
|
|
|
47
45
|
labelSave = '',
|
|
48
46
|
size = 'small',
|
|
49
47
|
className,
|
|
50
|
-
startIcon = true,
|
|
51
|
-
labelProps,
|
|
52
48
|
...rest
|
|
53
49
|
}: Props): JSX.Element => {
|
|
54
50
|
const { classes, cx } = useStyles();
|
|
@@ -77,9 +73,7 @@ const SaveButton = ({
|
|
|
77
73
|
loading={loading}
|
|
78
74
|
loadingPosition={labelLoading ? 'start' : 'center'}
|
|
79
75
|
size={size}
|
|
80
|
-
startIcon={
|
|
81
|
-
startIcon && <StartIcon startIconConfig={startIconConfig} />
|
|
82
|
-
}
|
|
76
|
+
startIcon={<StartIcon startIconConfig={startIconConfig} />}
|
|
83
77
|
variant="contained"
|
|
84
78
|
{...rest}
|
|
85
79
|
>
|
|
@@ -88,8 +82,7 @@ const SaveButton = ({
|
|
|
88
82
|
labelSave,
|
|
89
83
|
labelSucceeded,
|
|
90
84
|
loading,
|
|
91
|
-
succeeded
|
|
92
|
-
...labelProps
|
|
85
|
+
succeeded
|
|
93
86
|
})}
|
|
94
87
|
</LoadingButton>
|
|
95
88
|
</div>
|
|
@@ -2,7 +2,7 @@ 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, {
|
|
5
|
+
import Typography, { TypographyTypeMap } from '@mui/material/Typography';
|
|
6
6
|
import { FormControlLabel, Checkbox as MuiCheckbox, Box } from '@mui/material';
|
|
7
7
|
|
|
8
8
|
export type LabelPlacement = 'bottom' | 'top' | 'end' | 'start' | undefined;
|
|
@@ -56,7 +56,7 @@ interface Props {
|
|
|
56
56
|
disabled?: boolean;
|
|
57
57
|
label: string;
|
|
58
58
|
labelPlacement?: LabelPlacement;
|
|
59
|
-
labelProps?:
|
|
59
|
+
labelProps?: TypographyTypeMap['props'];
|
|
60
60
|
onChange?: (e) => void;
|
|
61
61
|
}
|
|
62
62
|
|
|
@@ -2,7 +2,7 @@ import { equals, includes } from 'ramda';
|
|
|
2
2
|
import { makeStyles } from 'tss-react/mui';
|
|
3
3
|
|
|
4
4
|
import FormGroup, { FormGroupProps } from '@mui/material/FormGroup';
|
|
5
|
-
import {
|
|
5
|
+
import { TypographyTypeMap } from '@mui/material/Typography';
|
|
6
6
|
|
|
7
7
|
import Checkbox, { LabelPlacement } from '../Checkbox';
|
|
8
8
|
|
|
@@ -13,7 +13,7 @@ interface Props {
|
|
|
13
13
|
disabled?: boolean;
|
|
14
14
|
formGroupProps?: FormGroupProps;
|
|
15
15
|
labelPlacement?: LabelPlacement;
|
|
16
|
-
labelProps?:
|
|
16
|
+
labelProps?: TypographyTypeMap['props'];
|
|
17
17
|
onChange?: (e) => void;
|
|
18
18
|
options: Array<string>;
|
|
19
19
|
values: Array<string>;
|
package/src/Dialog/index.tsx
CHANGED
|
@@ -43,7 +43,7 @@ export type Props = {
|
|
|
43
43
|
dialogTitleClassName?: string;
|
|
44
44
|
labelCancel?: string | null;
|
|
45
45
|
labelConfirm?: string | null;
|
|
46
|
-
labelTitle?:
|
|
46
|
+
labelTitle?: string | null;
|
|
47
47
|
onCancel?: () => void;
|
|
48
48
|
onClose?: () => void;
|
|
49
49
|
onConfirm: (event, value?) => void;
|
|
@@ -17,7 +17,7 @@ const useStyles = makeStyles()((theme) => ({
|
|
|
17
17
|
logo: {
|
|
18
18
|
alignSelf: 'flex-end',
|
|
19
19
|
height: theme.spacing(11),
|
|
20
|
-
width: '
|
|
20
|
+
width: '239px'
|
|
21
21
|
},
|
|
22
22
|
message: {
|
|
23
23
|
color: theme.palette.text.primary
|
|
@@ -66,9 +66,9 @@ export const FallbackPage: FC<FallbackPageProps> = typedMemo(
|
|
|
66
66
|
|
|
67
67
|
return (
|
|
68
68
|
<div className={classes.notAuthorizedContainer}>
|
|
69
|
-
<
|
|
69
|
+
<div className={classes.logo}>
|
|
70
70
|
<CentreonLogo />
|
|
71
|
-
</
|
|
71
|
+
</div>
|
|
72
72
|
<section className={classes.messageBlock}>
|
|
73
73
|
<header>
|
|
74
74
|
<Typography color="primary" fontWeight="bold" variant="h3">
|
|
@@ -141,132 +141,126 @@ type Multiple = boolean;
|
|
|
141
141
|
type DisableClearable = boolean;
|
|
142
142
|
type FreeSolo = boolean;
|
|
143
143
|
|
|
144
|
-
const AutocompleteField =
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
): JSX.Element => {
|
|
169
|
-
const { classes, cx } = useStyles({ hideInput });
|
|
170
|
-
const { t } = useTranslation();
|
|
171
|
-
const theme = useTheme();
|
|
144
|
+
const AutocompleteField = ({
|
|
145
|
+
options,
|
|
146
|
+
label,
|
|
147
|
+
placeholder,
|
|
148
|
+
loading = false,
|
|
149
|
+
onTextChange = (): void => undefined,
|
|
150
|
+
endAdornment = undefined,
|
|
151
|
+
inputValue,
|
|
152
|
+
displayOptionThumbnail = false,
|
|
153
|
+
required = false,
|
|
154
|
+
error,
|
|
155
|
+
displayPopupIcon = true,
|
|
156
|
+
autoFocus = false,
|
|
157
|
+
hideInput = false,
|
|
158
|
+
dataTestId,
|
|
159
|
+
autoSize = false,
|
|
160
|
+
autoSizeDefaultWidth = 0,
|
|
161
|
+
autoSizeCustomPadding,
|
|
162
|
+
getOptionItemLabel = (option) => option.name,
|
|
163
|
+
...autocompleteProps
|
|
164
|
+
}: Props): JSX.Element => {
|
|
165
|
+
const { classes, cx } = useStyles({ hideInput });
|
|
166
|
+
const { t } = useTranslation();
|
|
167
|
+
const theme = useTheme();
|
|
172
168
|
|
|
173
|
-
|
|
174
|
-
|
|
169
|
+
const areSelectEntriesEqual = (option, value): boolean => {
|
|
170
|
+
const identifyingProps = ['id', 'name'];
|
|
175
171
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
);
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
const renderInput = (params): JSX.Element => (
|
|
183
|
-
<TextField
|
|
184
|
-
{...params}
|
|
185
|
-
InputLabelProps={{
|
|
186
|
-
classes: {
|
|
187
|
-
marginDense: classes.inputLabel,
|
|
188
|
-
shrink: classes.inputLabelShrink
|
|
189
|
-
}
|
|
190
|
-
}}
|
|
191
|
-
InputProps={{
|
|
192
|
-
...params.InputProps,
|
|
193
|
-
endAdornment: (
|
|
194
|
-
<>
|
|
195
|
-
{endAdornment && (
|
|
196
|
-
<InputAdornment position="end">{endAdornment}</InputAdornment>
|
|
197
|
-
)}
|
|
198
|
-
{params.InputProps.endAdornment}
|
|
199
|
-
</>
|
|
200
|
-
),
|
|
201
|
-
style: {
|
|
202
|
-
background: 'transparent',
|
|
203
|
-
paddingRight: theme.spacing(5)
|
|
204
|
-
}
|
|
205
|
-
}}
|
|
206
|
-
autoFocus={autoFocus}
|
|
207
|
-
autoSize={autoSize}
|
|
208
|
-
autoSizeCustomPadding={7 + (autoSizeCustomPadding || 0)}
|
|
209
|
-
autoSizeDefaultWidth={autoSizeDefaultWidth}
|
|
210
|
-
classes={{
|
|
211
|
-
root: classes.textfield
|
|
212
|
-
}}
|
|
213
|
-
error={error}
|
|
214
|
-
externalValueForAutoSize={autocompleteProps?.value?.name}
|
|
215
|
-
inputProps={{
|
|
216
|
-
...params.inputProps,
|
|
217
|
-
'aria-label': label,
|
|
218
|
-
'data-testid': dataTestId || label,
|
|
219
|
-
id: getNormalizedId(label || '')
|
|
220
|
-
}}
|
|
221
|
-
label={label}
|
|
222
|
-
placeholder={isNil(placeholder) ? t(searchLabel) : placeholder}
|
|
223
|
-
required={required}
|
|
224
|
-
value={inputValue || undefined}
|
|
225
|
-
onChange={onTextChange}
|
|
226
|
-
/>
|
|
172
|
+
return equals(
|
|
173
|
+
pick(identifyingProps, option),
|
|
174
|
+
pick(identifyingProps, value)
|
|
227
175
|
);
|
|
176
|
+
};
|
|
228
177
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
178
|
+
const renderInput = (params): JSX.Element => (
|
|
179
|
+
<TextField
|
|
180
|
+
{...params}
|
|
181
|
+
InputLabelProps={{
|
|
182
|
+
classes: {
|
|
183
|
+
marginDense: classes.inputLabel,
|
|
184
|
+
shrink: classes.inputLabelShrink
|
|
185
|
+
}
|
|
186
|
+
}}
|
|
187
|
+
InputProps={{
|
|
188
|
+
...params.InputProps,
|
|
189
|
+
endAdornment: (
|
|
190
|
+
<>
|
|
191
|
+
{endAdornment && (
|
|
192
|
+
<InputAdornment position="end">{endAdornment}</InputAdornment>
|
|
193
|
+
)}
|
|
194
|
+
{params.InputProps.endAdornment}
|
|
195
|
+
</>
|
|
196
|
+
),
|
|
197
|
+
style: {
|
|
198
|
+
background: 'transparent',
|
|
199
|
+
paddingRight: theme.spacing(5)
|
|
244
200
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
201
|
+
}}
|
|
202
|
+
autoFocus={autoFocus}
|
|
203
|
+
autoSize={autoSize}
|
|
204
|
+
autoSizeCustomPadding={7 + (autoSizeCustomPadding || 0)}
|
|
205
|
+
autoSizeDefaultWidth={autoSizeDefaultWidth}
|
|
206
|
+
classes={{
|
|
207
|
+
root: classes.textfield
|
|
208
|
+
}}
|
|
209
|
+
error={error}
|
|
210
|
+
externalValueForAutoSize={autocompleteProps?.value?.name}
|
|
211
|
+
inputProps={{
|
|
212
|
+
...params.inputProps,
|
|
213
|
+
'aria-label': label,
|
|
214
|
+
'data-testid': dataTestId || label,
|
|
215
|
+
id: getNormalizedId(label || '')
|
|
216
|
+
}}
|
|
217
|
+
label={label}
|
|
218
|
+
placeholder={isNil(placeholder) ? t(searchLabel) : placeholder}
|
|
219
|
+
required={required}
|
|
220
|
+
value={inputValue || undefined}
|
|
221
|
+
onChange={onTextChange}
|
|
222
|
+
/>
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
return (
|
|
226
|
+
<Autocomplete
|
|
227
|
+
disableClearable
|
|
228
|
+
classes={{
|
|
229
|
+
groupLabel: classes.inputLabel,
|
|
230
|
+
inputRoot: cx([
|
|
231
|
+
classes.input,
|
|
232
|
+
label ? classes.inputWithLabel : classes.inputWithoutLabel
|
|
233
|
+
]),
|
|
234
|
+
popper: classes.popper,
|
|
235
|
+
root: classes.textfield
|
|
236
|
+
}}
|
|
237
|
+
forcePopupIcon={displayPopupIcon}
|
|
238
|
+
getOptionLabel={(option): string =>
|
|
239
|
+
(option as SelectEntry)?.name?.toString() || ''
|
|
240
|
+
}
|
|
241
|
+
isOptionEqualToValue={areSelectEntriesEqual}
|
|
242
|
+
loading={loading}
|
|
243
|
+
loadingText={<LoadingIndicator />}
|
|
244
|
+
options={options}
|
|
245
|
+
renderInput={renderInput}
|
|
246
|
+
renderOption={(props, option): JSX.Element => {
|
|
247
|
+
return (
|
|
248
|
+
<li
|
|
249
|
+
className={classes.options}
|
|
250
|
+
{...(props as React.HTMLAttributes<HTMLLIElement>)}
|
|
251
|
+
>
|
|
252
|
+
<Option
|
|
253
|
+
thumbnailUrl={displayOptionThumbnail ? option.url : undefined}
|
|
256
254
|
>
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
/>
|
|
268
|
-
);
|
|
269
|
-
}
|
|
270
|
-
);
|
|
255
|
+
{getOptionItemLabel(option)}
|
|
256
|
+
</Option>
|
|
257
|
+
</li>
|
|
258
|
+
);
|
|
259
|
+
}}
|
|
260
|
+
size="small"
|
|
261
|
+
{...autocompleteProps}
|
|
262
|
+
/>
|
|
263
|
+
);
|
|
264
|
+
};
|
|
271
265
|
|
|
272
266
|
export default AutocompleteField;
|
|
@@ -107,7 +107,21 @@ const DataCell = ({
|
|
|
107
107
|
const isCellHidden = getHiddenCondition?.(isRowSelected);
|
|
108
108
|
|
|
109
109
|
if (isCellHidden) {
|
|
110
|
-
return
|
|
110
|
+
return (
|
|
111
|
+
<Cell
|
|
112
|
+
className={classes.cell}
|
|
113
|
+
isRowHighlighted={isRowHighlighted}
|
|
114
|
+
listingVariant={listingVariant}
|
|
115
|
+
onClick={(e): void => {
|
|
116
|
+
if (!clickable) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
e.preventDefault();
|
|
120
|
+
e.stopPropagation();
|
|
121
|
+
}}
|
|
122
|
+
{...commonCellProps}
|
|
123
|
+
/>
|
|
124
|
+
);
|
|
111
125
|
}
|
|
112
126
|
|
|
113
127
|
return (
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
|
|
3
|
-
import { isNil } from 'ramda';
|
|
4
1
|
import { useTranslation } from 'react-i18next';
|
|
5
2
|
|
|
6
3
|
import { FallbackPage } from '../../../FallbackPage/FallbackPage';
|
|
7
|
-
import { PageSkeleton, useFetchQuery } from '../../..';
|
|
4
|
+
import { MenuSkeleton, PageSkeleton, useFetchQuery } from '../../..';
|
|
8
5
|
import { getModuleLicenseCheckEndpoint } from '../api';
|
|
9
6
|
|
|
10
7
|
import { licenseDecoder } from './decoder';
|
|
@@ -17,17 +14,27 @@ import {
|
|
|
17
14
|
|
|
18
15
|
export interface LicenseCheckProps {
|
|
19
16
|
children: React.ReactElement;
|
|
17
|
+
isFederatedComponent?: boolean;
|
|
20
18
|
moduleName: string;
|
|
21
19
|
}
|
|
22
20
|
|
|
23
21
|
interface ContentProps {
|
|
24
22
|
children: React.ReactElement;
|
|
23
|
+
isFederatedComponent?: boolean;
|
|
25
24
|
isValid: boolean;
|
|
26
25
|
}
|
|
27
26
|
|
|
28
|
-
const Content = ({
|
|
27
|
+
const Content = ({
|
|
28
|
+
children,
|
|
29
|
+
isValid,
|
|
30
|
+
isFederatedComponent
|
|
31
|
+
}: ContentProps): JSX.Element | null => {
|
|
29
32
|
const { t } = useTranslation();
|
|
30
33
|
|
|
34
|
+
if (isFederatedComponent && !isValid) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
31
38
|
return isValid ? (
|
|
32
39
|
children
|
|
33
40
|
) : (
|
|
@@ -41,9 +48,10 @@ const Content = ({ children, isValid }: ContentProps): JSX.Element => {
|
|
|
41
48
|
|
|
42
49
|
const LicenseCheck = ({
|
|
43
50
|
children,
|
|
44
|
-
moduleName
|
|
51
|
+
moduleName,
|
|
52
|
+
isFederatedComponent
|
|
45
53
|
}: LicenseCheckProps): JSX.Element | null => {
|
|
46
|
-
const { isError, data } = useFetchQuery<License>({
|
|
54
|
+
const { isError, data, isLoading } = useFetchQuery<License>({
|
|
47
55
|
decoder: licenseDecoder,
|
|
48
56
|
getEndpoint: () => getModuleLicenseCheckEndpoint(moduleName),
|
|
49
57
|
getQueryKey: () => ['license', moduleName]
|
|
@@ -55,10 +63,17 @@ const LicenseCheck = ({
|
|
|
55
63
|
|
|
56
64
|
const isValid = data?.success;
|
|
57
65
|
|
|
58
|
-
|
|
59
|
-
|
|
66
|
+
const skeleton = isFederatedComponent ? <MenuSkeleton /> : <PageSkeleton />;
|
|
67
|
+
|
|
68
|
+
return isLoading ? (
|
|
69
|
+
skeleton
|
|
60
70
|
) : (
|
|
61
|
-
<Content
|
|
71
|
+
<Content
|
|
72
|
+
isFederatedComponent={isFederatedComponent}
|
|
73
|
+
isValid={isValid as boolean}
|
|
74
|
+
>
|
|
75
|
+
{children}
|
|
76
|
+
</Content>
|
|
62
77
|
);
|
|
63
78
|
};
|
|
64
79
|
|
|
@@ -7,11 +7,17 @@ type Props = ModuleProps & LicenseCheckProps;
|
|
|
7
7
|
const LicensedModule = ({
|
|
8
8
|
moduleName,
|
|
9
9
|
children,
|
|
10
|
+
isFederatedComponent,
|
|
10
11
|
...props
|
|
11
12
|
}: Props): JSX.Element => {
|
|
12
13
|
return (
|
|
13
14
|
<Module {...props}>
|
|
14
|
-
<LicenseCheck
|
|
15
|
+
<LicenseCheck
|
|
16
|
+
isFederatedComponent={isFederatedComponent}
|
|
17
|
+
moduleName={moduleName}
|
|
18
|
+
>
|
|
19
|
+
{children}
|
|
20
|
+
</LicenseCheck>
|
|
15
21
|
</Module>
|
|
16
22
|
);
|
|
17
23
|
};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { createStore } from 'jotai';
|
|
2
|
+
|
|
3
|
+
import { Method } from '..';
|
|
4
|
+
|
|
5
|
+
import LicensedModule from './LicensedModule';
|
|
6
|
+
|
|
7
|
+
import Module from '.';
|
|
8
|
+
|
|
9
|
+
const initializeModule = (): void => {
|
|
10
|
+
cy.mount({
|
|
11
|
+
Component: (
|
|
12
|
+
<Module seedName="seed" store={createStore()}>
|
|
13
|
+
<p>Module</p>
|
|
14
|
+
</Module>
|
|
15
|
+
)
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const initializeModuleWithValidLicense = (
|
|
20
|
+
isFederatedComponent = false
|
|
21
|
+
): void => {
|
|
22
|
+
cy.interceptAPIRequest({
|
|
23
|
+
alias: 'getValidLicense',
|
|
24
|
+
method: Method.GET,
|
|
25
|
+
path: './api/internal.php?object=centreon_license_manager&action=licenseValid&productName=valid',
|
|
26
|
+
response: {
|
|
27
|
+
success: true
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
cy.mount({
|
|
32
|
+
Component: (
|
|
33
|
+
<div style={{ height: '100vh' }}>
|
|
34
|
+
<LicensedModule
|
|
35
|
+
isFederatedComponent={isFederatedComponent}
|
|
36
|
+
moduleName="valid"
|
|
37
|
+
seedName="seed"
|
|
38
|
+
store={createStore()}
|
|
39
|
+
>
|
|
40
|
+
<p>Module</p>
|
|
41
|
+
</LicensedModule>
|
|
42
|
+
</div>
|
|
43
|
+
)
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const initializeModuleWithInvalidLicense = (
|
|
48
|
+
isFederatedComponent = false
|
|
49
|
+
): void => {
|
|
50
|
+
cy.interceptAPIRequest({
|
|
51
|
+
alias: 'getInvalidLicense',
|
|
52
|
+
method: Method.GET,
|
|
53
|
+
path: './api/internal.php?object=centreon_license_manager&action=licenseValid&productName=invalid',
|
|
54
|
+
response: {
|
|
55
|
+
success: false
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
cy.mount({
|
|
60
|
+
Component: (
|
|
61
|
+
<div style={{ height: '100vh' }}>
|
|
62
|
+
<LicensedModule
|
|
63
|
+
isFederatedComponent={isFederatedComponent}
|
|
64
|
+
moduleName="invalid"
|
|
65
|
+
seedName="seed"
|
|
66
|
+
store={createStore()}
|
|
67
|
+
>
|
|
68
|
+
<p>Module</p>
|
|
69
|
+
</LicensedModule>
|
|
70
|
+
</div>
|
|
71
|
+
)
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
describe('Module', () => {
|
|
76
|
+
beforeEach(() => {
|
|
77
|
+
initializeModule();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('displays the content of the module', () => {
|
|
81
|
+
cy.contains('Module').should('be.visible');
|
|
82
|
+
|
|
83
|
+
cy.makeSnapshot();
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
describe('Valid license module', () => {
|
|
88
|
+
it('displays the content of the page when the license is valid license', () => {
|
|
89
|
+
initializeModuleWithValidLicense();
|
|
90
|
+
cy.waitForRequest('@getValidLicense');
|
|
91
|
+
|
|
92
|
+
cy.contains('Module').should('be.visible');
|
|
93
|
+
|
|
94
|
+
cy.makeSnapshot();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('displays the content of the component when the license is valid license', () => {
|
|
98
|
+
initializeModuleWithValidLicense(true);
|
|
99
|
+
|
|
100
|
+
cy.contains('Module').should('be.visible');
|
|
101
|
+
|
|
102
|
+
cy.makeSnapshot();
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
describe('Invalid license module', () => {
|
|
107
|
+
it('displays the content of the page when the license is invalid license', () => {
|
|
108
|
+
initializeModuleWithInvalidLicense();
|
|
109
|
+
cy.waitForRequest('@getInvalidLicense');
|
|
110
|
+
|
|
111
|
+
cy.contains('Module').should('not.exist');
|
|
112
|
+
|
|
113
|
+
cy.contains('Oops').should('be.visible');
|
|
114
|
+
cy.contains('License invalid or expired').should('be.visible');
|
|
115
|
+
cy.contains('Please contact your administrator.').should('be.visible');
|
|
116
|
+
cy.get('img[alt="License invalid or expired !"]').should('be.visible');
|
|
117
|
+
cy.get('img[alt="Centreon Logo"]').should('be.visible');
|
|
118
|
+
|
|
119
|
+
cy.makeSnapshot();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('displays the content of the module when the license is invalid license', () => {
|
|
123
|
+
initializeModuleWithInvalidLicense(true);
|
|
124
|
+
|
|
125
|
+
cy.contains('Module').should('not.exist');
|
|
126
|
+
|
|
127
|
+
cy.makeSnapshot();
|
|
128
|
+
});
|
|
129
|
+
});
|
package/src/Module/index.tsx
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
|
|
3
1
|
import { Provider as JotaiProvider, createStore } from 'jotai';
|
|
4
2
|
|
|
5
3
|
import { createGenerateClassName, StylesProvider } from '@mui/styles';
|
|
@@ -9,7 +7,7 @@ import SnackbarProvider from '../Snackbar/SnackbarProvider';
|
|
|
9
7
|
|
|
10
8
|
export interface ModuleProps {
|
|
11
9
|
children: React.ReactElement;
|
|
12
|
-
maxSnackbars
|
|
10
|
+
maxSnackbars?: number;
|
|
13
11
|
seedName: string;
|
|
14
12
|
store: ReturnType<typeof createStore>;
|
|
15
13
|
}
|
|
@@ -17,7 +15,7 @@ export interface ModuleProps {
|
|
|
17
15
|
const Module = ({
|
|
18
16
|
children,
|
|
19
17
|
seedName,
|
|
20
|
-
maxSnackbars,
|
|
18
|
+
maxSnackbars = 3,
|
|
21
19
|
store
|
|
22
20
|
}: ModuleProps): JSX.Element => {
|
|
23
21
|
const generateClassName = createGenerateClassName({
|
|
@@ -4,11 +4,7 @@ import dayjs, { Dayjs } from 'dayjs';
|
|
|
4
4
|
import { useAtomValue } from 'jotai';
|
|
5
5
|
import { equals } from 'ramda';
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
DateTimePicker,
|
|
9
|
-
DateTimePickerProps,
|
|
10
|
-
LocalizationProvider
|
|
11
|
-
} from '@mui/x-date-pickers';
|
|
7
|
+
import { DateTimePicker, LocalizationProvider } from '@mui/x-date-pickers';
|
|
12
8
|
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
|
|
13
9
|
|
|
14
10
|
import { userAtom } from '@centreon/ui-context';
|
|
@@ -27,7 +23,6 @@ interface Props {
|
|
|
27
23
|
disabled?: boolean;
|
|
28
24
|
maxDate?: Date;
|
|
29
25
|
minDate?: Date;
|
|
30
|
-
minDateTime?: Date;
|
|
31
26
|
property: CustomTimePeriodProperty | string;
|
|
32
27
|
}
|
|
33
28
|
|
|
@@ -35,13 +30,11 @@ const DateTimePickerInput = ({
|
|
|
35
30
|
date,
|
|
36
31
|
maxDate,
|
|
37
32
|
minDate,
|
|
38
|
-
minDateTime,
|
|
39
33
|
property,
|
|
40
34
|
changeDate,
|
|
41
35
|
disabled = false,
|
|
42
|
-
desktopMediaQuery
|
|
43
|
-
|
|
44
|
-
}: Props & DateTimePickerProps<dayjs.Dayjs>): JSX.Element => {
|
|
36
|
+
desktopMediaQuery
|
|
37
|
+
}: Props): JSX.Element => {
|
|
45
38
|
const desktopPickerMediaQuery =
|
|
46
39
|
'@media (min-width: 1024px) or (pointer: fine)';
|
|
47
40
|
|
|
@@ -74,10 +67,8 @@ const DateTimePickerInput = ({
|
|
|
74
67
|
disabled={disabled}
|
|
75
68
|
maxDate={maxDate && formatDate(maxDate)}
|
|
76
69
|
minDate={minDate && formatDate(minDate)}
|
|
77
|
-
minDateTime={minDateTime && formatDate(minDateTime)}
|
|
78
70
|
value={formatDate(date)}
|
|
79
71
|
onChange={changeTime}
|
|
80
|
-
{...rest}
|
|
81
72
|
/>
|
|
82
73
|
</LocalizationProvider>
|
|
83
74
|
);
|
package/src/index.ts
CHANGED
|
@@ -165,5 +165,3 @@ export { default as SimpleCustomTimePeriod } from './TimePeriods/CustomTimePerio
|
|
|
165
165
|
export { default as DateTimePickerInput } from './TimePeriods/DateTimePickerInput';
|
|
166
166
|
export * from './ParentSize';
|
|
167
167
|
export { default as Subtitle } from './Typography/Subtitle';
|
|
168
|
-
export { default as TablePagination } from './Listing/ActionBar/Pagination';
|
|
169
|
-
export { default as PaginationActions } from './Listing/ActionBar/PaginationActions';
|