@centreon/ui 25.3.4 → 25.4.0-MON-191119-npm-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 +25 -11
- package/public/mockServiceWorker.js +8 -31
- package/src/Button/Save/index.stories.tsx +1 -0
- package/src/Checkbox/Checkbox.tsx +3 -1
- package/src/Checkbox/CheckboxGroup/index.tsx +6 -1
- package/src/Colors/index.tsx +1 -1
- package/src/Dashboard/Dashboard.styles.ts +1 -1
- package/src/Dashboard/Layout.tsx +1 -1
- package/src/Dialog/UnsavedChanges/index.stories.tsx +1 -0
- package/src/Form/CollapsibleGroup.tsx +13 -13
- package/src/Form/Form.cypress.spec.tsx +137 -2
- package/src/Form/Form.stories.tsx +11 -31
- package/src/Form/Form.tsx +2 -0
- package/src/Form/Inputs/Checkbox.tsx +3 -2
- package/src/Form/Inputs/ConnectedAutocomplete.tsx +6 -1
- package/src/Form/Inputs/Grid.tsx +18 -29
- package/src/Form/Inputs/SubGroupDivider.tsx +7 -0
- package/src/Form/Inputs/Text.tsx +1 -0
- package/src/Form/Inputs/index.tsx +31 -24
- package/src/Form/Inputs/models.ts +8 -1
- package/src/Form/Section/FormSection.tsx +34 -0
- package/src/Form/Section/PanelTabs.tsx +13 -0
- package/src/Form/Section/navigateToSection.ts +9 -0
- package/src/Form/storiesData.tsx +14 -4
- package/src/Graph/BarChart/BarChart.cypress.spec.tsx +46 -6
- package/src/Graph/BarChart/BarChart.stories.tsx +60 -0
- package/src/Graph/BarChart/BarChart.tsx +56 -32
- package/src/Graph/BarChart/BarGroup.tsx +22 -32
- package/src/Graph/BarChart/MemoizedGroup.tsx +8 -11
- package/src/Graph/BarChart/ResponsiveBarChart.tsx +145 -32
- package/src/Graph/BarChart/Tooltip/BarChartTooltip.tsx +2 -2
- package/src/Graph/Chart/BasicComponents/Lines/StackedLines/index.tsx +7 -1
- package/src/Graph/Chart/BasicComponents/Lines/StackedLines/useStackedLines.ts +18 -45
- package/src/Graph/Chart/BasicComponents/Lines/index.tsx +42 -28
- package/src/Graph/Chart/Chart.cypress.spec.tsx +85 -15
- package/src/Graph/Chart/Chart.stories.tsx +84 -1
- package/src/Graph/Chart/Chart.tsx +17 -4
- package/src/Graph/Chart/InteractiveComponents/AnchorPoint/RegularAnchorPoint.tsx +8 -2
- package/src/Graph/Chart/InteractiveComponents/AnchorPoint/StackedAnchorPoint.tsx +10 -3
- package/src/Graph/Chart/InteractiveComponents/AnchorPoint/useTickGraph.ts +19 -2
- package/src/Graph/Chart/InteractiveComponents/GraphValueTooltip/useGraphValueTooltip.ts +2 -4
- package/src/Graph/Chart/InteractiveComponents/ZoomPreview/index.tsx +14 -3
- package/src/Graph/Chart/InteractiveComponents/ZoomPreview/models.ts +3 -0
- package/src/Graph/Chart/InteractiveComponents/ZoomPreview/useZoomPreview.ts +12 -10
- package/src/Graph/Chart/InteractiveComponents/index.tsx +63 -5
- package/src/Graph/Chart/Legend/index.tsx +26 -2
- package/src/Graph/Chart/index.tsx +45 -45
- package/src/Graph/Chart/models.ts +8 -0
- package/src/Graph/Chart/useChartData.ts +14 -2
- package/src/Graph/Gauge/Gauge.tsx +18 -14
- package/src/Graph/Gauge/ResponsiveGauge.tsx +10 -6
- package/src/Graph/Gauge/useResizeObserver.ts +68 -0
- package/src/Graph/SingleBar/ResponsiveSingleBar.tsx +18 -16
- package/src/Graph/SingleBar/ThresholdLine.tsx +4 -4
- package/src/Graph/SingleBar/models.ts +1 -0
- package/src/Graph/Text/Text.styles.ts +2 -2
- package/src/Graph/Text/Text.tsx +23 -10
- package/src/Graph/Timeline/ResponsiveTimeline.tsx +4 -0
- package/src/Graph/Timeline/Timeline.tsx +21 -4
- package/src/Graph/Tree/Links.tsx +2 -2
- package/src/Graph/Tree/Tree.tsx +2 -2
- package/src/Graph/Tree/constants.ts +1 -1
- package/src/Graph/common/BaseChart/BaseChart.tsx +6 -1
- package/src/Graph/common/BaseChart/ChartSvgWrapper.tsx +5 -4
- package/src/Graph/common/BaseChart/Header/index.tsx +3 -1
- package/src/Graph/common/BaseChart/useComputeBaseChartDimensions.ts +13 -9
- package/src/Graph/common/timeSeries/index.test.ts +20 -0
- package/src/Graph/common/timeSeries/index.ts +225 -44
- package/src/Graph/common/timeSeries/models.ts +6 -2
- package/src/Graph/common/utils.ts +45 -12
- package/src/Graph/index.ts +3 -1
- package/src/Graph/mockedData/dataWithMissingPoint.json +74 -0
- package/src/Graph/mockedData/pingServiceWithStackedKeys.json +205 -0
- package/src/Icon/RegexIcon.tsx +20 -0
- package/src/Icon/index.ts +1 -0
- package/src/InputField/Select/Autocomplete/Connected/Multi/MultiConnectedAutocompleteField.cypress.spec.tsx +68 -14
- package/src/InputField/Select/Autocomplete/Connected/index.tsx +49 -14
- package/src/InputField/Select/Autocomplete/Multi/Listbox.tsx +78 -0
- package/src/InputField/Select/Autocomplete/Multi/Multi.styles.ts +26 -0
- package/src/InputField/Select/Autocomplete/Multi/Multi.tsx +124 -0
- package/src/InputField/Select/Autocomplete/Multi/index.tsx +1 -117
- package/src/InputField/Select/Autocomplete/index.tsx +28 -17
- package/src/InputField/Select/Option.tsx +3 -3
- package/src/InputField/Select/index.tsx +4 -0
- package/src/InputField/Text/index.tsx +4 -2
- package/src/InputField/translatedLabels.ts +4 -0
- package/src/Listing/ActionBar/Pagination.tsx +10 -23
- package/src/Listing/ActionBar/PaginationActions.tsx +1 -10
- package/src/Listing/ActionBar/index.tsx +1 -1
- package/src/Listing/Cell/DataCell.tsx +6 -6
- package/src/Listing/Cell/EllipsisTypography.tsx +10 -32
- package/src/Listing/Cell/index.tsx +37 -76
- package/src/Listing/Checkbox.tsx +8 -20
- package/src/Listing/Header/Cell/ListingHeaderCell.tsx +17 -14
- package/src/Listing/Header/Cell/SelectActionListingHeaderCell.tsx +5 -9
- package/src/Listing/Header/ListingHeader.tsx +2 -5
- package/src/Listing/Header/_internals/Label.tsx +1 -17
- package/src/Listing/Row/EmptyRow.tsx +2 -6
- package/src/Listing/Row/Row.tsx +7 -36
- package/src/Listing/index.stories.tsx +1 -0
- package/src/Listing/index.tsx +26 -26
- package/src/Listing/useStyleTable.ts +58 -32
- package/src/ListingPage/index.stories.tsx +1 -0
- package/src/Module/index.tsx +8 -2
- package/src/MultiSelectEntries/index.stories.tsx +1 -0
- package/src/MultiSelectEntries/index.tsx +1 -1
- package/src/Pagination/Pagination.cypress.spec.tsx +137 -0
- package/src/Pagination/Pagination.stories.tsx +46 -0
- package/src/Pagination/Pagination.styles.ts +56 -0
- package/src/Pagination/Pagination.tsx +146 -0
- package/src/Pagination/index.ts +3 -0
- package/src/Pagination/utils.ts +7 -0
- package/src/SortableItems/index.stories.tsx +2 -2
- package/src/StoryBookThemeProvider/index.tsx +3 -1
- package/src/ThemeProvider/base.css +49 -0
- package/src/ThemeProvider/index.tsx +21 -47
- package/src/ThemeProvider/palettes.ts +3 -1
- package/src/ThemeProvider/tailwindcss.css +230 -0
- package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/PickersStartEndDate.tsx +9 -11
- package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/models.ts +1 -0
- package/src/TimePeriods/DateTimePickerInput.tsx +3 -1
- package/src/api/models.ts +9 -0
- package/src/api/useGraphQuery/index.ts +108 -12
- package/src/components/Avatar/Avatar.stories.tsx +1 -0
- package/src/components/Button/Button.module.css +38 -0
- package/src/components/Button/Button.stories.tsx +25 -0
- package/src/components/Button/Button.tsx +2 -5
- package/src/components/CrudPage/CrudPage.stories.tsx +1 -0
- package/src/components/CrudPage/CrudPageRoot.tsx +1 -1
- package/src/components/DataTable/DataTable.stories.tsx +1 -0
- package/src/components/DataTable/EmptyState/DataTableEmptyState.stories.tsx +1 -0
- package/src/components/DataTable/EmptyState/DataTableEmptyState.styles.ts +3 -1
- package/src/components/DataTable/EmptyState/DataTableEmptyState.tsx +4 -1
- package/src/components/DataTable/Item/DataTableItem.stories.tsx +1 -0
- package/src/components/Form/AccessRights/AccessRights.stories.tsx +1 -0
- package/src/components/Form/AccessRights/ShareInput/ShareInput.tsx +4 -3
- package/src/components/Form/AccessRights/ShareInput/useShareInput.tsx +15 -10
- package/src/components/Form/FormActions.tsx +21 -12
- package/src/components/Layout/AreaIndicator.tsx +4 -6
- package/src/components/Layout/PageLayout/PageLayout.stories.tsx +1 -0
- package/src/components/Layout/PageLayout/PageLayout.tsx +9 -3
- package/src/components/Layout/PageLayout/PageLayoutActions.tsx +5 -3
- package/src/components/Layout/PageLayout/PageLayoutBody.tsx +5 -3
- package/src/components/Layout/PageLayout/PageLayoutHeader.tsx +5 -3
- package/src/components/Layout/PageLayout/PageQuickAccess.tsx +17 -17
- package/src/components/Menu/Button/MenuButton.tsx +6 -6
- package/src/components/Menu/MenuDivider.tsx +1 -5
- package/src/components/Menu/MenuItem.tsx +1 -5
- package/src/components/Menu/MenuItems.tsx +5 -4
- package/src/components/Modal/ConfirmationModal/ConfirmationModal.stories.tsx +1 -0
- package/src/components/Modal/ConfirmationModal/ConfirmationModal.tsx +4 -1
- package/src/components/Modal/Modal.stories.tsx +21 -0
- package/src/components/Modal/Modal.styles.ts +1 -19
- package/src/components/Modal/Modal.tsx +1 -1
- package/src/components/Modal/ModalBody.tsx +6 -4
- package/src/components/Modal/ModalHeader.tsx +9 -5
- package/src/components/Modal/modal.module.css +16 -0
- package/src/components/Tabs/Tab.styles.ts +0 -6
- package/src/components/Tabs/Tabs.tsx +37 -15
- package/src/index.ts +3 -0
- package/src/queryParameters/url/index.ts +7 -2
- package/src/utils/index.ts +1 -0
- package/src/utils/useLocale/index.ts +9 -0
- package/src/utils/useLocale/useLocale.cypress.spec.tsx +38 -0
- package/src/utils/useLocaleDateTimeFormat/index.ts +4 -2
- package/src/utils/usePluralizedTranslation.ts +2 -3
- package/src/Listing/Cell/DataCell.styles.ts +0 -27
- package/src/Listing/Header/Cell/ListingHeaderCell.styles.ts +0 -71
- package/src/Listing/Header/Cell/SelectActionListingHeaderCell.styles.ts +0 -26
- package/src/Listing/Header/ListingHeader.styles.ts +0 -16
- package/src/Listing/Listing.styles.ts +0 -78
- package/src/Listing/Row/EmptyRow.styles.ts +0 -14
- package/src/components/Button/Button.styles.ts +0 -44
- package/src/components/Layout/AreaIndicator.styles.ts +0 -33
- package/src/components/Menu/Button/MenuButton.styles.ts +0 -27
- package/src/components/Menu/Menu.styles.ts +0 -68
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { useEffect } from 'react';
|
|
1
|
+
import { useEffect, useMemo } from 'react';
|
|
2
2
|
|
|
3
3
|
import { useAtomValue, useSetAtom } from 'jotai';
|
|
4
|
-
import { equals, isNil, pick, type } from 'ramda';
|
|
4
|
+
import { equals, isEmpty, isNil, pick, type, update } from 'ramda';
|
|
5
5
|
import { CSSObject } from 'tss-react';
|
|
6
6
|
|
|
7
7
|
import { Theme } from '@mui/material';
|
|
@@ -12,14 +12,11 @@ import { Column, TableStyleAtom as Style } from './models';
|
|
|
12
12
|
import { tableStyleAtom, tableStyleDerivedAtom } from './tableAtoms';
|
|
13
13
|
|
|
14
14
|
interface TableStyle {
|
|
15
|
-
checkable?: boolean;
|
|
16
|
-
currentVisibleColumns?: Array<Column>;
|
|
17
15
|
listingVariant?: ListingVariant;
|
|
18
16
|
}
|
|
19
17
|
|
|
20
18
|
interface TableStyleState {
|
|
21
19
|
dataStyle: Style;
|
|
22
|
-
getGridTemplateColumn: string;
|
|
23
20
|
}
|
|
24
21
|
|
|
25
22
|
const isCompactMode = equals<ListingVariant | undefined>(
|
|
@@ -40,35 +37,11 @@ export const getTextStyleByViewMode = ({
|
|
|
40
37
|
theme.typography[isCompactMode(listingVariant) ? 'body2' : 'body1']
|
|
41
38
|
);
|
|
42
39
|
|
|
43
|
-
const useStyleTable = ({
|
|
44
|
-
checkable,
|
|
45
|
-
currentVisibleColumns,
|
|
46
|
-
listingVariant
|
|
47
|
-
}: TableStyle): TableStyleState => {
|
|
40
|
+
const useStyleTable = ({ listingVariant }: TableStyle): TableStyleState => {
|
|
48
41
|
const dataStyle = useAtomValue(tableStyleAtom);
|
|
49
42
|
|
|
50
43
|
const updateStyleTable = useSetAtom(tableStyleDerivedAtom);
|
|
51
44
|
|
|
52
|
-
const getGridTemplateColumn = (): string => {
|
|
53
|
-
const checkbox = checkable ? 'fit-content(1rem) ' : ''; // SelectAction (checkbox) cell adjusts to content
|
|
54
|
-
|
|
55
|
-
const columnTemplate = currentVisibleColumns
|
|
56
|
-
?.filter((column) => column)
|
|
57
|
-
?.map(({ width, shortLabel }) => {
|
|
58
|
-
if (!isNil(shortLabel)) {
|
|
59
|
-
return 'min-content';
|
|
60
|
-
}
|
|
61
|
-
if (isNil(width)) {
|
|
62
|
-
return 'auto';
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return equals(type(width), 'Number') ? `${width}px` : width;
|
|
66
|
-
})
|
|
67
|
-
.join(' ');
|
|
68
|
-
|
|
69
|
-
return `${checkbox}${columnTemplate}`;
|
|
70
|
-
};
|
|
71
|
-
|
|
72
45
|
useEffect(() => {
|
|
73
46
|
if (listingVariant) {
|
|
74
47
|
updateStyleTable({ listingVariant });
|
|
@@ -76,9 +49,62 @@ const useStyleTable = ({
|
|
|
76
49
|
}, [listingVariant]);
|
|
77
50
|
|
|
78
51
|
return {
|
|
79
|
-
dataStyle
|
|
80
|
-
getGridTemplateColumn: getGridTemplateColumn()
|
|
52
|
+
dataStyle
|
|
81
53
|
};
|
|
82
54
|
};
|
|
83
55
|
|
|
84
56
|
export default useStyleTable;
|
|
57
|
+
|
|
58
|
+
interface UseColumnStyleProps {
|
|
59
|
+
checkable?: boolean;
|
|
60
|
+
currentVisibleColumns?: Array<Column>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export const useColumnStyle = ({
|
|
64
|
+
checkable,
|
|
65
|
+
currentVisibleColumns
|
|
66
|
+
}: UseColumnStyleProps): string => {
|
|
67
|
+
const gridTemplateColumn = useMemo((): string => {
|
|
68
|
+
const checkbox = checkable ? 'fit-content(1rem) ' : ''; // SelectAction (checkbox) cell adjusts to content
|
|
69
|
+
|
|
70
|
+
const columnTemplate: Array<string> =
|
|
71
|
+
currentVisibleColumns
|
|
72
|
+
?.filter((column) => column)
|
|
73
|
+
?.map(({ width, shortLabel }) => {
|
|
74
|
+
if (!isNil(shortLabel)) {
|
|
75
|
+
return 'min-content';
|
|
76
|
+
}
|
|
77
|
+
if (isNil(width)) {
|
|
78
|
+
return 'auto';
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
equals(type(width), 'Number') ? `${width}px` : width
|
|
83
|
+
) as string;
|
|
84
|
+
}) || [];
|
|
85
|
+
|
|
86
|
+
const hasOnlyContainerResponsiveColumns =
|
|
87
|
+
!isEmpty(columnTemplate) &&
|
|
88
|
+
columnTemplate.every(
|
|
89
|
+
(width: string) =>
|
|
90
|
+
width.includes('auto') ||
|
|
91
|
+
width.includes('fr') ||
|
|
92
|
+
width.includes('%') ||
|
|
93
|
+
width.includes('px')
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
if (!hasOnlyContainerResponsiveColumns) {
|
|
97
|
+
const fixedColumnTemplate = update(
|
|
98
|
+
columnTemplate.length - 1,
|
|
99
|
+
'auto',
|
|
100
|
+
columnTemplate
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
return `${checkbox}${fixedColumnTemplate.join(' ')}`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return `${checkbox}${columnTemplate.join(' ')}`;
|
|
107
|
+
}, [checkable, currentVisibleColumns]);
|
|
108
|
+
|
|
109
|
+
return gridTemplateColumn;
|
|
110
|
+
};
|
package/src/Module/index.tsx
CHANGED
|
@@ -3,6 +3,7 @@ import { Provider as JotaiProvider, createStore } from 'jotai';
|
|
|
3
3
|
|
|
4
4
|
import { StylesProvider, createGenerateClassName } from '@mui/styles';
|
|
5
5
|
|
|
6
|
+
import { ThemeOptions } from '@mui/material';
|
|
6
7
|
import { QueryProvider, ThemeProvider } from '..';
|
|
7
8
|
import SnackbarProvider from '../Snackbar/SnackbarProvider';
|
|
8
9
|
|
|
@@ -12,6 +13,10 @@ export interface ModuleProps {
|
|
|
12
13
|
queryClient?: QueryClient;
|
|
13
14
|
seedName: string;
|
|
14
15
|
store: ReturnType<typeof createStore>;
|
|
16
|
+
overrideTheme?: {
|
|
17
|
+
light: Partial<ThemeOptions>;
|
|
18
|
+
dark: Partial<ThemeOptions>;
|
|
19
|
+
};
|
|
15
20
|
}
|
|
16
21
|
|
|
17
22
|
const Module = ({
|
|
@@ -19,7 +24,8 @@ const Module = ({
|
|
|
19
24
|
seedName,
|
|
20
25
|
maxSnackbars = 3,
|
|
21
26
|
store,
|
|
22
|
-
queryClient
|
|
27
|
+
queryClient,
|
|
28
|
+
overrideTheme
|
|
23
29
|
}: ModuleProps): JSX.Element => {
|
|
24
30
|
const generateClassName = createGenerateClassName({
|
|
25
31
|
seed: seedName
|
|
@@ -29,7 +35,7 @@ const Module = ({
|
|
|
29
35
|
<QueryProvider queryClient={queryClient}>
|
|
30
36
|
<JotaiProvider store={store}>
|
|
31
37
|
<StylesProvider generateClassName={generateClassName}>
|
|
32
|
-
<ThemeProvider>
|
|
38
|
+
<ThemeProvider overrideTheme={overrideTheme}>
|
|
33
39
|
<SnackbarProvider maxSnackbars={maxSnackbars}>
|
|
34
40
|
{children}
|
|
35
41
|
</SnackbarProvider>
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { labelNextPage, labelPreviousPage } from '../Listing/translatedLabels';
|
|
2
|
+
import TestQueryProvider from '../api/TestQueryProvider';
|
|
3
|
+
import { Method } from '../api/useMutationQuery';
|
|
4
|
+
import Pagination from './Pagination';
|
|
5
|
+
import { generateItems } from './utils';
|
|
6
|
+
|
|
7
|
+
const defaultTotalItems = 25;
|
|
8
|
+
const itemsPerPage = 6;
|
|
9
|
+
const totalPages = Math.ceil(defaultTotalItems / itemsPerPage);
|
|
10
|
+
|
|
11
|
+
const initialize = ({
|
|
12
|
+
total = defaultTotalItems,
|
|
13
|
+
currentPage = 1
|
|
14
|
+
}: { total?: number; currentPage?: number }) => {
|
|
15
|
+
cy.interceptAPIRequest({
|
|
16
|
+
alias: 'list',
|
|
17
|
+
method: Method.GET,
|
|
18
|
+
path: '**/listing**',
|
|
19
|
+
response: {
|
|
20
|
+
result: generateItems(itemsPerPage),
|
|
21
|
+
meta: {
|
|
22
|
+
page: currentPage,
|
|
23
|
+
total,
|
|
24
|
+
limit: itemsPerPage
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
cy.mount({
|
|
30
|
+
Component: (
|
|
31
|
+
<div
|
|
32
|
+
style={{
|
|
33
|
+
width: '100%',
|
|
34
|
+
height: '100vh',
|
|
35
|
+
display: 'flex',
|
|
36
|
+
justifyContent: 'center',
|
|
37
|
+
alignItems: 'center'
|
|
38
|
+
}}
|
|
39
|
+
>
|
|
40
|
+
<div
|
|
41
|
+
style={{
|
|
42
|
+
height: '176px',
|
|
43
|
+
boxShadow: '2px 2px 4px rgba(0, 0, 0, 0.2)'
|
|
44
|
+
}}
|
|
45
|
+
>
|
|
46
|
+
<TestQueryProvider>
|
|
47
|
+
<Pagination
|
|
48
|
+
api={{ baseEndpoint: '/test/listing', queryKey: ['test'] }}
|
|
49
|
+
/>
|
|
50
|
+
</TestQueryProvider>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
)
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
describe('Pagination Component', () => {
|
|
58
|
+
it('render with correct initial state', () => {
|
|
59
|
+
initialize({});
|
|
60
|
+
cy.waitForRequest('@list');
|
|
61
|
+
|
|
62
|
+
cy.findByTestId(labelPreviousPage).should('be.disabled');
|
|
63
|
+
|
|
64
|
+
cy.findByTestId(labelNextPage).should('not.be.disabled');
|
|
65
|
+
|
|
66
|
+
cy.contains(`Page 1/${totalPages}`);
|
|
67
|
+
|
|
68
|
+
cy.makeSnapshot();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('hides pagination controls when only one page exists', () => {
|
|
72
|
+
initialize({ total: itemsPerPage });
|
|
73
|
+
cy.waitForRequest('@list');
|
|
74
|
+
|
|
75
|
+
cy.findByTestId(labelPreviousPage).should('not.exist');
|
|
76
|
+
cy.findByTestId(labelNextPage).should('not.exist');
|
|
77
|
+
cy.contains(/Page \d+\/\d+/).should('not.exist');
|
|
78
|
+
|
|
79
|
+
cy.makeSnapshot();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('navigates forward through pages correctly', () => {
|
|
83
|
+
initialize({});
|
|
84
|
+
cy.waitForRequest('@list');
|
|
85
|
+
|
|
86
|
+
cy.contains(`Page 1/${totalPages}`);
|
|
87
|
+
|
|
88
|
+
Array.from({ length: totalPages - 1 }).forEach((_, index) => {
|
|
89
|
+
cy.findByTestId(labelNextPage).click();
|
|
90
|
+
cy.waitForRequest('@list');
|
|
91
|
+
|
|
92
|
+
cy.contains(`Page ${index + 2}/${totalPages}`);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
cy.findByTestId(labelNextPage).should('be.disabled');
|
|
96
|
+
|
|
97
|
+
cy.makeSnapshot();
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('navigates backward through pages correctly', () => {
|
|
101
|
+
initialize({});
|
|
102
|
+
|
|
103
|
+
cy.waitForRequest('@list');
|
|
104
|
+
|
|
105
|
+
Array.from({ length: totalPages - 1 }).forEach(() => {
|
|
106
|
+
cy.findByTestId(labelNextPage).click();
|
|
107
|
+
|
|
108
|
+
cy.waitForRequest('@list');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
Array.from({ length: totalPages - 1 }).forEach((_, index) => {
|
|
112
|
+
cy.findByTestId(labelPreviousPage).click();
|
|
113
|
+
cy.waitForRequest('@list');
|
|
114
|
+
|
|
115
|
+
cy.contains(`Page ${totalPages - index - 1}/${totalPages}`);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
cy.findByTestId(labelPreviousPage).should('be.disabled');
|
|
119
|
+
|
|
120
|
+
cy.makeSnapshot();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('enables both buttons when on middle page', () => {
|
|
124
|
+
initialize({});
|
|
125
|
+
|
|
126
|
+
cy.waitForRequest('@list');
|
|
127
|
+
|
|
128
|
+
cy.findByTestId(labelNextPage).click();
|
|
129
|
+
|
|
130
|
+
cy.waitForRequest('@list');
|
|
131
|
+
|
|
132
|
+
cy.findByTestId(labelPreviousPage).should('not.be.disabled');
|
|
133
|
+
cy.findByTestId(labelNextPage).should('not.be.disabled');
|
|
134
|
+
|
|
135
|
+
cy.makeSnapshot();
|
|
136
|
+
});
|
|
137
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { http, HttpResponse } from 'msw';
|
|
3
|
+
import Pagination from '.';
|
|
4
|
+
import { generateItems } from './utils';
|
|
5
|
+
|
|
6
|
+
const mockedListing = {
|
|
7
|
+
result: generateItems(6),
|
|
8
|
+
meta: {
|
|
9
|
+
page: 1,
|
|
10
|
+
total: 35,
|
|
11
|
+
limit: 6
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const meta: Meta<typeof Pagination> = {
|
|
16
|
+
args: {},
|
|
17
|
+
component: Pagination,
|
|
18
|
+
parameters: {
|
|
19
|
+
msw: {
|
|
20
|
+
handlers: [
|
|
21
|
+
http.get('**/listing**', () => {
|
|
22
|
+
return HttpResponse.json(mockedListing);
|
|
23
|
+
})
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
render: (args) => {
|
|
28
|
+
return (
|
|
29
|
+
<div
|
|
30
|
+
style={{
|
|
31
|
+
width: '240px',
|
|
32
|
+
background: '#EDEDED'
|
|
33
|
+
}}
|
|
34
|
+
>
|
|
35
|
+
<Pagination {...args} />
|
|
36
|
+
</div>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export default meta;
|
|
42
|
+
type Story = StoryObj<typeof Pagination>;
|
|
43
|
+
|
|
44
|
+
export const Default: Story = {
|
|
45
|
+
args: { api: { baseEndpoint: '/test/listing', queryKey: ['pagination'] } }
|
|
46
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { makeStyles } from 'tss-react/mui';
|
|
2
|
+
|
|
3
|
+
export const useStyles = makeStyles()((theme) => ({
|
|
4
|
+
container: {
|
|
5
|
+
height: theme.spacing(22),
|
|
6
|
+
width: theme.spacing(30),
|
|
7
|
+
padding: theme.spacing(1),
|
|
8
|
+
display: 'flex',
|
|
9
|
+
flexDirection: 'column',
|
|
10
|
+
justifyContent: 'space-between',
|
|
11
|
+
alignItems: 'center',
|
|
12
|
+
gap: theme.spacing(2)
|
|
13
|
+
},
|
|
14
|
+
notFound: {
|
|
15
|
+
height: theme.spacing(10),
|
|
16
|
+
width: theme.spacing(30),
|
|
17
|
+
padding: theme.spacing(1)
|
|
18
|
+
},
|
|
19
|
+
body: {
|
|
20
|
+
width: '100%',
|
|
21
|
+
height: '100%',
|
|
22
|
+
display: 'flex',
|
|
23
|
+
justifyContent: 'space-between',
|
|
24
|
+
gap: theme.spacing(1)
|
|
25
|
+
},
|
|
26
|
+
content: {
|
|
27
|
+
width: '100%',
|
|
28
|
+
display: 'flex',
|
|
29
|
+
flexDirection: 'column',
|
|
30
|
+
gap: theme.spacing(0.5)
|
|
31
|
+
},
|
|
32
|
+
page: {
|
|
33
|
+
fontWeight: theme.typography.fontWeightMedium
|
|
34
|
+
},
|
|
35
|
+
arrowContainer: {
|
|
36
|
+
display: 'flex',
|
|
37
|
+
justifyContent: 'space-between',
|
|
38
|
+
alignItems: 'center'
|
|
39
|
+
},
|
|
40
|
+
icon: {
|
|
41
|
+
color: theme.palette.text.primary
|
|
42
|
+
},
|
|
43
|
+
arrow: {
|
|
44
|
+
fontSize: theme.spacing(2)
|
|
45
|
+
},
|
|
46
|
+
item: {
|
|
47
|
+
color: 'inherit',
|
|
48
|
+
textDecoration: 'none'
|
|
49
|
+
},
|
|
50
|
+
link: {
|
|
51
|
+
'&:hover': {
|
|
52
|
+
cursor: 'pointer',
|
|
53
|
+
color: theme.palette.primary.main
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}));
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { CircularProgress, Link, Typography } from '@mui/material';
|
|
2
|
+
import { equals, isEmpty, isNil } from 'ramda';
|
|
3
|
+
import { useMemo, useState } from 'react';
|
|
4
|
+
|
|
5
|
+
import ArrowBackIcon from '@mui/icons-material/ArrowBackIosNew';
|
|
6
|
+
import ArrowForwardIcon from '@mui/icons-material/ArrowForwardIos';
|
|
7
|
+
import { useTranslation } from 'react-i18next';
|
|
8
|
+
import IconButton from '../Button/Icon';
|
|
9
|
+
import {
|
|
10
|
+
labelNextPage,
|
|
11
|
+
labelNoResultFound,
|
|
12
|
+
labelPreviousPage
|
|
13
|
+
} from '../Listing/translatedLabels';
|
|
14
|
+
import buildListingEndpoint from '../api/buildListingEndpoint';
|
|
15
|
+
import { Listing } from '../api/models';
|
|
16
|
+
import useFetchQuery from '../api/useFetchQuery';
|
|
17
|
+
import { truncate } from '../utils';
|
|
18
|
+
import { useStyles } from './Pagination.styles';
|
|
19
|
+
|
|
20
|
+
interface Props {
|
|
21
|
+
api: {
|
|
22
|
+
baseEndpoint: string;
|
|
23
|
+
queryKey: Array<string>;
|
|
24
|
+
searchConditions?;
|
|
25
|
+
};
|
|
26
|
+
labelHasNoElements?: string;
|
|
27
|
+
onItemClick?: ({ id }: { id: number }) => void;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const limit = 6;
|
|
31
|
+
|
|
32
|
+
const Pagination = ({
|
|
33
|
+
api: { baseEndpoint, queryKey, searchConditions },
|
|
34
|
+
labelHasNoElements = labelNoResultFound,
|
|
35
|
+
onItemClick
|
|
36
|
+
}: Props) => {
|
|
37
|
+
const { t } = useTranslation();
|
|
38
|
+
const { cx, classes } = useStyles();
|
|
39
|
+
const [page, setPage] = useState(1);
|
|
40
|
+
|
|
41
|
+
const { data, isLoading } = useFetchQuery<
|
|
42
|
+
Listing<{ id: number; name: string }>
|
|
43
|
+
>({
|
|
44
|
+
getEndpoint: (parameters): string =>
|
|
45
|
+
buildListingEndpoint({
|
|
46
|
+
baseEndpoint: baseEndpoint,
|
|
47
|
+
parameters: {
|
|
48
|
+
...parameters,
|
|
49
|
+
page,
|
|
50
|
+
limit,
|
|
51
|
+
...(searchConditions
|
|
52
|
+
? {
|
|
53
|
+
search: {
|
|
54
|
+
conditions: searchConditions
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
: {}),
|
|
58
|
+
sort: { status: 'DESC' }
|
|
59
|
+
}
|
|
60
|
+
}),
|
|
61
|
+
getQueryKey: () => [...queryKey, page],
|
|
62
|
+
queryOptions: {
|
|
63
|
+
suspense: false
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const pagesCount = Math.ceil(data?.meta.total / limit);
|
|
68
|
+
const arePaginationComponentsDisplayed = !equals(pagesCount, 1);
|
|
69
|
+
|
|
70
|
+
const hasNoElements = useMemo(
|
|
71
|
+
() => isEmpty(data?.result) || isNil(data?.result),
|
|
72
|
+
[data]
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
if (hasNoElements) {
|
|
76
|
+
return (
|
|
77
|
+
<div className={classes.notFound}>
|
|
78
|
+
<Typography color="disabled">{t(labelHasNoElements)}</Typography>
|
|
79
|
+
</div>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return (
|
|
84
|
+
<div className={classes.container}>
|
|
85
|
+
<div className={classes.body}>
|
|
86
|
+
{arePaginationComponentsDisplayed && (
|
|
87
|
+
<div className={classes.arrowContainer}>
|
|
88
|
+
<IconButton
|
|
89
|
+
onClick={() => setPage(page - 1)}
|
|
90
|
+
disabled={equals(page, 1)}
|
|
91
|
+
dataTestid={labelPreviousPage}
|
|
92
|
+
className={classes.icon}
|
|
93
|
+
>
|
|
94
|
+
<ArrowBackIcon className={classes.arrow} />
|
|
95
|
+
</IconButton>
|
|
96
|
+
</div>
|
|
97
|
+
)}
|
|
98
|
+
|
|
99
|
+
<div className={classes.content}>
|
|
100
|
+
{isLoading ? (
|
|
101
|
+
<CircularProgress color="inherit" size={25} />
|
|
102
|
+
) : (
|
|
103
|
+
data?.result.map(({ id, name }) => (
|
|
104
|
+
<Link
|
|
105
|
+
key={id}
|
|
106
|
+
variant="body2"
|
|
107
|
+
className={cx({
|
|
108
|
+
[classes.item]: true,
|
|
109
|
+
[classes.link]: !!onItemClick
|
|
110
|
+
})}
|
|
111
|
+
onClick={() => onItemClick?.({ id })}
|
|
112
|
+
>
|
|
113
|
+
{truncate({
|
|
114
|
+
content: name,
|
|
115
|
+
maxLength: 25
|
|
116
|
+
})}
|
|
117
|
+
</Link>
|
|
118
|
+
))
|
|
119
|
+
)}
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
{arePaginationComponentsDisplayed && (
|
|
123
|
+
<div className={classes.arrowContainer}>
|
|
124
|
+
<IconButton
|
|
125
|
+
onClick={() => setPage(page + 1)}
|
|
126
|
+
disabled={equals(pagesCount, page)}
|
|
127
|
+
className={classes.icon}
|
|
128
|
+
dataTestid={labelNextPage}
|
|
129
|
+
>
|
|
130
|
+
<ArrowForwardIcon className={classes.arrow} />
|
|
131
|
+
</IconButton>
|
|
132
|
+
</div>
|
|
133
|
+
)}
|
|
134
|
+
</div>
|
|
135
|
+
|
|
136
|
+
{arePaginationComponentsDisplayed && (
|
|
137
|
+
<Typography
|
|
138
|
+
className={classes.page}
|
|
139
|
+
variant="body2"
|
|
140
|
+
>{`Page ${page}/${pagesCount}`}</Typography>
|
|
141
|
+
)}
|
|
142
|
+
</div>
|
|
143
|
+
);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
export default Pagination;
|
|
@@ -230,7 +230,7 @@ const ContentWithGrid = ({
|
|
|
230
230
|
const { classes } = useContentStyles({ isDragging });
|
|
231
231
|
|
|
232
232
|
return (
|
|
233
|
-
<Grid item style={style}
|
|
233
|
+
<Grid item style={style} size={xs} {...listeners} {...attributes}>
|
|
234
234
|
<Paper className={classes.content} ref={itemRef}>
|
|
235
235
|
<Typography>{name as string}</Typography>
|
|
236
236
|
</Paper>
|
|
@@ -244,7 +244,7 @@ const RootComponent = ({
|
|
|
244
244
|
}: RootComponentProps): JSX.Element => (
|
|
245
245
|
<Grid container spacing={1} style={{ width: '550px' }}>
|
|
246
246
|
{not(isInDragOverlay) && (
|
|
247
|
-
<Grid item
|
|
247
|
+
<Grid item size={12}>
|
|
248
248
|
<Typography align="center">This item cannot move</Typography>
|
|
249
249
|
</Grid>
|
|
250
250
|
)}
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
|
|
10
10
|
import { ThemeMode } from '@centreon/ui-context';
|
|
11
11
|
|
|
12
|
+
import { GlobalStyles } from '@mui/system';
|
|
12
13
|
import { getTheme } from '../ThemeProvider';
|
|
13
14
|
|
|
14
15
|
interface Props {
|
|
@@ -23,7 +24,8 @@ const StoryBookThemeProvider = ({
|
|
|
23
24
|
const theme = useMemo(() => createTheme(getTheme(themeMode)), [themeMode]);
|
|
24
25
|
|
|
25
26
|
return (
|
|
26
|
-
<StyledEngineProvider injectFirst>
|
|
27
|
+
<StyledEngineProvider injectFirst enableCssLayer>
|
|
28
|
+
<GlobalStyles styles="@layer theme,base,mui,components,utilities;" />
|
|
27
29
|
<MuiThemeProvider theme={theme}>
|
|
28
30
|
{children}
|
|
29
31
|
<CssBaseline />
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
@layer base {
|
|
2
|
+
::-webkit-scrollbar {
|
|
3
|
+
height: var(--spacing-2);
|
|
4
|
+
width: var(--spacing-2);
|
|
5
|
+
background-color: transparent;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
::-webkit-scrollbar-thumb {
|
|
9
|
+
background-color: var(--color-text-disabled);
|
|
10
|
+
border-radius: var(--spacing-1);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
::-webkit-scrollbar-thumb:hover {
|
|
14
|
+
background-color: var(--color-primary-main);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
* {
|
|
18
|
+
scrollbar-color: var(--color-text-disabled) var(--color-background-default);
|
|
19
|
+
scrollbar-width: thin;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
html {
|
|
23
|
+
margin: 0;
|
|
24
|
+
padding: 0;
|
|
25
|
+
width: 100%;
|
|
26
|
+
height: 100%;
|
|
27
|
+
text-rendering: optimizeLegibility;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
body {
|
|
31
|
+
background-color: var(--color-background-paper);
|
|
32
|
+
height: 100%;
|
|
33
|
+
padding: 0;
|
|
34
|
+
width: 100%;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
#root {
|
|
38
|
+
background-color: var(--color-background-paper) !important;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@variant dark {
|
|
42
|
+
::-webkit-scrollbar-thumb {
|
|
43
|
+
background-color: var(--color-divider);
|
|
44
|
+
}
|
|
45
|
+
* {
|
|
46
|
+
scrollbar-color: var(--color-divider) var(--color-background-default);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|