Skip to content

Commit 5fa01c4

Browse files
committed
refactor: rewrite dg pagination
1 parent d761425 commit 5fa01c4

30 files changed

+320
-220
lines changed

packages/pluggableWidgets/datagrid-web/src/Datagrid.tsx

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { useClickActionHelper } from "@mendix/widget-plugin-grid/helpers/ClickActionHelper";
22
import { useFocusTargetController } from "@mendix/widget-plugin-grid/keyboard-navigation/useFocusTargetController";
3-
import { useSelectionHelper } from "@mendix/widget-plugin-grid/selection";
43
import { useConst } from "@mendix/widget-plugin-mobx-kit/react/useConst";
54
import { generateUUID } from "@mendix/widget-plugin-platform/framework/generate-uuid";
65
import { ContainerProvider } from "brandi-react";
@@ -9,7 +8,6 @@ import { ReactElement, useCallback, useMemo } from "react";
98
import { DatagridContainerProps } from "../typings/DatagridProps";
109
import { Cell } from "./components/Cell";
1110
import { Widget } from "./components/Widget";
12-
import { WidgetHeaderContext } from "./components/WidgetHeaderContext";
1311
import { useDataExport } from "./features/data-export/useDataExport";
1412
import { useCellEventsController } from "./features/row-interaction/CellEventsController";
1513
import { useCheckboxEventsController } from "./features/row-interaction/CheckboxEventsController";
@@ -21,26 +19,20 @@ import {
2119
useExportProgressService,
2220
useLoaderViewModel,
2321
useMainGate,
24-
usePaginationService
22+
useSelectionHelper
2523
} from "./model/hooks/injection-hooks";
2624
import { useDatagridContainer } from "./model/hooks/useDatagridContainer";
2725

2826
const DatagridRoot = observer((props: DatagridContainerProps): ReactElement => {
2927
const gate = useMainGate();
3028
const columnsStore = useColumnsStore();
31-
const paginationService = usePaginationService();
3229
const exportProgress = useExportProgressService();
3330
const loaderVM = useLoaderViewModel();
3431
const items = gate.props.datasource.items ?? [];
3532

3633
const [abortExport] = useDataExport(props, columnsStore, exportProgress);
3734

38-
const selectionHelper = useSelectionHelper(
39-
gate.props.itemSelection,
40-
gate.props.datasource,
41-
props.onSelectionChange,
42-
props.keepSelection ? "always keep" : "always clear"
43-
);
35+
const selectionHelper = useSelectionHelper();
4436

4537
const selectActionHelper = useSelectActionHelper(props, selectionHelper);
4638

@@ -92,27 +84,14 @@ const DatagridRoot = observer((props: DatagridContainerProps): ReactElement => {
9284
[columnsStore.columnFilters]
9385
)}
9486
headerTitle={props.filterSectionTitle?.value}
95-
headerContent={
96-
props.filtersPlaceholder && (
97-
<WidgetHeaderContext selectionHelper={selectionHelper}>
98-
{props.filtersPlaceholder}
99-
</WidgetHeaderContext>
100-
)
101-
}
102-
hasMoreItems={props.datasource.hasMoreItems ?? false}
87+
headerContent={props.filtersPlaceholder}
10388
headerWrapperRenderer={useCallback((_columnIndex: number, header: ReactElement) => header, [])}
10489
id={useMemo(() => `DataGrid${generateUUID()}`, [])}
10590
numberOfItems={props.datasource.totalCount}
10691
onExportCancel={abortExport}
107-
page={paginationService.currentPage}
108-
pageSize={props.pageSize}
10992
paginationType={props.pagination}
11093
loadMoreButtonCaption={props.loadMoreButtonCaption?.value}
111-
paging={paginationService.showPagination}
112-
pagingPosition={props.pagingPosition}
113-
showPagingButtons={props.showPagingButtons}
11494
rowClass={useCallback((value: any) => props.rowClass?.get(value)?.value ?? "", [props.rowClass])}
115-
setPage={paginationService.setPage}
11695
styles={props.style}
11796
exporting={exportProgress.inProgress}
11897
processedRows={exportProgress.loaded}

packages/pluggableWidgets/datagrid-web/src/components/GridBody.tsx

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
import { useInfiniteControl } from "@mendix/widget-plugin-grid/components/InfiniteBody";
12
import classNames from "classnames";
2-
import { Fragment, ReactElement, ReactNode } from "react";
3-
import { LoadingTypeEnum, PaginationEnum } from "../../typings/DatagridProps";
4-
import { SpinnerLoader } from "./loader/SpinnerLoader";
3+
import { Fragment, ReactElement, ReactNode, useCallback } from "react";
4+
import { LoadingTypeEnum } from "../../typings/DatagridProps";
5+
import { usePaginationService } from "../model/hooks/injection-hooks";
56
import { RowSkeletonLoader } from "./loader/RowSkeletonLoader";
6-
import { useInfiniteControl } from "@mendix/widget-plugin-grid/components/InfiniteBody";
7+
import { SpinnerLoader } from "./loader/SpinnerLoader";
78

89
interface Props {
910
className?: string;
@@ -14,30 +15,30 @@ interface Props {
1415
columnsHidable: boolean;
1516
columnsSize: number;
1617
rowsSize: number;
17-
pageSize: number;
18-
pagination: PaginationEnum;
19-
hasMoreItems: boolean;
20-
setPage?: (update: (page: number) => number) => void;
2118
}
2219

2320
export function GridBody(props: Props): ReactElement {
24-
const { children, pagination, hasMoreItems, setPage } = props;
21+
const { children } = props;
22+
23+
const paging = usePaginationService();
24+
const pageSize = paging.pageSize;
25+
const setPage = useCallback((cb: (n: number) => number) => paging.setPage(cb), [paging]);
2526

26-
const isInfinite = pagination === "virtualScrolling";
27+
const isInfinite = paging.pagination === "virtualScrolling";
2728
const [trackScrolling, bodySize, containerRef] = useInfiniteControl({
28-
hasMoreItems,
29+
hasMoreItems: paging.hasMoreItems,
2930
isInfinite,
3031
setPage
3132
});
3233

3334
const content = (): ReactElement => {
3435
if (props.isFirstLoad) {
35-
return <Loader {...props} rowsSize={props.rowsSize > 0 ? props.rowsSize : props.pageSize} />;
36+
return <Loader {...props} rowsSize={props.rowsSize > 0 ? props.rowsSize : pageSize} />;
3637
}
3738
return (
3839
<Fragment>
3940
{children}
40-
{props.isFetchingNextBatch && <Loader {...props} rowsSize={props.pageSize} useBorderTop={false} />}
41+
{props.isFetchingNextBatch && <Loader {...props} rowsSize={pageSize} useBorderTop={false} />}
4142
</Fragment>
4243
);
4344
};
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { Pagination as PaginationComponent } from "@mendix/widget-plugin-grid/components/Pagination";
2+
import { observer } from "mobx-react-lite";
3+
import { ReactNode } from "react";
4+
import { usePaginationService } from "../model/hooks/injection-hooks";
5+
6+
export const Pagination = observer(function Pagination(): ReactNode {
7+
const paging = usePaginationService();
8+
9+
if (!paging.paginationVisible) return null;
10+
11+
return (
12+
<PaginationComponent
13+
canNextPage={paging.hasMoreItems}
14+
canPreviousPage={paging.currentPage !== 0}
15+
gotoPage={page => paging.setPage(page)}
16+
nextPage={() => paging.setPage(n => n + 1)}
17+
numberOfItems={paging.totalCount}
18+
page={paging.currentPage}
19+
pageSize={paging.pageSize}
20+
showPagingButtons={paging.showPagingButtons}
21+
previousPage={() => paging.setPage(n => n - 1)}
22+
pagination={paging.pagination}
23+
/>
24+
);
25+
});

packages/pluggableWidgets/datagrid-web/src/components/RowsRenderer.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ interface RowsRendererProps {
1414
eventsController: EventsController;
1515
focusController: FocusTargetController;
1616
interactive: boolean;
17-
pageSize: number;
1817
preview: boolean;
1918
rowClass?: (item: ObjectItem) => string;
2019
rows: ObjectItem[];

packages/pluggableWidgets/datagrid-web/src/components/Widget.tsx

Lines changed: 6 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
import { RefreshIndicator } from "@mendix/widget-plugin-component-kit/RefreshIndicator";
2-
import { Pagination } from "@mendix/widget-plugin-grid/components/Pagination";
32
import { FocusTargetController } from "@mendix/widget-plugin-grid/keyboard-navigation/FocusTargetController";
43
import { ListActionValue, ObjectItem } from "mendix";
54
import { observer } from "mobx-react-lite";
65
import { CSSProperties, Fragment, ReactElement, ReactNode } from "react";
7-
import {
8-
LoadingTypeEnum,
9-
PaginationEnum,
10-
PagingPositionEnum,
11-
ShowPagingButtonsEnum
12-
} from "../../typings/DatagridProps";
6+
import { LoadingTypeEnum, PaginationEnum } from "../../typings/DatagridProps";
137

148
import { EmptyPlaceholder } from "../features/empty-message/EmptyPlaceholder";
159
import { SelectAllBar } from "../features/select-all/SelectAllBar";
@@ -40,28 +34,19 @@ export interface WidgetProps<C extends GridColumn, T extends ObjectItem = Object
4034
data: T[];
4135
exporting: boolean;
4236
filterRenderer: (renderWrapper: (children: ReactNode) => ReactElement, columnIndex: number) => ReactElement;
43-
hasMoreItems: boolean;
4437
headerContent?: ReactNode;
4538
headerTitle?: string;
4639
headerWrapperRenderer: (columnIndex: number, header: ReactElement) => ReactElement;
4740
id: string;
4841
numberOfItems?: number;
4942
onExportCancel?: () => void;
50-
page: number;
5143
paginationType: PaginationEnum;
5244
loadMoreButtonCaption?: string;
5345

54-
pageSize: number;
55-
paging: boolean;
56-
pagingPosition: PagingPositionEnum;
57-
showPagingButtons: ShowPagingButtonsEnum;
58-
preview?: boolean;
5946
processedRows: number;
6047
rowClass?: (item: T) => string;
61-
setPage?: (computePage: (prevPage: number) => number) => void;
6248
styles?: CSSProperties;
6349
rowAction?: ListActionValue;
64-
showSelectAllToggle?: boolean;
6550
isFirstLoad: boolean;
6651
isFetchingNextBatch: boolean;
6752
loadingType: LoadingTypeEnum;
@@ -116,43 +101,16 @@ const Main = observer(<C extends GridColumn>(props: WidgetProps<C>): ReactElemen
116101
CellComponent,
117102
columnsHidable,
118103
data: rows,
119-
hasMoreItems,
120104
headerContent,
121105
headerTitle,
122106
loadMoreButtonCaption,
123-
numberOfItems,
124-
page,
125-
pageSize,
126-
paginationType,
127-
paging,
128-
pagingPosition,
129107
showRefreshIndicator,
130108
selectActionHelper,
131-
setPage,
132109
visibleColumns
133110
} = props;
134111

135112
const basicData = useBasicData();
136113

137-
const showHeader = !!headerContent;
138-
const showTopBarPagination = paging && (pagingPosition === "top" || pagingPosition === "both");
139-
const showFooterPagination = paging && (pagingPosition === "bottom" || pagingPosition === "both");
140-
141-
const pagination = paging ? (
142-
<Pagination
143-
canNextPage={hasMoreItems}
144-
canPreviousPage={page !== 0}
145-
gotoPage={(page: number) => setPage && setPage(() => page)}
146-
nextPage={() => setPage && setPage(prev => prev + 1)}
147-
numberOfItems={numberOfItems}
148-
page={page}
149-
pageSize={pageSize}
150-
showPagingButtons={props.showPagingButtons}
151-
previousPage={() => setPage && setPage(prev => prev - 1)}
152-
pagination={paginationType}
153-
/>
154-
) : null;
155-
156114
const cssGridStyles = gridStyle(visibleColumns, {
157115
selectItemColumn: selectActionHelper.showCheckboxColumn,
158116
visibilitySelectorColumn: columnsHidable
@@ -162,8 +120,8 @@ const Main = observer(<C extends GridColumn>(props: WidgetProps<C>): ReactElemen
162120

163121
return (
164122
<Fragment>
165-
<WidgetTopBar pagination={showTopBarPagination ? pagination : undefined} />
166-
{showHeader && <WidgetHeader headerTitle={headerTitle}>{headerContent}</WidgetHeader>}
123+
<WidgetTopBar />
124+
<WidgetHeader headerTitle={headerTitle} headerContent={headerContent} />
167125
<WidgetContent>
168126
<Grid
169127
aria-multiselectable={selectionEnabled ? selectActionHelper.selectionType === "Multi" : undefined}
@@ -183,7 +141,7 @@ const Main = observer(<C extends GridColumn>(props: WidgetProps<C>): ReactElemen
183141
headerWrapperRenderer={props.headerWrapperRenderer}
184142
id={props.id}
185143
isLoading={props.columnsLoading}
186-
preview={props.preview}
144+
preview={false}
187145
/>
188146
<SelectAllBar />
189147
{showRefreshIndicator ? <RefreshIndicator /> : null}
@@ -194,13 +152,9 @@ const Main = observer(<C extends GridColumn>(props: WidgetProps<C>): ReactElemen
194152
columnsHidable={columnsHidable}
195153
columnsSize={visibleColumns.length}
196154
rowsSize={rows.length}
197-
pageSize={pageSize}
198-
pagination={props.paginationType}
199-
hasMoreItems={hasMoreItems}
200-
setPage={setPage}
201155
>
202156
<RowsRenderer
203-
preview={props.preview ?? false}
157+
preview={false}
204158
interactive={basicData.gridInteractive}
205159
Cell={CellComponent}
206160
columns={visibleColumns}
@@ -211,19 +165,12 @@ const Main = observer(<C extends GridColumn>(props: WidgetProps<C>): ReactElemen
211165
selectActionHelper={selectActionHelper}
212166
focusController={props.focusController}
213167
eventsController={props.cellEventsController}
214-
pageSize={props.pageSize}
215168
/>
216169
<EmptyPlaceholder />
217170
</GridBody>
218171
</Grid>
219172
</WidgetContent>
220-
<WidgetFooter
221-
pagination={showFooterPagination ? pagination : undefined}
222-
paginationType={paginationType}
223-
loadMoreButtonCaption={loadMoreButtonCaption}
224-
hasMoreItems={hasMoreItems}
225-
setPage={setPage}
226-
/>
173+
<WidgetFooter loadMoreButtonCaption={loadMoreButtonCaption} />
227174
</Fragment>
228175
);
229176
});

packages/pluggableWidgets/datagrid-web/src/components/WidgetFooter.tsx

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,45 @@
11
import { If } from "@mendix/widget-plugin-component-kit/If";
22
import { observer } from "mobx-react-lite";
3-
import { ComponentPropsWithoutRef, ReactElement, ReactNode } from "react";
4-
import { PaginationEnum } from "../../typings/DatagridProps";
3+
import { ReactElement } from "react";
54
import { SelectionCounter } from "../features/selection-counter/SelectionCounter";
65
import { useSelectionCounterViewModel } from "../features/selection-counter/injection-hooks";
6+
import { useDatagridConfig, usePaginationService } from "../model/hooks/injection-hooks";
7+
import { Pagination } from "./Pagination";
78

89
type WidgetFooterProps = {
9-
pagination: ReactNode;
10-
paginationType: PaginationEnum;
1110
loadMoreButtonCaption?: string;
12-
hasMoreItems: boolean;
13-
setPage?: (computePage: (prevPage: number) => number) => void;
14-
} & ComponentPropsWithoutRef<"div">;
11+
};
1512

1613
export const WidgetFooter = observer(function WidgetFooter(props: WidgetFooterProps): ReactElement | null {
17-
const { pagination, paginationType, loadMoreButtonCaption, hasMoreItems, setPage, ...rest } = props;
14+
const config = useDatagridConfig();
15+
const paging = usePaginationService();
16+
const { loadMoreButtonCaption } = props;
1817
const selectionCounterVM = useSelectionCounterViewModel();
1918

2019
return (
21-
<div {...rest} className="widget-datagrid-footer table-footer">
20+
<div className="widget-datagrid-footer table-footer">
2221
<div className="widget-datagrid-paging-bottom">
2322
<div className="widget-datagrid-pb-start">
2423
<If condition={selectionCounterVM.isBottomCounterVisible}>
2524
<SelectionCounter />
2625
</If>
2726
</div>
28-
{hasMoreItems && paginationType === "loadMore" && (
27+
<If condition={paging.hasMoreItems && paging.pagination === "loadMore"}>
2928
<div className="widget-datagrid-pb-middle">
3029
<button
3130
className="btn btn-primary widget-datagrid-load-more"
32-
onClick={() => setPage && setPage(prev => prev + 1)}
31+
onClick={() => paging.setPage(n => n + 1)}
3332
tabIndex={0}
3433
>
3534
{loadMoreButtonCaption}
3635
</button>
3736
</div>
38-
)}
39-
<div className="widget-datagrid-pb-end">{pagination}</div>
37+
</If>
38+
<div className="widget-datagrid-pb-end">
39+
<If condition={config.pagingPosition !== "top"}>
40+
<Pagination />
41+
</If>
42+
</div>
4043
</div>
4144
</div>
4245
);

0 commit comments

Comments
 (0)