Skip to content

Commit 340421b

Browse files
committed
refactor: implement ds reset
1 parent ac6e018 commit 340421b

File tree

6 files changed

+73
-48
lines changed

6 files changed

+73
-48
lines changed

packages/modules/data-widgets/src/themesource/datawidgets/web/_datagrid.scss

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -420,8 +420,7 @@ $root: ".widget-datagrid";
420420
align-items: center;
421421
}
422422

423-
&-exporting,
424-
&-selecting-all-pages {
423+
&-exporting {
425424
.widget-datagrid-top-bar,
426425
.widget-datagrid-header,
427426
.widget-datagrid-content,
@@ -435,28 +434,28 @@ $root: ".widget-datagrid";
435434
}
436435

437436
// Better positioning for multi-page selection modal
438-
&-selecting-all-pages {
439-
.widget-datagrid-modal {
440-
&-overlay {
441-
position: fixed;
442-
top: 0;
443-
right: 0;
444-
bottom: 0;
445-
left: 0;
446-
}
447-
448-
&-main {
449-
position: fixed;
450-
top: 0;
451-
left: 0;
452-
right: 0;
453-
bottom: 0;
454-
display: flex;
455-
align-items: center;
456-
justify-content: center;
457-
}
458-
}
459-
}
437+
// &-selecting-all-pages {
438+
// .widget-datagrid-modal {
439+
// &-overlay {
440+
// position: fixed;
441+
// top: 0;
442+
// right: 0;
443+
// bottom: 0;
444+
// left: 0;
445+
// }
446+
447+
// &-main {
448+
// position: fixed;
449+
// top: 0;
450+
// left: 0;
451+
// right: 0;
452+
// bottom: 0;
453+
// display: flex;
454+
// align-items: center;
455+
// justify-content: center;
456+
// }
457+
// }
458+
// }
460459

461460
&-col-select input:focus-visible {
462461
outline-offset: 0;
@@ -591,6 +590,9 @@ $root: ".widget-datagrid";
591590
padding: 0;
592591
display: inline-block;
593592
}
593+
:where(#{$root}-select-all-bar) {
594+
grid-column: 1 / -1;
595+
}
594596

595597
@keyframes skeleton-loading {
596598
0% {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const Container = observer((props: Props): ReactElement => {
3030
const { columnsStore, rootStore } = props;
3131
const { paginationCtrl } = rootStore;
3232

33-
const items = props.datasource.items ?? [];
33+
const items = rootStore.query.items ?? [];
3434

3535
const [exportProgress, abortExport] = useDataExport(props, props.columnsStore, props.progressStore);
3636

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export const SelectAllBar = observer(function SelectAllBar(): React.ReactNode {
1313
if (selectionStatus === "none") return null;
1414

1515
return (
16-
<div>
16+
<div className="widget-datagrid-select-all-bar">
1717
<button onClick={() => selectAllController.selectAllPages()}>Select remaining</button>
1818
</div>
1919
);

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,17 +169,23 @@ export class DatasourceController implements ReactiveController, QueryController
169169
this.pageSize = size;
170170
}
171171

172+
reload(): Promise<void> {
173+
const ds = this.datasource;
174+
this.datasource.reload();
175+
return when(() => this.datasource !== ds);
176+
}
177+
172178
fetchPage({
173179
limit,
174180
offset,
175181
signal
176182
}: {
177183
limit: number;
178184
offset: number;
179-
signal: AbortSignal;
185+
signal?: AbortSignal;
180186
}): Promise<ObjectItem[]> {
181187
return new Promise((resolve, reject) => {
182-
if (signal.aborted) {
188+
if (signal && signal.aborted) {
183189
return reject(signal.reason);
184190
}
185191

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,6 @@ export interface QueryController extends Pick<ListValue, Members> {
1919
isFirstLoad: boolean;
2020
isRefreshing: boolean;
2121
isFetchingNextBatch: boolean;
22-
fetchPage(params: { limit: number; offset: number; signal: AbortSignal }): Promise<ObjectItem[]>;
22+
fetchPage(params: { limit: number; offset: number; signal?: AbortSignal }): Promise<ObjectItem[]>;
23+
reload(): Promise<void>;
2324
}

packages/shared/widget-plugin-grid/src/select-all/SelectAllController.ts

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { DerivedPropsGate } from "@mendix/widget-plugin-mobx-kit/props-gate";
22
import { ReactiveController, ReactiveControllerHost } from "@mendix/widget-plugin-mobx-kit/reactive-controller";
33
import { ObjectItem, SelectionMultiValue, SelectionSingleValue } from "mendix";
4-
import { action, computed, makeObservable, observable } from "mobx";
4+
import { action, computed, makeObservable, observable, when } from "mobx";
55
import { QueryController } from "../query/query-controller";
66

77
type Gate = DerivedPropsGate<{ itemSelection?: SelectionMultiValue | SelectionSingleValue }>;
@@ -19,7 +19,7 @@ export class SelectAllController implements ReactiveController {
1919
private readonly query: QueryController;
2020
private abortController?: AbortController;
2121
private locked = false;
22-
readonly pageSize: number = 500;
22+
readonly pageSize: number = 1024;
2323
private readonly emitter = new EventTarget();
2424

2525
constructor(host: ReactiveControllerHost, spec: SelectAllControllerSpec) {
@@ -32,6 +32,7 @@ export class SelectAllController implements ReactiveController {
3232
setIsLocked: action,
3333
canExecute: computed,
3434
isExecuting: computed,
35+
selection: computed,
3536
locked: observable,
3637
selectAllPages: action,
3738
clearSelection: action,
@@ -51,13 +52,10 @@ export class SelectAllController implements ReactiveController {
5152
this.emitter.removeEventListener(type, listener);
5253
}
5354

54-
/**
55-
* @throws if selection is undefined or single
56-
*/
57-
selection(): SelectionMultiValue {
55+
get selection(): SelectionMultiValue | undefined {
5856
const selection = this.gate.props.itemSelection;
59-
if (selection === undefined) throw new Error("SelectAllController: selection is undefined.");
60-
if (selection.type === "Single") throw new Error("SelectAllController: single selection is not supported.");
57+
if (selection === undefined) return;
58+
if (selection.type === "Single") return;
6159
return selection;
6260
}
6361

@@ -100,11 +98,11 @@ export class SelectAllController implements ReactiveController {
10098
this.setIsLocked(true);
10199

102100
const { offset: initOffset, limit: initLimit } = this.query;
103-
const initSelection = this.selection().selection;
104101
const hasTotal = typeof this.query.totalCount === "number";
105102
const totalCount = this.query.totalCount ?? 0;
106103
let loaded = 0;
107104
let offset = 0;
105+
let success = false;
108106
const pe = (type: SelectAllEventType): ProgressEvent =>
109107
new ProgressEvent(type, { loaded, total: totalCount, lengthComputable: hasTotal });
110108
// We should avoid duplicates, so, we start with clean array.
@@ -129,32 +127,50 @@ export class SelectAllController implements ReactiveController {
129127
this.emitter.dispatchEvent(pe("progress"));
130128
loading = !signal.aborted && this.query.hasMoreItems;
131129
}
132-
// Set allItems on success
133-
this.selection().setSelection(allItems);
130+
success = true;
134131
} catch (error) {
135132
if (!signal.aborted) {
136-
throw error;
133+
console.error("SelectAllController: an error was encountered during the 'select all' action.");
134+
console.error(error);
137135
}
138-
// Restore selection on abort
139-
this.selection().setSelection(initSelection);
140136
} finally {
141-
this.query.setOffset(initOffset);
142-
this.query.setLimit(initLimit);
143-
this.locked = false;
137+
// Restore init view
138+
// This step should be done before loadend to avoid UI flickering
139+
await this.query.fetchPage({
140+
limit: initLimit,
141+
offset: initOffset
142+
});
143+
144144
this.emitter.dispatchEvent(pe("loadend"));
145+
146+
const selectionBeforeReload = this.selection?.selection ?? [];
147+
// Reload selection to make sure setSelection is working as expected.
148+
await this.reloadSelection();
149+
150+
this.selection?.setSelection(success ? allItems : selectionBeforeReload);
151+
152+
this.locked = false;
153+
console.info(success, initLimit, initOffset);
145154
this.abortController = undefined;
146155
performance.mark("SelectAll_End");
147156
const measure1 = performance.measure("Measure1", "SelectAll_Start", "SelectAll_End");
148-
console.debug(`Data grid 2: select all took ${(measure1.duration / 1000).toFixed(2)} seconds`);
157+
console.debug(`Data grid 2: 'select all' took ${(measure1.duration / 1000).toFixed(2)} seconds.`);
149158
}
150159
}
151160

161+
reloadSelection(): Promise<void> {
162+
const selection = this.selection;
163+
selection?.setSelection([]);
164+
// Resolve when selection value is updated
165+
return when(() => this.selection !== selection);
166+
}
167+
152168
clearSelection(): void {
153169
if (this.locked) {
154170
console.debug("SelectAllController: can't clear selection while executing.");
155171
return;
156172
}
157-
this.selection().setSelection([]);
173+
this.selection?.setSelection([]);
158174
}
159175

160176
abort(): void {

0 commit comments

Comments
 (0)