Skip to content

Commit d81db8b

Browse files
committed
refactor: migrate to helpers context
1 parent 420526b commit d81db8b

File tree

14 files changed

+331
-332
lines changed

14 files changed

+331
-332
lines changed

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

+66-60
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { ColumnPreview } from "./helpers/ColumnPreview";
1212
import { useSelectActionHelper } from "./helpers/SelectActionHelper";
1313
import { useFocusTargetController } from "@mendix/widget-plugin-grid/keyboard-navigation/useFocusTargetController";
1414
import "./ui/DatagridPreview.scss";
15+
import { HelpersProvider } from "./helpers/helpers-context";
1516

1617
// Fix type definition for Selectable
1718
// TODO: Open PR to fix in appdev.
@@ -80,67 +81,72 @@ export function preview(props: DatagridPreviewProps): ReactElement {
8081
const eventsController = { getProps: () => Object.create({}) };
8182

8283
return (
83-
<Widget
84-
CellComponent={Cell}
85-
className={props.class}
86-
columnsDraggable={props.columnsDraggable}
87-
columnsFilterable={props.columnsFilterable}
88-
columnsHidable={props.columnsHidable}
89-
columnsResizable={props.columnsResizable}
90-
columnsSortable={props.columnsSortable}
91-
visibleColumns={columns}
92-
availableColumns={[]}
93-
columnsSwap={noop}
94-
columnsCreateSizeSnapshot={noop}
95-
data={data}
96-
emptyPlaceholderRenderer={useCallback(
97-
(renderWrapper: (children: ReactNode) => ReactElement) => (
98-
<EmptyPlaceholder caption="Empty list message: Place widgets here">
99-
{renderWrapper(null)}
100-
</EmptyPlaceholder>
101-
),
102-
[EmptyPlaceholder]
103-
)}
104-
exporting={false}
105-
filterRenderer={useCallback(
106-
(renderWrapper, columnIndex) => {
107-
const column = props.columns.at(columnIndex);
108-
return column?.filter ? (
109-
<column.filter.renderer caption="Place filter widget here">
84+
<HelpersProvider
85+
value={{
86+
selectActionHelper,
87+
selectionHelper: undefined,
88+
focusController,
89+
cellEventsController: eventsController,
90+
checkboxEventsController: eventsController
91+
}}
92+
>
93+
<Widget
94+
CellComponent={Cell}
95+
className={props.class}
96+
columnsDraggable={props.columnsDraggable}
97+
columnsFilterable={props.columnsFilterable}
98+
columnsHidable={props.columnsHidable}
99+
columnsResizable={props.columnsResizable}
100+
columnsSortable={props.columnsSortable}
101+
visibleColumns={columns}
102+
availableColumns={[]}
103+
columnsSwap={noop}
104+
columnsCreateSizeSnapshot={noop}
105+
data={data}
106+
emptyPlaceholderRenderer={useCallback(
107+
(renderWrapper: (children: ReactNode) => ReactElement) => (
108+
<EmptyPlaceholder caption="Empty list message: Place widgets here">
110109
{renderWrapper(null)}
111-
</column.filter.renderer>
112-
) : (
113-
renderWrapper(null)
114-
);
115-
},
116-
[props.columns]
117-
)}
118-
headerContent={
119-
<props.filtersPlaceholder.renderer caption="Place widgets like filter widget(s) and action button(s) here">
120-
<div />
121-
</props.filtersPlaceholder.renderer>
122-
}
123-
hasMoreItems={false}
124-
headerWrapperRenderer={selectableWrapperRenderer(previewColumns)}
125-
numberOfItems={props.pageSize ?? numberOfItems}
126-
page={0}
127-
paginationType={props.pagination}
128-
pageSize={props.pageSize ?? numberOfItems}
129-
showPagingButtons={props.showPagingButtons}
130-
loadMoreButtonCaption={props.loadMoreButtonCaption}
131-
paging={props.pagination === "buttons"}
132-
pagingPosition={props.pagingPosition}
133-
preview
134-
processedRows={0}
135-
styles={parseStyle(props.style)}
136-
selectionStatus={"none"}
137-
id={gridId}
138-
gridInteractive={!!(props.itemSelection !== "None" || props.onClick)}
139-
selectActionHelper={selectActionHelper}
140-
cellEventsController={eventsController}
141-
checkboxEventsController={eventsController}
142-
focusController={focusController}
143-
/>
110+
</EmptyPlaceholder>
111+
),
112+
[EmptyPlaceholder]
113+
)}
114+
exporting={false}
115+
filterRenderer={useCallback(
116+
(renderWrapper, columnIndex) => {
117+
const column = props.columns.at(columnIndex);
118+
return column?.filter ? (
119+
<column.filter.renderer caption="Place filter widget here">
120+
{renderWrapper(null)}
121+
</column.filter.renderer>
122+
) : (
123+
renderWrapper(null)
124+
);
125+
},
126+
[props.columns]
127+
)}
128+
headerContent={
129+
<props.filtersPlaceholder.renderer caption="Place widgets like filter widget(s) and action button(s) here">
130+
<div />
131+
</props.filtersPlaceholder.renderer>
132+
}
133+
hasMoreItems={false}
134+
headerWrapperRenderer={selectableWrapperRenderer(previewColumns)}
135+
numberOfItems={props.pageSize ?? numberOfItems}
136+
page={0}
137+
paginationType={props.pagination}
138+
pageSize={props.pageSize ?? numberOfItems}
139+
showPagingButtons={props.showPagingButtons}
140+
loadMoreButtonCaption={props.loadMoreButtonCaption}
141+
paging={props.pagination === "buttons"}
142+
pagingPosition={props.pagingPosition}
143+
preview
144+
processedRows={0}
145+
styles={parseStyle(props.style)}
146+
id={gridId}
147+
gridInteractive={!!(props.itemSelection !== "None" || props.onClick)}
148+
/>
149+
</HelpersProvider>
144150
);
145151
}
146152

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

+70-98
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,19 @@
1-
import { useSelectionHelper } from "@mendix/widget-plugin-grid/selection";
1+
import { useOnResetFiltersEvent } from "@mendix/widget-plugin-external-events/hooks";
22
import { generateUUID } from "@mendix/widget-plugin-platform/framework/generate-uuid";
3+
import { observer } from "mobx-react-lite";
34
import { ReactElement, ReactNode, createElement, useCallback, useEffect, useMemo } from "react";
45
import { DatagridContainerProps } from "../typings/DatagridProps";
56
import { Cell } from "./components/Cell";
67
import { Widget } from "./components/Widget";
78
import { WidgetHeaderContext } from "./components/WidgetHeaderContext";
8-
import "./ui/Datagrid.scss";
9-
import { useShowPagination } from "./utils/useShowPagination";
10-
import { useSelectActionHelper } from "./helpers/SelectActionHelper";
11-
import { useClickActionHelper } from "@mendix/widget-plugin-grid/helpers/ClickActionHelper";
12-
import { useCellEventsController } from "./features/row-interaction/CellEventsController";
13-
import { useCheckboxEventsController } from "./features/row-interaction/CheckboxEventsController";
14-
import { useFocusTargetController } from "@mendix/widget-plugin-grid/keyboard-navigation/useFocusTargetController";
15-
import { useOnResetFiltersEvent } from "@mendix/widget-plugin-external-events/hooks";
9+
import { ProgressStore } from "./features/data-export/ProgressStore";
10+
import { useDataExport } from "./features/data-export/useDataExport";
1611
import { IColumnGroupStore } from "./helpers/state/ColumnGroupStore";
17-
import { observer } from "mobx-react-lite";
1812
import { RootGridStore } from "./helpers/state/RootGridStore";
1913
import { useRootStore } from "./helpers/state/useRootStore";
20-
import { useDataExport } from "./features/data-export/useDataExport";
21-
import { ProgressStore } from "./features/data-export/ProgressStore";
14+
import "./ui/Datagrid.scss";
15+
import { useShowPagination } from "./utils/useShowPagination";
16+
import { HelpersProvider, useProvideGridHelpers } from "./helpers/helpers-context";
2217

2318
interface Props extends DatagridContainerProps {
2419
columnsStore: IColumnGroupStore;
@@ -64,96 +59,73 @@ const Container = observer((props: Props): ReactElement => {
6459
[props.datasource, props.pageSize, isInfiniteLoad, currentPage]
6560
);
6661

67-
const selectionHelper = useSelectionHelper(props.itemSelection, props.datasource, props.onSelectionChange);
68-
69-
const selectActionHelper = useSelectActionHelper(props, selectionHelper);
70-
71-
const clickActionHelper = useClickActionHelper({
72-
onClickTrigger: props.onClickTrigger,
73-
onClick: props.onClick
74-
});
7562
useOnResetFiltersEvent(props.rootStore.staticInfo.name, props.rootStore.staticInfo.filtersChannelName);
7663

77-
const visibleColumnsCount = selectActionHelper.showCheckboxColumn
78-
? columnsStore.visibleColumns.length + 1
79-
: columnsStore.visibleColumns.length;
80-
81-
const focusController = useFocusTargetController({
82-
rows: items.length,
83-
columns: visibleColumnsCount,
84-
pageSize: props.pageSize
85-
});
86-
87-
const cellEventsController = useCellEventsController(selectActionHelper, clickActionHelper, focusController);
88-
89-
const checkboxEventsController = useCheckboxEventsController(selectActionHelper, focusController);
64+
const helpers = useProvideGridHelpers(props);
9065

9166
return (
92-
<Widget
93-
className={props.class}
94-
CellComponent={Cell}
95-
columnsDraggable={props.columnsDraggable}
96-
columnsFilterable={props.columnsFilterable}
97-
columnsHidable={props.columnsHidable}
98-
columnsResizable={props.columnsResizable}
99-
columnsSortable={props.columnsSortable}
100-
data={items}
101-
emptyPlaceholderRenderer={useCallback(
102-
(renderWrapper: (children: ReactNode) => ReactElement) =>
103-
props.showEmptyPlaceholder === "custom" ? renderWrapper(props.emptyPlaceholder) : <div />,
104-
[props.emptyPlaceholder, props.showEmptyPlaceholder]
105-
)}
106-
filterRenderer={useCallback(
107-
(renderWrapper, columnIndex) => {
108-
const columnFilter = columnsStore.columnFilters[columnIndex];
109-
return renderWrapper(columnFilter.renderFilterWidgets());
110-
},
111-
[columnsStore.columnFilters]
112-
)}
113-
headerTitle={props.filterSectionTitle?.value}
114-
headerContent={
115-
props.filtersPlaceholder && (
116-
<WidgetHeaderContext selectionHelper={selectionHelper} filtersStore={rootStore.headerFiltersStore}>
117-
{props.filtersPlaceholder}
118-
</WidgetHeaderContext>
119-
)
120-
}
121-
hasMoreItems={props.datasource.hasMoreItems ?? false}
122-
headerWrapperRenderer={useCallback((_columnIndex: number, header: ReactElement) => header, [])}
123-
id={useMemo(() => `DataGrid${generateUUID()}`, [])}
124-
numberOfItems={props.datasource.totalCount}
125-
onExportCancel={abortExport}
126-
page={currentPage}
127-
pageSize={props.pageSize}
128-
paginationType={props.pagination}
129-
loadMoreButtonCaption={props.loadMoreButtonCaption?.value}
130-
paging={useShowPagination({
131-
pagination: props.pagination,
132-
showPagingButtons: props.showPagingButtons,
133-
totalCount: props.datasource.totalCount,
134-
limit: props.datasource.limit
135-
})}
136-
pagingPosition={props.pagingPosition}
137-
showPagingButtons={props.showPagingButtons}
138-
rowClass={useCallback((value: any) => props.rowClass?.get(value)?.value ?? "", [props.rowClass])}
139-
gridInteractive={!!(props.itemSelection || props.onClick)}
140-
setPage={setPage}
141-
styles={props.style}
142-
selectionStatus={selectionHelper?.type === "Multi" ? selectionHelper.selectionStatus : "unknown"}
143-
exporting={exportProgress.exporting}
144-
processedRows={exportProgress.loaded}
145-
exportDialogLabel={props.exportDialogLabel?.value}
146-
cancelExportLabel={props.cancelExportLabel?.value}
147-
selectRowLabel={props.selectRowLabel?.value}
148-
visibleColumns={columnsStore.visibleColumns}
149-
availableColumns={columnsStore.availableColumns}
150-
columnsCreateSizeSnapshot={() => columnsStore.createSizeSnapshot()}
151-
columnsSwap={(moved, [target, placement]) => columnsStore.swapColumns(moved, [target, placement])}
152-
selectActionHelper={selectActionHelper}
153-
cellEventsController={cellEventsController}
154-
checkboxEventsController={checkboxEventsController}
155-
focusController={focusController}
156-
/>
67+
<HelpersProvider value={helpers}>
68+
<Widget
69+
className={props.class}
70+
CellComponent={Cell}
71+
columnsDraggable={props.columnsDraggable}
72+
columnsFilterable={props.columnsFilterable}
73+
columnsHidable={props.columnsHidable}
74+
columnsResizable={props.columnsResizable}
75+
columnsSortable={props.columnsSortable}
76+
data={items}
77+
emptyPlaceholderRenderer={useCallback(
78+
(renderWrapper: (children: ReactNode) => ReactElement) =>
79+
props.showEmptyPlaceholder === "custom" ? renderWrapper(props.emptyPlaceholder) : <div />,
80+
[props.emptyPlaceholder, props.showEmptyPlaceholder]
81+
)}
82+
filterRenderer={useCallback(
83+
(renderWrapper, columnIndex) => {
84+
const columnFilter = columnsStore.columnFilters[columnIndex];
85+
return renderWrapper(columnFilter.renderFilterWidgets());
86+
},
87+
[columnsStore.columnFilters]
88+
)}
89+
headerTitle={props.filterSectionTitle?.value}
90+
headerContent={
91+
props.filtersPlaceholder && (
92+
<WidgetHeaderContext filtersStore={rootStore.headerFiltersStore}>
93+
{props.filtersPlaceholder}
94+
</WidgetHeaderContext>
95+
)
96+
}
97+
hasMoreItems={props.datasource.hasMoreItems ?? false}
98+
headerWrapperRenderer={useCallback((_columnIndex: number, header: ReactElement) => header, [])}
99+
id={useMemo(() => `DataGrid${generateUUID()}`, [])}
100+
numberOfItems={props.datasource.totalCount}
101+
onExportCancel={abortExport}
102+
page={currentPage}
103+
pageSize={props.pageSize}
104+
paginationType={props.pagination}
105+
loadMoreButtonCaption={props.loadMoreButtonCaption?.value}
106+
paging={useShowPagination({
107+
pagination: props.pagination,
108+
showPagingButtons: props.showPagingButtons,
109+
totalCount: props.datasource.totalCount,
110+
limit: props.datasource.limit
111+
})}
112+
pagingPosition={props.pagingPosition}
113+
showPagingButtons={props.showPagingButtons}
114+
rowClass={useCallback((value: any) => props.rowClass?.get(value)?.value ?? "", [props.rowClass])}
115+
gridInteractive={!!(props.itemSelection || props.onClick)}
116+
setPage={setPage}
117+
styles={props.style}
118+
exporting={exportProgress.exporting}
119+
processedRows={exportProgress.loaded}
120+
exportDialogLabel={props.exportDialogLabel?.value}
121+
cancelExportLabel={props.cancelExportLabel?.value}
122+
selectRowLabel={props.selectRowLabel?.value}
123+
visibleColumns={columnsStore.visibleColumns}
124+
availableColumns={columnsStore.availableColumns}
125+
columnsCreateSizeSnapshot={() => columnsStore.createSizeSnapshot()}
126+
columnsSwap={(moved, [target, placement]) => columnsStore.swapColumns(moved, [target, placement])}
127+
/>
128+
</HelpersProvider>
157129
);
158130
});
159131

packages/pluggableWidgets/datagrid-web/src/__tests__/perf.spec.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ describe("Datagrid", () => {
5858
});
5959
window.IntersectionObserver = mockIntersectionObserver;
6060
});
61-
it("should not take more then 9s to hide 3 column", async () => {
61+
it("should not take eternity to hide 3 column", async () => {
6262
const props: DatagridContainerProps = {
6363
advanced: false,
6464
name: "datagrid",

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

+13-4
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,32 @@ import { createElement, ReactElement } from "react";
22
import { ObjectItem } from "mendix";
33
import { useFocusTargetProps } from "@mendix/widget-plugin-grid/keyboard-navigation/useFocusTargetProps";
44
import { CellElement, CellElementProps } from "./CellElement";
5-
import { useWidgetProps } from "../helpers/useWidgetProps";
5+
import { useHelpersContext } from "../helpers/helpers-context";
66

77
export type CheckboxCellProps = CellElementProps & {
88
rowIndex: number;
99
lastRow?: boolean;
1010
item: ObjectItem;
11+
interactive: boolean;
12+
selectRowLabel?: string;
1113
};
1214

13-
export function CheckboxCell({ item, rowIndex, lastRow, ...rest }: CheckboxCellProps): ReactElement {
15+
export function CheckboxCell({
16+
item,
17+
rowIndex,
18+
lastRow,
19+
interactive,
20+
selectRowLabel,
21+
...rest
22+
}: CheckboxCellProps): ReactElement {
23+
const { selectActionHelper, checkboxEventsController } = useHelpersContext();
1424
const keyNavProps = useFocusTargetProps<HTMLInputElement>({
1525
columnIndex: 0,
1626
rowIndex
1727
});
1828

19-
const { selectActionHelper, checkboxEventsController, selectRowLabel, gridInteractive } = useWidgetProps();
2029
return (
21-
<CellElement {...rest} clickable={gridInteractive} className="widget-datagrid-col-select" tabIndex={-1}>
30+
<CellElement {...rest} clickable={interactive} className="widget-datagrid-col-select" tabIndex={-1}>
2231
<input
2332
checked={selectActionHelper.isSelected(item)}
2433
type="checkbox"

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

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { ThreeStateCheckBox } from "@mendix/widget-plugin-grid/components/ThreeStateCheckBox";
22
import { Fragment, ReactElement, createElement } from "react";
3-
import { useWidgetProps } from "../helpers/useWidgetProps";
3+
import { useHelpersContext } from "../helpers/helpers-context";
44

55
export function CheckboxColumnHeader(): ReactElement {
6-
const { selectActionHelper, selectionStatus } = useWidgetProps();
6+
const { selectActionHelper, selectionHelper } = useHelpersContext();
77
const { showCheckboxColumn, showSelectAllToggle, onSelectAll } = selectActionHelper;
8+
const selectionStatus = selectionHelper?.type === "Multi" ? selectionHelper.selectionStatus : "unknown";
89

910
if (showCheckboxColumn === false) {
1011
return <Fragment />;

0 commit comments

Comments
 (0)