@centreon/ui 24.4.33 → 24.4.35
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 +19 -14
- package/public/mockServiceWorker.js +1 -1
- package/src/Button/Icon/index.tsx +1 -1
- package/src/Button/Save/StartIcon.tsx +3 -3
- package/src/Button/Save/index.tsx +9 -5
- package/src/Checkbox/Checkbox.tsx +2 -2
- package/src/Checkbox/CheckboxGroup/index.tsx +2 -2
- package/src/Dashboard/Item.tsx +1 -1
- package/src/Dashboard/Layout.tsx +2 -2
- package/src/Dialog/index.tsx +1 -1
- package/src/FallbackPage/FallbackPage.tsx +3 -3
- package/src/FileDropZone/index.tsx +3 -1
- package/src/Form/Form.cypress.spec.tsx +133 -0
- package/src/Form/Inputs/CheckboxGroup.tsx +1 -4
- package/src/Form/Inputs/List/Content.tsx +62 -0
- package/src/Form/Inputs/List/List.styles.ts +29 -0
- package/src/Form/Inputs/List/List.tsx +58 -0
- package/src/Form/Inputs/List/useList.ts +81 -0
- package/src/Form/Inputs/index.tsx +3 -1
- package/src/Form/Inputs/models.ts +9 -1
- package/src/Graph/LineChart/BasicComponents/Lines/Threshold/Circle.tsx +2 -2
- package/src/Graph/LineChart/BasicComponents/Lines/Threshold/index.tsx +5 -4
- package/src/Graph/LineChart/BasicComponents/Thresholds.tsx +2 -2
- package/src/Graph/LineChart/BasicComponents/useFilterLines.ts +1 -1
- package/src/Graph/LineChart/InteractiveComponents/AnchorPoint/GuidingLines.tsx +2 -2
- package/src/Graph/LineChart/InteractiveComponents/Annotations/Annotation/index.tsx +2 -3
- package/src/Graph/LineChart/InteractiveComponents/Annotations/EventAnnotations.tsx +1 -1
- package/src/Graph/LineChart/Legend/useLegend.ts +3 -3
- package/src/Graph/LineChart/helpers/doc.ts +16 -13
- package/src/Graph/LineChart/helpers/index.ts +1 -1
- package/src/Graph/LineChart/index.stories.tsx +4 -2
- package/src/Graph/SingleBar/Thresholds.tsx +2 -2
- package/src/Graph/Text/Text.stories.tsx +60 -4
- package/src/Graph/common/timeSeries/index.ts +3 -3
- package/src/InputField/Select/Autocomplete/Connected/index.tsx +10 -7
- package/src/InputField/Select/Autocomplete/Draggable/SortableList.tsx +1 -1
- package/src/InputField/Select/Autocomplete/Draggable/SortableListContent.tsx +1 -1
- package/src/InputField/Select/Autocomplete/Draggable/index.tsx +1 -1
- package/src/InputField/Select/Autocomplete/index.tsx +121 -115
- package/src/InputField/Select/IconPopover/index.tsx +2 -2
- package/src/InputField/Select/index.tsx +1 -1
- package/src/InputField/Text/index.tsx +2 -2
- package/src/Listing/Cell/DataCell.tsx +15 -1
- package/src/Listing/Header/ListingHeader.tsx +1 -1
- package/src/Listing/Listing.cypress.spec.tsx +2 -2
- package/src/Listing/Listing.styles.ts +2 -3
- package/src/Listing/index.stories.tsx +14 -3
- package/src/Listing/index.tsx +10 -9
- package/src/Module/Module.cypress.spec.tsx +129 -0
- package/src/Module/index.tsx +2 -4
- package/src/RichTextEditor/RichTextEditor.tsx +12 -1
- package/src/SortableItems/index.tsx +2 -7
- package/src/ThemeProvider/index.tsx +24 -0
- package/src/TimePeriods/CustomTimePeriod/CompactCustomTimePeriod.styles.ts +6 -7
- package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/PickersStartEndDate.tsx +8 -3
- package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/models.ts +0 -2
- package/src/TimePeriods/DateTimePickerInput.tsx +56 -19
- package/src/TimePeriods/ResolutionTimePeriod.cypress.spec.tsx +12 -9
- package/src/TimePeriods/TimePeriods.cypress.spec.tsx +9 -33
- package/src/TimePeriods/helpers/index.ts +1 -1
- package/src/TimePeriods/index.stories.tsx +12 -4
- package/src/TimePeriods/index.tsx +2 -2
- package/src/api/QueryProvider.tsx +1 -1
- package/src/api/TestQueryProvider.tsx +1 -1
- package/src/api/useFetchQuery/index.ts +27 -23
- package/src/api/useMutationQuery/index.ts +45 -21
- package/src/components/Button/Icon/IconButton.tsx +6 -2
- package/src/components/DataTable/DataListing.tsx +6 -0
- package/src/components/DataTable/DataTable.cypress.spec.tsx +193 -0
- package/src/components/DataTable/DataTable.stories.tsx +40 -0
- package/src/components/DataTable/DataTable.styles.ts +3 -0
- package/src/components/DataTable/DataTable.tsx +3 -3
- package/src/components/DataTable/Item/DataTableItem.styles.ts +7 -2
- package/src/components/DataTable/Item/DataTableItem.tsx +4 -4
- package/src/components/DataTable/index.ts +3 -1
- package/src/components/Form/AccessRights/__fixtures__/contactAccessRight.mock.ts +2 -0
- package/src/components/Form/AccessRights/useAccessRightsForm.utils.ts +1 -1
- package/src/components/Form/Dashboard/DashboardForm.tsx +15 -12
- package/src/components/Layout/PageLayout/PageLayout.tsx +1 -1
- package/src/components/Layout/PageLayout/PageLayoutActions.tsx +1 -0
- package/src/components/Layout/PageLayout/PageLayoutBody.tsx +1 -0
- package/src/components/Layout/PageLayout/PageLayoutHeader.tsx +5 -1
- package/src/components/Layout/PageLayout/PageQuickAccess.tsx +76 -0
- package/src/components/Layout/PageLayout/index.ts +3 -1
- package/src/components/Layout/PageLayout.cypress.spec.tsx +66 -0
- package/src/components/Modal/Modal.styles.ts +4 -3
- package/src/components/Modal/ModalActions.tsx +4 -2
- package/src/components/Tooltip/ConfirmationTooltip/ConfirmationTooltip.stories.tsx +3 -3
- package/src/components/Tooltip/ConfirmationTooltip/ConfirmationTooltip.tsx +1 -1
- package/src/components/Tooltip/ConfirmationTooltip/models.ts +1 -1
- package/src/index.ts +2 -2
- package/src/queryParameters/url/index.ts +5 -1
- package/src/utils/index.ts +1 -1
- package/src/utils/{useLicenseExpirationWarning.cypress.spec.tsx → useLicenseExpirationWarning.test.tsx} +48 -37
- package/src/utils/useLicenseExpirationWarning.ts +18 -18
- package/src/utils/usePluralizedTranslation.ts +21 -0
- package/src/screens/dashboard/DashboardsDetail.stories.tsx +0 -108
- package/src/screens/dashboard/DashboardsOverview.stories.tsx +0 -281
- package/src/utils/useDateTimePickerAdapter.ts +0 -309
|
@@ -73,14 +73,14 @@ const IconPopoverMultiAutocomplete = ({
|
|
|
73
73
|
};
|
|
74
74
|
|
|
75
75
|
const isSelected = (id: number | string): boolean => {
|
|
76
|
-
return pipe(find(propEq(
|
|
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(
|
|
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(
|
|
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
|
|
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 (
|
|
@@ -77,9 +77,9 @@ const mountListing = (): void => {
|
|
|
77
77
|
subItems={{
|
|
78
78
|
canCheckSubItems: false,
|
|
79
79
|
enable: true,
|
|
80
|
+
getRowProperty: () => 'subItems',
|
|
80
81
|
labelCollapse: 'Collapse',
|
|
81
|
-
labelExpand: 'Expand'
|
|
82
|
-
rowProperty: 'subItems'
|
|
82
|
+
labelExpand: 'Expand'
|
|
83
83
|
}}
|
|
84
84
|
totalRows={10}
|
|
85
85
|
/>
|
|
@@ -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
|
|
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 ||
|
|
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,
|
|
@@ -377,10 +387,11 @@ export const ListingWithSubItems = {
|
|
|
377
387
|
subItems: {
|
|
378
388
|
canCheckSubItems: false,
|
|
379
389
|
enable: true,
|
|
390
|
+
getRowProperty: () => 'subItems',
|
|
380
391
|
labelCollapse: 'Collapse',
|
|
381
|
-
labelExpand: 'Expand'
|
|
382
|
-
rowProperty: 'subItems'
|
|
392
|
+
labelExpand: 'Expand'
|
|
383
393
|
},
|
|
384
394
|
totalRows: 10
|
|
385
|
-
}
|
|
395
|
+
},
|
|
396
|
+
render: TemplateSubItems
|
|
386
397
|
};
|
package/src/Listing/index.tsx
CHANGED
|
@@ -69,7 +69,7 @@ const getVisibleColumns = ({
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
return selectedColumnIds.map((id) =>
|
|
72
|
-
columns.find(propEq(
|
|
72
|
+
columns.find(propEq(id, 'id'))
|
|
73
73
|
) as Array<Column>;
|
|
74
74
|
};
|
|
75
75
|
|
|
@@ -123,9 +123,9 @@ export interface Props<TRow> {
|
|
|
123
123
|
subItems?: {
|
|
124
124
|
canCheckSubItems: boolean;
|
|
125
125
|
enable: boolean;
|
|
126
|
+
getRowProperty: (row?) => string;
|
|
126
127
|
labelCollapse: string;
|
|
127
128
|
labelExpand: string;
|
|
128
|
-
rowProperty: string;
|
|
129
129
|
};
|
|
130
130
|
totalRows?: number;
|
|
131
131
|
viewerModeConfiguration?: ViewerModeConfiguration;
|
|
@@ -180,9 +180,9 @@ const Listing = <TRow extends { id: RowId }>({
|
|
|
180
180
|
subItems = {
|
|
181
181
|
canCheckSubItems: false,
|
|
182
182
|
enable: false,
|
|
183
|
+
getRowProperty: () => '',
|
|
183
184
|
labelCollapse: 'Collapse',
|
|
184
|
-
labelExpand: 'Expand'
|
|
185
|
-
rowProperty: ''
|
|
185
|
+
labelExpand: 'Expand'
|
|
186
186
|
}
|
|
187
187
|
}: Props<TRow>): JSX.Element => {
|
|
188
188
|
const currentVisibleColumns = getVisibleColumns({
|
|
@@ -215,10 +215,10 @@ const Listing = <TRow extends { id: RowId }>({
|
|
|
215
215
|
? reduce<TRow, Array<TRow>>(
|
|
216
216
|
(acc, row): Array<TRow> => {
|
|
217
217
|
if (
|
|
218
|
-
row[subItems.
|
|
218
|
+
row[subItems.getRowProperty()] &&
|
|
219
219
|
subItemsPivots.includes(row.id)
|
|
220
220
|
) {
|
|
221
|
-
return [...acc, row, ...row[subItems.
|
|
221
|
+
return [...acc, row, ...row[subItems.getRowProperty()]];
|
|
222
222
|
}
|
|
223
223
|
|
|
224
224
|
return [...acc, row];
|
|
@@ -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
|
});
|
|
@@ -454,7 +453,7 @@ const Listing = <TRow extends { id: RowId }>({
|
|
|
454
453
|
reduce<TRow | number, Array<string | number>>(
|
|
455
454
|
(acc, row) => [
|
|
456
455
|
...acc,
|
|
457
|
-
...pluck('id', row[subItems?.
|
|
456
|
+
...pluck('id', row[subItems?.getRowProperty() || ''] || [])
|
|
458
457
|
],
|
|
459
458
|
[],
|
|
460
459
|
rows
|
|
@@ -632,7 +631,9 @@ const Listing = <TRow extends { id: RowId }>({
|
|
|
632
631
|
listingVariant={listingVariant}
|
|
633
632
|
row={row}
|
|
634
633
|
rowColorConditions={rowColorConditions}
|
|
635
|
-
subItemsRowProperty={subItems?.
|
|
634
|
+
subItemsRowProperty={subItems?.getRowProperty(
|
|
635
|
+
row
|
|
636
|
+
)}
|
|
636
637
|
/>
|
|
637
638
|
))}
|
|
638
639
|
</ListingRow>
|
|
@@ -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({
|
|
@@ -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={
|
|
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(
|
|
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;
|
|
@@ -12,22 +12,21 @@ const useStyles = makeStyles()((theme) => ({
|
|
|
12
12
|
},
|
|
13
13
|
containerDates: {
|
|
14
14
|
display: 'flex',
|
|
15
|
-
gap: theme.spacing(0.5),
|
|
16
15
|
[theme.breakpoints.down('sm')]: {
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
flexDirection: 'column',
|
|
17
|
+
gap: theme.spacing(0.5)
|
|
19
18
|
}
|
|
20
19
|
},
|
|
21
20
|
date: {
|
|
22
|
-
minWidth: theme.spacing(12
|
|
21
|
+
minWidth: theme.spacing(12),
|
|
23
22
|
textAlign: 'start'
|
|
24
23
|
},
|
|
25
24
|
error: {
|
|
26
25
|
textAlign: 'center'
|
|
27
26
|
},
|
|
28
27
|
label: {
|
|
29
|
-
minWidth: theme.spacing(3),
|
|
30
|
-
textAlign: '
|
|
28
|
+
minWidth: theme.spacing(3.5),
|
|
29
|
+
textAlign: 'end'
|
|
31
30
|
},
|
|
32
31
|
|
|
33
32
|
picker: {
|
|
@@ -39,7 +38,7 @@ const useStyles = makeStyles()((theme) => ({
|
|
|
39
38
|
},
|
|
40
39
|
timeContainer: {
|
|
41
40
|
alignItems: 'center',
|
|
42
|
-
columnGap: theme.spacing(
|
|
41
|
+
columnGap: theme.spacing(0.5),
|
|
43
42
|
display: 'flex',
|
|
44
43
|
flexDirection: 'row',
|
|
45
44
|
[theme.breakpoints.down('sm')]: {
|
|
@@ -2,12 +2,15 @@ import { useAtomValue } from 'jotai';
|
|
|
2
2
|
import { makeStyles } from 'tss-react/mui';
|
|
3
3
|
import { equals } from 'ramda';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
|
+
import dayjs from 'dayjs';
|
|
6
|
+
import utc from 'dayjs/plugin/utc';
|
|
7
|
+
import timezone from 'dayjs/plugin/timezone';
|
|
5
8
|
|
|
9
|
+
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
|
|
6
10
|
import { Typography } from '@mui/material';
|
|
7
11
|
import { LocalizationProvider } from '@mui/x-date-pickers';
|
|
8
12
|
|
|
9
13
|
import { userAtom } from '@centreon/ui-context';
|
|
10
|
-
import { useDateTimePickerAdapter } from '@centreon/ui';
|
|
11
14
|
|
|
12
15
|
import DateTimePickerInput from '../../DateTimePickerInput';
|
|
13
16
|
import {
|
|
@@ -20,6 +23,9 @@ import ErrorText from './ErrorText';
|
|
|
20
23
|
import { PickersData, PickersStartEndDateDirection } from './models';
|
|
21
24
|
import { PickersStartEndDateModel } from './usePickersStartEndDate';
|
|
22
25
|
|
|
26
|
+
dayjs.extend(utc);
|
|
27
|
+
dayjs.extend(timezone);
|
|
28
|
+
|
|
23
29
|
const useStyles = makeStyles()((theme) => ({
|
|
24
30
|
error: {
|
|
25
31
|
textAlign: 'center'
|
|
@@ -104,7 +110,6 @@ const PickersStartEndDate = ({
|
|
|
104
110
|
direction = PickersStartEndDateDirection.column
|
|
105
111
|
}: Props): JSX.Element => {
|
|
106
112
|
const { classes, cx } = useStyles();
|
|
107
|
-
const { Adapter } = useDateTimePickerAdapter();
|
|
108
113
|
|
|
109
114
|
const { locale } = useAtomValue(userAtom);
|
|
110
115
|
const error = useAtomValue(errorTimePeriodAtom);
|
|
@@ -126,7 +131,7 @@ const PickersStartEndDate = ({
|
|
|
126
131
|
return (
|
|
127
132
|
<LocalizationProvider
|
|
128
133
|
adapterLocale={locale.substring(0, 2)}
|
|
129
|
-
dateAdapter={
|
|
134
|
+
dateAdapter={AdapterDayjs}
|
|
130
135
|
>
|
|
131
136
|
<div className={styleContainer}>
|
|
132
137
|
<PickerDateWithLabel
|
|
@@ -18,8 +18,6 @@ export interface PickersData {
|
|
|
18
18
|
getError?: (value: boolean) => void;
|
|
19
19
|
isDisabledEndPicker?: boolean;
|
|
20
20
|
isDisabledStartPicker?: boolean;
|
|
21
|
-
onCloseEndPicker?: (isClosed: boolean) => void;
|
|
22
|
-
onCloseStartPicker?: (isClosed: boolean) => void;
|
|
23
21
|
rangeEndDate?: RangeDate;
|
|
24
22
|
rangeStartDate?: RangeDate;
|
|
25
23
|
}
|
|
@@ -1,48 +1,85 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import dayjs, { Dayjs } from 'dayjs';
|
|
4
|
+
import { useAtomValue } from 'jotai';
|
|
5
|
+
import { equals } from 'ramda';
|
|
4
6
|
|
|
5
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
DateTimePicker,
|
|
9
|
+
DateTimePickerProps,
|
|
10
|
+
LocalizationProvider
|
|
11
|
+
} from '@mui/x-date-pickers';
|
|
12
|
+
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
|
|
13
|
+
|
|
14
|
+
import { userAtom } from '@centreon/ui-context';
|
|
6
15
|
|
|
7
16
|
import { CustomTimePeriodProperty } from './models';
|
|
8
17
|
|
|
18
|
+
interface ChangeDateProps {
|
|
19
|
+
date: Date;
|
|
20
|
+
property: CustomTimePeriodProperty | string;
|
|
21
|
+
}
|
|
22
|
+
|
|
9
23
|
interface Props {
|
|
10
|
-
changeDate: (props) => void;
|
|
24
|
+
changeDate: (props: ChangeDateProps) => void;
|
|
11
25
|
date: Date | null;
|
|
12
26
|
desktopMediaQuery?: string;
|
|
13
27
|
disabled?: boolean;
|
|
14
28
|
maxDate?: Date;
|
|
15
29
|
minDate?: Date;
|
|
16
|
-
|
|
30
|
+
minDateTime?: Date;
|
|
31
|
+
property: CustomTimePeriodProperty | string;
|
|
17
32
|
}
|
|
18
33
|
|
|
19
34
|
const DateTimePickerInput = ({
|
|
20
35
|
date,
|
|
21
36
|
maxDate,
|
|
22
37
|
minDate,
|
|
38
|
+
minDateTime,
|
|
23
39
|
property,
|
|
24
40
|
changeDate,
|
|
25
41
|
disabled = false,
|
|
26
|
-
desktopMediaQuery
|
|
27
|
-
|
|
28
|
-
|
|
42
|
+
desktopMediaQuery,
|
|
43
|
+
...rest
|
|
44
|
+
}: Props & DateTimePickerProps<dayjs.Dayjs>): JSX.Element => {
|
|
45
|
+
const desktopPickerMediaQuery =
|
|
46
|
+
'@media (min-width: 1024px) or (pointer: fine)';
|
|
47
|
+
|
|
48
|
+
const { timezone, locale } = useAtomValue(userAtom);
|
|
49
|
+
|
|
50
|
+
const isUTC = equals(timezone, 'UTC');
|
|
29
51
|
|
|
30
52
|
const changeTime = (newValue: dayjs.Dayjs | null): void => {
|
|
31
53
|
changeDate({ date: dayjs(newValue).toDate(), property });
|
|
32
54
|
};
|
|
33
55
|
|
|
56
|
+
const formatDate = useCallback(
|
|
57
|
+
(currentDate: Date | null): Dayjs => {
|
|
58
|
+
return isUTC ? dayjs.utc(currentDate) : dayjs.tz(currentDate, timezone);
|
|
59
|
+
},
|
|
60
|
+
[isUTC, timezone]
|
|
61
|
+
);
|
|
62
|
+
|
|
34
63
|
return (
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
64
|
+
<LocalizationProvider
|
|
65
|
+
adapterLocale={locale.substring(0, 2)}
|
|
66
|
+
dateAdapter={AdapterDayjs}
|
|
67
|
+
dateLibInstance={dayjs}
|
|
68
|
+
>
|
|
69
|
+
<DateTimePicker<dayjs.Dayjs>
|
|
70
|
+
dayOfWeekFormatter={(dayOfWeek) =>
|
|
71
|
+
dayOfWeek.substring(0, 2).toLocaleUpperCase()
|
|
72
|
+
}
|
|
73
|
+
desktopModeMediaQuery={desktopMediaQuery ?? desktopPickerMediaQuery}
|
|
74
|
+
disabled={disabled}
|
|
75
|
+
maxDate={maxDate && formatDate(maxDate)}
|
|
76
|
+
minDate={minDate && formatDate(minDate)}
|
|
77
|
+
minDateTime={minDateTime && formatDate(minDateTime)}
|
|
78
|
+
value={formatDate(date)}
|
|
79
|
+
onChange={changeTime}
|
|
80
|
+
{...rest}
|
|
81
|
+
/>
|
|
82
|
+
</LocalizationProvider>
|
|
46
83
|
);
|
|
47
84
|
};
|
|
48
85
|
|