@genesislcap/grid-pro 15.30.0 → 15.30.2
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 +8196 -7794
- package/dist/dts/column-selection/column-selection.d.ts +4 -3
- package/dist/dts/column-selection/column-selection.d.ts.map +1 -1
- package/dist/dts/column-selection/column-selection.styles.d.ts.map +1 -1
- package/dist/dts/datasource/base.datasource.d.ts +69 -8
- package/dist/dts/datasource/base.datasource.d.ts.map +1 -1
- package/dist/dts/datasource/base.types.d.ts +10 -0
- package/dist/dts/datasource/base.types.d.ts.map +1 -1
- package/dist/dts/datasource/dataserver-result.filter.d.ts +17 -0
- package/dist/dts/datasource/dataserver-result.filter.d.ts.map +1 -0
- package/dist/dts/datasource/delivered-block.ledger.d.ts +37 -0
- package/dist/dts/datasource/delivered-block.ledger.d.ts.map +1 -0
- package/dist/dts/datasource/infinite.datasource.d.ts +65 -1
- package/dist/dts/datasource/infinite.datasource.d.ts.map +1 -1
- package/dist/dts/datasource/infinite.resource.d.ts +136 -6
- package/dist/dts/datasource/infinite.resource.d.ts.map +1 -1
- package/dist/dts/datasource/server-side.datasource.d.ts +8 -4
- package/dist/dts/datasource/server-side.datasource.d.ts.map +1 -1
- package/dist/dts/datasource/server-side.resource-base.d.ts +23 -0
- package/dist/dts/datasource/server-side.resource-base.d.ts.map +1 -1
- package/dist/dts/datasource/server-side.resource-dataserver.d.ts +28 -0
- 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/dts/grid-pro-beta.d.ts +6 -0
- package/dist/dts/grid-pro-beta.d.ts.map +1 -1
- package/dist/dts/grid-pro-genesis-datasource/datasource-events.types.d.ts +4 -0
- package/dist/dts/grid-pro-genesis-datasource/datasource-events.types.d.ts.map +1 -1
- package/dist/dts/grid-pro.d.ts.map +1 -1
- package/dist/dts/react.d.ts +20 -20
- package/dist/esm/column-selection/column-selection.js +11 -9
- package/dist/esm/column-selection/column-selection.styles.js +0 -2
- package/dist/esm/column-selection/column-selection.template.js +1 -1
- package/dist/esm/datasource/base.datasource.js +182 -27
- package/dist/esm/datasource/dataserver-result.filter.js +28 -0
- package/dist/esm/datasource/delivered-block.ledger.js +52 -0
- package/dist/esm/datasource/infinite.datasource.js +131 -20
- package/dist/esm/datasource/infinite.resource.js +221 -16
- package/dist/esm/datasource/server-side.datasource.js +80 -29
- package/dist/esm/datasource/server-side.resource-base.js +39 -0
- package/dist/esm/datasource/server-side.resource-dataserver.js +110 -23
- package/dist/esm/datasource/server-side.resource-reqrep.js +25 -3
- package/dist/esm/grid-pro-beta.js +20 -2
- package/dist/esm/grid-pro.js +4 -1
- package/dist/grid-pro.api.json +66 -66
- package/dist/grid-pro.d.ts +294 -21
- package/dist/react.cjs +23 -23
- package/dist/react.mjs +21 -21
- package/package.json +13 -13
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { __awaiter } from "tslib";
|
|
2
|
-
import {
|
|
2
|
+
import { MessageType, } from '@genesislcap/foundation-comms';
|
|
3
3
|
import { logger } from '../utils';
|
|
4
|
+
import { filterDataserverResult } from './dataserver-result.filter';
|
|
5
|
+
import { DeliveredBlockLedger } from './delivered-block.ledger';
|
|
4
6
|
import { convertFilterModelToCriteria } from './filter.utils';
|
|
5
7
|
/**
|
|
6
8
|
* Converts an AG Grid sort model to the Genesis ORDER_BY form the resource expects.
|
|
@@ -39,12 +41,71 @@ export function convertSortModelToOrderBy(sortModel, resourceIndexes, isRequestS
|
|
|
39
41
|
logger.warn(`Column '${colId}' is not part of any named INDEX. Server-side sorting is not available for this column.`);
|
|
40
42
|
return { orderBy: null, reverse: false };
|
|
41
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Turns whatever a rejected resource read produced into a message worth showing.
|
|
46
|
+
* @remarks Genesis rejects with a message object (`{ ERROR: [{ TEXT }], MESSAGE_TYPE }`), not an
|
|
47
|
+
* `Error`, so stringifying it naively yields "[object Object]" in the grid's error dialog.
|
|
48
|
+
* @internal
|
|
49
|
+
*/
|
|
50
|
+
export function describeResourceError(error) {
|
|
51
|
+
var _a, _b, _c;
|
|
52
|
+
if (error instanceof Error) {
|
|
53
|
+
return error.message;
|
|
54
|
+
}
|
|
55
|
+
if (typeof error === 'string') {
|
|
56
|
+
return error;
|
|
57
|
+
}
|
|
58
|
+
const details = error;
|
|
59
|
+
for (const candidate of [details, details === null || details === void 0 ? void 0 : details.receivedMessage]) {
|
|
60
|
+
const texts = (_a = candidate === null || candidate === void 0 ? void 0 : candidate.ERROR) === null || _a === void 0 ? void 0 : _a.map((entry) => entry === null || entry === void 0 ? void 0 : entry.TEXT).filter(Boolean);
|
|
61
|
+
if (texts === null || texts === void 0 ? void 0 : texts.length) {
|
|
62
|
+
return texts.join('; ');
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (typeof (details === null || details === void 0 ? void 0 : details.message) === 'string' && details.message) {
|
|
66
|
+
return details.message;
|
|
67
|
+
}
|
|
68
|
+
const messageType = (_b = details === null || details === void 0 ? void 0 : details.MESSAGE_TYPE) !== null && _b !== void 0 ? _b : (_c = details === null || details === void 0 ? void 0 : details.receivedMessage) === null || _c === void 0 ? void 0 : _c.MESSAGE_TYPE;
|
|
69
|
+
if (messageType) {
|
|
70
|
+
return messageType;
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
return JSON.stringify(error);
|
|
74
|
+
}
|
|
75
|
+
catch (_d) {
|
|
76
|
+
return String(error);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
42
79
|
/**
|
|
43
80
|
* AG Grid Infinite Row Model datasource implementation.
|
|
44
81
|
* This class implements the IDatasource interface required by AG Grid's Infinite Row Model.
|
|
45
82
|
*/
|
|
46
83
|
export class GenesisInfiniteDatasource {
|
|
47
84
|
constructor(options) {
|
|
85
|
+
var _a;
|
|
86
|
+
/** The `reverse` attribute, applied alongside `defaultOrderBy` on DATASERVER. @internal */
|
|
87
|
+
this.defaultReverse = false;
|
|
88
|
+
/**
|
|
89
|
+
* Bumped whenever the rows this datasource was reading for are dropped (a teardown, or a
|
|
90
|
+
* filter/sort change). A REQUEST_SERVER reply that resolves for an earlier generation was read
|
|
91
|
+
* for a cache the grid no longer has.
|
|
92
|
+
* @remarks Deliberately a generation rather than a "destroyed" flag: AG Grid calls `destroy()`
|
|
93
|
+
* on the datasource bean it then keeps using (`InfiniteRowModel.start()` re-applies the
|
|
94
|
+
* `datasource` grid option, and `setDatasource` destroys the previous one first), so a sticky
|
|
95
|
+
* flag would disable the instance the grid is still driving.
|
|
96
|
+
* @internal
|
|
97
|
+
*/
|
|
98
|
+
this.loadGeneration = 0;
|
|
99
|
+
/**
|
|
100
|
+
* Set once the host has dropped this instance for a replacement (a criteria change, a resource
|
|
101
|
+
* change, teardown). AG Grid keeps calling the bean it was given until the new one is attached,
|
|
102
|
+
* and its purge re-requests blocks immediately, so without this the replaced instance keeps
|
|
103
|
+
* reading with its captured criteria and reporting those rows to the host as delivered.
|
|
104
|
+
* @remarks Distinct from `destroy()`, which AG Grid itself calls on a bean it then keeps using;
|
|
105
|
+
* only the host calls `detach()`, and only when it will never use this instance again.
|
|
106
|
+
* @internal
|
|
107
|
+
*/
|
|
108
|
+
this.detached = false;
|
|
48
109
|
/**
|
|
49
110
|
* Session-cumulative row cache, keyed by row id. A Map preserves insertion order, so the
|
|
50
111
|
* cache can be sliced by block range; Genesis splits batches across messages and later
|
|
@@ -69,7 +130,11 @@ export class GenesisInfiniteDatasource {
|
|
|
69
130
|
this.getMoreRowsFunc = options.getMoreRowsFunc;
|
|
70
131
|
this.onRowsInvalidatedFunc = options.onRowsInvalidatedFunc;
|
|
71
132
|
this.onRowsUpdatedFunc = options.onRowsUpdatedFunc;
|
|
133
|
+
this.onRowsDeliveredFunc = options.onRowsDeliveredFunc;
|
|
134
|
+
this.onRowsWithdrawnFunc = options.onRowsWithdrawnFunc;
|
|
135
|
+
this.onRowCacheResetFunc = options.onRowCacheResetFunc;
|
|
72
136
|
this.errorHandlerFunc = options.errorHandlerFunc;
|
|
137
|
+
this.ledger = new DeliveredBlockLedger(options.rowId);
|
|
73
138
|
this.resourceName = options.resourceName;
|
|
74
139
|
this.resourceParams = Object.assign({}, options.resourceParams);
|
|
75
140
|
this.resourceIndexes = options.resourceIndexes;
|
|
@@ -78,6 +143,10 @@ export class GenesisInfiniteDatasource {
|
|
|
78
143
|
this.rowId = options.rowId;
|
|
79
144
|
this.baseCriteria = options.baseCriteria || '';
|
|
80
145
|
this.isRequestServer = options.isRequestServer;
|
|
146
|
+
this.defaultOrderBy = options.defaultOrderBy || undefined;
|
|
147
|
+
this.defaultReverse = (_a = options.defaultReverse) !== null && _a !== void 0 ? _a : false;
|
|
148
|
+
this.onNoDataAvailableFunc = options.onNoDataAvailableFunc;
|
|
149
|
+
this.onDataAvailableFunc = options.onDataAvailableFunc;
|
|
81
150
|
}
|
|
82
151
|
/**
|
|
83
152
|
* Builds request parameters for REQUEST_SERVER resources.
|
|
@@ -153,6 +222,15 @@ export class GenesisInfiniteDatasource {
|
|
|
153
222
|
*/
|
|
154
223
|
getRows(params) {
|
|
155
224
|
return __awaiter(this, void 0, void 0, function* () {
|
|
225
|
+
var _a, _b;
|
|
226
|
+
// The host has replaced this instance; the grid is only still asking because the replacement
|
|
227
|
+
// has not been attached yet. Reading would use this instance's captured criteria and report
|
|
228
|
+
// rows the grid will drop. fail() releases AG Grid's request slot for the new datasource.
|
|
229
|
+
if (this.detached) {
|
|
230
|
+
logger.debug('Infinite getRows ignored: the datasource was detached by its host');
|
|
231
|
+
params.failCallback();
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
156
234
|
logger.debug('Infinite getRows called', {
|
|
157
235
|
startRow: params.startRow,
|
|
158
236
|
endRow: params.endRow,
|
|
@@ -163,7 +241,8 @@ export class GenesisInfiniteDatasource {
|
|
|
163
241
|
const filterCriteria = convertFilterModelToCriteria(params.filterModel, this.resourceColDefs);
|
|
164
242
|
const combinedCriteria = [this.baseCriteria, filterCriteria].filter(Boolean).join(' && ');
|
|
165
243
|
// Build sort config
|
|
166
|
-
const sortConfig =
|
|
244
|
+
const sortConfig = this.resolveSortConfig(params.sortModel);
|
|
245
|
+
this.noteRequestKey(combinedCriteria, sortConfig);
|
|
167
246
|
// DATASERVER pages through a persistent subscription; REQUEST_SERVER is stateless and
|
|
168
247
|
// pages by OFFSET on a fresh request each time.
|
|
169
248
|
if (!this.isRequestServer) {
|
|
@@ -172,25 +251,51 @@ export class GenesisInfiniteDatasource {
|
|
|
172
251
|
}
|
|
173
252
|
const requestParams = this.buildRequestServerParams(params.startRow, combinedCriteria, sortConfig);
|
|
174
253
|
logger.debug('Infinite datasource request params', requestParams);
|
|
254
|
+
// Taken after noteRequestKey, so this is the generation the request belongs to: only a
|
|
255
|
+
// reset that lands while it is in flight invalidates the reply.
|
|
256
|
+
const generation = this.loadGeneration;
|
|
175
257
|
const result = yield this.createSnapshotFunc(requestParams);
|
|
258
|
+
// The rows this block was read for have since been dropped (a filter or sort change): AG
|
|
259
|
+
// Grid has purged the block, and the host must not learn of rows the grid will never hold.
|
|
260
|
+
// The block is still failed rather than left hanging - AG Grid caps concurrent requests
|
|
261
|
+
// and frees a slot only on success or fail, so a silent return stops it ever asking again.
|
|
262
|
+
if (generation !== this.loadGeneration) {
|
|
263
|
+
logger.debug('Infinite REQUEST_SERVER reply discarded: the block cache was reset');
|
|
264
|
+
params.failCallback();
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
176
267
|
if (!result) {
|
|
177
268
|
params.failCallback();
|
|
178
269
|
return;
|
|
179
270
|
}
|
|
271
|
+
// A rejected request answers with a message, not a REPLY. Settling it as an empty block
|
|
272
|
+
// would tell the grid the dataset simply ends here, so the user sees a short grid with no
|
|
273
|
+
// indication that anything failed.
|
|
274
|
+
const messageType = result.MESSAGE_TYPE;
|
|
275
|
+
if (messageType === MessageType.LOGOFF_ACK || messageType === MessageType.MSG_NACK) {
|
|
276
|
+
const message = messageType === MessageType.LOGOFF_ACK
|
|
277
|
+
? `Connection lost to ${this.resourceName}`
|
|
278
|
+
: `Request rejected by ${this.resourceName}`;
|
|
279
|
+
logger.error(`Infinite REQUEST_SERVER block failed: ${message}`, result);
|
|
280
|
+
(_a = this.errorHandlerFunc) === null || _a === void 0 ? void 0 : _a.call(this, message, 'connection');
|
|
281
|
+
params.failCallback();
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
180
284
|
if ('REPLY' in result && Array.isArray(result.REPLY)) {
|
|
181
285
|
const rowData = result.REPLY;
|
|
182
286
|
const lastRow = this.getLastRow(result, params.startRow, rowData.length, Boolean(combinedCriteria));
|
|
183
287
|
params.successCallback(rowData, lastRow);
|
|
288
|
+
this.deliverRows(params.startRow, rowData);
|
|
289
|
+
this.notifyDataAvailability(params.startRow, rowData.length);
|
|
184
290
|
return;
|
|
185
291
|
}
|
|
186
292
|
// Fallback - empty result
|
|
187
293
|
params.successCallback([], params.startRow);
|
|
294
|
+
this.notifyDataAvailability(params.startRow, 0);
|
|
188
295
|
}
|
|
189
296
|
catch (error) {
|
|
190
297
|
logger.error('Error in infinite getRows:', error);
|
|
191
|
-
|
|
192
|
-
this.errorHandlerFunc(error instanceof Error ? error.message : String(error), 'unknown');
|
|
193
|
-
}
|
|
298
|
+
(_b = this.errorHandlerFunc) === null || _b === void 0 ? void 0 : _b.call(this, describeResourceError(error), 'unknown');
|
|
194
299
|
params.failCallback();
|
|
195
300
|
}
|
|
196
301
|
});
|
|
@@ -202,20 +307,57 @@ export class GenesisInfiniteDatasource {
|
|
|
202
307
|
* outstanding at once, and each settles as soon as the cache covers its range.
|
|
203
308
|
* @internal
|
|
204
309
|
*/
|
|
310
|
+
/**
|
|
311
|
+
* Notes the CRITERIA_MATCH/ORDER_BY a block is being read with. A change means AG Grid has
|
|
312
|
+
* purged its cache and restarted from block 0: on DATASERVER the subscription is re-opened
|
|
313
|
+
* (those are DATA_LOGON parameters), and on both transports the host is told the rows it held
|
|
314
|
+
* are gone, so the rows read under the new filter or sort are reported as new.
|
|
315
|
+
* @internal
|
|
316
|
+
*/
|
|
317
|
+
/**
|
|
318
|
+
* The sort a block is read with: the grid's own sort model when the user has sorted, and the
|
|
319
|
+
* `order-by` / `reverse` attributes otherwise.
|
|
320
|
+
* @remarks Without the fallback those attributes reached the comms datasource but were then
|
|
321
|
+
* dropped, because the logon builder removes ORDER_BY and REVERSE whenever the grid is
|
|
322
|
+
* unsorted. Sorting from the grid still wins, as it is the more specific instruction.
|
|
323
|
+
* @internal
|
|
324
|
+
*/
|
|
325
|
+
resolveSortConfig(sortModel) {
|
|
326
|
+
const fromGrid = convertSortModelToOrderBy(sortModel, this.resourceIndexes, this.isRequestServer);
|
|
327
|
+
if (fromGrid.orderBy || !this.defaultOrderBy) {
|
|
328
|
+
return fromGrid;
|
|
329
|
+
}
|
|
330
|
+
return { orderBy: this.defaultOrderBy, reverse: this.defaultReverse };
|
|
331
|
+
}
|
|
332
|
+
noteRequestKey(criteria, sortConfig) {
|
|
333
|
+
var _a;
|
|
334
|
+
const key = JSON.stringify(Object.assign({ criteria }, sortConfig));
|
|
335
|
+
// Tracked separately from `subscriptionKey`, which a teardown clears: `reset()` tears the
|
|
336
|
+
// subscription down on every structural push, and a filter change landing between that and
|
|
337
|
+
// the next block read would otherwise look like the very first request - leaving the host
|
|
338
|
+
// holding every row read under the old filter.
|
|
339
|
+
if (this.rowCacheKey !== undefined && this.rowCacheKey !== key) {
|
|
340
|
+
// Whatever is in flight was read for the old filter or sort.
|
|
341
|
+
this.loadGeneration += 1;
|
|
342
|
+
this.ledger.clear();
|
|
343
|
+
(_a = this.onRowCacheResetFunc) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
344
|
+
}
|
|
345
|
+
this.rowCacheKey = key;
|
|
346
|
+
// CRITERIA_MATCH and ORDER_BY are DATA_LOGON parameters, so a change needs a fresh
|
|
347
|
+
// subscription. A teardown has already left `subscriptionKey` undefined.
|
|
348
|
+
if (!this.isRequestServer &&
|
|
349
|
+
this.subscriptionKey !== undefined &&
|
|
350
|
+
this.subscriptionKey !== key) {
|
|
351
|
+
this.teardownDataserverSubscription();
|
|
352
|
+
}
|
|
353
|
+
this.subscriptionKey = key;
|
|
354
|
+
}
|
|
205
355
|
getDataserverRows(params, criteria, sortConfig) {
|
|
206
356
|
if (!this.createDataserverStreamFunc || !this.getMoreRowsFunc) {
|
|
207
357
|
logger.error('Infinite DATASERVER paging requires a stream and a getMoreRows function');
|
|
208
358
|
params.failCallback();
|
|
209
359
|
return;
|
|
210
360
|
}
|
|
211
|
-
// CRITERIA_MATCH and ORDER_BY are DATA_LOGON parameters, so a filter or sort change needs a
|
|
212
|
-
// fresh subscription and a fresh cache. AG Grid purges its own cache on those changes and
|
|
213
|
-
// restarts from block 0, so nothing is lost.
|
|
214
|
-
const key = JSON.stringify(Object.assign({ criteria }, sortConfig));
|
|
215
|
-
if (this.subscriptionKey !== undefined && this.subscriptionKey !== key) {
|
|
216
|
-
this.teardownDataserverSubscription();
|
|
217
|
-
}
|
|
218
|
-
this.subscriptionKey = key;
|
|
219
361
|
const startRow = Number.isFinite(Number(params.startRow)) ? Number(params.startRow) : 0;
|
|
220
362
|
const endRow = Number.isFinite(Number(params.endRow))
|
|
221
363
|
? Number(params.endRow)
|
|
@@ -318,7 +460,7 @@ export class GenesisInfiniteDatasource {
|
|
|
318
460
|
return;
|
|
319
461
|
}
|
|
320
462
|
this.sourceRef = (_b = message === null || message === void 0 ? void 0 : message.SOURCE_REF) !== null && _b !== void 0 ? _b : this.sourceRef;
|
|
321
|
-
const filtered = (message === null || message === void 0 ? void 0 : message.ROW) ?
|
|
463
|
+
const filtered = (message === null || message === void 0 ? void 0 : message.ROW) ? filterDataserverResult(message, this.rowId) : undefined;
|
|
322
464
|
// A DATASERVER subscription is live by definition: batches answering the logon or a
|
|
323
465
|
// MORE_ROWS carry the rows we asked for, and anything else is a change pushed by the server.
|
|
324
466
|
// Replies only ever deliver view rows (INSERT operations), so a batch carrying a MODIFY or
|
|
@@ -380,7 +522,7 @@ export class GenesisInfiniteDatasource {
|
|
|
380
522
|
deletes: (_k = (_j = result.deletes) === null || _j === void 0 ? void 0 : _j.length) !== null && _k !== void 0 ? _k : 0,
|
|
381
523
|
});
|
|
382
524
|
this.reset();
|
|
383
|
-
(_l = this.onRowsInvalidatedFunc) === null || _l === void 0 ? void 0 : _l.call(this);
|
|
525
|
+
(_l = this.onRowsInvalidatedFunc) === null || _l === void 0 ? void 0 : _l.call(this, result);
|
|
384
526
|
return;
|
|
385
527
|
}
|
|
386
528
|
if (modified) {
|
|
@@ -388,7 +530,7 @@ export class GenesisInfiniteDatasource {
|
|
|
388
530
|
logger.debug('Infinite DATASERVER live update patched into the cache', {
|
|
389
531
|
updates: (_o = (_m = result.updates) === null || _m === void 0 ? void 0 : _m.length) !== null && _o !== void 0 ? _o : 0,
|
|
390
532
|
});
|
|
391
|
-
(_p = this.onRowsUpdatedFunc) === null || _p === void 0 ? void 0 : _p.call(this);
|
|
533
|
+
(_p = this.onRowsUpdatedFunc) === null || _p === void 0 ? void 0 : _p.call(this, result);
|
|
392
534
|
}
|
|
393
535
|
}
|
|
394
536
|
/**
|
|
@@ -506,6 +648,46 @@ export class GenesisInfiniteDatasource {
|
|
|
506
648
|
lastRow,
|
|
507
649
|
});
|
|
508
650
|
block.success(rows, lastRow);
|
|
651
|
+
this.deliverRows(block.startRow, rows);
|
|
652
|
+
this.notifyDataAvailability(block.startRow, rows.length);
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Raises the no-data / data-available hooks for the first block, as the server-side resource
|
|
656
|
+
* does. Later blocks say nothing: the question is whether the resource has any rows at all,
|
|
657
|
+
* and the answer cannot change once the first block has been served.
|
|
658
|
+
* @internal
|
|
659
|
+
*/
|
|
660
|
+
notifyDataAvailability(startRow, rowCount) {
|
|
661
|
+
var _a, _b;
|
|
662
|
+
if (startRow !== 0 || this.detached) {
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
665
|
+
if (rowCount === 0) {
|
|
666
|
+
(_a = this.onNoDataAvailableFunc) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
667
|
+
}
|
|
668
|
+
else {
|
|
669
|
+
(_b = this.onDataAvailableFunc) === null || _b === void 0 ? void 0 : _b.call(this);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* Reports rows handed to the grid for a block, then the rows a re-read of that block no longer
|
|
674
|
+
* carries and the rows whose block the grid evicted.
|
|
675
|
+
* @internal
|
|
676
|
+
*/
|
|
677
|
+
deliverRows(startRow, rows) {
|
|
678
|
+
var _a, _b;
|
|
679
|
+
// A reply that resolves after the host dropped this instance belongs to a cache the grid no
|
|
680
|
+
// longer has; reporting it would tell consumers about rows the grid will never show.
|
|
681
|
+
if (this.detached) {
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
684
|
+
const { withdrawnRowIds } = this.ledger.record(startRow, rows);
|
|
685
|
+
if (rows.length > 0) {
|
|
686
|
+
(_a = this.onRowsDeliveredFunc) === null || _a === void 0 ? void 0 : _a.call(this, rows);
|
|
687
|
+
}
|
|
688
|
+
if (withdrawnRowIds.length > 0) {
|
|
689
|
+
(_b = this.onRowsWithdrawnFunc) === null || _b === void 0 ? void 0 : _b.call(this, withdrawnRowIds);
|
|
690
|
+
}
|
|
509
691
|
}
|
|
510
692
|
/**
|
|
511
693
|
* Warns when the view filled up before the data ran out.
|
|
@@ -566,10 +748,33 @@ export class GenesisInfiniteDatasource {
|
|
|
566
748
|
this.moreRows = undefined;
|
|
567
749
|
this.moreRowsInFlight = false;
|
|
568
750
|
}
|
|
751
|
+
/**
|
|
752
|
+
* Drops the subscription and the cached rows.
|
|
753
|
+
* @remarks AG Grid calls this on the bean it then keeps using (`InfiniteRowModel.start()`
|
|
754
|
+
* re-applies the `datasource` grid option, and `setDatasource` destroys the previous one
|
|
755
|
+
* first), and it can land while a block request is in flight. So it must leave the datasource
|
|
756
|
+
* able to serve that reply and the next `getRows`: it drops the subscription, not the instance.
|
|
757
|
+
*/
|
|
569
758
|
destroy() {
|
|
570
759
|
this.teardownDataserverSubscription();
|
|
760
|
+
this.ledger.clear();
|
|
571
761
|
logger.debug('GenesisInfiniteDatasource destroyed');
|
|
572
762
|
}
|
|
763
|
+
/**
|
|
764
|
+
* Drops this instance for good: the host is replacing it, so it must stop serving the grid and
|
|
765
|
+
* stop reporting rows, even though AG Grid still holds it as its `datasource` until the
|
|
766
|
+
* replacement is attached.
|
|
767
|
+
* @remarks Deliberately separate from `destroy()`, which AG Grid calls on a bean it then keeps
|
|
768
|
+
* using (`InfiniteRowModel.start()` re-applies the `datasource` grid option, and `setDatasource`
|
|
769
|
+
* destroys the previous one first).
|
|
770
|
+
*/
|
|
771
|
+
detach() {
|
|
772
|
+
this.detached = true;
|
|
773
|
+
this.loadGeneration += 1;
|
|
774
|
+
this.rowCacheKey = undefined;
|
|
775
|
+
this.destroy();
|
|
776
|
+
logger.debug('GenesisInfiniteDatasource detached by its host');
|
|
777
|
+
}
|
|
573
778
|
}
|
|
574
779
|
/**
|
|
575
780
|
* Max time a DATASERVER block may stay pending before the safety valve resolves it with the
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { __awaiter, __decorate } from "tslib";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { Datasource, MessageType, normaliseCriteria, toFieldMetadata, } from '@genesislcap/foundation-comms';
|
|
3
|
+
import { LifecycleMixin } from '@genesislcap/foundation-utils';
|
|
4
4
|
import { attr, customElement, DOM, observable } from '@microsoft/fast-element';
|
|
5
5
|
import { gridProGenesisDatasourceEventNames } from '../grid-pro-genesis-datasource';
|
|
6
6
|
import { datasourceEventNames, } from '../grid-pro-genesis-datasource/datasource-events.types';
|
|
7
7
|
import { logger } from '../utils';
|
|
8
8
|
import { GridProBaseDatasource } from './base.datasource';
|
|
9
|
+
import { filterDataserverResult } from './dataserver-result.filter';
|
|
9
10
|
import { getFilterByFieldType, getServerSideFilterParamsByFieldType, } from './server-side.grid-definitions';
|
|
10
11
|
import { DataserverServerSideDatasource } from './server-side.resource-dataserver';
|
|
11
12
|
import { ReqRepServerSideDatasource } from './server-side.resource-reqrep';
|
|
@@ -30,7 +31,7 @@ const withoutColumnDefs = null;
|
|
|
30
31
|
* @fires base-datasource-connected - Fired when error state is cleared after connection succeeds
|
|
31
32
|
* @fires datasource-loading-finished - Fired when pending stream transactions are flushed with no row changes
|
|
32
33
|
* @fires datasource-no-data-available - Fired when loading finishes with an empty row set
|
|
33
|
-
* @fires datasource-data-changed - Fired when
|
|
34
|
+
* @fires datasource-data-changed - Fired when rows are delivered to the grid, a live stream pushes a change, a poll detects one, or a re-read no longer returns a row; `add` are rows the grid did not hold before, `update` are held rows whose content changed, `remove` carries the row id. detail: `DataChangedEventDetail`
|
|
34
35
|
* @fires cache-filter-config - Fired to persist filter configuration for the grid
|
|
35
36
|
* @fires refresh-server-side - Fired to request a server-side refresh. detail: `RefreshServerSideEventDetail`
|
|
36
37
|
* @fires set-server-side-datasource - Fired to attach or clear the server-side row model datasource
|
|
@@ -41,7 +42,7 @@ const withoutColumnDefs = null;
|
|
|
41
42
|
* @fires datasource-init - Fired when the server-side grid model should initialize data
|
|
42
43
|
* @fires datasource-schema-updated - Fired when column metadata or defs are updated. detail: `SchemaUpdatedEventDetail`
|
|
43
44
|
* @fires datasource-filters-restored - Fired when persisted filters are reapplied
|
|
44
|
-
* @fires datasource-data-cleared - Fired when
|
|
45
|
+
* @fires datasource-data-cleared - Fired when the grid drops every row it held (reload, filter or sort change, destroy); `includeSchema` says whether the columns went too. detail: `DataClearedEventDetail`
|
|
45
46
|
* @fires apply-server-side-transaction - Fired to apply a server-side row transaction
|
|
46
47
|
* @fires datasource-ready - Fired when the host grid is ready to start loading data
|
|
47
48
|
*/
|
|
@@ -91,6 +92,8 @@ let GridProServerSideDatasource = class GridProServerSideDatasource extends Life
|
|
|
91
92
|
errorHandlerFunc: this.handleErrors.bind(this),
|
|
92
93
|
onNoDataAvailableFunc: () => this.$emit(datasourceEventNames.noDataAvailable),
|
|
93
94
|
onDataAvailableFunc: () => this.$emit(datasourceEventNames.loadingFinished),
|
|
95
|
+
onRowsDeliveredFunc: this.reportDeliveredRows.bind(this),
|
|
96
|
+
onRowsWithdrawnFunc: this.reportWithdrawnRows.bind(this),
|
|
94
97
|
resourceName: this.resourceName,
|
|
95
98
|
resourceParams: this.datasource.requestOnlyParams,
|
|
96
99
|
resourceIndexes: this.indexes,
|
|
@@ -107,6 +110,8 @@ let GridProServerSideDatasource = class GridProServerSideDatasource extends Life
|
|
|
107
110
|
errorHandlerFunc: this.handleErrors.bind(this),
|
|
108
111
|
onNoDataAvailableFunc: () => this.$emit(datasourceEventNames.noDataAvailable),
|
|
109
112
|
onDataAvailableFunc: () => this.$emit(datasourceEventNames.loadingFinished),
|
|
113
|
+
onRowsDeliveredFunc: this.reportDeliveredRows.bind(this),
|
|
114
|
+
onRowsWithdrawnFunc: this.reportWithdrawnRows.bind(this),
|
|
110
115
|
resourceName: this.resourceName,
|
|
111
116
|
resourceParams: this.datasource.dataserverOnlyParams,
|
|
112
117
|
resourceIndexes: this.indexes,
|
|
@@ -195,9 +200,12 @@ let GridProServerSideDatasource = class GridProServerSideDatasource extends Life
|
|
|
195
200
|
*/
|
|
196
201
|
reloadResourceData(params) {
|
|
197
202
|
return __awaiter(this, void 0, void 0, function* () {
|
|
198
|
-
var _a;
|
|
203
|
+
var _a, _b, _c;
|
|
199
204
|
this.datasource.destroy();
|
|
200
|
-
|
|
205
|
+
// A block request still in flight was read for the cache being dropped here; its reply must
|
|
206
|
+
// not be reported as rows the grid holds.
|
|
207
|
+
(_b = (_a = this.ssrmDatasource) === null || _a === void 0 ? void 0 : _a.invalidatePendingLoads) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
208
|
+
(_c = this.liveUpdatesStream) === null || _c === void 0 ? void 0 : _c.unsubscribe();
|
|
201
209
|
this.liveUpdatesStream = undefined;
|
|
202
210
|
// Emit event to cache current filter model before clearing data
|
|
203
211
|
this.$emit(datasourceEventNames.cacheFilterConfig);
|
|
@@ -329,20 +337,22 @@ let GridProServerSideDatasource = class GridProServerSideDatasource extends Life
|
|
|
329
337
|
yield this.init();
|
|
330
338
|
});
|
|
331
339
|
}
|
|
340
|
+
/**
|
|
341
|
+
* Forgets every held row and tells consumers, as the client-side datasource does: the grid is
|
|
342
|
+
* dropping its rows (a reload, a filter or sort change, or teardown). `withColumnDefs` also
|
|
343
|
+
* clears the column definitions.
|
|
344
|
+
* @internal
|
|
345
|
+
*/
|
|
332
346
|
clearRowData(withColumnDefs = true) {
|
|
333
347
|
this.rowData = new Map();
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
this.transactionData = { remove: [] };
|
|
348
|
+
this.resetTransaction();
|
|
349
|
+
this.$emit(datasourceEventNames.dataCleared, {
|
|
350
|
+
includeSchema: Boolean(withColumnDefs),
|
|
351
|
+
});
|
|
341
352
|
// Emit event to apply server side transaction for removing all data
|
|
342
353
|
this.$emit(datasourceEventNames.applyServerSideTransaction, {
|
|
343
|
-
transaction:
|
|
354
|
+
transaction: { remove: [] },
|
|
344
355
|
});
|
|
345
|
-
this.transactionData = undefined;
|
|
346
356
|
}
|
|
347
357
|
/**
|
|
348
358
|
* Checks whether the resolved resource can be served through the Server-Side Row Model.
|
|
@@ -471,7 +481,7 @@ let GridProServerSideDatasource = class GridProServerSideDatasource extends Life
|
|
|
471
481
|
const rowId = row[this.rowId];
|
|
472
482
|
if (this.previousPollResult.has(rowId)) {
|
|
473
483
|
const previousRow = this.previousPollResult.get(rowId);
|
|
474
|
-
if (this.
|
|
484
|
+
if (this.hasRowContentChanged(previousRow, row)) {
|
|
475
485
|
rowsToUpdate.push(row);
|
|
476
486
|
}
|
|
477
487
|
}
|
|
@@ -492,6 +502,31 @@ let GridProServerSideDatasource = class GridProServerSideDatasource extends Life
|
|
|
492
502
|
removed: rowsToDelete.length,
|
|
493
503
|
totalInPoll: currentPollMap.size,
|
|
494
504
|
});
|
|
505
|
+
// The poll has already classified the rows against the previous poll, so re-classify the
|
|
506
|
+
// inserts against the rows actually held: a row shifted into the polled page from a block
|
|
507
|
+
// above is new to the poll but not to the grid, and reporting it as `add` would duplicate
|
|
508
|
+
// it for consumers.
|
|
509
|
+
const transaction = this.resetTransaction();
|
|
510
|
+
rowsToInsert.forEach((row) => {
|
|
511
|
+
const rowId = row[this.rowId];
|
|
512
|
+
const known = this.rowData.get(rowId);
|
|
513
|
+
if (!known) {
|
|
514
|
+
transaction.add.push(row);
|
|
515
|
+
}
|
|
516
|
+
else if (this.hasRowContentChanged(known, row)) {
|
|
517
|
+
transaction.update.push(row);
|
|
518
|
+
}
|
|
519
|
+
});
|
|
520
|
+
transaction.update.push(...rowsToUpdate);
|
|
521
|
+
transaction.remove.push(...rowsToDelete.map((row) => ({ [this.rowId]: row[this.rowId] })));
|
|
522
|
+
[...rowsToInsert, ...rowsToUpdate].forEach((row) => this.rowData.set(row[this.rowId], row));
|
|
523
|
+
rowsToDelete.forEach((row) => this.rowData.delete(row[this.rowId]));
|
|
524
|
+
this.emitTransaction(transaction);
|
|
525
|
+
// A consumer's handler may have reloaded or destroyed this datasource synchronously; the
|
|
526
|
+
// grid is then being purged and the transaction belongs to rows it no longer holds.
|
|
527
|
+
if (this.transactionData !== transaction) {
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
495
530
|
this.$emit(datasourceEventNames.applyServerSideTransaction, {
|
|
496
531
|
transaction: {
|
|
497
532
|
add: rowsToInsert,
|
|
@@ -514,25 +549,41 @@ let GridProServerSideDatasource = class GridProServerSideDatasource extends Life
|
|
|
514
549
|
this.ssrmDatasource.serverRowsCount += netRowChange;
|
|
515
550
|
this.ssrmDatasource.clientRowsCount += netRowChange;
|
|
516
551
|
}
|
|
517
|
-
|
|
552
|
+
const transaction = this.resetTransaction();
|
|
518
553
|
this.handleStreamInserts(inserts);
|
|
519
554
|
this.handleStreamUpdates(updates);
|
|
520
555
|
this.handleStreamDeletes(deletes);
|
|
521
|
-
|
|
556
|
+
// A MODIFY for a row this element has not seen delivered is not reported to consumers (they
|
|
557
|
+
// do not hold it), but it still goes to the grid, which ignores rows outside its store: the
|
|
558
|
+
// stream pre-merge above made it a full row, and the grid may hold it from a block loaded
|
|
559
|
+
// before this element started mirroring deliveries.
|
|
560
|
+
const gridOnlyUpdates = updates.filter((row) => {
|
|
561
|
+
const rowId = row === null || row === void 0 ? void 0 : row[this.rowId];
|
|
562
|
+
return rowId !== undefined && rowId !== null && !this.rowData.has(rowId);
|
|
563
|
+
});
|
|
564
|
+
// Consumers hear the change first; the grid transactions below then catch the grid up.
|
|
565
|
+
this.emitTransaction(transaction);
|
|
566
|
+
// A consumer's handler may have reloaded or destroyed this datasource synchronously; the
|
|
567
|
+
// grid is then being purged and the transaction belongs to rows it no longer holds.
|
|
568
|
+
if (this.transactionData !== transaction) {
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
if (transaction.add.length > 0) {
|
|
522
572
|
this.$emit(datasourceEventNames.applyServerSideTransaction, {
|
|
523
573
|
transaction: {
|
|
524
574
|
route: [],
|
|
525
|
-
add:
|
|
526
|
-
addIndex: this.reverse ? 0 :
|
|
575
|
+
add: transaction.add,
|
|
576
|
+
addIndex: this.reverse ? 0 : transaction.addIndex,
|
|
527
577
|
},
|
|
528
578
|
});
|
|
529
579
|
}
|
|
530
|
-
|
|
580
|
+
const gridUpdates = [...transaction.update, ...gridOnlyUpdates];
|
|
581
|
+
if (gridUpdates.length > 0 || transaction.remove.length > 0) {
|
|
531
582
|
this.$emit(datasourceEventNames.applyServerSideTransaction, {
|
|
532
583
|
transaction: {
|
|
533
584
|
route: [],
|
|
534
|
-
update:
|
|
535
|
-
remove:
|
|
585
|
+
update: gridUpdates,
|
|
586
|
+
remove: transaction.remove,
|
|
536
587
|
},
|
|
537
588
|
});
|
|
538
589
|
}
|
|
@@ -563,9 +614,12 @@ let GridProServerSideDatasource = class GridProServerSideDatasource extends Life
|
|
|
563
614
|
// a complete row — without this, unchanged columns are cleared on every update.
|
|
564
615
|
const rowData = this.ssrmDatasource.rowData;
|
|
565
616
|
const mergedRows = normalizedRows.map((row) => {
|
|
566
|
-
var _a;
|
|
617
|
+
var _a, _b;
|
|
567
618
|
const details = (_a = row.DETAILS) !== null && _a !== void 0 ? _a : {};
|
|
568
|
-
|
|
619
|
+
// Genesis keys pushes by the default id. Under a custom `row-id` DETAILS carries no
|
|
620
|
+
// custom id at all, so fall back to the held row that carries this ROW_REF.
|
|
621
|
+
const defaultRowId = this.defaultRowIdByResourceType;
|
|
622
|
+
const rowRef = ((_b = details[this.rowId]) !== null && _b !== void 0 ? _b : this.resolveRowId(Object.assign(Object.assign({}, row), { [defaultRowId]: details[defaultRowId] })));
|
|
569
623
|
const existingRow = rowRef != null ? rowData === null || rowData === void 0 ? void 0 : rowData.get(rowRef) : undefined;
|
|
570
624
|
if (!existingRow)
|
|
571
625
|
return row;
|
|
@@ -577,7 +631,7 @@ let GridProServerSideDatasource = class GridProServerSideDatasource extends Life
|
|
|
577
631
|
return Object.assign(Object.assign({}, merged), { DETAILS: details });
|
|
578
632
|
});
|
|
579
633
|
const normalizedMessage = Object.assign(Object.assign({}, rawMessage), { ROW: mergedRows });
|
|
580
|
-
const nextMessage =
|
|
634
|
+
const nextMessage = filterDataserverResult(normalizedMessage, this.rowId);
|
|
581
635
|
this.applyLiveServerSideUpdate(nextMessage);
|
|
582
636
|
});
|
|
583
637
|
const onError = (error) => {
|
|
@@ -611,9 +665,6 @@ let GridProServerSideDatasource = class GridProServerSideDatasource extends Life
|
|
|
611
665
|
throw new Error('loadMore() method is not supported for server-side datasource');
|
|
612
666
|
}
|
|
613
667
|
};
|
|
614
|
-
__decorate([
|
|
615
|
-
JSONSerializer
|
|
616
|
-
], GridProServerSideDatasource.prototype, "serializer", void 0);
|
|
617
668
|
__decorate([
|
|
618
669
|
Datasource
|
|
619
670
|
], GridProServerSideDatasource.prototype, "pollingDatasource", void 0);
|