@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
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
|
-
import React, { ReactElement } from 'react';
|
|
3
|
-
|
|
4
|
-
import { Meta } from '@storybook/react';
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
Add as AddIcon,
|
|
8
|
-
Settings as SettingsIcon,
|
|
9
|
-
Share as ShareIcon
|
|
10
|
-
} from '@mui/icons-material';
|
|
11
|
-
|
|
12
|
-
import {
|
|
13
|
-
Button,
|
|
14
|
-
IconButton,
|
|
15
|
-
Menu,
|
|
16
|
-
PageHeader,
|
|
17
|
-
PageLayout
|
|
18
|
-
} from '../../components';
|
|
19
|
-
|
|
20
|
-
const meta: Meta = {
|
|
21
|
-
args: {
|
|
22
|
-
actions: {}
|
|
23
|
-
},
|
|
24
|
-
parameters: {
|
|
25
|
-
layout: 'fullscreen'
|
|
26
|
-
},
|
|
27
|
-
title: 'screens/Dashboards detail'
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export default meta;
|
|
31
|
-
|
|
32
|
-
const DefaultView = (args): ReactElement => {
|
|
33
|
-
const { data } = args;
|
|
34
|
-
|
|
35
|
-
return (
|
|
36
|
-
<PageLayout>
|
|
37
|
-
<PageLayout.Header>
|
|
38
|
-
<PageHeader>
|
|
39
|
-
<PageHeader.Main>
|
|
40
|
-
<PageHeader.Menu>
|
|
41
|
-
<Menu>
|
|
42
|
-
<Menu.Button />
|
|
43
|
-
<Menu.Items>
|
|
44
|
-
<Menu.Item>Menu Item</Menu.Item>
|
|
45
|
-
<Menu.Item>Menu Item</Menu.Item>
|
|
46
|
-
<Menu.Item>Menu Item</Menu.Item>
|
|
47
|
-
<Menu.Divider />
|
|
48
|
-
<Menu.Item>
|
|
49
|
-
<Button
|
|
50
|
-
icon={<AddIcon />}
|
|
51
|
-
iconVariant="start"
|
|
52
|
-
variant="ghost"
|
|
53
|
-
>
|
|
54
|
-
Add item
|
|
55
|
-
</Button>
|
|
56
|
-
</Menu.Item>
|
|
57
|
-
</Menu.Items>
|
|
58
|
-
</Menu>
|
|
59
|
-
</PageHeader.Menu>
|
|
60
|
-
<PageHeader.Title
|
|
61
|
-
description={data.dashboard.description}
|
|
62
|
-
title={data.dashboard.name}
|
|
63
|
-
/>
|
|
64
|
-
</PageHeader.Main>
|
|
65
|
-
</PageHeader>
|
|
66
|
-
</PageLayout.Header>
|
|
67
|
-
<PageLayout.Body>
|
|
68
|
-
<PageLayout.Actions>
|
|
69
|
-
<IconButton
|
|
70
|
-
aria-label="edit"
|
|
71
|
-
data-testid="edit"
|
|
72
|
-
icon={<SettingsIcon />}
|
|
73
|
-
size="small"
|
|
74
|
-
variant="ghost"
|
|
75
|
-
/>
|
|
76
|
-
<IconButton
|
|
77
|
-
aria-label="share"
|
|
78
|
-
data-testid="share"
|
|
79
|
-
icon={<ShareIcon />}
|
|
80
|
-
size="small"
|
|
81
|
-
variant="ghost"
|
|
82
|
-
/>
|
|
83
|
-
</PageLayout.Actions>
|
|
84
|
-
</PageLayout.Body>
|
|
85
|
-
</PageLayout>
|
|
86
|
-
);
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
export const Default = {
|
|
90
|
-
args: {
|
|
91
|
-
data: {
|
|
92
|
-
dashboard: {
|
|
93
|
-
description:
|
|
94
|
-
'Description et culpa sit commodo ea enim excepteur elit. Velit irure velit tempor culpa commodo eu adipisicing eu proident ullamco.',
|
|
95
|
-
id: 1,
|
|
96
|
-
name: 'Dashboard 1'
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
},
|
|
100
|
-
render: DefaultView
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
export const AsEditLayoutState = {
|
|
104
|
-
args: {
|
|
105
|
-
...Default.args
|
|
106
|
-
},
|
|
107
|
-
render: DefaultView
|
|
108
|
-
};
|
|
@@ -1,281 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
|
-
import { useEffect } from 'react';
|
|
3
|
-
|
|
4
|
-
import { Meta } from '@storybook/react';
|
|
5
|
-
import { atom, useAtom } from 'jotai';
|
|
6
|
-
|
|
7
|
-
import { Add as AddIcon } from '@mui/icons-material';
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
Button,
|
|
11
|
-
DashboardForm,
|
|
12
|
-
DashboardFormProps,
|
|
13
|
-
DataTable,
|
|
14
|
-
Modal,
|
|
15
|
-
PageHeader,
|
|
16
|
-
PageLayout
|
|
17
|
-
} from '../../components';
|
|
18
|
-
import { Default as DashboardFormDefaultStory } from '../../components/Form/Dashboard/DashboardForm.stories';
|
|
19
|
-
|
|
20
|
-
const meta: Meta = {
|
|
21
|
-
args: {
|
|
22
|
-
actions: {
|
|
23
|
-
create: {
|
|
24
|
-
label: 'Create a dashboard'
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
|
-
deleteConfirmation: {
|
|
28
|
-
labels: {
|
|
29
|
-
actions: {
|
|
30
|
-
cancel: 'Cancel',
|
|
31
|
-
confirm: 'Delete'
|
|
32
|
-
},
|
|
33
|
-
description: (name) => (
|
|
34
|
-
<>
|
|
35
|
-
Are you sure you want to delete <strong>{name}</strong> ?
|
|
36
|
-
</>
|
|
37
|
-
),
|
|
38
|
-
title: 'Delete dashboard'
|
|
39
|
-
}
|
|
40
|
-
},
|
|
41
|
-
form: {
|
|
42
|
-
labels: {
|
|
43
|
-
...DashboardFormDefaultStory.args!.labels,
|
|
44
|
-
title: {
|
|
45
|
-
create: 'Create dashboard',
|
|
46
|
-
update: 'Update dashboard'
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
},
|
|
50
|
-
list: {
|
|
51
|
-
emptyState: {
|
|
52
|
-
labels: {
|
|
53
|
-
actions: {
|
|
54
|
-
create: 'Create dashboard'
|
|
55
|
-
},
|
|
56
|
-
title: 'No dashboards found'
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
title: 'Dashboards overview'
|
|
61
|
-
},
|
|
62
|
-
parameters: {
|
|
63
|
-
layout: 'fullscreen'
|
|
64
|
-
},
|
|
65
|
-
title: 'screens/Dashboards overview'
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
export default meta;
|
|
69
|
-
|
|
70
|
-
interface dashboardItem {
|
|
71
|
-
description: string;
|
|
72
|
-
id: number;
|
|
73
|
-
name: string;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const dialogStateAtom = atom<{
|
|
77
|
-
item: dashboardItem | null;
|
|
78
|
-
open: boolean;
|
|
79
|
-
variant: DashboardFormProps['variant'];
|
|
80
|
-
}>({
|
|
81
|
-
item: null,
|
|
82
|
-
open: false,
|
|
83
|
-
variant: 'create'
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
const deleteDialogStateAtom = atom<{
|
|
87
|
-
item: dashboardItem | null;
|
|
88
|
-
open: boolean;
|
|
89
|
-
}>({
|
|
90
|
-
item: null,
|
|
91
|
-
open: false
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
const dataDashboardsAtom = atom<Array<dashboardItem>>([]);
|
|
95
|
-
|
|
96
|
-
const DefaultView = (args): JSX.Element => {
|
|
97
|
-
const { data, title, actions, list, form, deleteConfirmation } = args;
|
|
98
|
-
const [dialogState, setDialogState] = useAtom(dialogStateAtom);
|
|
99
|
-
const [deleteDialogState, setDeleteDialogState] = useAtom(
|
|
100
|
-
deleteDialogStateAtom
|
|
101
|
-
);
|
|
102
|
-
const [dataDashboards, setDataDashboards] = useAtom(dataDashboardsAtom);
|
|
103
|
-
|
|
104
|
-
useEffect(() => {
|
|
105
|
-
setDataDashboards(data.dashboards);
|
|
106
|
-
}, [data.dashboards]);
|
|
107
|
-
|
|
108
|
-
const createDashboard = (d): void => {
|
|
109
|
-
const dashboard = { ...d };
|
|
110
|
-
dashboard.id = dataDashboards.length
|
|
111
|
-
? Math.max(...dataDashboards.map((db) => db.id)) + 1
|
|
112
|
-
: 0;
|
|
113
|
-
setDataDashboards((prev) =>
|
|
114
|
-
[...prev, dashboard].sort((a, b) => a.name.localeCompare(b.name))
|
|
115
|
-
);
|
|
116
|
-
setDialogState({ item: null, open: false, variant: 'create' });
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
const updateDashboard = (d): void => {
|
|
120
|
-
setDataDashboards((prev) =>
|
|
121
|
-
prev
|
|
122
|
-
.map((dashboard) => (dashboard.id === d.id ? d : dashboard))
|
|
123
|
-
.sort((a, b) => a.name.localeCompare(b.name))
|
|
124
|
-
);
|
|
125
|
-
setDialogState({ item: null, open: false, variant: 'update' });
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
const deleteDashboard = (id): void => {
|
|
129
|
-
setDataDashboards((prev) =>
|
|
130
|
-
prev.filter((dashboard) => dashboard.id !== id)
|
|
131
|
-
);
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
return (
|
|
135
|
-
<PageLayout>
|
|
136
|
-
<PageLayout.Header>
|
|
137
|
-
<PageHeader>
|
|
138
|
-
<PageHeader.Main>
|
|
139
|
-
<PageHeader.Title title={title} />
|
|
140
|
-
</PageHeader.Main>
|
|
141
|
-
</PageHeader>
|
|
142
|
-
</PageLayout.Header>
|
|
143
|
-
<PageLayout.Body>
|
|
144
|
-
<PageLayout.Actions>
|
|
145
|
-
{dataDashboards.length !== 0 && (
|
|
146
|
-
<Button
|
|
147
|
-
aria-label="add"
|
|
148
|
-
icon={<AddIcon />}
|
|
149
|
-
iconVariant="start"
|
|
150
|
-
onClick={() =>
|
|
151
|
-
setDialogState({ item: null, open: true, variant: 'create' })
|
|
152
|
-
}
|
|
153
|
-
>
|
|
154
|
-
{actions.create.label}
|
|
155
|
-
</Button>
|
|
156
|
-
)}
|
|
157
|
-
</PageLayout.Actions>
|
|
158
|
-
|
|
159
|
-
<DataTable isEmpty={dataDashboards.length === 0}>
|
|
160
|
-
{dataDashboards.length === 0 ? (
|
|
161
|
-
<DataTable.EmptyState
|
|
162
|
-
labels={list.emptyState.labels}
|
|
163
|
-
onCreate={() =>
|
|
164
|
-
setDialogState({
|
|
165
|
-
item: null,
|
|
166
|
-
open: true,
|
|
167
|
-
variant: 'create'
|
|
168
|
-
})
|
|
169
|
-
}
|
|
170
|
-
/>
|
|
171
|
-
) : (
|
|
172
|
-
dataDashboards.map((dashboard) => (
|
|
173
|
-
<DataTable.Item
|
|
174
|
-
hasActions
|
|
175
|
-
hasCardAction
|
|
176
|
-
description={dashboard.description}
|
|
177
|
-
key={dashboard.id}
|
|
178
|
-
title={dashboard.name}
|
|
179
|
-
onDelete={() =>
|
|
180
|
-
setDeleteDialogState({ item: dashboard, open: true })
|
|
181
|
-
}
|
|
182
|
-
onEdit={() =>
|
|
183
|
-
setDialogState({
|
|
184
|
-
item: dashboard,
|
|
185
|
-
open: true,
|
|
186
|
-
variant: 'update'
|
|
187
|
-
})
|
|
188
|
-
}
|
|
189
|
-
/>
|
|
190
|
-
))
|
|
191
|
-
)}
|
|
192
|
-
</DataTable>
|
|
193
|
-
</PageLayout.Body>
|
|
194
|
-
|
|
195
|
-
<Modal
|
|
196
|
-
open={dialogState.open}
|
|
197
|
-
onClose={() =>
|
|
198
|
-
setDialogState({
|
|
199
|
-
item: null,
|
|
200
|
-
open: false,
|
|
201
|
-
variant: dialogState.variant
|
|
202
|
-
})
|
|
203
|
-
}
|
|
204
|
-
>
|
|
205
|
-
<Modal.Header>
|
|
206
|
-
{form.labels.title[dialogState.variant ?? 'create']}
|
|
207
|
-
</Modal.Header>
|
|
208
|
-
<Modal.Body>
|
|
209
|
-
<DashboardForm
|
|
210
|
-
labels={DashboardFormDefaultStory!.args!.labels!}
|
|
211
|
-
resource={dialogState.item || undefined}
|
|
212
|
-
variant={dialogState.variant}
|
|
213
|
-
onCancel={() =>
|
|
214
|
-
setDialogState({
|
|
215
|
-
item: null,
|
|
216
|
-
open: false,
|
|
217
|
-
variant: dialogState.variant
|
|
218
|
-
})
|
|
219
|
-
}
|
|
220
|
-
onSubmit={(values) =>
|
|
221
|
-
dialogState.variant === 'create'
|
|
222
|
-
? createDashboard(values)
|
|
223
|
-
: updateDashboard(values)
|
|
224
|
-
}
|
|
225
|
-
/>
|
|
226
|
-
</Modal.Body>
|
|
227
|
-
</Modal>
|
|
228
|
-
<Modal
|
|
229
|
-
open={deleteDialogState.open}
|
|
230
|
-
onClose={() =>
|
|
231
|
-
setDeleteDialogState({
|
|
232
|
-
...deleteDialogState,
|
|
233
|
-
open: false
|
|
234
|
-
})
|
|
235
|
-
}
|
|
236
|
-
>
|
|
237
|
-
<Modal.Header>{deleteConfirmation.labels.title}</Modal.Header>
|
|
238
|
-
<Modal.Body>
|
|
239
|
-
<p>
|
|
240
|
-
{deleteConfirmation.labels.description(
|
|
241
|
-
deleteDialogState.item?.name
|
|
242
|
-
)}
|
|
243
|
-
</p>
|
|
244
|
-
</Modal.Body>
|
|
245
|
-
<Modal.Actions
|
|
246
|
-
isDanger
|
|
247
|
-
labels={deleteConfirmation.labels.actions}
|
|
248
|
-
onCancel={() => setDeleteDialogState({ item: null, open: false })}
|
|
249
|
-
onConfirm={() => {
|
|
250
|
-
deleteDashboard(deleteDialogState.item?.id);
|
|
251
|
-
setDeleteDialogState({ item: null, open: false });
|
|
252
|
-
}}
|
|
253
|
-
/>
|
|
254
|
-
</Modal>
|
|
255
|
-
</PageLayout>
|
|
256
|
-
);
|
|
257
|
-
};
|
|
258
|
-
|
|
259
|
-
export const Default = {
|
|
260
|
-
args: {
|
|
261
|
-
data: {
|
|
262
|
-
dashboards: [
|
|
263
|
-
{ description: 'Dashboard 1 description', id: 1, name: 'Dashboard 1' },
|
|
264
|
-
{ description: 'Dashboard 2 description', id: 2, name: 'Dashboard 2' },
|
|
265
|
-
{ description: 'Dashboard 3 description', id: 3, name: 'Dashboard 3' },
|
|
266
|
-
{ description: 'Dashboard 4 description', id: 4, name: 'Dashboard 4' },
|
|
267
|
-
{ description: 'Dashboard 5 description', id: 5, name: 'Dashboard 5' }
|
|
268
|
-
]
|
|
269
|
-
}
|
|
270
|
-
},
|
|
271
|
-
render: DefaultView
|
|
272
|
-
};
|
|
273
|
-
|
|
274
|
-
export const AsInitialState = {
|
|
275
|
-
args: {
|
|
276
|
-
data: {
|
|
277
|
-
dashboards: []
|
|
278
|
-
}
|
|
279
|
-
},
|
|
280
|
-
render: DefaultView
|
|
281
|
-
};
|
|
@@ -1,309 +0,0 @@
|
|
|
1
|
-
/* eslint-disable class-methods-use-this */
|
|
2
|
-
import { useCallback } from 'react';
|
|
3
|
-
|
|
4
|
-
import dayjs from 'dayjs';
|
|
5
|
-
import { useAtomValue } from 'jotai';
|
|
6
|
-
import { equals, isNil, not } from 'ramda';
|
|
7
|
-
|
|
8
|
-
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
|
|
9
|
-
|
|
10
|
-
import { useLocaleDateTimeFormat } from '@centreon/ui';
|
|
11
|
-
import { userAtom } from '@centreon/ui-context';
|
|
12
|
-
|
|
13
|
-
interface GetDestinationAndConfiguredTimezoneOffsetProps {
|
|
14
|
-
endTimezone?: string;
|
|
15
|
-
startTimezone?: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface UseDateTimePickerAdapterProps {
|
|
19
|
-
Adapter;
|
|
20
|
-
desktopPickerMediaQuery: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
enum DSTState {
|
|
24
|
-
SUMMER,
|
|
25
|
-
WINTER,
|
|
26
|
-
NODST
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
interface ToTimezonedDateProps {
|
|
30
|
-
date: Date;
|
|
31
|
-
timeZone?: string;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
interface GetDSTStateProps {
|
|
35
|
-
date: dayjs.Dayjs;
|
|
36
|
-
timezoneToUse?: string;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export const useDateTimePickerAdapter = (): UseDateTimePickerAdapterProps => {
|
|
40
|
-
const { timezone, locale } = useAtomValue(userAtom);
|
|
41
|
-
const { format } = useLocaleDateTimeFormat();
|
|
42
|
-
|
|
43
|
-
const desktopPickerMediaQuery =
|
|
44
|
-
'@media (pointer: fine) or (min-width: 1024px)';
|
|
45
|
-
|
|
46
|
-
const toTimezonedDate = ({
|
|
47
|
-
date,
|
|
48
|
-
timeZone = undefined
|
|
49
|
-
}: ToTimezonedDateProps): Date => {
|
|
50
|
-
if (isNil(timeZone)) {
|
|
51
|
-
return new Date(date.toLocaleString('en-US'));
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return new Date(date.toLocaleString('en-US', { timeZone }));
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
const getDestinationAndConfiguredTimezoneOffset = ({
|
|
58
|
-
startTimezone = undefined,
|
|
59
|
-
endTimezone = timezone
|
|
60
|
-
}: GetDestinationAndConfiguredTimezoneOffsetProps): number => {
|
|
61
|
-
const now = new Date();
|
|
62
|
-
const currentTimezoneDate = toTimezonedDate({
|
|
63
|
-
date: now,
|
|
64
|
-
timeZone: startTimezone
|
|
65
|
-
});
|
|
66
|
-
const destinationTimezoneDate = toTimezonedDate({
|
|
67
|
-
date: now,
|
|
68
|
-
timeZone: endTimezone
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
return Math.floor(
|
|
72
|
-
(currentTimezoneDate.getTime() - destinationTimezoneDate.getTime()) /
|
|
73
|
-
60 /
|
|
74
|
-
60 /
|
|
75
|
-
1000
|
|
76
|
-
);
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
const getDSTState = useCallback(
|
|
80
|
-
({ date, timezoneToUse }: GetDSTStateProps): DSTState => {
|
|
81
|
-
const hasNoTimezone = isNil(timezoneToUse);
|
|
82
|
-
const currentYear = toTimezonedDate({
|
|
83
|
-
date: new Date(),
|
|
84
|
-
timeZone: timezoneToUse
|
|
85
|
-
}).getFullYear();
|
|
86
|
-
|
|
87
|
-
const january = hasNoTimezone
|
|
88
|
-
? dayjs(new Date(currentYear, 0, 1)).utcOffset()
|
|
89
|
-
: dayjs(new Date(currentYear, 0, 1)).tz(timezoneToUse).utcOffset();
|
|
90
|
-
const july = hasNoTimezone
|
|
91
|
-
? dayjs(new Date(currentYear, 6, 1)).utcOffset()
|
|
92
|
-
: dayjs(new Date(currentYear, 6, 1)).tz(timezoneToUse).utcOffset();
|
|
93
|
-
|
|
94
|
-
if (equals(january, july)) {
|
|
95
|
-
return DSTState.NODST;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return july === date.tz().utcOffset() ? DSTState.SUMMER : DSTState.WINTER;
|
|
99
|
-
},
|
|
100
|
-
[timezone]
|
|
101
|
-
);
|
|
102
|
-
|
|
103
|
-
const getDSTStateForCurrentTimezone = useCallback(
|
|
104
|
-
(date: dayjs.Dayjs): DSTState => {
|
|
105
|
-
return getDSTState({ date });
|
|
106
|
-
},
|
|
107
|
-
[]
|
|
108
|
-
);
|
|
109
|
-
|
|
110
|
-
interface Chunk {
|
|
111
|
-
array: Array<unknown>;
|
|
112
|
-
size: number;
|
|
113
|
-
}
|
|
114
|
-
class Adapter extends AdapterDayjs {
|
|
115
|
-
public formatByString = (value, formatKey: string): string => {
|
|
116
|
-
return format({
|
|
117
|
-
date: value.tz(timezone).toDate(),
|
|
118
|
-
formatString: formatKey
|
|
119
|
-
});
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
public format = (date: dayjs.Dayjs, formatKey: string): string => {
|
|
123
|
-
return this.formatByString(
|
|
124
|
-
date.tz(timezone, true),
|
|
125
|
-
this.formats[formatKey]
|
|
126
|
-
);
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
public startOfWeek = (date: dayjs.Dayjs): dayjs.Dayjs => {
|
|
130
|
-
if (date.tz(timezone).isUTC()) {
|
|
131
|
-
return date.tz(timezone).startOf('week').utc();
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return date.tz(timezone).startOf('week');
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
public setMinutes = (date: dayjs.Dayjs, count: number): dayjs.Dayjs => {
|
|
138
|
-
return date.minute(count);
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
public setHours = (date: dayjs.Dayjs, count: number): dayjs.Dayjs => {
|
|
142
|
-
return date.hour(count);
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
public isSameDay = (date: dayjs.Dayjs, comparing: dayjs.Dayjs): boolean => {
|
|
146
|
-
const isSameYearAndMonth = this.isSameYear(date, comparing)
|
|
147
|
-
? this.isSameMonth(date, comparing)
|
|
148
|
-
: false;
|
|
149
|
-
|
|
150
|
-
return (
|
|
151
|
-
isSameYearAndMonth &&
|
|
152
|
-
date.tz(timezone).isSame(comparing.tz(timezone), 'day')
|
|
153
|
-
);
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
public startOfDay = (date: dayjs.Dayjs): dayjs.Dayjs => {
|
|
157
|
-
return date.tz(timezone).startOf('day') as dayjs.Dayjs;
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
public endOfDay = (date: dayjs.Dayjs): dayjs.Dayjs => {
|
|
161
|
-
return date.tz(timezone).endOf('day') as dayjs.Dayjs;
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
public startOfMonth = (date: dayjs.Dayjs): dayjs.Dayjs => {
|
|
165
|
-
if (date.tz(timezone).isUTC()) {
|
|
166
|
-
return date.tz(timezone).utc();
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return date.tz(timezone);
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
public endOfMonth = (date: dayjs.Dayjs): dayjs.Dayjs => {
|
|
173
|
-
return date.tz(timezone).endOf('month') as dayjs.Dayjs;
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
public isSameMonth = (
|
|
177
|
-
date: dayjs.Dayjs,
|
|
178
|
-
comparing: dayjs.Dayjs
|
|
179
|
-
): boolean => {
|
|
180
|
-
return date.tz(timezone).isSame(comparing.tz(timezone), 'month');
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
public getMonth = (date: dayjs.Dayjs): number => {
|
|
184
|
-
return date.tz(timezone).month();
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
public isAfter = (date: dayjs.Dayjs, value: dayjs.Dayjs): boolean => {
|
|
188
|
-
return date.isAfter(value.endOf('month'));
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
public isBefore = (date: dayjs.Dayjs, value: dayjs.Dayjs): boolean => {
|
|
192
|
-
return date.isBefore(value.startOf('month'));
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
public getDaysInMonth = (date: dayjs.Dayjs): number => {
|
|
196
|
-
return date.tz(timezone).daysInMonth();
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
public getWeekdays = (): Array<string> => {
|
|
200
|
-
const start = dayjs().locale(locale).tz(timezone).startOf('week');
|
|
201
|
-
|
|
202
|
-
return [0, 1, 2, 3, 4, 5, 6].map((diff) =>
|
|
203
|
-
this.formatByString(start.add(diff, 'day'), 'dd')
|
|
204
|
-
);
|
|
205
|
-
};
|
|
206
|
-
|
|
207
|
-
public getChunkFromArray = ({ array, size }: Chunk): Array<unknown> => {
|
|
208
|
-
if (!array.length) {
|
|
209
|
-
return [];
|
|
210
|
-
}
|
|
211
|
-
const head = array.slice(0, size);
|
|
212
|
-
const tail = array.slice(size);
|
|
213
|
-
|
|
214
|
-
return [head, ...this.getChunkFromArray({ array: tail, size })];
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
public getWeekArray = (date: dayjs.Dayjs): Array<Array<dayjs.Dayjs>> => {
|
|
218
|
-
const isMorning = equals(dayjs().tz(timezone).format('a'), 'am');
|
|
219
|
-
const startOfWeek = date.tz(timezone).startOf('month').startOf('week');
|
|
220
|
-
const endOfWeek = date.tz(timezone).endOf('month').endOf('week');
|
|
221
|
-
const start = startOfWeek.startOf('day');
|
|
222
|
-
const end = endOfWeek.endOf('day');
|
|
223
|
-
const customStart = isMorning
|
|
224
|
-
? startOfWeek.startOf('day')
|
|
225
|
-
: startOfWeek.startOf('day');
|
|
226
|
-
const customEnd = isMorning
|
|
227
|
-
? endOfWeek.startOf('day')
|
|
228
|
-
: endOfWeek.startOf('day');
|
|
229
|
-
const currentStart = start.isUTC()
|
|
230
|
-
? start.tz(timezone, true)
|
|
231
|
-
: customStart;
|
|
232
|
-
const currentEnd = end.isUTC() ? end.tz(timezone, true) : customEnd;
|
|
233
|
-
const numberOfDaysInCurrentMonth = currentEnd.diff(
|
|
234
|
-
currentStart,
|
|
235
|
-
'd',
|
|
236
|
-
true
|
|
237
|
-
);
|
|
238
|
-
const daysOfMonthWithTimezone = [
|
|
239
|
-
...Array(Math.round(numberOfDaysInCurrentMonth)).keys()
|
|
240
|
-
].reduce(
|
|
241
|
-
(acc, _, currentIndex) => {
|
|
242
|
-
if (acc[currentIndex].isUTC()) {
|
|
243
|
-
const newCurrent = acc[currentIndex]
|
|
244
|
-
.utc()
|
|
245
|
-
.add(1, 'day')
|
|
246
|
-
.tz(timezone, true);
|
|
247
|
-
|
|
248
|
-
return [...acc, newCurrent];
|
|
249
|
-
}
|
|
250
|
-
const newCurrent = acc[currentIndex].add(1, 'day');
|
|
251
|
-
|
|
252
|
-
return [...acc, newCurrent];
|
|
253
|
-
},
|
|
254
|
-
[currentStart]
|
|
255
|
-
);
|
|
256
|
-
const weeksArray = this.getChunkFromArray({
|
|
257
|
-
array: daysOfMonthWithTimezone,
|
|
258
|
-
size: 7
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
return weeksArray as Array<Array<dayjs.Dayjs>>;
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
public mergeDateAndTime = (
|
|
265
|
-
date: dayjs.Dayjs,
|
|
266
|
-
time: dayjs.Dayjs
|
|
267
|
-
): dayjs.Dayjs => {
|
|
268
|
-
const dateWithTimezone = date.tz(timezone).startOf('day');
|
|
269
|
-
const timeWithTimezone = time.tz(timezone);
|
|
270
|
-
const dateDSTState = getDSTState({
|
|
271
|
-
date: dateWithTimezone,
|
|
272
|
-
timezoneToUse: timezone
|
|
273
|
-
});
|
|
274
|
-
const dateDSTStateWithCurrentTimezone =
|
|
275
|
-
getDSTStateForCurrentTimezone(date);
|
|
276
|
-
|
|
277
|
-
if (equals(dateDSTStateWithCurrentTimezone, DSTState.WINTER)) {
|
|
278
|
-
return dateWithTimezone
|
|
279
|
-
.add(
|
|
280
|
-
timeWithTimezone.hour() -
|
|
281
|
-
getDestinationAndConfiguredTimezoneOffset({
|
|
282
|
-
endTimezone: 'UTC',
|
|
283
|
-
startTimezone: dayjs.tz.guess()
|
|
284
|
-
}),
|
|
285
|
-
'hour'
|
|
286
|
-
)
|
|
287
|
-
.add(timeWithTimezone.minute(), 'minute')
|
|
288
|
-
.add(timeWithTimezone.second(), 'second');
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
if (not(equals(dateDSTState, DSTState.SUMMER))) {
|
|
292
|
-
return dateWithTimezone
|
|
293
|
-
.add(timeWithTimezone.hour(), 'hour')
|
|
294
|
-
.add(timeWithTimezone.minute(), 'minute')
|
|
295
|
-
.add(timeWithTimezone.second(), 'second');
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
return dateWithTimezone
|
|
299
|
-
.hour(timeWithTimezone.hour())
|
|
300
|
-
.minute(timeWithTimezone.minute())
|
|
301
|
-
.second(timeWithTimezone.second());
|
|
302
|
-
};
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
return {
|
|
306
|
-
Adapter,
|
|
307
|
-
desktopPickerMediaQuery
|
|
308
|
-
};
|
|
309
|
-
};
|