@genesislcap/grid-pro 14.480.0 → 14.481.1-alpha-69af5f8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/custom-elements.json +327 -7
- package/dist/dts/datasource/server-side.datasource.d.ts.map +1 -1
- package/dist/dts/datasource/server-side.resource-base.d.ts +26 -2
- package/dist/dts/datasource/server-side.resource-base.d.ts.map +1 -1
- package/dist/dts/datasource/server-side.resource-dataserver.d.ts +7 -1
- package/dist/dts/datasource/server-side.resource-dataserver.d.ts.map +1 -1
- package/dist/dts/datasource/server-side.resource-reqrep.d.ts +1 -1
- package/dist/dts/datasource/server-side.resource-reqrep.d.ts.map +1 -1
- package/dist/esm/datasource/server-side.datasource.js +13 -2
- package/dist/esm/datasource/server-side.resource-base.js +204 -135
- package/dist/esm/datasource/server-side.resource-dataserver.js +205 -23
- package/dist/esm/datasource/server-side.resource-reqrep.js +3 -2
- package/package.json +14 -14
|
@@ -24,6 +24,12 @@ export class BaseServerSideDatasource {
|
|
|
24
24
|
this.moreRows = false;
|
|
25
25
|
this.calculatedRowsCount = 0;
|
|
26
26
|
this.currentSequenceId = null;
|
|
27
|
+
/**
|
|
28
|
+
* Whether the corrective ROWS_COUNT snapshot() has already resolved for the current
|
|
29
|
+
* CRITERIA_MATCH. Reset in destroy() so it re-resolves whenever the filter/sort changes.
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
32
|
+
this.criteriaRowCountResolved = false;
|
|
27
33
|
this.reloadResourceDataFunc = options.reloadResourceDataFunc;
|
|
28
34
|
this.errorHandlerFunc = options.errorHandlerFunc;
|
|
29
35
|
this.onNoDataAvailableFunc = options.onNoDataAvailableFunc;
|
|
@@ -79,6 +85,10 @@ export class BaseServerSideDatasource {
|
|
|
79
85
|
/**
|
|
80
86
|
* Handles filtering setup for server-side datasources.
|
|
81
87
|
* Common logic used by both dataserver and req-rep implementations.
|
|
88
|
+
*
|
|
89
|
+
* @returns `true` when a filter change triggered {@link refreshDatasource} - in that case
|
|
90
|
+
* the current getRows() request is superseded and the caller MUST stop processing it
|
|
91
|
+
* (see the corresponding handling in the dataserver implementation's getRows()).
|
|
82
92
|
*/
|
|
83
93
|
setupFiltering(params) {
|
|
84
94
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -91,15 +101,21 @@ export class BaseServerSideDatasource {
|
|
|
91
101
|
this.currentFilterModel = null;
|
|
92
102
|
this.setResourceParam('CRITERIA_MATCH', this.originalCriteriaMatch);
|
|
93
103
|
yield this.refreshDatasource(params);
|
|
94
|
-
|
|
104
|
+
// A refresh was triggered and this request is superseded: refreshDatasource() ->
|
|
105
|
+
// reloadResourceDataFunc has already re-initialized the underlying datasource and
|
|
106
|
+
// purged AG Grid's SSRM cache, so AG Grid re-invokes getRows() with fresh params
|
|
107
|
+
// on its own. Continuing with THIS invocation's stale params would attach a
|
|
108
|
+
// duplicate subscription to the freshly-created stream.
|
|
109
|
+
return true;
|
|
95
110
|
}
|
|
96
111
|
else if (filterModelBeingAppliedDiffersFromCurrent && filtersAreBeingApplied) {
|
|
97
112
|
this.currentFilterModel = filterModelBeingApplied;
|
|
98
113
|
this.setResourceParam('CRITERIA_MATCH', this.buildCriteriaMatchFromFilters());
|
|
99
114
|
yield this.refreshDatasource(params);
|
|
100
|
-
return;
|
|
115
|
+
return true;
|
|
101
116
|
}
|
|
102
117
|
}
|
|
118
|
+
return false;
|
|
103
119
|
});
|
|
104
120
|
}
|
|
105
121
|
/**
|
|
@@ -122,6 +138,7 @@ export class BaseServerSideDatasource {
|
|
|
122
138
|
this.moreRows = false;
|
|
123
139
|
this.sourceRef = undefined;
|
|
124
140
|
this.lastSuccessRowData = undefined;
|
|
141
|
+
this.criteriaRowCountResolved = false;
|
|
125
142
|
}
|
|
126
143
|
refreshDatasource(params) {
|
|
127
144
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -173,142 +190,184 @@ export class BaseServerSideDatasource {
|
|
|
173
190
|
criteriaFromFilters() {
|
|
174
191
|
const filters = [];
|
|
175
192
|
this.getFiltersByType('text').forEach((k) => {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
filters.push(
|
|
179
|
-
}
|
|
180
|
-
else {
|
|
181
|
-
switch (this.currentFilterModel[k].type) {
|
|
182
|
-
case 'blank':
|
|
183
|
-
filters.push(`(${k} == '' || ${k} == null)`);
|
|
184
|
-
break;
|
|
185
|
-
case 'contains':
|
|
186
|
-
filters.push(`Expr.containsIgnoreCase(${k}, '${this.currentFilterModel[k].filter}')`);
|
|
187
|
-
break;
|
|
188
|
-
case 'equals':
|
|
189
|
-
filters.push(`${k} == '${this.currentFilterModel[k].filter}'`);
|
|
190
|
-
break;
|
|
191
|
-
case 'notBlank':
|
|
192
|
-
filters.push(`(${k} != '' && ${k} != null)`);
|
|
193
|
-
break;
|
|
194
|
-
case 'notEqual':
|
|
195
|
-
filters.push(`${k} != '${this.currentFilterModel[k].filter}'`);
|
|
196
|
-
break;
|
|
197
|
-
case 'wordStartsWith':
|
|
198
|
-
filters.push(`Expr.containsWordsStartingWithIgnoreCase(${k}, '${this.currentFilterModel[k].filter}')`);
|
|
199
|
-
break;
|
|
200
|
-
}
|
|
193
|
+
const fragment = this.criteriaForSingleModel(k, this.currentFilterModel[k]);
|
|
194
|
+
if (fragment) {
|
|
195
|
+
filters.push(fragment);
|
|
201
196
|
}
|
|
202
197
|
});
|
|
203
|
-
// TODO: Handle multi filters if we decide we want to use them in SSRM
|
|
204
198
|
// Handle set filters (typically used for enum fields with ag-set-column-filter)
|
|
205
199
|
this.getFiltersByType('set').forEach((k) => {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
if (!selectedValues || selectedValues.length === 0) {
|
|
210
|
-
// Nothing selected means no additional criteria
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
// Try to detect "all values selected" using VALID_VALUES from metadata.
|
|
214
|
-
// In that case we don't want to send any criteria, as it would be equivalent
|
|
215
|
-
// to no filter at all.
|
|
216
|
-
const colMeta = (_c = this.resourceColDefs) === null || _c === void 0 ? void 0 : _c.find((o) => o.NAME === k);
|
|
217
|
-
let allValues;
|
|
218
|
-
if (colMeta === null || colMeta === void 0 ? void 0 : colMeta.VALID_VALUES) {
|
|
219
|
-
try {
|
|
220
|
-
allValues = Array.isArray(colMeta.VALID_VALUES)
|
|
221
|
-
? colMeta.VALID_VALUES
|
|
222
|
-
: colMeta.VALID_VALUES.split('|');
|
|
223
|
-
}
|
|
224
|
-
catch (_d) {
|
|
225
|
-
allValues = undefined;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
if (allValues &&
|
|
229
|
-
allValues.length === selectedValues.length &&
|
|
230
|
-
allValues.every((v) => selectedValues.includes(v))) {
|
|
231
|
-
// All enum options are selected – skip adding criteria for this column
|
|
232
|
-
return;
|
|
233
|
-
}
|
|
234
|
-
const orConditions = selectedValues.map((val) => {
|
|
235
|
-
const safeVal = String(val).replace(/'/g, "\\'");
|
|
236
|
-
return `${k} == '${safeVal}'`;
|
|
237
|
-
});
|
|
238
|
-
if (orConditions.length > 0) {
|
|
239
|
-
filters.push(`(${orConditions.join(' || ')})`);
|
|
200
|
+
const fragment = this.criteriaForSingleModel(k, this.currentFilterModel[k]);
|
|
201
|
+
if (fragment) {
|
|
202
|
+
filters.push(fragment);
|
|
240
203
|
}
|
|
241
204
|
});
|
|
242
205
|
this.getFiltersByType('number').forEach((k) => {
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
case 'equals':
|
|
247
|
-
!isNaN(value) && filters.push(`${k} == ${value}`);
|
|
248
|
-
break;
|
|
249
|
-
case 'notEqual':
|
|
250
|
-
!isNaN(value) && filters.push(`${k} != ${value}`);
|
|
251
|
-
break;
|
|
252
|
-
case 'greaterThan':
|
|
253
|
-
!isNaN(value) && filters.push(`${k} > ${value}`);
|
|
254
|
-
break;
|
|
255
|
-
case 'greaterThanOrEqual':
|
|
256
|
-
!isNaN(value) && filters.push(`${k} >= ${value}`);
|
|
257
|
-
break;
|
|
258
|
-
case 'lessThan':
|
|
259
|
-
!isNaN(value) && filters.push(`${k} < ${value}`);
|
|
260
|
-
break;
|
|
261
|
-
case 'lessThanOrEqual':
|
|
262
|
-
!isNaN(value) && filters.push(`${k} <= ${value}`);
|
|
263
|
-
break;
|
|
264
|
-
case 'inRange':
|
|
265
|
-
!isNaN(value) &&
|
|
266
|
-
!isNaN(valueTwo) &&
|
|
267
|
-
filters.push(`${k} >= ${value} && ${k} <= ${valueTwo}`);
|
|
268
|
-
break;
|
|
269
|
-
case 'blank':
|
|
270
|
-
filters.push(`${k} == 0`);
|
|
271
|
-
break;
|
|
272
|
-
case 'notBlank':
|
|
273
|
-
filters.push(`${k} != 0`);
|
|
274
|
-
break;
|
|
206
|
+
const fragment = this.criteriaForSingleModel(k, this.currentFilterModel[k]);
|
|
207
|
+
if (fragment) {
|
|
208
|
+
filters.push(fragment);
|
|
275
209
|
}
|
|
276
210
|
});
|
|
277
211
|
this.getFiltersByType('date').forEach((k) => {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
filters.push(`Expr.dateIsEqual(${k}, '${todayStr}')`);
|
|
301
|
-
break;
|
|
302
|
-
case 'blank':
|
|
303
|
-
filters.push(`${k} == null`);
|
|
304
|
-
break;
|
|
305
|
-
case 'notBlank':
|
|
306
|
-
filters.push(`${k} != null`);
|
|
307
|
-
break;
|
|
212
|
+
const fragment = this.criteriaForSingleModel(k, this.currentFilterModel[k]);
|
|
213
|
+
if (fragment) {
|
|
214
|
+
filters.push(fragment);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
// Handle multi filters (ag-multi-column-filter, e.g. text+set combos on enum/currency columns).
|
|
218
|
+
// AG Grid wraps these as { filterType: 'multi', filterModels: [...] } which none of the
|
|
219
|
+
// per-type branches above recognize, so the filter was previously silently dropped and
|
|
220
|
+
// CRITERIA_MATCH never reflected it - the grid kept showing unfiltered server-side data.
|
|
221
|
+
this.getFiltersByType('multi').forEach((k) => {
|
|
222
|
+
var _a;
|
|
223
|
+
const subModels = (_a = this.currentFilterModel[k].filterModels) !== null && _a !== void 0 ? _a : [];
|
|
224
|
+
const operator = (this.currentFilterModel[k].operator || 'AND').toUpperCase();
|
|
225
|
+
const joiner = operator === 'OR' ? ' || ' : ' && ';
|
|
226
|
+
const fragments = subModels
|
|
227
|
+
.map((subModel) => this.criteriaForSingleModel(k, subModel))
|
|
228
|
+
.filter((f) => !!f);
|
|
229
|
+
if (fragments.length === 1) {
|
|
230
|
+
filters.push(fragments[0]);
|
|
231
|
+
}
|
|
232
|
+
else if (fragments.length > 1) {
|
|
233
|
+
filters.push(`(${fragments.join(joiner)})`);
|
|
308
234
|
}
|
|
309
235
|
});
|
|
310
236
|
return filters;
|
|
311
237
|
}
|
|
238
|
+
/**
|
|
239
|
+
* Builds a single criteria fragment for one filter model. Used both for flat per-column
|
|
240
|
+
* filter models and to unwrap the sub-filters inside an ag-multi-column-filter's
|
|
241
|
+
* `filterModels` array.
|
|
242
|
+
* @internal
|
|
243
|
+
*/
|
|
244
|
+
criteriaForSingleModel(k, model) {
|
|
245
|
+
if (!model)
|
|
246
|
+
return null;
|
|
247
|
+
switch (model.filterType) {
|
|
248
|
+
case 'text':
|
|
249
|
+
return this.criteriaForTextModel(k, model);
|
|
250
|
+
case 'set':
|
|
251
|
+
return this.criteriaForSetModel(k, model);
|
|
252
|
+
case 'number':
|
|
253
|
+
return this.criteriaForNumberModel(k, model);
|
|
254
|
+
case 'date':
|
|
255
|
+
return this.criteriaForDateModel(k, model);
|
|
256
|
+
default:
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
criteriaForTextModel(k, model) {
|
|
261
|
+
const type = model.type;
|
|
262
|
+
const val = model.filter;
|
|
263
|
+
if (!val && (type === 'false' || type === 'true')) {
|
|
264
|
+
return `${k} == ${type}`;
|
|
265
|
+
}
|
|
266
|
+
switch (type) {
|
|
267
|
+
case 'blank':
|
|
268
|
+
return `(${k} == '' || ${k} == null)`;
|
|
269
|
+
case 'contains':
|
|
270
|
+
return `Expr.containsIgnoreCase(${k}, '${val}')`;
|
|
271
|
+
case 'equals':
|
|
272
|
+
return `${k} == '${val}'`;
|
|
273
|
+
case 'notBlank':
|
|
274
|
+
return `(${k} != '' && ${k} != null)`;
|
|
275
|
+
case 'notEqual':
|
|
276
|
+
return `${k} != '${val}'`;
|
|
277
|
+
case 'wordStartsWith':
|
|
278
|
+
return `Expr.containsWordsStartingWithIgnoreCase(${k}, '${val}')`;
|
|
279
|
+
default:
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
criteriaForSetModel(k, model) {
|
|
284
|
+
var _a, _b;
|
|
285
|
+
const selectedValues = ((_a = model.values) !== null && _a !== void 0 ? _a : []);
|
|
286
|
+
if (!selectedValues.length) {
|
|
287
|
+
// Nothing selected means no additional criteria
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
290
|
+
// Try to detect "all values selected" using VALID_VALUES from metadata.
|
|
291
|
+
// In that case we don't want to send any criteria, as it would be equivalent
|
|
292
|
+
// to no filter at all.
|
|
293
|
+
const colMeta = (_b = this.resourceColDefs) === null || _b === void 0 ? void 0 : _b.find((o) => o.NAME === k);
|
|
294
|
+
let allValues;
|
|
295
|
+
if (colMeta === null || colMeta === void 0 ? void 0 : colMeta.VALID_VALUES) {
|
|
296
|
+
try {
|
|
297
|
+
allValues = Array.isArray(colMeta.VALID_VALUES)
|
|
298
|
+
? colMeta.VALID_VALUES
|
|
299
|
+
: colMeta.VALID_VALUES.split('|');
|
|
300
|
+
}
|
|
301
|
+
catch (_c) {
|
|
302
|
+
allValues = undefined;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
if (allValues &&
|
|
306
|
+
allValues.length === selectedValues.length &&
|
|
307
|
+
allValues.every((v) => selectedValues.includes(v))) {
|
|
308
|
+
// All enum options are selected – skip adding criteria for this column
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
const orConditions = selectedValues.map((val) => {
|
|
312
|
+
const safeVal = String(val).replace(/'/g, "\\'");
|
|
313
|
+
return `${k} == '${safeVal}'`;
|
|
314
|
+
});
|
|
315
|
+
return orConditions.length ? `(${orConditions.join(' || ')})` : null;
|
|
316
|
+
}
|
|
317
|
+
criteriaForNumberModel(k, model) {
|
|
318
|
+
const value = model.filter;
|
|
319
|
+
const valueTwo = model.filterTo;
|
|
320
|
+
switch (model.type) {
|
|
321
|
+
case 'equals':
|
|
322
|
+
return !isNaN(value) ? `${k} == ${value}` : null;
|
|
323
|
+
case 'notEqual':
|
|
324
|
+
return !isNaN(value) ? `${k} != ${value}` : null;
|
|
325
|
+
case 'greaterThan':
|
|
326
|
+
return !isNaN(value) ? `${k} > ${value}` : null;
|
|
327
|
+
case 'greaterThanOrEqual':
|
|
328
|
+
return !isNaN(value) ? `${k} >= ${value}` : null;
|
|
329
|
+
case 'lessThan':
|
|
330
|
+
return !isNaN(value) ? `${k} < ${value}` : null;
|
|
331
|
+
case 'lessThanOrEqual':
|
|
332
|
+
return !isNaN(value) ? `${k} <= ${value}` : null;
|
|
333
|
+
case 'inRange':
|
|
334
|
+
return !isNaN(value) && !isNaN(valueTwo) ? `${k} >= ${value} && ${k} <= ${valueTwo}` : null;
|
|
335
|
+
case 'blank':
|
|
336
|
+
return `${k} == 0`;
|
|
337
|
+
case 'notBlank':
|
|
338
|
+
return `${k} != 0`;
|
|
339
|
+
default:
|
|
340
|
+
return null;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
criteriaForDateModel(k, model) {
|
|
344
|
+
var _a, _b;
|
|
345
|
+
const dateFrom = (_a = model.dateFrom) === null || _a === void 0 ? void 0 : _a.replace(/-/g, '').replace('T', '-').split(' ')[0];
|
|
346
|
+
const dateTo = (_b = model.dateTo) === null || _b === void 0 ? void 0 : _b.replace(/-/g, '').replace('T', '-').split(' ')[0];
|
|
347
|
+
switch (model.type) {
|
|
348
|
+
case 'equals':
|
|
349
|
+
return `Expr.dateIsEqual(${k}, '${dateFrom}')`;
|
|
350
|
+
case 'lessThan':
|
|
351
|
+
return `Expr.dateIsBefore(${k}, '${dateFrom}')`;
|
|
352
|
+
case 'greaterThan':
|
|
353
|
+
return `Expr.dateIsAfter(${k}, '${dateFrom}')`;
|
|
354
|
+
case 'inRange':
|
|
355
|
+
return `Expr.dateIsAfter(${k}, '${dateFrom}') && Expr.dateIsBefore(${k}, '${dateTo}')`;
|
|
356
|
+
case 'isToday': {
|
|
357
|
+
const now = new Date();
|
|
358
|
+
const year = now.getFullYear();
|
|
359
|
+
const month = (now.getMonth() + 1).toString().padStart(2, '0');
|
|
360
|
+
const day = now.getDate().toString().padStart(2, '0');
|
|
361
|
+
return `Expr.dateIsEqual(${k}, '${year}-${month}-${day} 00:00:00')`;
|
|
362
|
+
}
|
|
363
|
+
case 'blank':
|
|
364
|
+
return `${k} == null`;
|
|
365
|
+
case 'notBlank':
|
|
366
|
+
return `${k} != null`;
|
|
367
|
+
default:
|
|
368
|
+
return null;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
312
371
|
getFiltersByType(filterType) {
|
|
313
372
|
var _a;
|
|
314
373
|
return Object.keys((_a = this.currentFilterModel) !== null && _a !== void 0 ? _a : {})
|
|
@@ -336,19 +395,29 @@ export class BaseServerSideDatasource {
|
|
|
336
395
|
}
|
|
337
396
|
return rowCount;
|
|
338
397
|
}
|
|
339
|
-
|
|
340
|
-
|
|
398
|
+
// Infinite scroll: getRows() only resolves a block once the session-cumulative row cache
|
|
399
|
+
// covers the block's full extent, or the stream reported no more data (see the accumulation
|
|
400
|
+
// logic in server-side.resource-dataserver.ts getRows()). So by construction, blocks handed
|
|
401
|
+
// to AG Grid are either FULL (more may follow) or FINAL (dataset ended) - which lets the
|
|
402
|
+
// count logic stay simple and honest:
|
|
403
|
+
if (!this.moreRows) {
|
|
404
|
+
// Dataset genuinely ends here. rowData is a Map keyed by rowId, so .size is the true
|
|
405
|
+
// unique-row count. Deliberately NOT serverRowsCount - GSF's ROWS_COUNT ignores
|
|
406
|
+
// CRITERIA_MATCH entirely (confirmed: it returns the full unfiltered total regardless of
|
|
407
|
+
// any filter). Deliberately NOT clientRowsCount either - it's a non-deduplicated running
|
|
408
|
+
// sum of inserts across stream messages and overcounts on live/reactive streams.
|
|
409
|
+
rowCount = Math.min(this.rowData.size, this.maxView);
|
|
341
410
|
}
|
|
342
|
-
else if (
|
|
343
|
-
|
|
411
|
+
else if (this.rowData.size >= this.maxView) {
|
|
412
|
+
// Hard cap - the view can't grow past maxView, stop AG Grid from requesting further.
|
|
413
|
+
rowCount = this.maxView;
|
|
344
414
|
}
|
|
345
|
-
else
|
|
346
|
-
//
|
|
347
|
-
//
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
rowCount = this.calculatedRowsCount;
|
|
415
|
+
else {
|
|
416
|
+
// Full block delivered and the stream says more may follow: leave rowCount undefined so
|
|
417
|
+
// AG Grid keeps its own "returned block was full, more may exist" heuristic - this both
|
|
418
|
+
// keeps infinite scroll going and preserves the open-ended "100+"-style count display,
|
|
419
|
+
// for filtered views exactly the same as for unfiltered ones.
|
|
420
|
+
rowCount = undefined;
|
|
352
421
|
}
|
|
353
422
|
return rowCount;
|
|
354
423
|
}
|