@centreon/ui 24.4.59 → 24.4.61
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 +50 -42
- package/public/mockServiceWorker.js +1 -1
- package/src/ActionsList/ActionsList.styles.ts +40 -71
- 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/Confirm/index.tsx +10 -2
- package/src/Dialog/UnsavedChanges/index.tsx +21 -20
- package/src/Dialog/UnsavedChanges/translatedLabels.ts +4 -6
- package/src/Dialog/index.tsx +9 -2
- 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/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/Text.tsx +3 -1
- package/src/Form/Inputs/index.tsx +3 -1
- package/src/Form/Inputs/models.ts +10 -1
- package/src/Graph/BarStack/BarStack.cypress.spec.tsx +154 -0
- package/src/Graph/BarStack/BarStack.stories.tsx +123 -0
- package/src/Graph/BarStack/BarStack.styles.ts +37 -0
- package/src/Graph/BarStack/BarStack.tsx +14 -0
- package/src/Graph/BarStack/ResponsiveBarStack.tsx +222 -0
- package/src/Graph/BarStack/index.ts +1 -0
- package/src/Graph/BarStack/models.ts +20 -0
- package/src/Graph/BarStack/useResponsiveBarStack.ts +137 -0
- package/src/Graph/Gauge/Gauge.cypress.spec.tsx +102 -0
- package/src/Graph/Gauge/Gauge.tsx +1 -1
- package/src/Graph/HeatMap/HeatMap.cypress.spec.tsx +145 -0
- package/src/Graph/HeatMap/HeatMap.stories.tsx +0 -25
- package/src/Graph/HeatMap/ResponsiveHeatMap.tsx +8 -2
- package/src/Graph/Legend/Legend.tsx +21 -0
- package/src/Graph/Legend/index.ts +1 -0
- package/src/Graph/Legend/models.ts +11 -0
- package/src/Graph/LineChart/BasicComponents/Lines/Threshold/Circle.tsx +2 -2
- 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/EventAnnotations.tsx +1 -1
- package/src/Graph/LineChart/Legend/Legend.styles.ts +1 -1
- package/src/Graph/LineChart/Legend/LegendHeader.tsx +1 -1
- package/src/Graph/LineChart/Legend/useInteractiveValues.ts +2 -2
- 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/LineChart/index.tsx +1 -1
- package/src/Graph/PieChart/PieChart.cypress.spec.tsx +169 -0
- package/src/Graph/PieChart/PieChart.stories.tsx +194 -0
- package/src/Graph/PieChart/PieChart.styles.ts +39 -0
- package/src/Graph/PieChart/PieChart.tsx +14 -0
- package/src/Graph/PieChart/ResponsivePie.tsx +254 -0
- package/src/Graph/PieChart/index.ts +1 -0
- package/src/Graph/PieChart/models.ts +20 -0
- package/src/Graph/PieChart/useResponsivePie.ts +85 -0
- package/src/Graph/SingleBar/SingleBar.cypress.spec.tsx +121 -0
- package/src/Graph/SingleBar/Thresholds.tsx +2 -2
- package/src/Graph/Text/Text.cypress.spec.tsx +101 -0
- package/src/Graph/Text/Text.stories.tsx +60 -4
- package/src/Graph/Text/Text.tsx +1 -1
- package/src/Graph/common/testUtils.ts +71 -0
- package/src/Graph/common/timeSeries/index.ts +22 -14
- package/src/Graph/common/utils.ts +19 -0
- package/src/Graph/index.ts +3 -0
- package/src/Graph/translatedLabels.ts +1 -0
- 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/Multi/index.tsx +4 -2
- package/src/InputField/Select/Autocomplete/index.tsx +129 -116
- package/src/InputField/Select/IconPopover/index.tsx +2 -2
- package/src/InputField/Select/index.tsx +15 -2
- package/src/InputField/Text/index.tsx +2 -2
- package/src/Listing/ActionBar/index.tsx +9 -8
- package/src/Listing/Cell/DataCell.styles.ts +3 -0
- package/src/Listing/Cell/DataCell.tsx +23 -5
- package/src/Listing/Header/ListingHeader.tsx +1 -1
- package/src/Listing/Listing.cypress.spec.tsx +218 -33
- package/src/Listing/Listing.styles.ts +4 -7
- package/src/Listing/Row/Row.tsx +7 -3
- package/src/Listing/index.stories.tsx +37 -3
- package/src/Listing/index.test.tsx +1 -1
- package/src/Listing/index.tsx +80 -36
- package/src/Listing/models.ts +1 -0
- package/src/Listing/useStyleTable.ts +1 -0
- package/src/Module/Module.cypress.spec.tsx +129 -0
- package/src/Module/index.tsx +2 -4
- package/src/PopoverMenu/index.tsx +6 -5
- 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/Typography/FluidTypography/FluidTypography.cypress.spec.tsx +27 -0
- package/src/Typography/FluidTypography/index.stories.tsx +2 -2
- package/src/Typography/FluidTypography/index.tsx +21 -28
- package/src/api/QueryProvider.tsx +1 -1
- package/src/api/TestQueryProvider.tsx +1 -1
- package/src/api/index.ts +3 -3
- package/src/api/useFetchQuery/index.ts +27 -23
- package/src/api/useMutationQuery/index.test.ts +4 -4
- package/src/api/useMutationQuery/index.ts +60 -25
- 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 +174 -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 -60
- package/src/components/DataTable/index.ts +3 -1
- package/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx +13 -13
- package/src/components/Form/AccessRights/ShareInput/ContactSwitch.tsx +3 -3
- package/src/components/Form/AccessRights/ShareInput/ShareInput.tsx +1 -0
- package/src/components/Form/AccessRights/storiesData.ts +22 -22
- package/src/components/Form/Dashboard/DashboardDuplicationForm.tsx +85 -0
- package/src/components/Form/Dashboard/DashboardForm.tsx +15 -12
- package/src/components/Form/Dashboard/index.ts +1 -0
- package/src/components/Form/FormActions.tsx +7 -2
- package/src/components/ItemComposition/ItemComposition.styles.ts +2 -2
- 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/List/Item/ListItem.tsx +3 -3
- package/src/components/Modal/ConfirmationModal/ConfirmationModal.cypress.spec.tsx +168 -0
- package/src/components/Modal/ConfirmationModal/ConfirmationModal.stories.tsx +62 -0
- package/src/components/Modal/ConfirmationModal/ConfirmationModal.tsx +87 -0
- package/src/components/Modal/Modal.styles.ts +8 -3
- package/src/components/Modal/index.ts +2 -0
- 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/useFullscreen/Fullscreen.cypress.spec.tsx +1 -3
- package/src/utils/useFullscreen/useFullscreenListener.ts +10 -7
- package/src/utils/useInfiniteScrollListing.ts +4 -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/Typography/FluidTypography/useFluidResizeObserver.ts +0 -56
- 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
package/src/Listing/index.tsx
CHANGED
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
map,
|
|
19
19
|
not,
|
|
20
20
|
pick,
|
|
21
|
-
pluck,
|
|
22
21
|
prop,
|
|
23
22
|
propEq,
|
|
24
23
|
reduce,
|
|
@@ -58,6 +57,8 @@ import { SkeletonLoader } from './Row/SkeletonLoaderRows';
|
|
|
58
57
|
import { ListingHeader } from './Header';
|
|
59
58
|
import { subItemsPivotsAtom } from './tableAtoms';
|
|
60
59
|
|
|
60
|
+
const subItemPrefixKey = 'listing';
|
|
61
|
+
|
|
61
62
|
const getVisibleColumns = ({
|
|
62
63
|
columnConfiguration,
|
|
63
64
|
columns
|
|
@@ -69,7 +70,7 @@ const getVisibleColumns = ({
|
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
return selectedColumnIds.map((id) =>
|
|
72
|
-
columns.find(propEq(
|
|
73
|
+
columns.find(propEq(id, 'id'))
|
|
73
74
|
) as Array<Column>;
|
|
74
75
|
};
|
|
75
76
|
|
|
@@ -102,6 +103,7 @@ export interface Props<TRow> {
|
|
|
102
103
|
getId?: (row: TRow) => RowId;
|
|
103
104
|
headerMemoProps?: Array<unknown>;
|
|
104
105
|
innerScrollDisabled?: boolean;
|
|
106
|
+
isResponsive?: boolean;
|
|
105
107
|
limit?: number;
|
|
106
108
|
listingVariant?: ListingVariant;
|
|
107
109
|
loading?: boolean;
|
|
@@ -139,7 +141,7 @@ const defaultColumnConfiguration = {
|
|
|
139
141
|
|
|
140
142
|
export const performanceRowsLimit = 60;
|
|
141
143
|
|
|
142
|
-
const Listing = <TRow extends { id: RowId }>({
|
|
144
|
+
const Listing = <TRow extends { id: RowId; internalListingParentId?: RowId }>({
|
|
143
145
|
customListingComponent,
|
|
144
146
|
displayCustomListing,
|
|
145
147
|
limit = 10,
|
|
@@ -147,6 +149,7 @@ const Listing = <TRow extends { id: RowId }>({
|
|
|
147
149
|
columns,
|
|
148
150
|
columnConfiguration = defaultColumnConfiguration,
|
|
149
151
|
customPaginationClassName,
|
|
152
|
+
isResponsive = false,
|
|
150
153
|
onResetColumns,
|
|
151
154
|
onSelectColumns,
|
|
152
155
|
rows = [],
|
|
@@ -209,6 +212,21 @@ const Listing = <TRow extends { id: RowId }>({
|
|
|
209
212
|
|
|
210
213
|
const subItemsPivots = useAtomValue(subItemsPivotsAtom);
|
|
211
214
|
|
|
215
|
+
const allSubItemIds = React.useMemo(
|
|
216
|
+
() =>
|
|
217
|
+
reduce<TRow | number, Array<string | number>>(
|
|
218
|
+
(acc, row) => [
|
|
219
|
+
...acc,
|
|
220
|
+
...(row[subItems?.getRowProperty() || ''] || []).map(
|
|
221
|
+
({ id }) => `${subItemPrefixKey}_${getId(row)}_${id}`
|
|
222
|
+
)
|
|
223
|
+
],
|
|
224
|
+
[],
|
|
225
|
+
rows
|
|
226
|
+
),
|
|
227
|
+
[rows, subItems]
|
|
228
|
+
);
|
|
229
|
+
|
|
212
230
|
const rowsToDisplay = React.useMemo(
|
|
213
231
|
() =>
|
|
214
232
|
subItems?.enable
|
|
@@ -218,7 +236,14 @@ const Listing = <TRow extends { id: RowId }>({
|
|
|
218
236
|
row[subItems.getRowProperty()] &&
|
|
219
237
|
subItemsPivots.includes(row.id)
|
|
220
238
|
) {
|
|
221
|
-
return [
|
|
239
|
+
return [
|
|
240
|
+
...acc,
|
|
241
|
+
row,
|
|
242
|
+
...row[subItems.getRowProperty()].map((subRow) => ({
|
|
243
|
+
...subRow,
|
|
244
|
+
internalListingParentId: row.id
|
|
245
|
+
}))
|
|
246
|
+
];
|
|
222
247
|
}
|
|
223
248
|
|
|
224
249
|
return [...acc, row];
|
|
@@ -230,11 +255,28 @@ const Listing = <TRow extends { id: RowId }>({
|
|
|
230
255
|
[rows, subItemsPivots, subItems]
|
|
231
256
|
);
|
|
232
257
|
|
|
258
|
+
const getSubItemRowId = React.useCallback((row: TRow) => {
|
|
259
|
+
return `${subItemPrefixKey}_${row.internalListingParentId}_${row.id}`;
|
|
260
|
+
}, []);
|
|
261
|
+
|
|
262
|
+
const getIsSubItem = React.useCallback(
|
|
263
|
+
(row: TRow) => {
|
|
264
|
+
return allSubItemIds.includes(getSubItemRowId(row));
|
|
265
|
+
},
|
|
266
|
+
[allSubItemIds]
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
const getRowId = React.useCallback(
|
|
270
|
+
(row: TRow) => {
|
|
271
|
+
return getIsSubItem(row) ? getSubItemRowId(row) : getId(row);
|
|
272
|
+
},
|
|
273
|
+
[allSubItemIds]
|
|
274
|
+
);
|
|
275
|
+
|
|
233
276
|
const { classes } = useListingStyles({
|
|
234
277
|
dataStyle,
|
|
235
278
|
getGridTemplateColumn,
|
|
236
|
-
|
|
237
|
-
listingVariant,
|
|
279
|
+
isResponsive,
|
|
238
280
|
rows: rowsToDisplay
|
|
239
281
|
});
|
|
240
282
|
|
|
@@ -254,7 +296,7 @@ const Listing = <TRow extends { id: RowId }>({
|
|
|
254
296
|
event.target.checked &&
|
|
255
297
|
event.target.getAttribute('data-indeterminate') === 'false'
|
|
256
298
|
) {
|
|
257
|
-
onSelectRows(reject(disableRowCheckCondition,
|
|
299
|
+
onSelectRows(reject(disableRowCheckCondition, rowsToDisplay));
|
|
258
300
|
setLastSelectionIndex(null);
|
|
259
301
|
|
|
260
302
|
return;
|
|
@@ -326,7 +368,11 @@ const Listing = <TRow extends { id: RowId }>({
|
|
|
326
368
|
const selectRowsWithShiftKey = (selectedRowIndex: number): void => {
|
|
327
369
|
const lastSelectedIndex = lastSelectionIndex as number;
|
|
328
370
|
if (isNil(shiftKeyDownRowPivot)) {
|
|
329
|
-
const selectedRowsFromTheStart = slice(
|
|
371
|
+
const selectedRowsFromTheStart = slice(
|
|
372
|
+
0,
|
|
373
|
+
selectedRowIndex + 1,
|
|
374
|
+
rowsToDisplay
|
|
375
|
+
);
|
|
330
376
|
|
|
331
377
|
onSelectRows(reject(disableRowCheckCondition, selectedRowsFromTheStart));
|
|
332
378
|
|
|
@@ -335,7 +381,10 @@ const Listing = <TRow extends { id: RowId }>({
|
|
|
335
381
|
|
|
336
382
|
const selectedRowsIndex = map(
|
|
337
383
|
(row) =>
|
|
338
|
-
findIndex(
|
|
384
|
+
findIndex(
|
|
385
|
+
(listingRow) => equals(getId(row), getId(listingRow)),
|
|
386
|
+
rowsToDisplay
|
|
387
|
+
),
|
|
339
388
|
selectedRows
|
|
340
389
|
).sort(subtract);
|
|
341
390
|
|
|
@@ -343,7 +392,7 @@ const Listing = <TRow extends { id: RowId }>({
|
|
|
343
392
|
const newSelection = slice(
|
|
344
393
|
selectedRowIndex,
|
|
345
394
|
(lastSelectionIndex as number) + 1,
|
|
346
|
-
|
|
395
|
+
rowsToDisplay
|
|
347
396
|
);
|
|
348
397
|
onSelectRows(
|
|
349
398
|
reject(
|
|
@@ -362,7 +411,11 @@ const Listing = <TRow extends { id: RowId }>({
|
|
|
362
411
|
return;
|
|
363
412
|
}
|
|
364
413
|
|
|
365
|
-
const newSelection = slice(
|
|
414
|
+
const newSelection = slice(
|
|
415
|
+
lastSelectedIndex,
|
|
416
|
+
selectedRowIndex + 1,
|
|
417
|
+
rowsToDisplay
|
|
418
|
+
);
|
|
366
419
|
onSelectRows(
|
|
367
420
|
reject(
|
|
368
421
|
disableRowCheckCondition,
|
|
@@ -386,7 +439,7 @@ const Listing = <TRow extends { id: RowId }>({
|
|
|
386
439
|
|
|
387
440
|
const selectedRowIndex = findIndex(
|
|
388
441
|
(listingRow) => equals(getId(row), getId(listingRow)),
|
|
389
|
-
|
|
442
|
+
rowsToDisplay
|
|
390
443
|
);
|
|
391
444
|
|
|
392
445
|
if (isShiftKeyDown) {
|
|
@@ -413,10 +466,10 @@ const Listing = <TRow extends { id: RowId }>({
|
|
|
413
466
|
};
|
|
414
467
|
|
|
415
468
|
const hoverRow = (row): void => {
|
|
416
|
-
if (equals(hoveredRowId,
|
|
469
|
+
if (equals(hoveredRowId, getRowId(row))) {
|
|
417
470
|
return;
|
|
418
471
|
}
|
|
419
|
-
setHoveredRowId(
|
|
472
|
+
setHoveredRowId(getRowId(row));
|
|
420
473
|
};
|
|
421
474
|
|
|
422
475
|
const clearHoveredRow = (): void => {
|
|
@@ -427,8 +480,6 @@ const Listing = <TRow extends { id: RowId }>({
|
|
|
427
480
|
return selectedRowsInclude(row);
|
|
428
481
|
};
|
|
429
482
|
|
|
430
|
-
const emptyRows = limit - Math.min(limit, totalRows - currentPage * limit);
|
|
431
|
-
|
|
432
483
|
const changeLimit = (updatedLimit: string): void => {
|
|
433
484
|
onLimitChange?.(Number(updatedLimit));
|
|
434
485
|
};
|
|
@@ -449,19 +500,6 @@ const Listing = <TRow extends { id: RowId }>({
|
|
|
449
500
|
|
|
450
501
|
const areColumnsEditable = not(isNil(onSelectColumns));
|
|
451
502
|
|
|
452
|
-
const allSubItemIds = React.useMemo(
|
|
453
|
-
() =>
|
|
454
|
-
reduce<TRow | number, Array<string | number>>(
|
|
455
|
-
(acc, row) => [
|
|
456
|
-
...acc,
|
|
457
|
-
...pluck('id', row[subItems?.getRowProperty() || ''] || [])
|
|
458
|
-
],
|
|
459
|
-
[],
|
|
460
|
-
rows
|
|
461
|
-
),
|
|
462
|
-
[rows, subItems]
|
|
463
|
-
);
|
|
464
|
-
|
|
465
503
|
return (
|
|
466
504
|
<div className={classes.listingContainer}>
|
|
467
505
|
{loading && rows.length > 0 && (
|
|
@@ -533,7 +571,7 @@ const Listing = <TRow extends { id: RowId }>({
|
|
|
533
571
|
listingVariant={listingVariant}
|
|
534
572
|
memoProps={headerMemoProps}
|
|
535
573
|
predefinedRowsSelection={predefinedRowsSelection}
|
|
536
|
-
rowCount={
|
|
574
|
+
rowCount={rowsToDisplay.length}
|
|
537
575
|
selectedRowCount={selectedRows.length}
|
|
538
576
|
sortField={sortField}
|
|
539
577
|
sortOrder={sortOrder}
|
|
@@ -550,8 +588,10 @@ const Listing = <TRow extends { id: RowId }>({
|
|
|
550
588
|
>
|
|
551
589
|
{rowsToDisplay.map((row, index) => {
|
|
552
590
|
const isRowSelected = isSelected(row);
|
|
553
|
-
const
|
|
554
|
-
|
|
591
|
+
const isSubItem = allSubItemIds.includes(
|
|
592
|
+
getSubItemRowId(row)
|
|
593
|
+
);
|
|
594
|
+
const isRowHovered = equals(hoveredRowId, getRowId(row));
|
|
555
595
|
|
|
556
596
|
return (
|
|
557
597
|
<ListingRow
|
|
@@ -568,7 +608,7 @@ const Listing = <TRow extends { id: RowId }>({
|
|
|
568
608
|
key={
|
|
569
609
|
gte(limit, performanceRowsLimit)
|
|
570
610
|
? `row_${index}`
|
|
571
|
-
:
|
|
611
|
+
: getRowId(row)
|
|
572
612
|
}
|
|
573
613
|
lastSelectionIndex={lastSelectionIndex}
|
|
574
614
|
limit={limit}
|
|
@@ -579,9 +619,13 @@ const Listing = <TRow extends { id: RowId }>({
|
|
|
579
619
|
subItemsPivots={subItemsPivots}
|
|
580
620
|
tabIndex={-1}
|
|
581
621
|
visibleColumns={visibleColumns}
|
|
582
|
-
onClick={
|
|
583
|
-
|
|
584
|
-
|
|
622
|
+
onClick={
|
|
623
|
+
isSubItem
|
|
624
|
+
? undefined
|
|
625
|
+
: (): void => {
|
|
626
|
+
onRowClick(row);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
585
629
|
onFocus={(): void => hoverRow(row)}
|
|
586
630
|
onMouseOver={(): void => hoverRow(row)}
|
|
587
631
|
>
|
package/src/Listing/models.ts
CHANGED
|
@@ -53,6 +53,7 @@ const useStyleTable = ({
|
|
|
53
53
|
const checkbox = checkable ? 'fit-content(1rem) ' : ''; // SelectAction (checkbox) cell adjusts to content
|
|
54
54
|
|
|
55
55
|
const columnTemplate = currentVisibleColumns
|
|
56
|
+
?.filter((column) => column)
|
|
56
57
|
?.map(({ width, shortLabel }) => {
|
|
57
58
|
if (!isNil(shortLabel)) {
|
|
58
59
|
return 'min-content';
|
|
@@ -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({
|
|
@@ -6,14 +6,16 @@ import {
|
|
|
6
6
|
ClickAwayListener,
|
|
7
7
|
Paper,
|
|
8
8
|
Popper,
|
|
9
|
-
PopperPlacementType
|
|
10
|
-
useTheme
|
|
9
|
+
PopperPlacementType
|
|
11
10
|
} from '@mui/material';
|
|
12
11
|
import { PopperProps } from '@mui/material/Popper';
|
|
13
12
|
|
|
14
13
|
import { IconButton } from '..';
|
|
15
14
|
|
|
16
|
-
const useStyles = makeStyles()(() => ({
|
|
15
|
+
const useStyles = makeStyles()((theme) => ({
|
|
16
|
+
popover: {
|
|
17
|
+
zIndex: theme.zIndex.tooltip
|
|
18
|
+
},
|
|
17
19
|
popoverIconButton: {
|
|
18
20
|
padding: 0,
|
|
19
21
|
width: '100%'
|
|
@@ -52,7 +54,6 @@ const PopoverMenu = ({
|
|
|
52
54
|
getPopoverData,
|
|
53
55
|
popperProps
|
|
54
56
|
}: Props): JSX.Element => {
|
|
55
|
-
const theme = useTheme();
|
|
56
57
|
const { classes, cx } = useStyles();
|
|
57
58
|
const [anchorEl, setAnchorEl] = useState<HTMLElement | undefined>();
|
|
58
59
|
const isOpen = Boolean(anchorEl);
|
|
@@ -105,9 +106,9 @@ const PopoverMenu = ({
|
|
|
105
106
|
<Popper
|
|
106
107
|
open
|
|
107
108
|
anchorEl={anchorEl}
|
|
109
|
+
className={classes.popover}
|
|
108
110
|
nonce={undefined}
|
|
109
111
|
placement={popperPlacement}
|
|
110
|
-
style={{ zIndex: theme.zIndex.tooltip }}
|
|
111
112
|
onResize={(): undefined => undefined}
|
|
112
113
|
onResizeCapture={(): undefined => undefined}
|
|
113
114
|
{...popperProps}
|
|
@@ -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
|
}
|