@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.
Files changed (134) hide show
  1. package/dist/+types.d.ts +442 -65
  2. package/dist/__play__/filter-select/filter-select.play.d.ts +4 -0
  3. package/dist/__play__/filter-select/filter-select.play.js +76 -0
  4. package/dist/__play__/test-utils/row-handler.js +3 -4
  5. package/dist/cell-selection/bound-selection-rect.js +1 -1
  6. package/dist/cell-selection/cell-selection-driver.js +7 -6
  7. package/dist/column-manager/branch.d.ts +1 -1
  8. package/dist/column-manager/branch.js +1 -1
  9. package/dist/column-manager/label.d.ts +1 -1
  10. package/dist/column-manager/label.js +1 -1
  11. package/dist/column-manager/leaf.js +1 -1
  12. package/dist/column-manager/move-handle.d.ts +1 -1
  13. package/dist/column-manager/move-handle.js +1 -2
  14. package/dist/column-manager/visibility-checkbox.d.ts +1 -1
  15. package/dist/column-manager/visibility-checkbox.js +1 -1
  16. package/dist/filter-selects/apply.d.ts +7 -0
  17. package/dist/filter-selects/apply.js +22 -0
  18. package/dist/filter-selects/clear.d.ts +7 -0
  19. package/dist/filter-selects/clear.js +22 -0
  20. package/dist/filter-selects/context.d.ts +13 -0
  21. package/dist/filter-selects/context.js +3 -0
  22. package/dist/filter-selects/filter-combinator.d.ts +10 -0
  23. package/dist/filter-selects/filter-combinator.js +19 -0
  24. package/dist/filter-selects/filter-row-context.d.ts +30 -0
  25. package/dist/filter-selects/filter-row-context.js +3 -0
  26. package/dist/filter-selects/filter-row.d.ts +13 -0
  27. package/dist/filter-selects/filter-row.js +118 -0
  28. package/dist/filter-selects/index.d.ts +22 -0
  29. package/dist/filter-selects/index.js +20 -0
  30. package/dist/filter-selects/is-complete-filter.d.ts +2 -0
  31. package/dist/filter-selects/is-complete-filter.js +5 -0
  32. package/dist/filter-selects/operator-select.d.ts +14 -0
  33. package/dist/filter-selects/operator-select.js +25 -0
  34. package/dist/filter-selects/options.d.ts +9 -0
  35. package/dist/filter-selects/options.js +100 -0
  36. package/dist/filter-selects/reset.d.ts +7 -0
  37. package/dist/filter-selects/reset.js +22 -0
  38. package/dist/filter-selects/root.d.ts +14 -0
  39. package/dist/filter-selects/root.js +5 -0
  40. package/dist/filter-selects/to-filter-item.d.ts +3 -0
  41. package/dist/filter-selects/to-filter-item.js +7 -0
  42. package/dist/filter-selects/use-filter-select.d.ts +38 -0
  43. package/dist/filter-selects/use-filter-select.js +168 -0
  44. package/dist/filter-selects/value-input.d.ts +12 -0
  45. package/dist/filter-selects/value-input.js +27 -0
  46. package/dist/filter-tree/branch.d.ts +1 -1
  47. package/dist/filter-tree/branch.js +1 -1
  48. package/dist/filter-tree/hooks/use-filter-tree.js +1 -1
  49. package/dist/filter-tree/inclusion-checkbox.d.ts +1 -1
  50. package/dist/filter-tree/inclusion-checkbox.js +1 -1
  51. package/dist/filter-tree/label.d.ts +1 -1
  52. package/dist/filter-tree/label.js +1 -1
  53. package/dist/filter-tree/root.d.ts +1 -1
  54. package/dist/filter-tree/root.js +1 -1
  55. package/dist/grid/header-cell.d.ts +1 -1
  56. package/dist/grid/header-cell.js +1 -2
  57. package/dist/grid/header.d.ts +1 -1
  58. package/dist/grid/row-full-width.d.ts +1 -1
  59. package/dist/grid/row-full-width.js +1 -2
  60. package/dist/grid/row.d.ts +1 -1
  61. package/dist/grid/row.js +0 -1
  62. package/dist/grid/rows-container.d.ts +1 -1
  63. package/dist/grid-box/item.d.ts +1 -1
  64. package/dist/grid-box/item.js +1 -2
  65. package/dist/grid-box/panel.js +1 -1
  66. package/dist/grid-box/use-aggregation-box-items.js +1 -1
  67. package/dist/grid-box/use-column-box-items.js +1 -1
  68. package/dist/grid-box/use-row-group-box-items.js +1 -1
  69. package/dist/grid.d.ts +2 -2
  70. package/dist/index.d.ts +2 -1
  71. package/dist/index.js +2 -1
  72. package/dist/license/index.d.ts +1 -0
  73. package/dist/license/index.js +1 -0
  74. package/dist/license/license.d.ts +3 -0
  75. package/dist/license/license.js +215 -0
  76. package/dist/license/md5-hash.d.ts +9 -0
  77. package/dist/license/md5-hash.js +167 -0
  78. package/dist/license.js +1 -1
  79. package/dist/listbox/item.js +1 -1
  80. package/dist/listbox/panel.js +2 -2
  81. package/dist/row-data-source-client/filter/compute-filtered-rows.js +1 -1
  82. package/dist/row-data-source-client/pivots/create-pivot-columns-from-paths.js +1 -1
  83. package/dist/row-data-source-client/use-client-data-source-paginated.js +3 -2
  84. package/dist/row-data-source-client/use-client-data-source.js +3 -2
  85. package/dist/row-data-source-client/use-client-tree-data-source.js +3 -2
  86. package/dist/row-data-source-server/server-data.d.ts +24 -2
  87. package/dist/row-data-source-server/server-data.js +173 -30
  88. package/dist/row-data-source-server/use-server-data-source.d.ts +1 -1
  89. package/dist/row-data-source-server/use-server-data-source.js +80 -11
  90. package/dist/sort-manager/hooks/use-sort-manager.js +2 -2
  91. package/dist/sort-manager/hooks/use-sort-row-item.js +1 -1
  92. package/dist/sort-manager/sort-add.d.ts +1 -1
  93. package/dist/sort-manager/sort-add.js +1 -1
  94. package/dist/sort-manager/sort-apply.d.ts +1 -1
  95. package/dist/sort-manager/sort-apply.js +2 -2
  96. package/dist/sort-manager/sort-cancel.d.ts +1 -1
  97. package/dist/sort-manager/sort-cancel.js +2 -2
  98. package/dist/sort-manager/sort-clear.d.ts +1 -1
  99. package/dist/sort-manager/sort-clear.js +1 -1
  100. package/dist/sort-manager/sort-column-select.d.ts +1 -1
  101. package/dist/sort-manager/sort-column-select.js +1 -1
  102. package/dist/sort-manager/sort-direction-select.d.ts +1 -1
  103. package/dist/sort-manager/sort-direction-select.js +1 -1
  104. package/dist/sort-manager/sort-remove.d.ts +1 -1
  105. package/dist/sort-manager/sort-remove.js +1 -1
  106. package/dist/sort-manager/sort-value-select.d.ts +1 -1
  107. package/dist/sort-manager/sort-value-select.js +1 -1
  108. package/dist/state/+types.d.ts +2 -1
  109. package/dist/state/api/column-field.js +1 -1
  110. package/dist/state/api/edit-begin.js +1 -1
  111. package/dist/state/api/focus-cell.js +1 -1
  112. package/dist/state/api/position-from-element.d.ts +5 -2
  113. package/dist/state/api/position-from-element.js +3 -3
  114. package/dist/state/api/row-handle-select.js +1 -1
  115. package/dist/state/api/use-row-drag.js +3 -2
  116. package/dist/state/helpers/column-add-row-group.js +1 -1
  117. package/dist/state/helpers/column-marker.js +1 -1
  118. package/dist/state/use-lytenyte.js +18 -3
  119. package/dist/tree-view/branch/branch.d.ts +1 -1
  120. package/dist/tree-view/branch/branch.js +1 -1
  121. package/dist/tree-view/branch/use-branch-keys.js +2 -2
  122. package/dist/tree-view/leaf.js +1 -1
  123. package/dist/tree-view/panel/make-handle-navigation.js +1 -1
  124. package/dist/tree-view/panel/make-handle-selection.js +1 -1
  125. package/dist/tree-view/panel/panel.js +2 -2
  126. package/dist/tree-view/panel/use-tree-navigation.js +1 -1
  127. package/dist/tree-view/root.js +1 -1
  128. package/dist/tree-view/utils/get-focusable-nodes.js +1 -1
  129. package/dist/tree-view/utils/get-focused-node.js +1 -1
  130. package/dist/tree-view/utils/get-sibling-branches.js +1 -1
  131. package/dist/tree-view/virtualized/use-row-start-and-end.d.ts +1 -1
  132. package/dist/tree-view/virtualized/use-row-start-and-end.js +1 -1
  133. package/dist/tree-view/virtualized/use-virtualized-tree.js +1 -1
  134. package/package.json +3 -7
@@ -1,4 +1,4 @@
1
- import { equal } from "@1771technologies/lytenyte-js-utils";
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
- #prevRequests = [];
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.#prevRequests = [
83
- {
84
- rowStartIndex: 0,
85
- rowEndIndex: this.#blocksize,
86
- id: getRequestId([], 0, this.#blocksize),
87
- path: [],
88
- start: 0,
89
- end: this.#blocksize,
90
- },
91
- ];
92
- const res = await this.#dataFetcher(this.#prevRequests, this.#expansions, this.#pivotExpansions);
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
- async handleViewBoundsChange() {
208
- const [start, end] = this.#rowViewBounds;
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
- const newRequests = requests.filter((c) => !this.#prevRequests.find((prev) => prev.id === c.id));
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
- this.#prevRequests = requests;
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 previousRequests = this.#prevRequests;
274
- const withError = this.#rowsWithError;
275
- const withLoading = this.#loadingRows;
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 (!previousRequests.find((c) => c.id === req.id)) {
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
- withLoading.add(c[0]);
344
- previousRequests.push(c[1]);
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
- withLoading.delete(c[0]);
352
- withError.set(c[0], e);
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
- withLoading.delete(c[0]);
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-shared";
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-js-utils";
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 (error) {
175
- return { ...row, error };
182
+ if (row.kind === "leaf") {
183
+ if (error || isLoading) {
184
+ return { ...row, loading: isLoading, error: error?.error };
185
+ }
176
186
  }
177
- if (isLoading) {
178
- return { ...row, loading: isLoading };
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 flat.rowIndexToRow.get(i) ?? null;
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
- grid?.state.rowDataStore.rowClearCache();
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(p);
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-js-utils";
3
+ import { itemsWithIdToMap } from "@1771technologies/lytenyte-shared";
4
4
  import { useSortRowItems } from "./use-sort-row-item.js";
5
- import { useEvent } from "@1771technologies/lytenyte-react-hooks";
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-js-utils";
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,4 +1,4 @@
1
- import { type SlotComponent } from "@1771technologies/lytenyte-react-hooks";
1
+ import { type SlotComponent } from "@1771technologies/lytenyte-core/yinternal";
2
2
  export interface SortAddProps {
3
3
  readonly as?: SlotComponent<{
4
4
  onAdd: () => void;
@@ -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,4 +1,4 @@
1
- import { type SlotComponent } from "@1771technologies/lytenyte-react-hooks";
1
+ import { type SlotComponent } from "@1771technologies/lytenyte-core/yinternal";
2
2
  export interface SortApplyProps {
3
3
  readonly as?: SlotComponent<{
4
4
  onApply: () => void;
@@ -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-js-utils";
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,4 +1,4 @@
1
- import { type SlotComponent } from "@1771technologies/lytenyte-react-hooks";
1
+ import { type SlotComponent } from "@1771technologies/lytenyte-core/yinternal";
2
2
  export interface SortCancelProps {
3
3
  readonly as?: SlotComponent<{
4
4
  onCancel: () => void;
@@ -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-js-utils";
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,4 +1,4 @@
1
- import { type SlotComponent } from "@1771technologies/lytenyte-react-hooks";
1
+ import { type SlotComponent } from "@1771technologies/lytenyte-core/yinternal";
2
2
  export interface SortClearProps {
3
3
  readonly as?: SlotComponent<{
4
4
  onClear: () => void;
@@ -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,4 +1,4 @@
1
- import { type SlotComponent } from "@1771technologies/lytenyte-react-hooks";
1
+ import { type SlotComponent } from "@1771technologies/lytenyte-core/yinternal";
2
2
  export interface SortRemoveProps {
3
3
  readonly as?: SlotComponent<{
4
4
  onRemove: () => void;
@@ -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[];