@centreon/ui 24.4.38 → 24.4.39

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.
Files changed (108) hide show
  1. package/package.json +19 -14
  2. package/public/mockServiceWorker.js +1 -1
  3. package/src/Button/Icon/index.tsx +1 -1
  4. package/src/Button/Save/StartIcon.tsx +3 -3
  5. package/src/Button/Save/index.tsx +9 -5
  6. package/src/Checkbox/Checkbox.tsx +2 -2
  7. package/src/Checkbox/CheckboxGroup/index.tsx +2 -2
  8. package/src/Dashboard/Item.tsx +1 -1
  9. package/src/Dashboard/Layout.tsx +2 -2
  10. package/src/Dialog/index.tsx +1 -1
  11. package/src/FallbackPage/FallbackPage.tsx +3 -3
  12. package/src/FileDropZone/index.tsx +3 -1
  13. package/src/Form/Form.cypress.spec.tsx +133 -0
  14. package/src/Form/Inputs/CheckboxGroup.tsx +1 -4
  15. package/src/Form/Inputs/List/Content.tsx +62 -0
  16. package/src/Form/Inputs/List/List.styles.ts +29 -0
  17. package/src/Form/Inputs/List/List.tsx +58 -0
  18. package/src/Form/Inputs/List/useList.ts +81 -0
  19. package/src/Form/Inputs/index.tsx +3 -1
  20. package/src/Form/Inputs/models.ts +9 -1
  21. package/src/Graph/LineChart/BasicComponents/Lines/Threshold/Circle.tsx +2 -2
  22. package/src/Graph/LineChart/BasicComponents/Lines/Threshold/index.tsx +5 -4
  23. package/src/Graph/LineChart/BasicComponents/Thresholds.tsx +2 -2
  24. package/src/Graph/LineChart/BasicComponents/useFilterLines.ts +1 -1
  25. package/src/Graph/LineChart/InteractiveComponents/AnchorPoint/GuidingLines.tsx +2 -2
  26. package/src/Graph/LineChart/InteractiveComponents/Annotations/Annotation/index.tsx +2 -3
  27. package/src/Graph/LineChart/InteractiveComponents/Annotations/EventAnnotations.tsx +1 -1
  28. package/src/Graph/LineChart/Legend/index.tsx +7 -8
  29. package/src/Graph/LineChart/Legend/useLegend.ts +3 -3
  30. package/src/Graph/LineChart/LineChart.tsx +4 -1
  31. package/src/Graph/LineChart/helpers/doc.ts +16 -13
  32. package/src/Graph/LineChart/helpers/index.ts +1 -1
  33. package/src/Graph/LineChart/index.stories.tsx +4 -2
  34. package/src/Graph/LineChart/index.tsx +4 -1
  35. package/src/Graph/SingleBar/Thresholds.tsx +2 -2
  36. package/src/Graph/Text/Text.stories.tsx +60 -4
  37. package/src/Graph/common/timeSeries/index.ts +3 -3
  38. package/src/InputField/Select/Autocomplete/Connected/index.tsx +10 -7
  39. package/src/InputField/Select/Autocomplete/Draggable/SortableList.tsx +1 -1
  40. package/src/InputField/Select/Autocomplete/Draggable/SortableListContent.tsx +1 -1
  41. package/src/InputField/Select/Autocomplete/Draggable/index.tsx +1 -1
  42. package/src/InputField/Select/Autocomplete/index.tsx +121 -115
  43. package/src/InputField/Select/IconPopover/index.tsx +2 -2
  44. package/src/InputField/Select/index.tsx +1 -1
  45. package/src/InputField/Text/index.tsx +2 -2
  46. package/src/Listing/Cell/DataCell.tsx +15 -1
  47. package/src/Listing/Header/ListingHeader.tsx +1 -1
  48. package/src/Listing/Listing.styles.ts +2 -3
  49. package/src/Listing/index.stories.tsx +12 -1
  50. package/src/Listing/index.tsx +1 -2
  51. package/src/Module/Module.cypress.spec.tsx +129 -0
  52. package/src/Module/index.tsx +2 -4
  53. package/src/RichTextEditor/RichTextEditor.tsx +12 -1
  54. package/src/SortableItems/index.tsx +2 -7
  55. package/src/ThemeProvider/index.tsx +24 -0
  56. package/src/TimePeriods/CustomTimePeriod/CompactCustomTimePeriod.styles.ts +6 -7
  57. package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/PickersStartEndDate.tsx +8 -3
  58. package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/models.ts +0 -2
  59. package/src/TimePeriods/DateTimePickerInput.tsx +56 -19
  60. package/src/TimePeriods/ResolutionTimePeriod.cypress.spec.tsx +12 -9
  61. package/src/TimePeriods/TimePeriods.cypress.spec.tsx +9 -33
  62. package/src/TimePeriods/helpers/index.ts +1 -1
  63. package/src/TimePeriods/index.stories.tsx +12 -4
  64. package/src/TimePeriods/index.tsx +2 -2
  65. package/src/api/QueryProvider.tsx +1 -1
  66. package/src/api/TestQueryProvider.tsx +1 -1
  67. package/src/api/useFetchQuery/index.ts +27 -23
  68. package/src/api/useGraphQuery/index.ts +26 -5
  69. package/src/api/useGraphQuery/models.ts +5 -0
  70. package/src/api/useMutationQuery/index.ts +45 -21
  71. package/src/components/Button/Icon/IconButton.tsx +6 -2
  72. package/src/components/CollapsibleItem/CollapsibleItem.cypress.spec.tsx +76 -0
  73. package/src/components/CollapsibleItem/CollapsibleItem.stories.tsx +26 -0
  74. package/src/components/CollapsibleItem/CollapsibleItem.tsx +43 -14
  75. package/src/components/CollapsibleItem/useCollapsibleItemStyles.ts +24 -1
  76. package/src/components/DataTable/DataListing.tsx +6 -0
  77. package/src/components/DataTable/DataTable.cypress.spec.tsx +193 -0
  78. package/src/components/DataTable/DataTable.stories.tsx +40 -0
  79. package/src/components/DataTable/DataTable.styles.ts +3 -0
  80. package/src/components/DataTable/DataTable.tsx +3 -3
  81. package/src/components/DataTable/Item/DataTableItem.styles.ts +7 -2
  82. package/src/components/DataTable/Item/DataTableItem.tsx +4 -4
  83. package/src/components/DataTable/index.ts +3 -1
  84. package/src/components/Form/Dashboard/DashboardForm.tsx +15 -12
  85. package/src/components/ItemComposition/Item.tsx +1 -1
  86. package/src/components/ItemComposition/ItemComposition.cypress.spec.tsx +116 -0
  87. package/src/components/ItemComposition/ItemComposition.styles.ts +8 -1
  88. package/src/components/ItemComposition/ItemComposition.tsx +26 -16
  89. package/src/components/Layout/PageLayout/PageLayout.tsx +1 -1
  90. package/src/components/Layout/PageLayout/PageLayoutActions.tsx +1 -0
  91. package/src/components/Layout/PageLayout/PageLayoutBody.tsx +1 -0
  92. package/src/components/Layout/PageLayout/PageLayoutHeader.tsx +5 -1
  93. package/src/components/Layout/PageLayout/PageQuickAccess.tsx +76 -0
  94. package/src/components/Layout/PageLayout/index.ts +3 -1
  95. package/src/components/Layout/PageLayout.cypress.spec.tsx +66 -0
  96. package/src/components/Modal/Modal.styles.ts +1 -1
  97. package/src/components/Tooltip/ConfirmationTooltip/ConfirmationTooltip.stories.tsx +3 -3
  98. package/src/components/Tooltip/ConfirmationTooltip/ConfirmationTooltip.tsx +1 -1
  99. package/src/components/Tooltip/ConfirmationTooltip/models.ts +1 -1
  100. package/src/index.ts +2 -2
  101. package/src/queryParameters/url/index.ts +5 -1
  102. package/src/utils/index.ts +2 -1
  103. package/src/utils/{useLicenseExpirationWarning.cypress.spec.tsx → useLicenseExpirationWarning.test.tsx} +48 -37
  104. package/src/utils/useLicenseExpirationWarning.ts +18 -18
  105. package/src/utils/usePluralizedTranslation.ts +21 -0
  106. package/src/screens/dashboard/DashboardsDetail.stories.tsx +0 -108
  107. package/src/screens/dashboard/DashboardsOverview.stories.tsx +0 -281
  108. package/src/utils/useDateTimePickerAdapter.ts +0 -309
@@ -141,126 +141,132 @@ type Multiple = boolean;
141
141
  type DisableClearable = boolean;
142
142
  type FreeSolo = boolean;
143
143
 
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();
144
+ const AutocompleteField = React.forwardRef(
145
+ (
146
+ {
147
+ options,
148
+ label,
149
+ placeholder,
150
+ loading = false,
151
+ onTextChange = (): void => undefined,
152
+ endAdornment = undefined,
153
+ inputValue,
154
+ displayOptionThumbnail = false,
155
+ required = false,
156
+ error,
157
+ displayPopupIcon = true,
158
+ autoFocus = false,
159
+ hideInput = false,
160
+ dataTestId,
161
+ autoSize = false,
162
+ autoSizeDefaultWidth = 0,
163
+ autoSizeCustomPadding,
164
+ getOptionItemLabel = (option) => option.name,
165
+ ...autocompleteProps
166
+ }: Props,
167
+ ref?: React.ForwardedRef<HTMLDivElement>
168
+ ): JSX.Element => {
169
+ const { classes, cx } = useStyles({ hideInput });
170
+ const { t } = useTranslation();
171
+ const theme = useTheme();
168
172
 
169
- const areSelectEntriesEqual = (option, value): boolean => {
170
- const identifyingProps = ['id', 'name'];
173
+ const areSelectEntriesEqual = (option, value): boolean => {
174
+ const identifyingProps = ['id', 'name'];
171
175
 
172
- return equals(
173
- pick(identifyingProps, option),
174
- pick(identifyingProps, value)
176
+ return equals(
177
+ pick(identifyingProps, option),
178
+ pick(identifyingProps, value)
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
+ />
175
227
  );
176
- };
177
228
 
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)
229
+ return (
230
+ <Autocomplete
231
+ disableClearable
232
+ classes={{
233
+ groupLabel: classes.inputLabel,
234
+ inputRoot: cx([
235
+ classes.input,
236
+ label ? classes.inputWithLabel : classes.inputWithoutLabel
237
+ ]),
238
+ popper: classes.popper,
239
+ root: classes.textfield
240
+ }}
241
+ forcePopupIcon={displayPopupIcon}
242
+ getOptionLabel={(option): string =>
243
+ (option as SelectEntry)?.name?.toString() || ''
200
244
  }
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}
245
+ isOptionEqualToValue={areSelectEntriesEqual}
246
+ loading={loading}
247
+ loadingText={<LoadingIndicator />}
248
+ options={options}
249
+ ref={ref}
250
+ renderInput={renderInput}
251
+ renderOption={(props, option): JSX.Element => {
252
+ return (
253
+ <li
254
+ className={classes.options}
255
+ {...(props as React.HTMLAttributes<HTMLLIElement>)}
254
256
  >
255
- {getOptionItemLabel(option)}
256
- </Option>
257
- </li>
258
- );
259
- }}
260
- size="small"
261
- {...autocompleteProps}
262
- />
263
- );
264
- };
257
+ <Option
258
+ thumbnailUrl={displayOptionThumbnail ? option.url : undefined}
259
+ >
260
+ {getOptionItemLabel(option)}
261
+ </Option>
262
+ </li>
263
+ );
264
+ }}
265
+ size="small"
266
+ {...autocompleteProps}
267
+ />
268
+ );
269
+ }
270
+ );
265
271
 
266
272
  export default AutocompleteField;
@@ -73,14 +73,14 @@ const IconPopoverMultiAutocomplete = ({
73
73
  };
74
74
 
75
75
  const isSelected = (id: number | string): boolean => {
76
- return pipe(find(propEq('id', id)), Boolean)(value);
76
+ return pipe(find(propEq(id, 'id')), Boolean)(value);
77
77
  };
78
78
 
79
79
  const unSelect = (option: SelectEntry): void => {
80
80
  const { id } = option;
81
81
 
82
82
  const updatedValue = isSelected(id)
83
- ? reject(propEq('id', id), value)
83
+ ? reject(propEq(id, 'id'), value)
84
84
  : [...value, option];
85
85
 
86
86
  onChange(updatedValue);
@@ -69,7 +69,7 @@ const SelectField = ({
69
69
  const { classes, cx } = useStyles();
70
70
 
71
71
  const getOption = (id): SelectEntry => {
72
- return options.find(propEq('id', id)) as SelectEntry;
72
+ return options.find(propEq(id, 'id')) as SelectEntry;
73
73
  };
74
74
 
75
75
  const changeOption = (event): void => {
@@ -154,9 +154,9 @@ const TextField = forwardRef(
154
154
  helperText={displayErrorInTooltip ? undefined : error}
155
155
  id={getNormalizedId(dataTestId || '')}
156
156
  inputProps={{
157
- ...rest.inputProps,
158
157
  'aria-label': ariaLabel,
159
- 'data-testid': dataTestId
158
+ 'data-testid': dataTestId,
159
+ ...rest.inputProps
160
160
  }}
161
161
  label={label}
162
162
  ref={ref}
@@ -107,7 +107,21 @@ const DataCell = ({
107
107
  const isCellHidden = getHiddenCondition?.(isRowSelected);
108
108
 
109
109
  if (isCellHidden) {
110
- return null;
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 (
@@ -71,7 +71,7 @@ const ListingHeader = ({
71
71
  });
72
72
 
73
73
  const getColumnById = (id: string): Column => {
74
- return find(propEq('id', id), columns) as Column;
74
+ return find(propEq(id, 'id'), columns) as Column;
75
75
  };
76
76
 
77
77
  const Content = React.useCallback(
@@ -9,13 +9,12 @@ const loadingIndicatorHeight = 3;
9
9
  interface StylesProps {
10
10
  dataStyle: TableStyle;
11
11
  getGridTemplateColumn: string;
12
- limit: number;
13
12
  listingVariant: ListingVariant;
14
13
  rows: Array<unknown>;
15
14
  }
16
15
 
17
16
  const useListingStyles = makeStyles<StylesProps>()(
18
- (theme, { dataStyle, getGridTemplateColumn, rows, limit }) => ({
17
+ (theme, { dataStyle, getGridTemplateColumn, rows }) => ({
19
18
  actionBar: {
20
19
  alignItems: 'center',
21
20
  display: 'flex'
@@ -56,7 +55,7 @@ const useListingStyles = makeStyles<StylesProps>()(
56
55
  display: 'grid',
57
56
  gridTemplateColumns: getGridTemplateColumn,
58
57
  gridTemplateRows: `${theme.spacing(dataStyle.header.height / 8)} repeat(${
59
- rows?.length || limit
58
+ rows?.length || 1
60
59
  }, ${dataStyle.body.height}px)`,
61
60
  position: 'relative'
62
61
  },
@@ -366,6 +366,16 @@ const columnsWithSubItems = [
366
366
  }
367
367
  ];
368
368
 
369
+ const TemplateSubItems = (args): JSX.Element => {
370
+ const { classes } = useStyles();
371
+
372
+ return (
373
+ <div className={classes.listing}>
374
+ <Listing {...args} />
375
+ </div>
376
+ );
377
+ };
378
+
369
379
  export const ListingWithSubItems = {
370
380
  args: {
371
381
  checkable: true,
@@ -382,5 +392,6 @@ export const ListingWithSubItems = {
382
392
  labelExpand: 'Expand'
383
393
  },
384
394
  totalRows: 10
385
- }
395
+ },
396
+ render: TemplateSubItems
386
397
  };
@@ -69,7 +69,7 @@ const getVisibleColumns = ({
69
69
  }
70
70
 
71
71
  return selectedColumnIds.map((id) =>
72
- columns.find(propEq('id', id))
72
+ columns.find(propEq(id, 'id'))
73
73
  ) as Array<Column>;
74
74
  };
75
75
 
@@ -233,7 +233,6 @@ const Listing = <TRow extends { id: RowId }>({
233
233
  const { classes } = useListingStyles({
234
234
  dataStyle,
235
235
  getGridTemplateColumn,
236
- limit,
237
236
  listingVariant,
238
237
  rows: rowsToDisplay
239
238
  });
@@ -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
+ });
@@ -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: number;
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({
@@ -12,6 +12,7 @@ import { LinkPlugin } from '@lexical/react/LexicalLinkPlugin';
12
12
  import { equals } from 'ramda';
13
13
  import { ListPlugin } from '@lexical/react/LexicalListPlugin';
14
14
  import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin';
15
+ import { $generateHtmlFromNodes } from '@lexical/html';
15
16
 
16
17
  import { Typography } from '@mui/material';
17
18
 
@@ -38,6 +39,7 @@ export interface RichTextEditorProps {
38
39
  openLinkInNewTab?: boolean;
39
40
  placeholder?: string;
40
41
  resetEditorToInitialStateCondition?: () => boolean;
42
+ setHtmlString?: (htmlString: string) => void;
41
43
  toolbarClassName?: string;
42
44
  toolbarPositions?: 'start' | 'end';
43
45
  }
@@ -143,6 +145,7 @@ const RichTextEditor = ({
143
145
  openLinkInNewTab = true,
144
146
  initialize,
145
147
  displayBlockButtons = true,
148
+ setHtmlString,
146
149
  toolbarClassName
147
150
  }: RichTextEditorProps): JSX.Element => {
148
151
  const { classes } = useStyles({ toolbarPositions });
@@ -178,6 +181,13 @@ const RichTextEditor = ({
178
181
  }
179
182
  };
180
183
 
184
+ const change = (state: EditorState, editor: LexicalEditor): void => {
185
+ editor.update(() => {
186
+ setHtmlString?.($generateHtmlFromNodes(editor, null));
187
+ });
188
+ getEditorState?.(state, editor);
189
+ };
190
+
181
191
  return (
182
192
  <LexicalComposer initialConfig={initialConfig}>
183
193
  <div className={classes.container}>
@@ -210,6 +220,7 @@ const RichTextEditor = ({
210
220
  resetEditorToInitialStateCondition={
211
221
  resetEditorToInitialStateCondition
212
222
  }
223
+ setHtmlString={setHtmlString}
213
224
  onBlur={onBlur}
214
225
  />
215
226
  }
@@ -218,7 +229,7 @@ const RichTextEditor = ({
218
229
  <HistoryPlugin />
219
230
  <LinkPlugin />
220
231
  <ListPlugin />
221
- <OnChangePlugin onChange={getEditorState} />
232
+ <OnChangePlugin onChange={change} />
222
233
  <AutoCompleteLinkPlugin openLinkInNewTab={openLinkInNewTab} />
223
234
  <FloatingLinkEditorPlugin
224
235
  editable={editable}
@@ -15,11 +15,7 @@ import {
15
15
  DragEndEvent,
16
16
  Over
17
17
  } from '@dnd-kit/core';
18
- import {
19
- SortableContext,
20
- sortableKeyboardCoordinates,
21
- SortingStrategy
22
- } from '@dnd-kit/sortable';
18
+ import { SortableContext, SortingStrategy } from '@dnd-kit/sortable';
23
19
  import {
24
20
  equals,
25
21
  find,
@@ -117,7 +113,6 @@ const SortableItems = <T extends { [propertyToFilterItemsOn]: string }>({
117
113
  useSensor(MouseSensor),
118
114
  useSensor(PointerSensor),
119
115
  useSensor(KeyboardSensor, {
120
- coordinateGetter: sortableKeyboardCoordinates,
121
116
  keyboardCodes: {
122
117
  cancel: ['Escape'],
123
118
  end: ['Space', 'Enter'],
@@ -169,7 +164,7 @@ const SortableItems = <T extends { [propertyToFilterItemsOn]: string }>({
169
164
  };
170
165
 
171
166
  const getItemById = (id): T | undefined =>
172
- find(propEq(propertyToFilterItemsOn, id), items);
167
+ find(propEq(id, propertyToFilterItemsOn), items);
173
168
 
174
169
  const activeItem = getItemById(activeId) as Record<string, unknown>;
175
170
 
@@ -147,6 +147,30 @@ export const getTheme = (mode: ThemeMode): ThemeOptions => ({
147
147
  },
148
148
  MuiCssBaseline: {
149
149
  styleOverrides: (theme) => `
150
+ ::-webkit-scrollbar {
151
+ height: ${theme.spacing(1)};
152
+ width: ${theme.spacing(1)};
153
+ background-color: transparent;
154
+ }
155
+ ::-webkit-scrollbar-thumb {
156
+ background-color: ${
157
+ equals(mode, 'dark')
158
+ ? theme.palette.divider
159
+ : theme.palette.text.disabled
160
+ };
161
+ border-radius: ${theme.spacing(0.5)};
162
+ }
163
+ ::-webkit-scrollbar-thumb:hover {
164
+ background-color: ${theme.palette.primary.main};
165
+ }
166
+ * {
167
+ scrollbar-color: ${
168
+ equals(mode, 'dark')
169
+ ? theme.palette.divider
170
+ : theme.palette.text.disabled
171
+ } ${theme.palette.background.default};
172
+ scrollbar-width: thin;
173
+ }
150
174
  html {
151
175
  margin: 0;
152
176
  padding: 0;