Skip to content

Commit 8340573

Browse files
committed
refactor: rewrite grid body
1 parent b387a47 commit 8340573

File tree

4 files changed

+100
-73
lines changed

4 files changed

+100
-73
lines changed
Lines changed: 82 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,107 @@
11
import { useInfiniteControl } from "@mendix/widget-plugin-grid/components/InfiniteBody";
22
import classNames from "classnames";
3-
import { Fragment, ReactElement, ReactNode, useCallback } from "react";
4-
import { LoadingTypeEnum } from "../../typings/DatagridProps";
5-
import { usePaginationService } from "../model/hooks/injection-hooks";
3+
import { observer } from "mobx-react-lite";
4+
import { Fragment, PropsWithChildren, ReactElement, ReactNode, RefObject, UIEventHandler, useCallback } from "react";
5+
import {
6+
useDatagridConfig,
7+
useItemCount,
8+
useLoaderViewModel,
9+
usePaginationService,
10+
useVisibleColumnsCount
11+
} from "../model/hooks/injection-hooks";
612
import { RowSkeletonLoader } from "./loader/RowSkeletonLoader";
713
import { SpinnerLoader } from "./loader/SpinnerLoader";
814

9-
interface Props {
10-
className?: string;
11-
children?: ReactNode;
12-
loadingType: LoadingTypeEnum;
13-
isFirstLoad: boolean;
14-
isFetchingNextBatch?: boolean;
15-
columnsHidable: boolean;
16-
columnsSize: number;
17-
rowsSize: number;
18-
}
19-
20-
export function GridBody(props: Props): ReactElement {
15+
export function GridBody(props: PropsWithChildren): ReactElement {
2116
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]);
26-
27-
const isInfinite = paging.pagination === "virtualScrolling";
28-
const [trackScrolling, bodySize, containerRef] = useInfiniteControl({
29-
hasMoreItems: paging.hasMoreItems,
30-
isInfinite,
31-
setPage
32-
});
33-
34-
const content = (): ReactElement => {
35-
if (props.isFirstLoad) {
36-
return <Loader {...props} rowsSize={props.rowsSize > 0 ? props.rowsSize : pageSize} />;
37-
}
38-
return (
39-
<Fragment>
40-
{children}
41-
{props.isFetchingNextBatch && <Loader {...props} rowsSize={pageSize} useBorderTop={false} />}
42-
</Fragment>
43-
);
44-
};
17+
const { bodySize, containerRef, isInfinite, handleScroll } = useBodyScroll();
4518

4619
return (
4720
<div
48-
className={classNames(
49-
"widget-datagrid-grid-body table-content",
50-
{ "infinite-loading": isInfinite },
51-
props.className
52-
)}
21+
className={classNames("widget-datagrid-grid-body table-content", { "infinite-loading": isInfinite })}
5322
style={isInfinite && bodySize > 0 ? { maxHeight: `${bodySize}px` } : {}}
5423
role="rowgroup"
5524
ref={containerRef}
56-
onScroll={isInfinite ? trackScrolling : undefined}
25+
onScroll={handleScroll}
5726
>
58-
{content()}
27+
<ContentGuard>{children}</ContentGuard>
5928
</div>
6029
);
6130
}
6231

63-
interface LoaderProps {
64-
loadingType: LoadingTypeEnum;
65-
columnsHidable: boolean;
66-
columnsSize: number;
67-
rowsSize: number;
68-
useBorderTop?: boolean;
69-
}
32+
const ContentGuard = observer(function ContentGuard(props: PropsWithChildren): ReactNode {
33+
const loaderVM = useLoaderViewModel();
34+
const { pageSize } = usePaginationService();
35+
const config = useDatagridConfig();
36+
const columnsCount = useVisibleColumnsCount().get();
37+
const itemCount = useItemCount().get();
7038

71-
function Loader(props: LoaderProps): ReactElement {
72-
if (props.loadingType === "spinner") {
39+
if (loaderVM.isFirstLoad && config.loadingType === "spinner") {
40+
return <Spinner />;
41+
}
42+
43+
if (loaderVM.isFirstLoad) {
7344
return (
74-
<div className="widget-datagrid-loader-container">
75-
<SpinnerLoader withMargins size="large" />
76-
</div>
45+
<RowSkeletonLoader
46+
columnsHidable={config.columnsHidable}
47+
columnsSize={columnsCount}
48+
pageSize={itemCount > 0 ? itemCount : pageSize}
49+
useBorderTop
50+
/>
7751
);
7852
}
7953

8054
return (
81-
<RowSkeletonLoader
82-
columnsHidable={props.columnsHidable}
83-
columnsSize={props.columnsSize}
84-
pageSize={props.rowsSize}
85-
useBorderTop={props.useBorderTop}
86-
/>
55+
<Fragment>
56+
{props.children}
57+
{(() => {
58+
if (loaderVM.isFetchingNextBatch && config.loadingType === "spinner") {
59+
return <Spinner />;
60+
}
61+
62+
if (loaderVM.isFetchingNextBatch) {
63+
return (
64+
<RowSkeletonLoader
65+
columnsHidable={config.columnsHidable}
66+
columnsSize={columnsCount}
67+
pageSize={pageSize}
68+
useBorderTop={false}
69+
/>
70+
);
71+
}
72+
73+
return null;
74+
})()}
75+
</Fragment>
8776
);
77+
});
78+
79+
function useBodyScroll(): {
80+
handleScroll: UIEventHandler<HTMLDivElement> | undefined;
81+
bodySize: number;
82+
containerRef: RefObject<HTMLDivElement | null>;
83+
isInfinite: boolean;
84+
} {
85+
const paging = usePaginationService();
86+
const setPage = useCallback((cb: (n: number) => number) => paging.setPage(cb), [paging]);
87+
88+
const isInfinite = paging.pagination === "virtualScrolling";
89+
const [trackScrolling, bodySize, containerRef] = useInfiniteControl({
90+
hasMoreItems: paging.hasMoreItems,
91+
isInfinite,
92+
setPage
93+
});
94+
95+
return {
96+
handleScroll: isInfinite ? trackScrolling : undefined,
97+
bodySize,
98+
containerRef,
99+
isInfinite
100+
};
88101
}
102+
103+
const Spinner = (): ReactNode => (
104+
<div className="widget-datagrid-loader-container">
105+
<SpinnerLoader withMargins size="large" />
106+
</div>
107+
);

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

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -135,14 +135,7 @@ const Main = observer(<C extends GridColumn>(props: WidgetProps<C>): ReactElemen
135135
/>
136136
<SelectAllBar />
137137
{showRefreshIndicator ? <RefreshIndicator /> : null}
138-
<GridBody
139-
isFirstLoad={props.isFirstLoad}
140-
isFetchingNextBatch={props.isFetchingNextBatch}
141-
loadingType={props.loadingType}
142-
columnsHidable={columnsHidable}
143-
columnsSize={visibleColumns.length}
144-
rowsSize={rows.length}
145-
>
138+
<GridBody>
146139
<RowsRenderer
147140
preview={false}
148141
interactive={basicData.gridInteractive}

packages/pluggableWidgets/datagrid-web/src/model/configs/Datagrid.config.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { generateUUID } from "@mendix/widget-plugin-platform/framework/generate-uuid";
2-
import { DatagridContainerProps, PagingPositionEnum } from "../../../typings/DatagridProps";
2+
import { DatagridContainerProps, LoadingTypeEnum, PagingPositionEnum } from "../../../typings/DatagridProps";
33

44
/** Config for static values that don't change at runtime. */
55
export interface DatagridConfig {
@@ -16,6 +16,12 @@ export interface DatagridConfig {
1616
keepSelection: boolean;
1717
pagingPosition: PagingPositionEnum;
1818
multiselectable: true | undefined;
19+
loadingType: LoadingTypeEnum;
20+
columnsDraggable: boolean;
21+
columnsFilterable: boolean;
22+
columnsHidable: boolean;
23+
columnsResizable: boolean;
24+
columnsSortable: boolean;
1925
}
2026

2127
export function datagridConfig(props: DatagridContainerProps): DatagridConfig {
@@ -34,7 +40,13 @@ export function datagridConfig(props: DatagridContainerProps): DatagridConfig {
3440
enableSelectAll: props.enableSelectAll,
3541
keepSelection: props.keepSelection,
3642
pagingPosition: props.pagingPosition,
37-
multiselectable: isMultiselectable(props)
43+
multiselectable: isMultiselectable(props),
44+
loadingType: props.loadingType,
45+
columnsHidable: props.columnsHidable,
46+
columnsDraggable: props.columnsDraggable,
47+
columnsFilterable: props.columnsFilterable,
48+
columnsResizable: props.columnsResizable,
49+
columnsSortable: props.columnsSortable
3850
};
3951

4052
return Object.freeze(config);

packages/pluggableWidgets/datagrid-web/src/model/hooks/injection-hooks.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,6 @@ export const [useMainGate] = createInjectionHooks(CORE.mainGate);
1111
export const [usePaginationService] = createInjectionHooks(DG.paginationService);
1212
export const [useSelectionHelper] = createInjectionHooks(DG.selectionHelper);
1313
export const [useGridStyle] = createInjectionHooks(DG.gridColumnsStyle);
14+
export const [useQueryService] = createInjectionHooks(DG.query);
15+
export const [useVisibleColumnsCount] = createInjectionHooks(CORE.atoms.visibleColumnsCount);
16+
export const [useItemCount] = createInjectionHooks(CORE.atoms.itemCount);

0 commit comments

Comments
 (0)