@centreon/ui 24.4.44 → 24.4.45-develop.0
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.styles.ts +2 -3
- package/src/Listing/index.stories.tsx +12 -1
- package/src/Listing/index.tsx +1 -2
- 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/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 +1 -1
- 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 +2 -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 (
|
|
@@ -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,
|
|
@@ -382,5 +392,6 @@ export const ListingWithSubItems = {
|
|
|
382
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
|
|
|
@@ -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
|
+
});
|
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
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import dayjs from 'dayjs';
|
|
2
|
-
import 'dayjs/locale/
|
|
2
|
+
import 'dayjs/locale/en';
|
|
3
3
|
import localizedFormatPlugin from 'dayjs/plugin/localizedFormat';
|
|
4
4
|
import timezonePlugin from 'dayjs/plugin/timezone';
|
|
5
5
|
import utcPlugin from 'dayjs/plugin/utc';
|
|
@@ -19,18 +19,18 @@ dayjs.extend(localizedFormatPlugin);
|
|
|
19
19
|
|
|
20
20
|
const data = [
|
|
21
21
|
{
|
|
22
|
-
locale: '
|
|
23
|
-
resolution: { height:
|
|
22
|
+
locale: 'en_US',
|
|
23
|
+
resolution: { height: 590, width: 500 },
|
|
24
24
|
timezone: 'Europe/Paris'
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
|
-
locale: '
|
|
28
|
-
resolution: { height:
|
|
27
|
+
locale: 'en_US',
|
|
28
|
+
resolution: { height: 590, width: 200 },
|
|
29
29
|
timezone: 'Europe/Paris'
|
|
30
30
|
},
|
|
31
31
|
{
|
|
32
|
-
locale: '
|
|
33
|
-
resolution: { height:
|
|
32
|
+
locale: 'en_US',
|
|
33
|
+
resolution: { height: 590, width: 1024 },
|
|
34
34
|
timezone: 'Europe/Paris'
|
|
35
35
|
}
|
|
36
36
|
];
|
|
@@ -45,7 +45,7 @@ data.forEach((item) =>
|
|
|
45
45
|
|
|
46
46
|
store.set(userAtom, {
|
|
47
47
|
...retrievedUser,
|
|
48
|
-
locale: '
|
|
48
|
+
locale: 'en_US',
|
|
49
49
|
timezone: 'Europe/Paris'
|
|
50
50
|
});
|
|
51
51
|
|
|
@@ -59,7 +59,10 @@ data.forEach((item) =>
|
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
it(`displays correctly the dates design when screen resolution is ${width}px`, () => {
|
|
62
|
-
cy.
|
|
62
|
+
cy.makeSnapshotWithCustomResolution({
|
|
63
|
+
resolution: { height, width },
|
|
64
|
+
title: `${width}px`
|
|
65
|
+
});
|
|
63
66
|
});
|
|
64
67
|
})
|
|
65
68
|
);
|