@1771technologies/lytenyte-pro 1.0.15 → 1.0.17-dev.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/+types.d.ts +442 -65
- package/dist/__play__/filter-select/filter-select.play.d.ts +4 -0
- package/dist/__play__/filter-select/filter-select.play.js +76 -0
- package/dist/__play__/test-utils/row-handler.js +3 -4
- package/dist/cell-selection/bound-selection-rect.js +1 -1
- package/dist/cell-selection/cell-selection-driver.js +7 -6
- package/dist/column-manager/branch.d.ts +1 -1
- package/dist/column-manager/branch.js +1 -1
- package/dist/column-manager/label.d.ts +1 -1
- package/dist/column-manager/label.js +1 -1
- package/dist/column-manager/leaf.js +1 -1
- package/dist/column-manager/move-handle.d.ts +1 -1
- package/dist/column-manager/move-handle.js +1 -2
- package/dist/column-manager/visibility-checkbox.d.ts +1 -1
- package/dist/column-manager/visibility-checkbox.js +1 -1
- package/dist/filter-selects/apply.d.ts +7 -0
- package/dist/filter-selects/apply.js +22 -0
- package/dist/filter-selects/clear.d.ts +7 -0
- package/dist/filter-selects/clear.js +22 -0
- package/dist/filter-selects/context.d.ts +13 -0
- package/dist/filter-selects/context.js +3 -0
- package/dist/filter-selects/filter-combinator.d.ts +10 -0
- package/dist/filter-selects/filter-combinator.js +19 -0
- package/dist/filter-selects/filter-row-context.d.ts +30 -0
- package/dist/filter-selects/filter-row-context.js +3 -0
- package/dist/filter-selects/filter-row.d.ts +13 -0
- package/dist/filter-selects/filter-row.js +118 -0
- package/dist/filter-selects/index.d.ts +22 -0
- package/dist/filter-selects/index.js +20 -0
- package/dist/filter-selects/is-complete-filter.d.ts +2 -0
- package/dist/filter-selects/is-complete-filter.js +5 -0
- package/dist/filter-selects/operator-select.d.ts +14 -0
- package/dist/filter-selects/operator-select.js +25 -0
- package/dist/filter-selects/options.d.ts +9 -0
- package/dist/filter-selects/options.js +100 -0
- package/dist/filter-selects/reset.d.ts +7 -0
- package/dist/filter-selects/reset.js +22 -0
- package/dist/filter-selects/root.d.ts +14 -0
- package/dist/filter-selects/root.js +5 -0
- package/dist/filter-selects/to-filter-item.d.ts +3 -0
- package/dist/filter-selects/to-filter-item.js +7 -0
- package/dist/filter-selects/use-filter-select.d.ts +38 -0
- package/dist/filter-selects/use-filter-select.js +168 -0
- package/dist/filter-selects/value-input.d.ts +12 -0
- package/dist/filter-selects/value-input.js +27 -0
- package/dist/filter-tree/branch.d.ts +1 -1
- package/dist/filter-tree/branch.js +1 -1
- package/dist/filter-tree/hooks/use-filter-tree.js +1 -1
- package/dist/filter-tree/inclusion-checkbox.d.ts +1 -1
- package/dist/filter-tree/inclusion-checkbox.js +1 -1
- package/dist/filter-tree/label.d.ts +1 -1
- package/dist/filter-tree/label.js +1 -1
- package/dist/filter-tree/root.d.ts +1 -1
- package/dist/filter-tree/root.js +1 -1
- package/dist/grid/header-cell.d.ts +1 -1
- package/dist/grid/header-cell.js +1 -2
- package/dist/grid/header.d.ts +1 -1
- package/dist/grid/row-full-width.d.ts +1 -1
- package/dist/grid/row-full-width.js +1 -2
- package/dist/grid/row.d.ts +1 -1
- package/dist/grid/row.js +0 -1
- package/dist/grid/rows-container.d.ts +1 -1
- package/dist/grid-box/item.d.ts +1 -1
- package/dist/grid-box/item.js +1 -2
- package/dist/grid-box/panel.js +1 -1
- package/dist/grid-box/use-aggregation-box-items.js +1 -1
- package/dist/grid-box/use-column-box-items.js +1 -1
- package/dist/grid-box/use-row-group-box-items.js +1 -1
- package/dist/grid.d.ts +2 -2
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/license/index.d.ts +1 -0
- package/dist/license/index.js +1 -0
- package/dist/license/license.d.ts +3 -0
- package/dist/license/license.js +215 -0
- package/dist/license/md5-hash.d.ts +9 -0
- package/dist/license/md5-hash.js +167 -0
- package/dist/license.js +1 -1
- package/dist/listbox/item.js +1 -1
- package/dist/listbox/panel.js +2 -2
- package/dist/row-data-source-client/filter/compute-filtered-rows.js +1 -1
- package/dist/row-data-source-client/pivots/create-pivot-columns-from-paths.js +1 -1
- package/dist/row-data-source-client/use-client-data-source-paginated.js +3 -2
- package/dist/row-data-source-client/use-client-data-source.js +3 -2
- package/dist/row-data-source-client/use-client-tree-data-source.js +3 -2
- package/dist/row-data-source-server/server-data.d.ts +24 -2
- package/dist/row-data-source-server/server-data.js +173 -30
- package/dist/row-data-source-server/use-server-data-source.d.ts +1 -1
- package/dist/row-data-source-server/use-server-data-source.js +80 -11
- package/dist/sort-manager/hooks/use-sort-manager.js +2 -2
- package/dist/sort-manager/hooks/use-sort-row-item.js +1 -1
- package/dist/sort-manager/sort-add.d.ts +1 -1
- package/dist/sort-manager/sort-add.js +1 -1
- package/dist/sort-manager/sort-apply.d.ts +1 -1
- package/dist/sort-manager/sort-apply.js +2 -2
- package/dist/sort-manager/sort-cancel.d.ts +1 -1
- package/dist/sort-manager/sort-cancel.js +2 -2
- package/dist/sort-manager/sort-clear.d.ts +1 -1
- package/dist/sort-manager/sort-clear.js +1 -1
- package/dist/sort-manager/sort-column-select.d.ts +1 -1
- package/dist/sort-manager/sort-column-select.js +1 -1
- package/dist/sort-manager/sort-direction-select.d.ts +1 -1
- package/dist/sort-manager/sort-direction-select.js +1 -1
- package/dist/sort-manager/sort-remove.d.ts +1 -1
- package/dist/sort-manager/sort-remove.js +1 -1
- package/dist/sort-manager/sort-value-select.d.ts +1 -1
- package/dist/sort-manager/sort-value-select.js +1 -1
- package/dist/state/+types.d.ts +2 -1
- package/dist/state/api/column-field.js +1 -1
- package/dist/state/api/edit-begin.js +1 -1
- package/dist/state/api/focus-cell.js +1 -1
- package/dist/state/api/position-from-element.d.ts +5 -2
- package/dist/state/api/position-from-element.js +3 -3
- package/dist/state/api/row-handle-select.js +1 -1
- package/dist/state/api/use-row-drag.js +3 -2
- package/dist/state/helpers/column-add-row-group.js +1 -1
- package/dist/state/helpers/column-marker.js +1 -1
- package/dist/state/use-lytenyte.js +18 -3
- package/dist/tree-view/branch/branch.d.ts +1 -1
- package/dist/tree-view/branch/branch.js +1 -1
- package/dist/tree-view/branch/use-branch-keys.js +2 -2
- package/dist/tree-view/leaf.js +1 -1
- package/dist/tree-view/panel/make-handle-navigation.js +1 -1
- package/dist/tree-view/panel/make-handle-selection.js +1 -1
- package/dist/tree-view/panel/panel.js +2 -2
- package/dist/tree-view/panel/use-tree-navigation.js +1 -1
- package/dist/tree-view/root.js +1 -1
- package/dist/tree-view/utils/get-focusable-nodes.js +1 -1
- package/dist/tree-view/utils/get-focused-node.js +1 -1
- package/dist/tree-view/utils/get-sibling-branches.js +1 -1
- package/dist/tree-view/virtualized/use-row-start-and-end.d.ts +1 -1
- package/dist/tree-view/virtualized/use-row-start-and-end.js +1 -1
- package/dist/tree-view/virtualized/use-virtualized-tree.js +1 -1
- package/package.json +3 -7
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { equal } from "@1771technologies/lytenyte-
|
|
1
|
+
import { equal } from "@1771technologies/lytenyte-shared";
|
|
2
2
|
import { makeAsyncTree } from "./async-tree/make-async-tree.js";
|
|
3
3
|
import { RangeTree } from "./range-tree/range-tree.js";
|
|
4
4
|
import { getRequestId } from "./utils/get-request-id.js";
|
|
@@ -19,13 +19,16 @@ export class ServerData {
|
|
|
19
19
|
#onResetLoadError;
|
|
20
20
|
#onResetLoadEnd;
|
|
21
21
|
#onFlatten;
|
|
22
|
+
#onInvalidate;
|
|
22
23
|
#rowViewBounds = [0, 0];
|
|
23
|
-
#
|
|
24
|
+
#seenRequests = new Set();
|
|
24
25
|
#loadingRows = new Set();
|
|
26
|
+
#loadingGroup = new Set();
|
|
25
27
|
#rowsWithError = new Map();
|
|
28
|
+
#rowsWithGroupError = new Map();
|
|
26
29
|
#controllers = new Set();
|
|
27
30
|
#defaultExpansion;
|
|
28
|
-
constructor({ blocksize, pivotMode, pivotExpansions, expansions, onResetLoadBegin, onResetLoadEnd, onResetLoadError, onFlatten, defaultExpansion, }) {
|
|
31
|
+
constructor({ blocksize, pivotMode, pivotExpansions, expansions, onResetLoadBegin, onResetLoadEnd, onResetLoadError, onFlatten, onInvalidate, defaultExpansion, }) {
|
|
29
32
|
this.#tree = makeAsyncTree();
|
|
30
33
|
this.#blocksize = blocksize;
|
|
31
34
|
this.#pivotMode = pivotMode;
|
|
@@ -36,6 +39,7 @@ export class ServerData {
|
|
|
36
39
|
this.#onResetLoadEnd = onResetLoadEnd;
|
|
37
40
|
this.#onResetLoadError = onResetLoadError;
|
|
38
41
|
this.#onFlatten = onFlatten;
|
|
42
|
+
this.#onInvalidate = onInvalidate;
|
|
39
43
|
}
|
|
40
44
|
// Properties
|
|
41
45
|
set dataFetcher(d) {
|
|
@@ -77,29 +81,54 @@ export class ServerData {
|
|
|
77
81
|
this.#controllers.forEach((c) => c.abort());
|
|
78
82
|
this.#tree = makeAsyncTree();
|
|
79
83
|
this.#flatten();
|
|
84
|
+
this.#rowsWithError.clear();
|
|
85
|
+
this.#rowsWithGroupError.clear();
|
|
86
|
+
this.#loadingRows.clear();
|
|
87
|
+
this.#loadingGroup.clear();
|
|
80
88
|
try {
|
|
81
89
|
this.#onResetLoadBegin();
|
|
82
|
-
this.#
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const res = await this.#dataFetcher(
|
|
90
|
+
this.#seenRequests.clear();
|
|
91
|
+
const req = {
|
|
92
|
+
rowStartIndex: 0,
|
|
93
|
+
rowEndIndex: this.#blocksize,
|
|
94
|
+
id: getRequestId([], 0, this.#blocksize),
|
|
95
|
+
path: [],
|
|
96
|
+
start: 0,
|
|
97
|
+
end: this.#blocksize,
|
|
98
|
+
};
|
|
99
|
+
this.#seenRequests.add(req.id);
|
|
100
|
+
const res = await this.#dataFetcher([req], this.#expansions, this.#pivotExpansions);
|
|
93
101
|
this.handleResponses(res);
|
|
94
102
|
}
|
|
95
103
|
catch (e) {
|
|
96
|
-
console.log(e);
|
|
97
104
|
this.#onResetLoadError(e);
|
|
98
105
|
}
|
|
99
106
|
finally {
|
|
100
107
|
this.#onResetLoadEnd();
|
|
101
108
|
}
|
|
102
109
|
};
|
|
110
|
+
requestForGroup(i) {
|
|
111
|
+
const ranges = this.#flat.rangeTree.findRangesForRowIndex(i);
|
|
112
|
+
const path = ranges.slice(1).map((c) => (c.parent.kind === "parent" ? c.parent.path : null));
|
|
113
|
+
const row = this.#flat.rowIndexToRow.get(i);
|
|
114
|
+
if (row?.kind !== "branch")
|
|
115
|
+
return null;
|
|
116
|
+
path.push(row.key);
|
|
117
|
+
const r = (ranges.at(-1)?.parent).byPath.get(row.key);
|
|
118
|
+
const blocksize = this.#blocksize;
|
|
119
|
+
const start = 0;
|
|
120
|
+
const end = Math.min(start + blocksize, r.size);
|
|
121
|
+
const reqSize = end - start;
|
|
122
|
+
const req = {
|
|
123
|
+
path,
|
|
124
|
+
start: start,
|
|
125
|
+
end: end,
|
|
126
|
+
id: getRequestId(path, 0, blocksize),
|
|
127
|
+
rowStartIndex: i + 1,
|
|
128
|
+
rowEndIndex: i + 1 + reqSize,
|
|
129
|
+
};
|
|
130
|
+
return req;
|
|
131
|
+
}
|
|
103
132
|
handleRequests = async (requests, opts = {}) => {
|
|
104
133
|
const controller = new AbortController();
|
|
105
134
|
this.#controllers.add(controller);
|
|
@@ -133,10 +162,11 @@ export class ServerData {
|
|
|
133
162
|
if (controller.signal.aborted)
|
|
134
163
|
return;
|
|
135
164
|
opts?.onError?.(e);
|
|
165
|
+
this.#onInvalidate();
|
|
136
166
|
if (!skip)
|
|
137
167
|
requests.forEach((req) => {
|
|
138
168
|
for (let i = req.rowStartIndex; i < req.rowEndIndex; i++)
|
|
139
|
-
this.#rowsWithError.set(i, e);
|
|
169
|
+
this.#rowsWithError.set(i, { error: e, request: req });
|
|
140
170
|
for (let i = req.rowStartIndex; i < req.rowEndIndex; i++)
|
|
141
171
|
this.#loadingRows.delete(i);
|
|
142
172
|
});
|
|
@@ -204,8 +234,38 @@ export class ServerData {
|
|
|
204
234
|
// Re-flatten our tree once everything has been re-updated.
|
|
205
235
|
this.#flatten(beforeOnFlat);
|
|
206
236
|
};
|
|
207
|
-
|
|
208
|
-
|
|
237
|
+
requestForNextSlice(req) {
|
|
238
|
+
let current = this.#tree;
|
|
239
|
+
for (const c of req.path) {
|
|
240
|
+
if (current.kind === "leaf")
|
|
241
|
+
return null;
|
|
242
|
+
const next = current.byPath.get(c);
|
|
243
|
+
if (!next)
|
|
244
|
+
return null;
|
|
245
|
+
current = next;
|
|
246
|
+
}
|
|
247
|
+
if (current.kind === "leaf")
|
|
248
|
+
return null;
|
|
249
|
+
const maxSize = current.size;
|
|
250
|
+
if (req.end >= maxSize)
|
|
251
|
+
return null;
|
|
252
|
+
const prevSize = req.end - req.start;
|
|
253
|
+
const start = req.end;
|
|
254
|
+
const end = Math.min(req.end + this.#blocksize, maxSize);
|
|
255
|
+
const size = end - start;
|
|
256
|
+
return {
|
|
257
|
+
id: getRequestId(req.path, start, start + this.#blocksize),
|
|
258
|
+
path: req.path,
|
|
259
|
+
start,
|
|
260
|
+
end,
|
|
261
|
+
rowStartIndex: req.rowStartIndex + prevSize,
|
|
262
|
+
rowEndIndex: req.rowStartIndex + prevSize + size,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
requestsForView(start, end) {
|
|
266
|
+
const bounds = this.#rowViewBounds;
|
|
267
|
+
start = start ?? bounds[0];
|
|
268
|
+
end = end ?? bounds[1];
|
|
209
269
|
const seen = new Set();
|
|
210
270
|
const requests = [];
|
|
211
271
|
for (let i = start; i < end; i++) {
|
|
@@ -237,13 +297,74 @@ export class ServerData {
|
|
|
237
297
|
}
|
|
238
298
|
});
|
|
239
299
|
}
|
|
240
|
-
|
|
300
|
+
return requests;
|
|
301
|
+
}
|
|
302
|
+
async handleViewBoundsChange() {
|
|
303
|
+
const requests = this.requestsForView();
|
|
304
|
+
const newRequests = requests.filter((c) => !this.#seenRequests.has(c.id));
|
|
241
305
|
// We don't have any new requests to make in our view, so we can return
|
|
242
306
|
if (!newRequests.length)
|
|
243
307
|
return;
|
|
244
|
-
|
|
308
|
+
for (const n of newRequests)
|
|
309
|
+
this.#seenRequests.add(n.id);
|
|
245
310
|
await this.handleRequests(newRequests);
|
|
246
311
|
}
|
|
312
|
+
retry() {
|
|
313
|
+
const inViewSet = new Set(this.requestsForView().map((c) => c.id));
|
|
314
|
+
const erroredRequests = [...this.#rowsWithError.values()]
|
|
315
|
+
.map((c) => c.request)
|
|
316
|
+
.filter(Boolean);
|
|
317
|
+
const erroredGroups = [...this.#rowsWithGroupError.entries()];
|
|
318
|
+
const errors = erroredRequests.filter((x) => inViewSet.has(x.id));
|
|
319
|
+
const [start, end] = this.#rowViewBounds;
|
|
320
|
+
const groupErrors = erroredGroups
|
|
321
|
+
.filter(([index]) => {
|
|
322
|
+
return index >= start && index < end;
|
|
323
|
+
})
|
|
324
|
+
.map(([index, c]) => [index, c.request]);
|
|
325
|
+
const seenRequests = this.#seenRequests;
|
|
326
|
+
console.log(structuredClone(seenRequests));
|
|
327
|
+
erroredRequests.map((x) => seenRequests.delete(x.id));
|
|
328
|
+
erroredGroups.map((x) => seenRequests.delete(x[1].request.id));
|
|
329
|
+
console.log(structuredClone(seenRequests));
|
|
330
|
+
this.#rowsWithError.clear();
|
|
331
|
+
this.#rowsWithGroupError.clear();
|
|
332
|
+
const requests = [];
|
|
333
|
+
const seen = new Set();
|
|
334
|
+
groupErrors.forEach((x) => {
|
|
335
|
+
if (seen.has(x[1].id))
|
|
336
|
+
return;
|
|
337
|
+
requests.push(x[1]);
|
|
338
|
+
seen.add(x[1].id);
|
|
339
|
+
});
|
|
340
|
+
errors.forEach((x) => {
|
|
341
|
+
if (seen.has(x.id))
|
|
342
|
+
return;
|
|
343
|
+
seen.add(x.id);
|
|
344
|
+
requests.push(x);
|
|
345
|
+
});
|
|
346
|
+
for (const x of groupErrors) {
|
|
347
|
+
this.#loadingGroup.add(x[0]);
|
|
348
|
+
}
|
|
349
|
+
requests.forEach((x) => seenRequests.add(x.id));
|
|
350
|
+
const invalidate = this.#onInvalidate;
|
|
351
|
+
const withGroupError = this.#rowsWithGroupError;
|
|
352
|
+
const loadingGroup = this.#loadingGroup;
|
|
353
|
+
this.handleRequests(requests, {
|
|
354
|
+
onError: (e) => {
|
|
355
|
+
invalidate();
|
|
356
|
+
groupErrors.forEach((c) => {
|
|
357
|
+
withGroupError.set(c[0], { error: e, request: c[1] });
|
|
358
|
+
loadingGroup.delete(c[0]);
|
|
359
|
+
});
|
|
360
|
+
},
|
|
361
|
+
onSuccess: () => {
|
|
362
|
+
groupErrors.forEach((c) => {
|
|
363
|
+
loadingGroup.delete(c[0]);
|
|
364
|
+
});
|
|
365
|
+
},
|
|
366
|
+
});
|
|
367
|
+
}
|
|
247
368
|
updateRow(id, data) {
|
|
248
369
|
const centerRow = this.#flat.rowIdToTreeNode.get(id);
|
|
249
370
|
if (centerRow) {
|
|
@@ -260,19 +381,28 @@ export class ServerData {
|
|
|
260
381
|
this.#top.rows[botIndex] = { ...this.#top.rows[botIndex], data };
|
|
261
382
|
}
|
|
262
383
|
}
|
|
384
|
+
flatten = () => {
|
|
385
|
+
this.#flatten();
|
|
386
|
+
};
|
|
263
387
|
#flatten = (beforeOnFlat) => {
|
|
388
|
+
// The mode we are in determines the expansions we will use for the server data.
|
|
264
389
|
const mode = this.#pivotMode;
|
|
265
390
|
const expansions = mode ? this.#pivotExpansions : this.#expansions;
|
|
266
391
|
const t = this.#tree;
|
|
392
|
+
// We use these maps to keep track of the current view. These are helpful for
|
|
393
|
+
// quick lookup. They are also used to implement many of the data source APIs.
|
|
267
394
|
const rowIdToRow = new Map();
|
|
268
395
|
const rowIndexToRow = new Map();
|
|
269
396
|
const rowIdToRowIndex = new Map();
|
|
270
397
|
const rowIdToTreeNode = new Map();
|
|
398
|
+
// When flattening the tree we need to keep track of the ranges. The tree itself
|
|
399
|
+
// will only have some rows loaded, but the ranges will be fully defined.
|
|
271
400
|
const ranges = [];
|
|
272
401
|
const blocksize = this.#blocksize;
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
const
|
|
402
|
+
const seen = this.#seenRequests;
|
|
403
|
+
// Tracks the error and loading state of the rows.
|
|
404
|
+
const withGroupError = this.#rowsWithGroupError;
|
|
405
|
+
const withLoadingGroup = this.#loadingGroup;
|
|
276
406
|
const handleRequests = this.handleRequests;
|
|
277
407
|
const defaultExpansion = this.#defaultExpansion;
|
|
278
408
|
const postFlatRequests = [];
|
|
@@ -286,11 +416,17 @@ export class ServerData {
|
|
|
286
416
|
rowIdToRowIndex.set(row.data.id, rowIndex);
|
|
287
417
|
rowIdToRow.set(row.data.id, row.data);
|
|
288
418
|
rowIdToTreeNode.set(row.data.id, row);
|
|
419
|
+
// If this rows is a parent row, we need to check if it is expanded. There are a couple of
|
|
420
|
+
// situations this to consider.
|
|
421
|
+
// - the row is not expanded, in which case we only add the row itself to the flat view
|
|
422
|
+
// - the row is expanded but it has no data loaded. We should then request data, but not add the rows
|
|
423
|
+
// - the row is expanded and there is add. This is the easy case, we simply add the child rows as we flatten
|
|
289
424
|
if (row.kind === "parent") {
|
|
290
425
|
const expanded = expansions[row.data.id] ??
|
|
291
426
|
(typeof defaultExpansion === "number"
|
|
292
427
|
? getNodeDepth(row) <= defaultExpansion
|
|
293
428
|
: defaultExpansion);
|
|
429
|
+
// Expanded but no data. Fetch the child data.
|
|
294
430
|
if (expanded && !row.byIndex.size) {
|
|
295
431
|
const path = getNodePath(row);
|
|
296
432
|
const start = 0;
|
|
@@ -304,8 +440,8 @@ export class ServerData {
|
|
|
304
440
|
rowStartIndex: rowIndex + 1,
|
|
305
441
|
rowEndIndex: rowIndex + 1 + reqSize,
|
|
306
442
|
};
|
|
307
|
-
// If we haven't already requested this node
|
|
308
|
-
if (!
|
|
443
|
+
// If we haven't already requested the children data for this node, let's request it.
|
|
444
|
+
if (!seen.has(req.id)) {
|
|
309
445
|
postFlatRequests.push([rowIndex, req]);
|
|
310
446
|
}
|
|
311
447
|
}
|
|
@@ -340,21 +476,25 @@ export class ServerData {
|
|
|
340
476
|
const rangeTree = new RangeTree(ranges);
|
|
341
477
|
if (postFlatRequests.length > 0) {
|
|
342
478
|
postFlatRequests.forEach((c) => {
|
|
343
|
-
|
|
344
|
-
|
|
479
|
+
withLoadingGroup.add(c[0]);
|
|
480
|
+
seen.add(c[1].id);
|
|
345
481
|
});
|
|
482
|
+
const invalidate = this.#onInvalidate;
|
|
346
483
|
const reqs = postFlatRequests.map((c) => c[1]);
|
|
347
484
|
handleRequests(reqs, {
|
|
348
485
|
skipState: true,
|
|
349
486
|
onError: (e) => {
|
|
487
|
+
invalidate();
|
|
350
488
|
postFlatRequests.forEach((c) => {
|
|
351
|
-
|
|
352
|
-
|
|
489
|
+
const rowIndex = c[0];
|
|
490
|
+
const req = c[1];
|
|
491
|
+
withLoadingGroup.delete(rowIndex);
|
|
492
|
+
withGroupError.set(rowIndex, { error: e, request: req });
|
|
353
493
|
});
|
|
354
494
|
},
|
|
355
495
|
onSuccess: () => {
|
|
356
496
|
postFlatRequests.forEach((c) => {
|
|
357
|
-
|
|
497
|
+
withLoadingGroup.delete(c[0]);
|
|
358
498
|
});
|
|
359
499
|
},
|
|
360
500
|
});
|
|
@@ -370,7 +510,10 @@ export class ServerData {
|
|
|
370
510
|
rowIdToRowIndex,
|
|
371
511
|
rowIdToTreeNode,
|
|
372
512
|
errored: this.#rowsWithError,
|
|
513
|
+
erroredGroup: this.#rowsWithGroupError,
|
|
373
514
|
loading: this.#loadingRows,
|
|
515
|
+
loadingGroup: this.#loadingGroup,
|
|
516
|
+
seenRequests: seen,
|
|
374
517
|
};
|
|
375
518
|
beforeOnFlat?.();
|
|
376
519
|
this.#onFlatten(this.#flat);
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { RowDataSourceServer, RowDataSourceServerParams } from "../+types.js";
|
|
2
|
-
export declare function makeServerDataSource<T>({ dataFetcher, dataInFilterItemFetcher, dataColumnPivotFetcher, cellUpdateHandler, cellUpdateOptimistically, blockSize, }: RowDataSourceServerParams<T>): RowDataSourceServer<T>;
|
|
2
|
+
export declare function makeServerDataSource<T>({ dataFetcher, dataInFilterItemFetcher, dataColumnPivotFetcher, cellUpdateHandler, cellUpdateOptimistically, blockSize, }: Omit<RowDataSourceServerParams<T>, "dataFetchExternals">): RowDataSourceServer<T>;
|
|
3
3
|
export declare function useServerDataSource<T>(p: RowDataSourceServerParams<T>): RowDataSourceServer<T>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { effect, makeAtom, signal } from "@1771technologies/lytenyte-
|
|
1
|
+
import { effect, makeAtom, signal } from "@1771technologies/lytenyte-core/yinternal";
|
|
2
2
|
import { useRef } from "react";
|
|
3
3
|
import { ServerData } from "./server-data.js";
|
|
4
|
-
import { equal } from "@1771technologies/lytenyte-
|
|
4
|
+
import { equal } from "@1771technologies/lytenyte-shared";
|
|
5
5
|
export function makeServerDataSource({ dataFetcher, dataInFilterItemFetcher, dataColumnPivotFetcher, cellUpdateHandler, cellUpdateOptimistically, blockSize = 200, }) {
|
|
6
6
|
let grid = null;
|
|
7
7
|
let flat;
|
|
@@ -9,6 +9,7 @@ export function makeServerDataSource({ dataFetcher, dataInFilterItemFetcher, dat
|
|
|
9
9
|
void grid;
|
|
10
10
|
const isLoading = makeAtom(signal(false));
|
|
11
11
|
const loadError = makeAtom(signal(null));
|
|
12
|
+
const requestsForView = makeAtom(signal([]));
|
|
12
13
|
const cleanup = [];
|
|
13
14
|
const init = (g) => {
|
|
14
15
|
grid = g;
|
|
@@ -22,6 +23,7 @@ export function makeServerDataSource({ dataFetcher, dataInFilterItemFetcher, dat
|
|
|
22
23
|
isLoading.set(true);
|
|
23
24
|
loadError.set(null);
|
|
24
25
|
},
|
|
26
|
+
onInvalidate: () => g.state.rowDataStore.rowClearCache(),
|
|
25
27
|
onResetLoadEnd: () => isLoading.set(false),
|
|
26
28
|
onResetLoadError: (e) => loadError.set(e),
|
|
27
29
|
onFlatten: (f) => {
|
|
@@ -119,6 +121,11 @@ export function makeServerDataSource({ dataFetcher, dataInFilterItemFetcher, dat
|
|
|
119
121
|
cleanup.push(g.state.viewBounds.watch(() => {
|
|
120
122
|
const bounds = g.state.viewBounds.get();
|
|
121
123
|
source.rowViewBounds = [bounds.rowCenterStart, bounds.rowCenterEnd];
|
|
124
|
+
const requests = source.requestsForView();
|
|
125
|
+
const current = requestsForView.get();
|
|
126
|
+
if (equal(requests, current))
|
|
127
|
+
return;
|
|
128
|
+
requestsForView.set(requests);
|
|
122
129
|
}));
|
|
123
130
|
source.dataFetcher = (req, expansions, pivotExpansions) => {
|
|
124
131
|
return dataFetcher({
|
|
@@ -161,8 +168,9 @@ export function makeServerDataSource({ dataFetcher, dataInFilterItemFetcher, dat
|
|
|
161
168
|
const rowByIndex = (i) => {
|
|
162
169
|
const row = flat.rowIndexToRow.get(i);
|
|
163
170
|
const isLoading = flat.loading.has(i);
|
|
171
|
+
const isGroupLoading = flat.loadingGroup.has(i);
|
|
172
|
+
const errorGroup = flat.erroredGroup.get(i);
|
|
164
173
|
const error = flat.errored.get(i);
|
|
165
|
-
// If we haven't loaded a row yet.
|
|
166
174
|
if (!row)
|
|
167
175
|
return {
|
|
168
176
|
id: `__loading__placeholder__${i}`,
|
|
@@ -171,13 +179,23 @@ export function makeServerDataSource({ dataFetcher, dataInFilterItemFetcher, dat
|
|
|
171
179
|
loading: isLoading,
|
|
172
180
|
error: error,
|
|
173
181
|
};
|
|
174
|
-
if (
|
|
175
|
-
|
|
182
|
+
if (row.kind === "leaf") {
|
|
183
|
+
if (error || isLoading) {
|
|
184
|
+
return { ...row, loading: isLoading, error: error?.error };
|
|
185
|
+
}
|
|
176
186
|
}
|
|
177
|
-
if (
|
|
178
|
-
|
|
187
|
+
else if (row.kind === "branch") {
|
|
188
|
+
if (error || isLoading || isGroupLoading || errorGroup) {
|
|
189
|
+
return {
|
|
190
|
+
...row,
|
|
191
|
+
loading: isLoading,
|
|
192
|
+
error: error?.error,
|
|
193
|
+
errorGroup: errorGroup?.error,
|
|
194
|
+
loadingGroup: isGroupLoading,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
179
197
|
}
|
|
180
|
-
return
|
|
198
|
+
return row ?? null;
|
|
181
199
|
};
|
|
182
200
|
const rowExpand = (expansions) => {
|
|
183
201
|
if (!grid)
|
|
@@ -290,7 +308,7 @@ export function makeServerDataSource({ dataFetcher, dataInFilterItemFetcher, dat
|
|
|
290
308
|
idMap.forEach((data, id) => {
|
|
291
309
|
source.updateRow(id, data);
|
|
292
310
|
});
|
|
293
|
-
|
|
311
|
+
source.flatten();
|
|
294
312
|
};
|
|
295
313
|
const inFilterItems = (c) => {
|
|
296
314
|
if (!dataInFilterItemFetcher || !grid)
|
|
@@ -309,7 +327,23 @@ export function makeServerDataSource({ dataFetcher, dataInFilterItemFetcher, dat
|
|
|
309
327
|
const pushRequests = (requests) => {
|
|
310
328
|
source.handleRequests(requests);
|
|
311
329
|
};
|
|
312
|
-
const retry = () => {
|
|
330
|
+
const retry = () => {
|
|
331
|
+
source.retry();
|
|
332
|
+
grid?.state.rowDataStore.rowClearCache();
|
|
333
|
+
};
|
|
334
|
+
const refresh = (onSuccess, onError) => {
|
|
335
|
+
const requests = source.requestsForView();
|
|
336
|
+
pushRequests(requests, onSuccess, onError);
|
|
337
|
+
};
|
|
338
|
+
const requestForGroup = (row) => {
|
|
339
|
+
const index = typeof row === "number" ? row : flat.rowIdToRowIndex.get(row.id);
|
|
340
|
+
if (index == null)
|
|
341
|
+
return null;
|
|
342
|
+
return source.requestForGroup(index);
|
|
343
|
+
};
|
|
344
|
+
const requestForNextSlice = (req) => {
|
|
345
|
+
return source.requestForNextSlice(req);
|
|
346
|
+
};
|
|
313
347
|
return {
|
|
314
348
|
init,
|
|
315
349
|
rowAdd,
|
|
@@ -333,12 +367,47 @@ export function makeServerDataSource({ dataFetcher, dataInFilterItemFetcher, dat
|
|
|
333
367
|
pushRequests,
|
|
334
368
|
reset,
|
|
335
369
|
retry,
|
|
370
|
+
refresh,
|
|
371
|
+
requestsForView: requestsForView,
|
|
372
|
+
requestForGroup,
|
|
373
|
+
requestForNextSlice,
|
|
374
|
+
get seenRequests() {
|
|
375
|
+
return flat.seenRequests;
|
|
376
|
+
},
|
|
336
377
|
};
|
|
337
378
|
}
|
|
338
379
|
export function useServerDataSource(p) {
|
|
339
380
|
const ds = useRef(null);
|
|
381
|
+
const fetcherRef = useRef(p.dataFetcher);
|
|
382
|
+
const prevExternal = useRef(p.dataFetchExternals ?? []);
|
|
383
|
+
const animRef = useRef(false);
|
|
384
|
+
if (!arrayShallow(prevExternal.current, p.dataFetchExternals ?? [])) {
|
|
385
|
+
prevExternal.current = p.dataFetchExternals ?? [];
|
|
386
|
+
fetcherRef.current = p.dataFetcher;
|
|
387
|
+
if (ds.current && !animRef.current) {
|
|
388
|
+
animRef.current = true;
|
|
389
|
+
queueMicrotask(() => {
|
|
390
|
+
ds.current.reset();
|
|
391
|
+
animRef.current = false;
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
}
|
|
340
395
|
if (!ds.current) {
|
|
341
|
-
ds.current = makeServerDataSource(
|
|
396
|
+
ds.current = makeServerDataSource({
|
|
397
|
+
...p,
|
|
398
|
+
dataFetcher: (params) => {
|
|
399
|
+
return fetcherRef.current(params);
|
|
400
|
+
},
|
|
401
|
+
});
|
|
342
402
|
}
|
|
343
403
|
return ds.current;
|
|
344
404
|
}
|
|
405
|
+
function arrayShallow(left, right) {
|
|
406
|
+
if (left.length !== right.length)
|
|
407
|
+
return false;
|
|
408
|
+
for (let i = 0; i < left.length; i++) {
|
|
409
|
+
if (left[i] !== right[i])
|
|
410
|
+
return false;
|
|
411
|
+
}
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
2
|
import { sortModelToSortItems } from "../utils/sort-model-to-sort-items.js";
|
|
3
|
-
import { itemsWithIdToMap } from "@1771technologies/lytenyte-
|
|
3
|
+
import { itemsWithIdToMap } from "@1771technologies/lytenyte-shared";
|
|
4
4
|
import { useSortRowItems } from "./use-sort-row-item.js";
|
|
5
|
-
import { useEvent } from "@1771technologies/lytenyte-
|
|
5
|
+
import { useEvent } from "@1771technologies/lytenyte-core/yinternal";
|
|
6
6
|
export function useSortManager({ grid, pivotMode }) {
|
|
7
7
|
const statePivotMode = grid.state.columnPivotMode.useValue();
|
|
8
8
|
const mode = pivotMode ?? statePivotMode;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useMemo } from "react";
|
|
2
2
|
import { useSortableColumnItems } from "./use-sortable-column-items.js";
|
|
3
|
-
import { itemsWithIdToMap } from "@1771technologies/lytenyte-
|
|
3
|
+
import { itemsWithIdToMap } from "@1771technologies/lytenyte-shared";
|
|
4
4
|
export function useSortRowItems(sortItems, setSortItems, grid, pivotMode) {
|
|
5
5
|
const columnItems = useSortableColumnItems(grid, pivotMode);
|
|
6
6
|
const pivotColumns = grid.state.columnPivotColumns.useValue();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useSlot } from "@1771technologies/lytenyte-react-hooks";
|
|
3
2
|
import { forwardRef } from "react";
|
|
4
3
|
import { useSortRowCtx } from "./context.js";
|
|
4
|
+
import { useSlot } from "@1771technologies/lytenyte-core/yinternal";
|
|
5
5
|
export const SortAdd = forwardRef(function SortAdd({ as: as, ...props }, forwarded) {
|
|
6
6
|
const row = useSortRowCtx();
|
|
7
7
|
const renderer = useSlot({
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useEvent, useSlot } from "@1771technologies/lytenyte-react-hooks";
|
|
3
2
|
import { forwardRef } from "react";
|
|
4
3
|
import { useSortManagerCtx } from "./context.js";
|
|
5
|
-
import { itemsWithIdToMap } from "@1771technologies/lytenyte-
|
|
4
|
+
import { itemsWithIdToMap } from "@1771technologies/lytenyte-shared";
|
|
6
5
|
import { sortItemsToSortModel } from "./utils/sort-item-to-sort-model.js";
|
|
6
|
+
import { useEvent, useSlot } from "@1771technologies/lytenyte-core/yinternal";
|
|
7
7
|
export const SortApply = forwardRef(function SortApply({ as, ...props }, forwarded) {
|
|
8
8
|
const ctx = useSortManagerCtx();
|
|
9
9
|
const onApply = useEvent(() => {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useEvent, useSlot } from "@1771technologies/lytenyte-react-hooks";
|
|
3
2
|
import { forwardRef } from "react";
|
|
4
3
|
import { useSortManagerCtx } from "./context.js";
|
|
5
4
|
import { sortModelToSortItems } from "./utils/sort-model-to-sort-items.js";
|
|
6
|
-
import { itemsWithIdToMap } from "@1771technologies/lytenyte-
|
|
5
|
+
import { itemsWithIdToMap } from "@1771technologies/lytenyte-shared";
|
|
6
|
+
import { useEvent, useSlot } from "@1771technologies/lytenyte-core/yinternal";
|
|
7
7
|
export const SortCancel = forwardRef(function SortCancel({ as, ...props }, forwarded) {
|
|
8
8
|
const ctx = useSortManagerCtx();
|
|
9
9
|
const onCancel = useEvent(() => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useEvent, useSlot } from "@1771technologies/lytenyte-react-hooks";
|
|
3
2
|
import { forwardRef } from "react";
|
|
4
3
|
import { useSortManagerCtx } from "./context.js";
|
|
4
|
+
import { useEvent, useSlot } from "@1771technologies/lytenyte-core/yinternal";
|
|
5
5
|
export const SortClear = forwardRef(function SortClear({ as, ...props }, forwarded) {
|
|
6
6
|
const ctx = useSortManagerCtx();
|
|
7
7
|
const onClear = useEvent(() => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type SlotComponent } from "@1771technologies/lytenyte-react-hooks";
|
|
2
1
|
import type { Option } from "./+types";
|
|
2
|
+
import { type SlotComponent } from "@1771technologies/lytenyte-core/yinternal";
|
|
3
3
|
export interface SortColumnSelectProps {
|
|
4
4
|
readonly as?: SlotComponent<{
|
|
5
5
|
options: Option[];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useSlot } from "@1771technologies/lytenyte-react-hooks";
|
|
3
2
|
import { forwardRef } from "react";
|
|
4
3
|
import { useSortRowCtx } from "./context.js";
|
|
4
|
+
import { useSlot } from "@1771technologies/lytenyte-core/yinternal";
|
|
5
5
|
export const SortColumnSelect = forwardRef(function SortColumnSelect({ as, ...props }, forwarded) {
|
|
6
6
|
const row = useSortRowCtx();
|
|
7
7
|
const el = (_jsxs("select", { "aria-label": "Select column to sort", value: row.columnItem?.value ?? "", onChange: (e) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type SlotComponent } from "@1771technologies/lytenyte-react-hooks";
|
|
2
1
|
import type { Option } from "./+types";
|
|
2
|
+
import { type SlotComponent } from "@1771technologies/lytenyte-core/yinternal";
|
|
3
3
|
export interface SortDirectionSelectProps {
|
|
4
4
|
readonly as?: SlotComponent<{
|
|
5
5
|
options: Option[];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useSlot } from "@1771technologies/lytenyte-react-hooks";
|
|
3
2
|
import { forwardRef } from "react";
|
|
4
3
|
import { useSortRowCtx } from "./context.js";
|
|
4
|
+
import { useSlot } from "@1771technologies/lytenyte-core/yinternal";
|
|
5
5
|
export const SortDirectionSelect = forwardRef(function SortDirectionSelect({ as, ...props }, forwarded) {
|
|
6
6
|
const row = useSortRowCtx();
|
|
7
7
|
const el = (_jsx("select", { "aria-label": "Select sort direction", value: row.sortDirectionSelected?.value ?? "", onChange: (e) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useSlot } from "@1771technologies/lytenyte-react-hooks";
|
|
3
2
|
import { forwardRef } from "react";
|
|
4
3
|
import { useSortRowCtx } from "./context.js";
|
|
4
|
+
import { useSlot } from "@1771technologies/lytenyte-core/yinternal";
|
|
5
5
|
export const SortRemove = forwardRef(function SortRemove({ as, ...props }, forwarded) {
|
|
6
6
|
const row = useSortRowCtx();
|
|
7
7
|
const renderer = useSlot({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type SlotComponent } from "@1771technologies/lytenyte-react-hooks";
|
|
2
1
|
import type { Option } from "./+types";
|
|
2
|
+
import { type SlotComponent } from "@1771technologies/lytenyte-core/yinternal";
|
|
3
3
|
export interface SortValueSelectProps {
|
|
4
4
|
readonly as?: SlotComponent<{
|
|
5
5
|
options: Option[];
|