Skip to content

Commit 979dd4f

Browse files
committed
WIP
1 parent 38cd47a commit 979dd4f

File tree

2 files changed

+60
-25
lines changed

2 files changed

+60
-25
lines changed

packages/pluggableWidgets/datagrid-web/src/features/multi-page-selection/MultiPageSelectionController.ts

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,29 @@
11
import { DatasourceController } from "@mendix/widget-plugin-grid/query/DatasourceController";
2-
import { MultiSelectionHelper, SelectionHelper } from "@mendix/widget-plugin-grid/selection/helpers";
2+
import { MultiSelectionHelper } from "@mendix/widget-plugin-grid/selection/helpers";
3+
import { DerivedPropsGate } from "@mendix/widget-plugin-mobx-kit/props-gate";
34
import { ReactiveController, ReactiveControllerHost } from "@mendix/widget-plugin-mobx-kit/reactive-controller";
4-
import { ListValue, ObjectItem } from "mendix";
5+
import { ListValue, ObjectItem, SelectionMultiValue, SelectionSingleValue } from "mendix";
56
import { SelectAllProgressStore } from "./SelectAllProgressStore";
67

78
interface MultiPageSelectionControllerSpec {
89
query: DatasourceController;
910
progressStore: SelectAllProgressStore;
11+
gate: Gate;
1012
}
13+
type Gate = DerivedPropsGate<{ itemSelection?: SelectionMultiValue | SelectionSingleValue }>;
1114

1215
export class MultiPageSelectionController implements ReactiveController {
1316
private query: DatasourceController;
1417
private progressStore: SelectAllProgressStore;
1518
private abortController?: AbortController;
1619
private locked = false;
20+
private gate: Gate;
1721

1822
constructor(host: ReactiveControllerHost, spec: MultiPageSelectionControllerSpec) {
1923
host.addController(this);
2024
this.query = spec.query;
2125
this.progressStore = spec.progressStore;
26+
this.gate = spec.gate;
2227
}
2328

2429
get isRunning(): boolean {
@@ -43,12 +48,12 @@ export class MultiPageSelectionController implements ReactiveController {
4348
/**
4449
* Starts the multi-page selection process
4550
*/
46-
async selectAllPages(datasource: ListValue, selectionHelper: SelectionHelper): Promise<boolean> {
51+
async selectAllPages(): Promise<boolean> {
4752
if (this.locked) {
4853
return false;
4954
}
5055

51-
if (selectionHelper.type !== "Multi") {
56+
if (!this.gate.props.itemSelection || this.gate.props.itemSelection.type !== "Multi") {
5257
return false;
5358
}
5459

@@ -75,11 +80,20 @@ export class MultiPageSelectionController implements ReactiveController {
7580

7681
// Use controller-based traversal to properly handle pagination
7782
const naturalChunkSize = datasource.limit ?? 25;
78-
if (selectionHelper.type !== "Multi") {
79-
throw new Error("Expected MultiSelectionHelper");
80-
}
83+
8184
const multiHelper = selectionHelper;
82-
await this.selectAllWithController(multiHelper, totalCount, naturalChunkSize);
85+
const originalOffset = this.query.offset;
86+
const originalLimit = this.query.limit;
87+
const allItems: ObjectItem[] = [];
88+
89+
const limit = 100;
90+
const offset = 0;
91+
92+
while (this.query.datasource.hasMoreItems) {
93+
const page = await this.query.fetchPage({ limit, offset, signal: this.abortController.signal });
94+
allItems.push(...page);
95+
}
96+
this.gate.props.itemSelection.setSelection(allItems);
8397

8498
success = true;
8599
} catch (_error) {
@@ -176,8 +190,7 @@ export class MultiPageSelectionController implements ReactiveController {
176190
}
177191

178192
// First, set the selection while we have all the items
179-
(multiHelper as any).selectionValue.setSelection(allItems);
180-
(multiHelper as any)._resetRange();
193+
this.query.datasource(multiHelper as any)._resetRange();
181194

182195
// Small delay to ensure selection is committed
183196
await new Promise(resolve => setTimeout(resolve, 50));
@@ -192,19 +205,19 @@ export class MultiPageSelectionController implements ReactiveController {
192205
/**
193206
* Waits for the datasource to reflect the controller changes
194207
*/
195-
private async waitForDatasourceUpdate(
196-
expectedOffset: number,
197-
expectedLimit: number,
198-
maxAttempts = 20
199-
): Promise<void> {
200-
for (let i = 0; i < maxAttempts; i++) {
201-
const ds = this.query.datasource;
202-
if (ds.status !== "loading" && ds.offset === expectedOffset && ds.limit === expectedLimit) {
203-
return;
204-
}
205-
await new Promise(resolve => setTimeout(resolve, 50));
206-
}
207-
}
208+
// private async waitForDatasourceUpdate(
209+
// expectedOffset: number,
210+
// expectedLimit: number,
211+
// maxAttempts = 20
212+
// ): Promise<void> {
213+
// for (let i = 0; i < maxAttempts; i++) {
214+
// const ds = this.query.datasource;
215+
// if (ds.status !== "loading" && ds.offset === expectedOffset && ds.limit === expectedLimit) {
216+
// return;
217+
// }
218+
// await new Promise(resolve => setTimeout(resolve, 50));
219+
// }
220+
// }
208221

209222
/**
210223
* Ensures totalCount is available, requesting it if necessary

packages/shared/widget-plugin-grid/src/query/DatasourceController.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { disposeBatch } from "@mendix/widget-plugin-mobx-kit/disposeBatch";
22
import { DerivedPropsGate } from "@mendix/widget-plugin-mobx-kit/props-gate";
33
import { ReactiveController, ReactiveControllerHost } from "@mendix/widget-plugin-mobx-kit/reactive-controller";
4-
import { ListValue, ValueStatus } from "mendix";
5-
import { action, autorun, computed, IComputedValue, makeAutoObservable } from "mobx";
4+
import { ListValue, ObjectItem, ValueStatus } from "mendix";
5+
import { action, autorun, computed, IComputedValue, makeAutoObservable, when } from "mobx";
66
import { QueryController } from "./query-controller";
77

88
type Gate = DerivedPropsGate<{ datasource: ListValue }>;
@@ -164,4 +164,26 @@ export class DatasourceController implements ReactiveController, QueryController
164164
setPageSize(size: number): void {
165165
this.pageSize = size;
166166
}
167+
168+
fetchPage(limit: number, offset: number, signal: AbortSignal): Promise<ObjectItem[]> {
169+
return new Promise((resolve, reject) => {
170+
if (signal.aborted) {
171+
return reject(signal.reason);
172+
}
173+
174+
const predicate = when(
175+
() =>
176+
this.datasource.offset === offset &&
177+
this.datasource.limit === limit &&
178+
this.datasource.status === "available"
179+
);
180+
181+
predicate.then(() => resolve(this.datasource.items ?? [])).catch(reject);
182+
183+
this.datasource.setOffset(offset);
184+
this.datasource.setLimit(limit);
185+
186+
signal.addEventListener("abort", () => predicate.cancel());
187+
});
188+
}
167189
}

0 commit comments

Comments
 (0)