Skip to content

Commit 81a812c

Browse files
committed
feat: switch remove root store
1 parent 387fb4b commit 81a812c

File tree

18 files changed

+214
-295
lines changed

18 files changed

+214
-295
lines changed

packages/pluggableWidgets/datagrid-web/src/Datagrid.depsContainer.ts

Lines changed: 88 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ type MainGateProps = Pick<
4444
| "clearSelectionButtonLabel"
4545
>;
4646

47+
/** Root Datagrid container that resolve and inject dependencies. */
48+
export const rootContainer = new Container();
49+
4750
/** Tokens to resolve dependencies from the container. */
4851
export const TOKENS = {
4952
basicDate: token<GridBasicData>("GridBasicData"),
@@ -69,45 +72,95 @@ export const TOKENS = {
6972
staticInfo: token<StaticInfo>("StaticInfo")
7073
};
7174

72-
/** Root Datagrid container that resolve and inject dependencies. */
73-
export const rootContainer = new Container();
74-
75-
// Class bindings, must be unique per container.
76-
rootContainer.bind(TOKENS.columnsStore).toInstance(ColumnGroupStore).inContainerScope();
77-
rootContainer.bind(TOKENS.combinedFilter).toInstance(CombinedFilter).inContainerScope();
78-
rootContainer.bind(TOKENS.exportProgressService).toInstance(ProgressStore).inContainerScope();
79-
rootContainer.bind(TOKENS.filterAPI).toInstance(WidgetFilterAPI).inContainerScope();
80-
rootContainer.bind(TOKENS.filterHost).toInstance(CustomFilterHost).inContainerScope();
81-
rootContainer.bind(TOKENS.paramsService).toInstance(DatasourceParamsController).inContainerScope();
82-
rootContainer.bind(TOKENS.personalizationService).toInstance(GridPersonalizationStore).inContainerScope();
83-
rootContainer.bind(TOKENS.query).toInstance(DatasourceController).inContainerScope();
84-
rootContainer.bind(TOKENS.refreshService).toInstance(RefreshController).inContainerScope();
85-
rootContainer.bind(TOKENS.setupService).toInstance(DatagridSetupService).inContainerScope();
86-
rootContainer
87-
.bind(TOKENS.parentChannelName)
88-
.toInstance(() => `datagrid/${generateUUID()}`)
89-
.inContainerScope();
90-
91-
// Inject dependencies
92-
injected(ColumnGroupStore, TOKENS.mainGate, TOKENS.staticInfo, TOKENS.filterHost);
93-
injected(DatasourceController, TOKENS.setupService, TOKENS.mainGate);
94-
injected(DatasourceParamsController, TOKENS.setupService, TOKENS.query, TOKENS.combinedFilter, TOKENS.columnsStore);
95-
injected(DerivedLoaderController, TOKENS.query, TOKENS.exportProgressService, TOKENS.columnsStore, TOKENS.loaderConfig);
96-
injected(GridPersonalizationStore, TOKENS.setupService, TOKENS.mainGate, TOKENS.columnsStore, TOKENS.filterHost);
97-
injected(RefreshController, TOKENS.setupService, TOKENS.query, TOKENS.refreshInterval.optional);
98-
injected(SelectionCountStore, TOKENS.mainGate);
99-
injected(WidgetFilterAPI, TOKENS.parentChannelName, TOKENS.filterHost);
100-
101-
/** Create new container that inherit bindings from root container. */
102-
export function createContainer(): Container {
103-
return new Container().extend(rootContainer);
75+
class DatagridContainer extends Container {
76+
constructor() {
77+
super();
78+
79+
/** Bindings */
80+
81+
// Column store
82+
this.bind(TOKENS.columnsStore).toInstance(ColumnGroupStore).inSingletonScope();
83+
injected(ColumnGroupStore, TOKENS.setupService, TOKENS.mainGate, TOKENS.staticInfo, TOKENS.filterHost);
84+
85+
// Basic data store
86+
this.bind(TOKENS.basicDate).toInstance(GridBasicData).inSingletonScope();
87+
injected(GridBasicData, TOKENS.mainGate);
88+
89+
// Combined filter
90+
this.bind(TOKENS.combinedFilter).toInstance(CombinedFilter).inSingletonScope();
91+
injected(CombinedFilter, TOKENS.setupService, TOKENS.combinedFilterConfig);
92+
93+
// Export progress store
94+
this.bind(TOKENS.exportProgressService).toInstance(ProgressStore).inSingletonScope();
95+
96+
// FilterAPI
97+
this.bind(TOKENS.filterAPI).toInstance(WidgetFilterAPI).inSingletonScope();
98+
injected(WidgetFilterAPI, TOKENS.parentChannelName, TOKENS.filterHost);
99+
100+
// Filter host
101+
this.bind(TOKENS.filterHost).toInstance(CustomFilterHost).inSingletonScope();
102+
103+
// Datasource params service
104+
this.bind(TOKENS.paramsService).toInstance(DatasourceParamsController).inSingletonScope();
105+
injected(
106+
DatasourceParamsController,
107+
TOKENS.setupService,
108+
TOKENS.query,
109+
TOKENS.combinedFilter,
110+
TOKENS.columnsStore
111+
);
112+
113+
// Personalization service
114+
this.bind(TOKENS.personalizationService).toInstance(GridPersonalizationStore).inSingletonScope();
115+
injected(
116+
GridPersonalizationStore,
117+
TOKENS.setupService,
118+
TOKENS.mainGate,
119+
TOKENS.columnsStore,
120+
TOKENS.filterHost
121+
);
122+
123+
// Query service
124+
this.bind(TOKENS.query).toInstance(DatasourceController).inSingletonScope();
125+
injected(DatasourceController, TOKENS.setupService, TOKENS.mainGate);
126+
127+
// Pagination service
128+
this.bind(TOKENS.paginationService).toInstance(PaginationController).inSingletonScope();
129+
injected(PaginationController, TOKENS.setupService, TOKENS.paginationConfig, TOKENS.query);
130+
131+
// Refresh service
132+
this.bind(TOKENS.refreshService).toInstance(RefreshController).inSingletonScope();
133+
injected(RefreshController, TOKENS.setupService, TOKENS.query, TOKENS.refreshInterval.optional);
134+
135+
// Setup service
136+
this.bind(TOKENS.setupService).toInstance(DatagridSetupService).inSingletonScope();
137+
138+
// Events channel for child widgets
139+
this.bind(TOKENS.parentChannelName)
140+
.toInstance(() => `datagrid/${generateUUID()}`)
141+
.inSingletonScope();
142+
143+
// Loader view model
144+
this.bind(TOKENS.loaderViewModel).toInstance(DerivedLoaderController).inSingletonScope();
145+
injected(
146+
DerivedLoaderController,
147+
TOKENS.query,
148+
TOKENS.exportProgressService,
149+
TOKENS.columnsStore,
150+
TOKENS.loaderConfig
151+
);
152+
153+
// Selection counter view model
154+
this.bind(TOKENS.selectionCounter).toInstance(SelectionCountStore).inSingletonScope();
155+
injected(SelectionCountStore, TOKENS.mainGate);
156+
}
104157
}
105158

106159
export function useDatagridDepsContainer(props: DatagridContainerProps): Container {
107160
const [container, mainGateProvider] = useConst(
108161
/** Function to clone container and setup prop dependant bindings. */
109162
function init(): [Container, GateProvider<MainGateProps>] {
110-
const container = createContainer();
163+
const container = new DatagridContainer();
111164
const exportProgress = container.get(TOKENS.exportProgressService);
112165
const gateProvider = new ClosableGateProvider<MainGateProps>(props, () => exportProgress.exporting);
113166

@@ -142,9 +195,10 @@ export function useDatagridDepsContainer(props: DatagridContainerProps): Contain
142195
pageSize: props.pageSize
143196
});
144197

145-
// Create internal services
198+
// Make sure essential services are created upfront
146199
container.get(TOKENS.refreshService);
147200
container.get(TOKENS.paramsService);
201+
container.get(TOKENS.paginationService);
148202

149203
// Hydrate filters from props
150204
container.get(TOKENS.combinedFilter).hydrate(props.datasource.filter);

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,8 @@ import { ColumnsPreviewType, DatagridPreviewProps } from "typings/DatagridProps"
1515
import { Cell } from "./components/Cell";
1616
import { Widget } from "./components/Widget";
1717
import { ColumnPreview } from "./helpers/ColumnPreview";
18-
import { DatagridContext } from "./helpers/root-context";
18+
import { LegacyContext } from "./helpers/root-context";
1919
import { useSelectActionHelper } from "./helpers/SelectActionHelper";
20-
import { GridBasicData } from "./helpers/state/GridBasicData";
2120

2221
import { SelectionCountStore } from "@mendix/widget-plugin-grid/selection/stores/SelectionCountStore";
2322
import "./ui/DatagridPreview.scss";
@@ -88,10 +87,8 @@ export function preview(props: DatagridPreviewProps): ReactElement {
8887

8988
const ctx = useConst(() => {
9089
const gateProvider = new GateProvider({});
91-
const basicData = new GridBasicData(gateProvider.gate);
9290
const selectionCountStore = new SelectionCountStore(gateProvider.gate);
9391
return {
94-
basicData,
9592
selectionHelper: undefined,
9693
selectActionHelper,
9794
cellEventsController: eventsController,
@@ -102,7 +99,7 @@ export function preview(props: DatagridPreviewProps): ReactElement {
10299
});
103100

104101
return (
105-
<DatagridContext.Provider value={ctx}>
102+
<LegacyContext.Provider value={ctx}>
106103
<Widget
107104
CellComponent={Cell}
108105
className={props.class}
@@ -167,7 +164,7 @@ export function preview(props: DatagridPreviewProps): ReactElement {
167164
isFirstLoad={false}
168165
showRefreshIndicator={false}
169166
/>
170-
</DatagridContext.Provider>
167+
</LegacyContext.Provider>
171168
);
172169
}
173170

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

Lines changed: 74 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useClickActionHelper } from "@mendix/widget-plugin-grid/helpers/ClickActionHelper";
22
import { useFocusTargetController } from "@mendix/widget-plugin-grid/keyboard-navigation/useFocusTargetController";
33
import { useSelectionHelper } from "@mendix/widget-plugin-grid/selection";
4+
import { useConst } from "@mendix/widget-plugin-mobx-kit/react/useConst";
45
import { generateUUID } from "@mendix/widget-plugin-platform/framework/generate-uuid";
56
import { ContainerProvider } from "brandi-react";
67
import { observer } from "mobx-react-lite";
@@ -20,6 +21,7 @@ import {
2021
import { useDataExport } from "./features/data-export/useDataExport";
2122
import { useCellEventsController } from "./features/row-interaction/CellEventsController";
2223
import { useCheckboxEventsController } from "./features/row-interaction/CheckboxEventsController";
24+
import { LegacyContext } from "./helpers/root-context";
2325
import { useSelectActionHelper } from "./helpers/SelectActionHelper";
2426
import { useDataGridJSActions } from "./helpers/useDataGridJSActions";
2527

@@ -64,67 +66,77 @@ const DatagridRoot = observer((props: DatagridContainerProps): ReactElement => {
6466
const checkboxEventsController = useCheckboxEventsController(selectActionHelper, focusController);
6567

6668
return (
67-
<Widget
68-
className={props.class}
69-
CellComponent={Cell}
70-
columnsDraggable={props.columnsDraggable}
71-
columnsFilterable={props.columnsFilterable}
72-
columnsHidable={props.columnsHidable}
73-
columnsResizable={props.columnsResizable}
74-
columnsSortable={props.columnsSortable}
75-
data={items}
76-
emptyPlaceholderRenderer={useCallback(
77-
(renderWrapper: (children: ReactNode) => ReactElement) =>
78-
props.showEmptyPlaceholder === "custom" ? renderWrapper(props.emptyPlaceholder) : <div />,
79-
[props.emptyPlaceholder, props.showEmptyPlaceholder]
80-
)}
81-
filterRenderer={useCallback(
82-
(renderWrapper, columnIndex) => {
83-
const columnFilter = columnsStore.columnFilters[columnIndex];
84-
return renderWrapper(columnFilter.renderFilterWidgets());
85-
},
86-
[columnsStore.columnFilters]
87-
)}
88-
headerTitle={props.filterSectionTitle?.value}
89-
headerContent={
90-
props.filtersPlaceholder && (
91-
<WidgetHeaderContext selectionHelper={selectionHelper}>
92-
{props.filtersPlaceholder}
93-
</WidgetHeaderContext>
94-
)
95-
}
96-
hasMoreItems={props.datasource.hasMoreItems ?? false}
97-
headerWrapperRenderer={useCallback((_columnIndex: number, header: ReactElement) => header, [])}
98-
id={useMemo(() => `DataGrid${generateUUID()}`, [])}
99-
numberOfItems={props.datasource.totalCount}
100-
onExportCancel={abortExport}
101-
page={paginationService.currentPage}
102-
pageSize={props.pageSize}
103-
paginationType={props.pagination}
104-
loadMoreButtonCaption={props.loadMoreButtonCaption?.value}
105-
selectionCountPosition={props.selectionCountPosition}
106-
paging={paginationService.showPagination}
107-
pagingPosition={props.pagingPosition}
108-
showPagingButtons={props.showPagingButtons}
109-
rowClass={useCallback((value: any) => props.rowClass?.get(value)?.value ?? "", [props.rowClass])}
110-
setPage={paginationService.setPage}
111-
styles={props.style}
112-
exporting={exportProgress.exporting}
113-
processedRows={exportProgress.loaded}
114-
visibleColumns={columnsStore.visibleColumns}
115-
availableColumns={columnsStore.availableColumns}
116-
setIsResizing={(status: boolean) => columnsStore.setIsResizing(status)}
117-
columnsSwap={(moved, [target, placement]) => columnsStore.swapColumns(moved, [target, placement])}
118-
selectActionHelper={selectActionHelper}
119-
cellEventsController={cellEventsController}
120-
checkboxEventsController={checkboxEventsController}
121-
focusController={focusController}
122-
isFirstLoad={loaderVM.isFirstLoad}
123-
isFetchingNextBatch={loaderVM.isFetchingNextBatch}
124-
showRefreshIndicator={loaderVM.showRefreshIndicator}
125-
loadingType={props.loadingType}
126-
columnsLoading={!columnsStore.loaded}
127-
/>
69+
<LegacyContext.Provider
70+
value={useConst({
71+
selectionHelper,
72+
selectActionHelper,
73+
cellEventsController,
74+
checkboxEventsController,
75+
focusController
76+
})}
77+
>
78+
<Widget
79+
className={props.class}
80+
CellComponent={Cell}
81+
columnsDraggable={props.columnsDraggable}
82+
columnsFilterable={props.columnsFilterable}
83+
columnsHidable={props.columnsHidable}
84+
columnsResizable={props.columnsResizable}
85+
columnsSortable={props.columnsSortable}
86+
data={items}
87+
emptyPlaceholderRenderer={useCallback(
88+
(renderWrapper: (children: ReactNode) => ReactElement) =>
89+
props.showEmptyPlaceholder === "custom" ? renderWrapper(props.emptyPlaceholder) : <div />,
90+
[props.emptyPlaceholder, props.showEmptyPlaceholder]
91+
)}
92+
filterRenderer={useCallback(
93+
(renderWrapper, columnIndex) => {
94+
const columnFilter = columnsStore.columnFilters[columnIndex];
95+
return renderWrapper(columnFilter.renderFilterWidgets());
96+
},
97+
[columnsStore.columnFilters]
98+
)}
99+
headerTitle={props.filterSectionTitle?.value}
100+
headerContent={
101+
props.filtersPlaceholder && (
102+
<WidgetHeaderContext selectionHelper={selectionHelper}>
103+
{props.filtersPlaceholder}
104+
</WidgetHeaderContext>
105+
)
106+
}
107+
hasMoreItems={props.datasource.hasMoreItems ?? false}
108+
headerWrapperRenderer={useCallback((_columnIndex: number, header: ReactElement) => header, [])}
109+
id={useMemo(() => `DataGrid${generateUUID()}`, [])}
110+
numberOfItems={props.datasource.totalCount}
111+
onExportCancel={abortExport}
112+
page={paginationService.currentPage}
113+
pageSize={props.pageSize}
114+
paginationType={props.pagination}
115+
loadMoreButtonCaption={props.loadMoreButtonCaption?.value}
116+
selectionCountPosition={props.selectionCountPosition}
117+
paging={paginationService.showPagination}
118+
pagingPosition={props.pagingPosition}
119+
showPagingButtons={props.showPagingButtons}
120+
rowClass={useCallback((value: any) => props.rowClass?.get(value)?.value ?? "", [props.rowClass])}
121+
setPage={paginationService.setPage}
122+
styles={props.style}
123+
exporting={exportProgress.exporting}
124+
processedRows={exportProgress.loaded}
125+
visibleColumns={columnsStore.visibleColumns}
126+
availableColumns={columnsStore.availableColumns}
127+
setIsResizing={(status: boolean) => columnsStore.setIsResizing(status)}
128+
columnsSwap={(moved, [target, placement]) => columnsStore.swapColumns(moved, [target, placement])}
129+
selectActionHelper={selectActionHelper}
130+
cellEventsController={cellEventsController}
131+
checkboxEventsController={checkboxEventsController}
132+
focusController={focusController}
133+
isFirstLoad={loaderVM.isFirstLoad}
134+
isFetchingNextBatch={loaderVM.isFetchingNextBatch}
135+
showRefreshIndicator={loaderVM.showRefreshIndicator}
136+
loadingType={props.loadingType}
137+
columnsLoading={!columnsStore.loaded}
138+
/>
139+
</LegacyContext.Provider>
128140
);
129141
});
130142

@@ -134,7 +146,7 @@ export default function Datagrid(props: DatagridContainerProps): ReactElement |
134146
const container = useDatagridDepsContainer(props);
135147

136148
return (
137-
<ContainerProvider container={container}>
149+
<ContainerProvider container={container} isolated>
138150
<DatagridRoot {...props} />
139151
</ContainerProvider>
140152
);

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { ReactElement, useMemo } from "react";
2-
import { observer } from "mobx-react-lite";
1+
import { useFocusTargetProps } from "@mendix/widget-plugin-grid/keyboard-navigation/useFocusTargetProps";
32
import { computed } from "mobx";
4-
import { GridColumn } from "../typings/GridColumn";
3+
import { observer } from "mobx-react-lite";
4+
import { ReactElement, useMemo } from "react";
55
import { CellComponentProps } from "../typings/CellComponent";
6+
import { GridColumn } from "../typings/GridColumn";
67
import { CellElement } from "./CellElement";
7-
import { useFocusTargetProps } from "@mendix/widget-plugin-grid/keyboard-navigation/useFocusTargetProps";
88

99
const component = observer(function Cell(props: CellComponentProps<GridColumn>): ReactElement {
1010
const keyNavProps = useFocusTargetProps<HTMLDivElement>({

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { useFocusTargetProps } from "@mendix/widget-plugin-grid/keyboard-navigation/useFocusTargetProps";
22
import { ObjectItem } from "mendix";
33
import { FocusEvent, ReactElement } from "react";
4-
import { useDatagridRootScope } from "../helpers/root-context";
4+
import { useBasicData } from "../deps-hooks";
5+
import { useLegacyContext } from "../helpers/root-context";
56
import { CellElement, CellElementProps } from "./CellElement";
67

78
export type CheckboxCellProps = CellElementProps & {
@@ -16,8 +17,8 @@ export function CheckboxCell({ item, rowIndex, lastRow, ...rest }: CheckboxCellP
1617
rowIndex
1718
});
1819

19-
const { selectActionHelper, checkboxEventsController, basicData } = useDatagridRootScope();
20-
const { selectRowLabel, gridInteractive } = basicData;
20+
const { selectActionHelper, checkboxEventsController } = useLegacyContext();
21+
const { selectRowLabel, gridInteractive } = useBasicData();
2122
return (
2223
<CellElement {...rest} clickable={gridInteractive} className="widget-datagrid-col-select" tabIndex={-1}>
2324
<input

0 commit comments

Comments
 (0)