From e884c0356595c161b746ca370efa4bd74088c458 Mon Sep 17 00:00:00 2001 From: Ghislain B Date: Sat, 19 Aug 2023 19:36:07 -0400 Subject: [PATCH] feat(TreeData): add auto-recalc feature for Tree Totals w/Aggregators (#1084) * feat(TreeData): add auto-recalc feature for Tree Totals w/Aggregators - add a new auto-recalc tree totals feature which is disabled by default, this new feature comes with 2 new properties - `autoRecalcTotalsOnFilterChange` to enabled the feature - `autoRecalcTotalsDebounce` to limit recalc execution when used with large tree dataset - add more functionalities into Example 6 to not just add new file but also remove last inserted song --- .../src/examples/example01.ts | 1 + .../src/examples/example06.html | 17 + .../src/examples/example06.ts | 52 +- .../src/examples/example07.ts | 1 - .../interfaces/treeDataOption.interface.ts | 18 +- .../services/__tests__/filter.service.spec.ts | 59 +- .../__tests__/treeData.service.spec.ts | 86 ++- .../src/services/__tests__/utilities.spec.ts | 30 + .../common/src/services/filter.service.ts | 57 +- .../common/src/services/treeData.service.ts | 75 ++- packages/common/src/services/utilities.ts | 19 +- test/cypress/e2e/example01.cy.ts | 2 +- test/cypress/e2e/example06.cy.ts | 611 +++++++++++------- 13 files changed, 730 insertions(+), 298 deletions(-) diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example01.ts b/examples/vite-demo-vanilla-bundle/src/examples/example01.ts index 27df602e6..2761a7450 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example01.ts +++ b/examples/vite-demo-vanilla-bundle/src/examples/example01.ts @@ -69,6 +69,7 @@ export default class Example1 { ...this.gridOptions1, ...{ gridHeight: 255, + headerRowHeight: 40, columnPicker: { onColumnsChanged: (_e, args) => console.log('onColumnPickerColumnsChanged - visible columns count', args.visibleColumns.length), }, diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example06.html b/examples/vite-demo-vanilla-bundle/src/examples/example06.html index 17bbdfecc..9d117f112 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example06.html +++ b/examples/vite-demo-vanilla-bundle/src/examples/example06.html @@ -20,6 +20,10 @@
Add New Pop Song + + @@ -84,6 +92,15 @@
Skip Other Filter Criteria when Parent with Tree is valid +
diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example06.ts b/examples/vite-demo-vanilla-bundle/src/examples/example06.ts index e2c9266fc..efd42deff 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example06.ts +++ b/examples/vite-demo-vanilla-bundle/src/examples/example06.ts @@ -29,6 +29,9 @@ export default class Example6 { durationOrderByCount = false; isExcludingChildWhenFiltering = false; isAutoApproveParentItemWhenTreeColumnIsValid = true; + isAutoRecalcTotalsOnFilterChange = false; + isRemoveLastInsertedPopSongDisabled = true; + lastInsertedPopSongId: number | undefined; searchString = ''; attached() { @@ -156,7 +159,14 @@ export default class Example6 { // Note: only 5 are currently supported: Avg, Sum, Min, Max and Count // Note 2: also note that Avg Aggregator will automatically give you the "avg", "count" and "sum" so if you need these 3 then simply calling Avg will give you better perf // aggregators: [new Aggregators.Sum('size')] - aggregators: [new Aggregators.Avg('size'), new Aggregators.Sum('size') /* , new Aggregators.Min('size'), new Aggregators.Max('size') */] + aggregators: [new Aggregators.Avg('size'), new Aggregators.Sum('size') /* , new Aggregators.Min('size'), new Aggregators.Max('size') */], + + // should we auto-recalc Tree Totals (when using Aggregators) anytime a filter changes + // it is disabled by default for perf reason, by default it will only calculate totals on first load + autoRecalcTotalsOnFilterChange: this.isAutoRecalcTotalsOnFilterChange, + + // add optional debounce time to limit number of execution that recalc is called, mostly useful on large dataset + // autoRecalcTotalsDebounce: 750 }, showCustomFooter: true, @@ -175,6 +185,17 @@ export default class Example6 { return true; } + changeAutoRecalcTotalsOnFilterChange() { + this.isAutoRecalcTotalsOnFilterChange = !this.isAutoRecalcTotalsOnFilterChange; + this.gridOptions.treeDataOptions!.autoRecalcTotalsOnFilterChange = this.isAutoRecalcTotalsOnFilterChange; + this.sgb.slickGrid?.setOptions(this.gridOptions); + + // since it doesn't take current filters in consideration, we better clear them + this.sgb.filterService.clearFilters(); + this.sgb.treeDataService.enableAutoRecalcTotalsFeature(); + return true; + } + changeExcludeChildWhenFiltering() { this.isExcludingChildWhenFiltering = !this.isExcludingChildWhenFiltering; this.gridOptions.treeDataOptions!.excludeChildrenWhenFilteringTree = this.isExcludingChildWhenFiltering; @@ -249,15 +270,17 @@ export default class Example6 { const newId = this.sgb.dataView!.getItemCount() + 50; // find first parent object and add the new item as a child - const popItem = findItemInTreeStructure(this.datasetHierarchical, x => x.file === 'pop', 'files'); + const popFolderItem = findItemInTreeStructure(this.datasetHierarchical, x => x.file === 'pop', 'files'); - if (popItem && Array.isArray(popItem.files)) { - popItem.files.push({ + if (popFolderItem && Array.isArray(popFolderItem.files)) { + popFolderItem.files.push({ id: newId, file: `pop-${newId}.mp3`, dateModified: new Date(), size: newId + 3, }); + this.lastInsertedPopSongId = newId; + this.isRemoveLastInsertedPopSongDisabled = false; // overwrite hierarchical dataset which will also trigger a grid sort and rendering this.sgb.datasetHierarchical = this.datasetHierarchical; @@ -270,6 +293,27 @@ export default class Example6 { } } + deleteFile() { + const popFolderItem = findItemInTreeStructure(this.datasetHierarchical, x => x.file === 'pop', 'files'); + const songItemFound = findItemInTreeStructure(this.datasetHierarchical, x => x.id === this.lastInsertedPopSongId, 'files'); + + if (popFolderItem && songItemFound) { + const songIdx = popFolderItem.files.findIndex(f => f.id === songItemFound.id); + if (songIdx >= 0) { + popFolderItem.files.splice(songIdx, 1); + this.lastInsertedPopSongId = undefined; + this.isRemoveLastInsertedPopSongDisabled = true; + + // overwrite hierarchical dataset which will also trigger a grid sort and rendering + this.sgb.datasetHierarchical = this.datasetHierarchical; + } + } + } + + clearFilters() { + this.sgb.filterService.clearFilters(); + } + collapseAll() { this.sgb.treeDataService.toggleTreeDataCollapse(true); } diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example07.ts b/examples/vite-demo-vanilla-bundle/src/examples/example07.ts index 887510304..3f933e6d7 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example07.ts +++ b/examples/vite-demo-vanilla-bundle/src/examples/example07.ts @@ -319,7 +319,6 @@ export default class Example7 { this.sgb.filterService.clearFilters(); } - allFilters() { const grid = this.sgb; const modalHtml = `