1
1
import { DerivedPropsGate } from "@mendix/widget-plugin-mobx-kit/props-gate" ;
2
2
import { ReactiveController , ReactiveControllerHost } from "@mendix/widget-plugin-mobx-kit/reactive-controller" ;
3
3
import { ObjectItem , SelectionMultiValue , SelectionSingleValue } from "mendix" ;
4
- import { action , computed , makeObservable , observable } from "mobx" ;
4
+ import { action , computed , makeObservable , observable , when } from "mobx" ;
5
5
import { QueryController } from "../query/query-controller" ;
6
6
7
7
type Gate = DerivedPropsGate < { itemSelection ?: SelectionMultiValue | SelectionSingleValue } > ;
@@ -19,7 +19,7 @@ export class SelectAllController implements ReactiveController {
19
19
private readonly query : QueryController ;
20
20
private abortController ?: AbortController ;
21
21
private locked = false ;
22
- readonly pageSize : number = 500 ;
22
+ readonly pageSize : number = 1024 ;
23
23
private readonly emitter = new EventTarget ( ) ;
24
24
25
25
constructor ( host : ReactiveControllerHost , spec : SelectAllControllerSpec ) {
@@ -32,6 +32,7 @@ export class SelectAllController implements ReactiveController {
32
32
setIsLocked : action ,
33
33
canExecute : computed ,
34
34
isExecuting : computed ,
35
+ selection : computed ,
35
36
locked : observable ,
36
37
selectAllPages : action ,
37
38
clearSelection : action ,
@@ -51,13 +52,10 @@ export class SelectAllController implements ReactiveController {
51
52
this . emitter . removeEventListener ( type , listener ) ;
52
53
}
53
54
54
- /**
55
- * @throws if selection is undefined or single
56
- */
57
- selection ( ) : SelectionMultiValue {
55
+ get selection ( ) : SelectionMultiValue | undefined {
58
56
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 ;
61
59
return selection ;
62
60
}
63
61
@@ -100,11 +98,11 @@ export class SelectAllController implements ReactiveController {
100
98
this . setIsLocked ( true ) ;
101
99
102
100
const { offset : initOffset , limit : initLimit } = this . query ;
103
- const initSelection = this . selection ( ) . selection ;
104
101
const hasTotal = typeof this . query . totalCount === "number" ;
105
102
const totalCount = this . query . totalCount ?? 0 ;
106
103
let loaded = 0 ;
107
104
let offset = 0 ;
105
+ let success = false ;
108
106
const pe = ( type : SelectAllEventType ) : ProgressEvent =>
109
107
new ProgressEvent ( type , { loaded, total : totalCount , lengthComputable : hasTotal } ) ;
110
108
// We should avoid duplicates, so, we start with clean array.
@@ -129,32 +127,50 @@ export class SelectAllController implements ReactiveController {
129
127
this . emitter . dispatchEvent ( pe ( "progress" ) ) ;
130
128
loading = ! signal . aborted && this . query . hasMoreItems ;
131
129
}
132
- // Set allItems on success
133
- this . selection ( ) . setSelection ( allItems ) ;
130
+ success = true ;
134
131
} catch ( error ) {
135
132
if ( ! signal . aborted ) {
136
- throw error ;
133
+ console . error ( "SelectAllController: an error was encountered during the 'select all' action." ) ;
134
+ console . error ( error ) ;
137
135
}
138
- // Restore selection on abort
139
- this . selection ( ) . setSelection ( initSelection ) ;
140
136
} 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
+
144
144
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 ) ;
145
154
this . abortController = undefined ;
146
155
performance . mark ( "SelectAll_End" ) ;
147
156
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. ` ) ;
149
158
}
150
159
}
151
160
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
+
152
168
clearSelection ( ) : void {
153
169
if ( this . locked ) {
154
170
console . debug ( "SelectAllController: can't clear selection while executing." ) ;
155
171
return ;
156
172
}
157
- this . selection ( ) . setSelection ( [ ] ) ;
173
+ this . selection ? .setSelection ( [ ] ) ;
158
174
}
159
175
160
176
abort ( ) : void {
0 commit comments