@vuu-ui/vuu-data-local 4.0.1 → 4.1.1

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/package.json CHANGED
@@ -1,23 +1,22 @@
1
1
  {
2
- "version": "4.0.1",
2
+ "version": "4.1.1",
3
3
  "main": "./src/index.js",
4
4
  "author": "heswell",
5
5
  "license": "Apache-2.0",
6
6
  "scripts": {
7
- "build:dev": "node ../../scripts/run-build.mjs",
8
7
  "build": "node ../../scripts/run-build-rslib.ts",
9
8
  "test": "vitest run",
10
9
  "type-defs": "node ../../scripts/build-type-defs.mjs"
11
10
  },
12
11
  "devDependencies": {
13
- "@vuu-ui/vuu-data-types": "4.0.1",
14
- "@vuu-ui/vuu-table-types": "4.0.1",
15
- "@vuu-ui/vuu-filter-types": "4.0.1",
16
- "@vuu-ui/vuu-protocol-types": "4.0.1"
12
+ "@vuu-ui/vuu-data-types": "4.1.1",
13
+ "@vuu-ui/vuu-table-types": "4.1.1",
14
+ "@vuu-ui/vuu-filter-types": "4.1.1",
15
+ "@vuu-ui/vuu-protocol-types": "4.1.1"
17
16
  },
18
17
  "dependencies": {
19
- "@vuu-ui/vuu-filter-parser": "4.0.1",
20
- "@vuu-ui/vuu-utils": "4.0.1"
18
+ "@vuu-ui/vuu-filter-parser": "4.1.1",
19
+ "@vuu-ui/vuu-utils": "4.1.1"
21
20
  },
22
21
  "sideEffects": false,
23
22
  "files": [
@@ -1,4 +1,4 @@
1
- import { BaseDataSource, KeySet, NULL_RANGE, getParentRow, isSingleValueFilter, lastPathSegment, metadataKeys, missingAncestor, treeToDataSourceRows, uuid } from "@vuu-ui/vuu-utils";
1
+ import { BaseDataSource, KeySet, NULL_RANGE, getParentRow, isSingleValueFilter, lastPathSegment, metadataKeys, treeToDataSourceRows, uuid } from "@vuu-ui/vuu-utils";
2
2
  import { IconProvider } from "./IconProvider.js";
3
3
  import { parseFilter } from "@vuu-ui/vuu-filter-parser";
4
4
  const treeSchema = (columns)=>({
@@ -32,6 +32,7 @@ class TreeDataSource extends BaseDataSource {
32
32
  #size = 0;
33
33
  #status = "initialising";
34
34
  #filterSet;
35
+ #filterCollapsedRows = new Set();
35
36
  rowCount;
36
37
  keys = new KeySet(this._range);
37
38
  constructor({ data, ...props }){
@@ -40,7 +41,6 @@ class TreeDataSource extends BaseDataSource {
40
41
  this.#iconProvider = new IconProvider();
41
42
  [this.columnDescriptors, this.#data] = treeToDataSourceRows(data, this.#iconProvider);
42
43
  this.expandedRows = getInitiallyExpandedKeys(data);
43
- console.table(this.#data);
44
44
  if (this.columnDescriptors) {
45
45
  const columns = this.columnDescriptors.map((c)=>c.name);
46
46
  this._configWithVisualLink = {
@@ -62,7 +62,7 @@ class TreeDataSource extends BaseDataSource {
62
62
  this.#status = "subscribed";
63
63
  this.#selectedRowsCount = selectedKeyValues?.length ?? 0;
64
64
  if (selectedKeyValues) this.applySelectedKeyValues(selectedKeyValues, revealSelected);
65
- [this.visibleRows, this.visibleRowIndex] = getVisibleRows(this.#data, this.expandedRows);
65
+ this.computeVisibleRows();
66
66
  this.clientCallback?.({
67
67
  aggregations: this.#aggregations,
68
68
  type: "subscribed",
@@ -72,7 +72,7 @@ class TreeDataSource extends BaseDataSource {
72
72
  groupBy: this._configWithVisualLink.groupBy,
73
73
  range: this.range,
74
74
  sort: this.sort,
75
- tableSchema: treeSchema(this.columnDescriptors)
75
+ tableSchema: this.tableSchema
76
76
  });
77
77
  this.clientCallback({
78
78
  clientViewportId: this.viewport,
@@ -118,7 +118,32 @@ class TreeDataSource extends BaseDataSource {
118
118
  };
119
119
  if (filter.filter) this.applyFilter(filter);
120
120
  else this.#filterSet = void 0;
121
- [this.visibleRows, this.visibleRowIndex] = getVisibleRows(this.#data, this.expandedRows, this.#filterSet);
121
+ this.refreshVisibleRows();
122
+ }
123
+ filterNodes(predicate) {
124
+ if (predicate) {
125
+ const filterSet = [];
126
+ const { count: nodeDataIndex } = metadataKeys;
127
+ for (const row of this.#data){
128
+ const { [DEPTH]: depth, [KEY]: key, [IDX]: idx } = row;
129
+ const label = row[nodeDataIndex + depth];
130
+ if (predicate({
131
+ depth,
132
+ key,
133
+ label: "string" == typeof label ? label : "",
134
+ nodeData: row[nodeDataIndex]
135
+ })) filterSet.push(idx);
136
+ }
137
+ this.#filterSet = filterSet;
138
+ } else this.#filterSet = void 0;
139
+ this.refreshVisibleRows();
140
+ }
141
+ computeVisibleRows() {
142
+ [this.visibleRows, this.visibleRowIndex] = getVisibleRows(this.#data, this.expandedRows, this.#filterSet, this.#filterCollapsedRows);
143
+ }
144
+ refreshVisibleRows() {
145
+ this.#filterCollapsedRows.clear();
146
+ this.computeVisibleRows();
122
147
  const { from, to } = this.range;
123
148
  this.clientCallback?.({
124
149
  clientViewportId: this.viewport,
@@ -134,8 +159,9 @@ class TreeDataSource extends BaseDataSource {
134
159
  const filterSet = [];
135
160
  const regex = new RegExp(`${filter.value}`, "i");
136
161
  for (const row of this.#data){
137
- const { [KEY]: key, [IDX]: idx } = row;
138
- if (regex.test(lastPathSegment(key, "|"))) filterSet.push(idx);
162
+ const { [DEPTH]: depth, [KEY]: key, [IDX]: idx } = row;
163
+ const label = row[metadataKeys.count + depth];
164
+ if (regex.test(lastPathSegment(key, "|")) || "string" == typeof label && regex.test(label)) filterSet.push(idx);
139
165
  }
140
166
  this.#filterSet = filterSet;
141
167
  }
@@ -198,8 +224,9 @@ class TreeDataSource extends BaseDataSource {
198
224
  }
199
225
  openTreeNode(keyOrIndex) {
200
226
  const key = this.getRowKey(keyOrIndex);
201
- this.expandedRows.add(key);
202
- [this.visibleRows, this.visibleRowIndex] = getVisibleRows(this.#data, this.expandedRows);
227
+ if (this.#filterSet) this.#filterCollapsedRows.delete(key);
228
+ else this.expandedRows.add(key);
229
+ this.computeVisibleRows();
203
230
  const { from, to } = this._range;
204
231
  this.clientCallback?.({
205
232
  clientViewportId: this.viewport,
@@ -211,13 +238,19 @@ class TreeDataSource extends BaseDataSource {
211
238
  }
212
239
  closeTreeNode(keyOrIndex, cascade = false) {
213
240
  const key = this.getRowKey(keyOrIndex);
214
- this.expandedRows.delete(key);
215
- if (cascade) {
216
- for (const rowKey of this.expandedRows.keys())if (rowKey.startsWith(key)) this.expandedRows.delete(rowKey);
241
+ if (this.#filterSet) this.#filterCollapsedRows.add(key);
242
+ else {
243
+ this.expandedRows.delete(key);
244
+ if (cascade) {
245
+ for (const rowKey of this.expandedRows.keys())if (rowKey.startsWith(key)) this.expandedRows.delete(rowKey);
246
+ }
217
247
  }
218
- [this.visibleRows, this.visibleRowIndex] = getVisibleRows(this.#data, this.expandedRows);
248
+ this.computeVisibleRows();
219
249
  this.sendRowsToClient();
220
250
  }
251
+ get tableSchema() {
252
+ return treeSchema(this.columnDescriptors);
253
+ }
221
254
  get status() {
222
255
  return this.#status;
223
256
  }
@@ -287,44 +320,45 @@ class TreeDataSource extends BaseDataSource {
287
320
  }
288
321
  }
289
322
  const getInitiallyExpandedKeys = (treeSourceNodes, keyBase = "$root", expandedKeys = new Set())=>{
290
- for (const { childNodes, expanded, label } of treeSourceNodes){
291
- const key = `${keyBase}|${label}`;
323
+ for (const { childNodes, expanded, keySegment, label } of treeSourceNodes){
324
+ const key = `${keyBase}|${keySegment ?? label}`;
292
325
  if (expanded) expandedKeys.add(key);
293
326
  if (childNodes) getInitiallyExpandedKeys(childNodes, key, expandedKeys);
294
327
  }
295
328
  return expandedKeys;
296
329
  };
297
- function getVisibleRows(rows, expandedKeys, filterset) {
330
+ function getVisibleRows(rows, expandedKeys, filterset, filterCollapsedKeys) {
298
331
  const visibleRows = [];
299
332
  const visibleRowIndex = {};
300
- const data = filterset ?? rows;
301
- for(let i = 0, index = 0; i < data.length; i++){
302
- const idx = filterset ? filterset[i] : i;
303
- const row = rows[idx];
304
- const { [COUNT]: count, [DEPTH]: depth, [KEY]: key, [IS_LEAF]: isLeaf } = row;
305
- if (filterset) {
306
- const previousRow = visibleRows.at(-1);
307
- if (missingAncestor(row, previousRow)) {
308
- let currentRow = row;
309
- const missingRows = [];
310
- while(currentRow){
311
- currentRow = getParentRow(rows, currentRow);
312
- if (currentRow) missingRows.unshift(currentRow);
313
- }
314
- missingRows.forEach((row)=>{
315
- visibleRows.push(cloneRow(row, index++, true));
316
- });
333
+ if (filterset) {
334
+ const included = new Set();
335
+ for (const idx of filterset){
336
+ let row = rows[idx];
337
+ while(row && !included.has(row[IDX])){
338
+ included.add(row[IDX]);
339
+ row = getParentRow(rows, row);
317
340
  }
318
- visibleRows.push(cloneRow(row, index++, true));
341
+ }
342
+ let collapsedKey;
343
+ for(let i = 0, index = 0; i < rows.length; i++){
344
+ const row = rows[i];
345
+ const { [COUNT]: count, [KEY]: key } = row;
346
+ if (!included.has(row[IDX])) continue;
347
+ if (void 0 !== collapsedKey && key.startsWith(`${collapsedKey}|`)) continue;
348
+ const isCollapsed = filterCollapsedKeys?.has(key) ?? false;
349
+ collapsedKey = isCollapsed ? key : void 0;
319
350
  visibleRowIndex[index] = i;
320
- } else {
321
- const isExpanded = expandedKeys.has(key);
322
- visibleRows.push(cloneRow(row, index, isExpanded));
323
- visibleRowIndex[index++] = i;
324
- const skipNonVisibleRows = !isLeaf && !isExpanded && count > 0;
325
- if (skipNonVisibleRows) do i += 1;
326
- while (i < rows.length - 1 && rows[i + 1][DEPTH] > depth)
351
+ visibleRows.push(cloneRow(row, index++, count > 0 && !isCollapsed));
327
352
  }
353
+ } else for(let i = 0, index = 0; i < rows.length; i++){
354
+ const row = rows[i];
355
+ const { [COUNT]: count, [DEPTH]: depth, [KEY]: key, [IS_LEAF]: isLeaf } = row;
356
+ const isExpanded = expandedKeys.has(key);
357
+ visibleRows.push(cloneRow(row, index, isExpanded));
358
+ visibleRowIndex[index++] = i;
359
+ const skipNonVisibleRows = !isLeaf && !isExpanded && count > 0;
360
+ if (skipNonVisibleRows) do i += 1;
361
+ while (i < rows.length - 1 && rows[i + 1][DEPTH] > depth)
328
362
  }
329
363
  return [
330
364
  visibleRows,
@@ -1,7 +1,18 @@
1
1
  import type { ColumnDescriptor } from "@vuu-ui/vuu-table-types";
2
2
  import type { LinkDescriptorWithLabel, VuuRange, VuuRpcResponse, VuuRpcRequest, SelectRequest } from "@vuu-ui/vuu-protocol-types";
3
- import type { DataSourceRow, DataSourceConstructorProps, DataSourceStatus, DataSourceSubscribeCallback, DataSourceSubscribeProps, MenuRpcResponse, DataSourceFilter, DataSourceBase } from "@vuu-ui/vuu-data-types";
3
+ import type { DataSourceRow, DataSourceConstructorProps, DataSourceStatus, DataSourceSubscribeCallback, DataSourceSubscribeProps, MenuRpcResponse, DataSourceFilter, TableSchema, DataSourceBase } from "@vuu-ui/vuu-data-types";
4
4
  import { BaseDataSource, TreeSourceNode } from "@vuu-ui/vuu-utils";
5
+ export interface TreeNodeFilterProps {
6
+ depth: number;
7
+ key: string;
8
+ label: string;
9
+ nodeData: unknown;
10
+ }
11
+ /**
12
+ * Tests a single tree node. Nodes that pass are displayed, along with all of
13
+ * their ancestors.
14
+ */
15
+ export type TreeNodeFilterPredicate = (node: TreeNodeFilterProps) => boolean;
5
16
  export interface TreeDataSourceConstructorProps extends Omit<DataSourceConstructorProps, "bufferSize" | "table"> {
6
17
  data: TreeSourceNode[];
7
18
  }
@@ -24,6 +35,13 @@ export declare class TreeDataSource extends BaseDataSource implements DataSource
24
35
  set data(data: TreeSourceNode[]);
25
36
  get filter(): DataSourceFilter;
26
37
  set filter(filter: DataSourceFilter);
38
+ /**
39
+ * An alternative to a filter expression, filters on any attribute of a
40
+ * tree node, including nodeData. Pass undefined to clear the filter.
41
+ */
42
+ filterNodes(predicate?: TreeNodeFilterPredicate): void;
43
+ private computeVisibleRows;
44
+ private refreshVisibleRows;
27
45
  private applyFilter;
28
46
  /**
29
47
  * used to apply an initial selection. These may not necessarily be
@@ -36,6 +54,7 @@ export declare class TreeDataSource extends BaseDataSource implements DataSource
36
54
  private getRowKey;
37
55
  openTreeNode(keyOrIndex: string | number): void;
38
56
  closeTreeNode(keyOrIndex: string | number, cascade?: boolean): void;
57
+ get tableSchema(): TableSchema;
39
58
  get status(): DataSourceStatus;
40
59
  get selectedRowsCount(): number;
41
60
  get size(): number;