@adaptabletools/adaptable 21.0.11 → 21.1.0-canary.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 (63) hide show
  1. package/base.css +1811 -2336
  2. package/base.css.map +1 -1
  3. package/index.css +1768 -1413
  4. package/index.css.map +1 -1
  5. package/package.json +3 -3
  6. package/src/AdaptableInterfaces/IAdaptable.d.ts +2 -1
  7. package/src/AdaptableOptions/FilterOptions.d.ts +7 -0
  8. package/src/AdaptableOptions/PredicateOptions.d.ts +4 -3
  9. package/src/AdaptableState/Common/AdaptableColumn.d.ts +1 -1
  10. package/src/AdaptableState/Common/AdaptablePredicate.d.ts +12 -0
  11. package/src/AdaptableState/Common/AdaptablePredicate.js +132 -18
  12. package/src/AdaptableState/Selection/GridCell.d.ts +10 -0
  13. package/src/Api/Implementation/ExportApiImpl.js +2 -8
  14. package/src/Api/Implementation/PredicateApiImpl.d.ts +3 -1
  15. package/src/Api/Implementation/PredicateApiImpl.js +25 -2
  16. package/src/Api/Internal/AdaptableInternalApi.d.ts +2 -1
  17. package/src/Api/Internal/AdaptableInternalApi.js +6 -0
  18. package/src/Api/Internal/PredicateInternalApi.d.ts +3 -1
  19. package/src/Api/Internal/PredicateInternalApi.js +14 -0
  20. package/src/Api/PredicateApi.d.ts +1 -1
  21. package/src/Redux/Store/AdaptableStore.js +111 -3
  22. package/src/Utilities/Helpers/Helper.js +26 -2
  23. package/src/Utilities/Hooks/index.d.ts +4 -0
  24. package/src/Utilities/Hooks/index.js +4 -0
  25. package/src/Utilities/Hooks/useAdaptableColumn.d.ts +2 -0
  26. package/src/Utilities/Hooks/useAdaptableColumn.js +6 -0
  27. package/src/Utilities/Hooks/useAdaptableOptions.d.ts +2 -0
  28. package/src/Utilities/Hooks/useAdaptableOptions.js +5 -0
  29. package/src/Utilities/Hooks/useAdaptableState.d.ts +3 -0
  30. package/src/Utilities/Hooks/useAdaptableState.js +39 -0
  31. package/src/Utilities/adaptableQlUtils.js +3 -0
  32. package/src/View/AdaptableComputedCSSVarsContext.d.ts +12 -0
  33. package/src/View/AdaptableComputedCSSVarsContext.js +25 -0
  34. package/src/View/Components/AdaptableInput/AdaptableDateInlineInput.d.ts +1 -1
  35. package/src/View/Components/ColumnFilter/FloatingFilter.js +5 -1
  36. package/src/View/Components/ColumnFilter/components/FloatingFilterInputList.js +1 -1
  37. package/src/View/Components/ColumnFilter/components/FloatingFilterValues.js +34 -9
  38. package/src/View/Components/FilterForm/ListBoxFilterForm.d.ts +1 -0
  39. package/src/View/Components/FilterForm/ListBoxFilterForm.js +93 -16
  40. package/src/View/Layout/Wizard/sections/ColumnsSection.js +1 -1
  41. package/src/View/renderWithAdaptableContext.js +3 -1
  42. package/src/agGrid/AdaptableAgGrid.d.ts +3 -1
  43. package/src/agGrid/AdaptableAgGrid.js +361 -24
  44. package/src/agGrid/AdaptableFilterHandler.d.ts +3 -1
  45. package/src/agGrid/AdaptableFilterHandler.js +16 -12
  46. package/src/agGrid/AgGridAdapter.js +12 -6
  47. package/src/agGrid/AgGridColumnAdapter.js +19 -13
  48. package/src/components/OverlayTrigger/index.js +1 -1
  49. package/src/components/Select/Select.js +22 -22
  50. package/src/components/Tree/TreeDropdown/index.d.ts +27 -0
  51. package/src/components/Tree/TreeDropdown/index.js +250 -0
  52. package/src/components/Tree/TreeList/index.d.ts +25 -0
  53. package/src/components/Tree/TreeList/index.js +35 -0
  54. package/src/devTools/DevToolsTracks.d.ts +31 -0
  55. package/src/devTools/DevToolsTracks.js +31 -0
  56. package/src/devTools/PerfMarker.d.ts +12 -0
  57. package/src/devTools/PerfMarker.js +1 -0
  58. package/src/devTools/index.d.ts +102 -0
  59. package/src/devTools/index.js +159 -0
  60. package/src/env.js +2 -2
  61. package/src/layout-manager/src/index.d.ts +2 -0
  62. package/src/layout-manager/src/index.js +24 -0
  63. package/tsconfig.esm.tsbuildinfo +1 -1
@@ -8,7 +8,7 @@ import Emitter from '../Utilities/Emitter';
8
8
  import { applyDefaultAdaptableOptions } from '../AdaptableOptions/DefaultAdaptableOptions';
9
9
  import { AgGridAdapter } from './AgGridAdapter';
10
10
  import * as GeneralConstants from '../Utilities/Constants/GeneralConstants';
11
- import { AG_GRID_GRAND_TOTAL_ROW_ID, AUTOGENERATED_PK_COLUMN, ERROR_LAYOUT, GROUP_PATH_SEPARATOR, HALF_SECOND, QUARTER_SECOND, } from '../Utilities/Constants/GeneralConstants';
11
+ import { AG_GRID_GRAND_TOTAL_ROW_ID, AG_GRID_GROUPED_COLUMN, AUTOGENERATED_PK_COLUMN, ERROR_LAYOUT, GROUP_PATH_SEPARATOR, HALF_SECOND, QUARTER_SECOND, } from '../Utilities/Constants/GeneralConstants';
12
12
  import { DataService } from '../Utilities/Services/DataService';
13
13
  import { AdaptableStore } from '../Redux/Store/AdaptableStore';
14
14
  import { AdaptableApiImpl } from '../Api/Implementation/AdaptableApiImpl';
@@ -99,6 +99,9 @@ import { AgGridThemeAdapter } from './AgGridThemeAdapter';
99
99
  import { mapOldTypeToDataType } from '../migration/VersionUpgrade20';
100
100
  import { tagProvidedByAdaptable } from '../Utilities/adaptableOverrideCheck';
101
101
  import { AgGridModulesAdapter } from './AgGridModulesAdapter';
102
+ import { getMarker } from '../devTools';
103
+ import { DeepMap } from '@infinite-table/infinite-react';
104
+ import { DateFormatter } from '../Utilities/Helpers/FormatHelper';
102
105
  const LocalEventService_Prototype = LocalEventService.prototype;
103
106
  const LocalEventService_dispatchEvent = LocalEventService_Prototype.dispatchEvent;
104
107
  LocalEventService_Prototype.dispatchEvent = function (event) {
@@ -277,6 +280,8 @@ export class AdaptableAgGrid {
277
280
  this._rawAdaptableOptions.adaptableId = `adaptable_id_${Date.now()}`;
278
281
  }
279
282
  this.logger = this.logger ?? new AdaptableLogger(this._rawAdaptableOptions.adaptableId);
283
+ const adaptableId = this._rawAdaptableOptions.adaptableId;
284
+ const initMarker = getMarker(adaptableId).track.Init.label.Init.start();
280
285
  const perfInitAdaptableAgGrid = this.logger.beginPerf(`Adaptable._initAdaptableAgGrid()`);
281
286
  AdaptableAgGrid.collectInstance(this, this._rawAdaptableOptions.adaptableId);
282
287
  this.variant = config.variant;
@@ -314,6 +319,7 @@ export class AdaptableAgGrid {
314
319
  this.forPlugins((plugin) => plugin.afterInitServices(this));
315
320
  this.adaptableModules = this.initModules();
316
321
  this.forPlugins((plugin) => plugin.afterInitModules(this, this.adaptableModules));
322
+ const loadStoreMarker = getMarker(adaptableId).track.Init.label.LoadStore.start();
317
323
  const perfLoadStore = this.logger.beginPerf(`loadStore()`);
318
324
  this.adaptableStore = this.initAdaptableStore();
319
325
  this.forPlugins((plugin) => plugin.afterInitStore(this));
@@ -340,6 +346,7 @@ export class AdaptableAgGrid {
340
346
  },
341
347
  });
342
348
  perfLoadStore.end();
349
+ loadStoreMarker.end();
343
350
  // just in case Adaptable was destroyed while loading the store (which is an async operation)
344
351
  if (this.isDestroyed) {
345
352
  this.midwayDestroy();
@@ -386,6 +393,7 @@ export class AdaptableAgGrid {
386
393
  this.lifecycleState = 'initAgGrid';
387
394
  this.agGridAdapter.initialGridOptions = gridOptions;
388
395
  const perfInitAgGrid = this.logger.beginPerf(`initAgGrid()`);
396
+ const initAgGridMarker = getMarker(adaptableId).track.Init.label.InitAGGrid.start();
389
397
  this.validateColumnDefTypes(gridOptions.columnDefs);
390
398
  const agGridApi = await this.initializeAgGrid(gridOptions, config.modules, config.renderAgGridFrameworkComponent);
391
399
  if (agGridApi === false) {
@@ -419,6 +427,7 @@ export class AdaptableAgGrid {
419
427
  this.logger.info(`Hide Loading Screen`);
420
428
  this.unmountLoadingScreen?.();
421
429
  perfInitAgGrid.end();
430
+ initAgGridMarker.end();
422
431
  // we need to intercept several AG Grid Api methods and trigger Adaptable state changes
423
432
  this.agGridAdapter.setAgGridApi(agGridApi);
424
433
  this.agGridAdapter.monkeyPatchingGridOptionsUpdates();
@@ -494,6 +503,7 @@ export class AdaptableAgGrid {
494
503
  });
495
504
  });
496
505
  perfInitAdaptableAgGrid.end();
506
+ initMarker.end();
497
507
  return Promise.resolve(this.api);
498
508
  }
499
509
  midwayDestroy() {
@@ -550,6 +560,36 @@ You need to define at least one Layout!`);
550
560
  // eg: might not include the generated row group columns in the column order
551
561
  // but the normalization does this for us
552
562
  state.Layout.Layouts = state.Layout.Layouts.map((layout) => normalizeLayout(layout, normalizeOptions));
563
+ //now let's normalize the In/NotIn predicate for the group column
564
+ // the inputs in this predicate should be an array of arrays
565
+ // but for ease of use (and also for similarity with the In predicate for
566
+ // other columns) we allow the inputs to be an array of strings
567
+ // and change them to an array of arrays
568
+ state.Layout.Layouts = state.Layout.Layouts.map((layout) => {
569
+ if (Array.isArray(layout.ColumnFilters)) {
570
+ layout.ColumnFilters = layout.ColumnFilters.map((columnFilter) => {
571
+ if (columnFilter.ColumnId === AG_GRID_GROUPED_COLUMN) {
572
+ if (Array.isArray(columnFilter.Predicates)) {
573
+ columnFilter.Predicates = columnFilter.Predicates.map((predicate) => {
574
+ if (predicate.PredicateId === 'In' || predicate.PredicateId === 'NotIn') {
575
+ if (Array.isArray(predicate.Inputs)) {
576
+ predicate.Inputs = predicate.Inputs.map((input) => {
577
+ if (!Array.isArray(input)) {
578
+ return [input];
579
+ }
580
+ return input;
581
+ });
582
+ }
583
+ }
584
+ return predicate;
585
+ });
586
+ }
587
+ }
588
+ return columnFilter;
589
+ });
590
+ }
591
+ return layout;
592
+ });
553
593
  }
554
594
  return state;
555
595
  }
@@ -1288,6 +1328,7 @@ You need to define at least one Layout!`);
1288
1328
  }
1289
1329
  initAdaptableStore() {
1290
1330
  const perfNewAdaptableStore = this.logger.beginPerf(`initAdaptableStore()`);
1331
+ const initAdaptableStoreMarker = getMarker(this.adaptableOptions.adaptableId).track.Init.label.InitStore.start();
1291
1332
  const adaptableStore = new AdaptableStore(this);
1292
1333
  adaptableStore.onAny((eventName, data) => {
1293
1334
  if (this.isReady) {
@@ -1296,6 +1337,7 @@ You need to define at least one Layout!`);
1296
1337
  this.forPlugins((plugin) => plugin.onStoreEvent(eventName, data, this.adaptableStore));
1297
1338
  });
1298
1339
  perfNewAdaptableStore.end();
1340
+ initAdaptableStoreMarker.end();
1299
1341
  return adaptableStore;
1300
1342
  }
1301
1343
  mapAdaptableStateToAgGridState(adaptableState, agGridColDefs, options) {
@@ -1714,12 +1756,12 @@ You need to define at least one Layout!`);
1714
1756
  /**
1715
1757
  * Use (lazy evaluated) getters to avoid unnecessary calculations and memoization to avoid recalculating the same values
1716
1758
  */
1717
- createGridCell(rowNode, columnId) {
1759
+ createGridCell(rowNode, columnId, defaults) {
1718
1760
  let _column;
1719
1761
  let _primaryKeyValue;
1720
- let _rawValue;
1721
- let _displayValue;
1722
- let _normalisedValue;
1762
+ let _rawValue = defaults ? defaults.rawValue : undefined;
1763
+ let _displayValue = defaults ? defaults.displayValue : undefined;
1764
+ let _normalisedValue = defaults ? defaults.normalisedValue : undefined;
1723
1765
  let _isRowGroupCell;
1724
1766
  const _isPivotCell = this.api.columnApi.isPivotResultColumn(columnId);
1725
1767
  const self = this;
@@ -2316,7 +2358,41 @@ You need to define at least one Layout!`);
2316
2358
  if (currentGridCells) {
2317
2359
  return currentGridCells;
2318
2360
  }
2319
- return (currentGridCells = this.getDistinctGridCellsForColumn(column));
2361
+ return (currentGridCells =
2362
+ column.columnId === AG_GRID_GROUPED_COLUMN
2363
+ ? this.getDistinctGridCellsForGroupedColumn()
2364
+ : column.dataType === 'date'
2365
+ ? this.getDistinctGridCellsForDateColumn(column)
2366
+ : this.getDistinctGridCellsForColumn(column));
2367
+ };
2368
+ // No distinct values so lets return unique grid cells
2369
+ const mapFn = (gridCell, level) => {
2370
+ if (level || Array.isArray(gridCell.children)) {
2371
+ const cell = gridCell;
2372
+ const inFilterValue = {
2373
+ value: gridCell.rawValue,
2374
+ label: gridCell.displayValue,
2375
+ level: level ?? 0,
2376
+ tooltip: false,
2377
+ get visible() {
2378
+ return gridCell.visible;
2379
+ },
2380
+ count: gridCell.count ?? 0,
2381
+ leafChildrenCount: cell.leafChildrenCount ?? 0,
2382
+ get visibleCount() {
2383
+ return gridCell.visibleCount ?? 0;
2384
+ },
2385
+ isSelected: gridCell.rowNode.displayed,
2386
+ children: cell.children
2387
+ ? cell.children.map((v) => mapFn(v, level ? level + 1 : 1))
2388
+ : undefined,
2389
+ };
2390
+ return inFilterValue;
2391
+ }
2392
+ return {
2393
+ value: gridCell.rawValue,
2394
+ label: gridCell.displayValue,
2395
+ };
2320
2396
  };
2321
2397
  // If there are custom distinct value, return them; otherwise return the Grids Cells just retrieved
2322
2398
  const customInFilterValues = this.adaptableOptions.filterOptions.customInFilterValues;
@@ -2337,13 +2413,21 @@ You need to define at least one Layout!`);
2337
2413
  label: gridCell.displayValue,
2338
2414
  value: gridCell.rawValue,
2339
2415
  isSelected: gridCell.rowNode.displayed,
2340
- count: gridCell.count,
2416
+ count: gridCell.count ?? 0,
2341
2417
  tooltip: false,
2418
+ level: 0,
2419
+ leafChildrenCount: gridCell.leafChildrenCount ?? 0,
2420
+ get children() {
2421
+ if (!gridCell.children) {
2422
+ return undefined;
2423
+ }
2424
+ return gridCell.children.map((gridCell) => mapFn(gridCell, 1));
2425
+ },
2342
2426
  get visible() {
2343
2427
  return gridCell.visible;
2344
2428
  },
2345
2429
  get visibleCount() {
2346
- return gridCell.visibleCount;
2430
+ return gridCell.visibleCount ?? 0;
2347
2431
  },
2348
2432
  };
2349
2433
  });
@@ -2355,13 +2439,21 @@ You need to define at least one Layout!`);
2355
2439
  label: gridCell.displayValue,
2356
2440
  value: gridCell.rawValue,
2357
2441
  isSelected: gridCell.rowNode.displayed,
2358
- count: gridCell.count,
2442
+ count: gridCell.count ?? 0,
2359
2443
  tooltip: false,
2444
+ level: 0,
2445
+ leafChildrenCount: gridCell.leafChildrenCount ?? 0,
2446
+ get children() {
2447
+ if (!gridCell.children) {
2448
+ return undefined;
2449
+ }
2450
+ return gridCell.children.map((gridCell) => mapFn(gridCell, 1));
2451
+ },
2360
2452
  get visible() {
2361
2453
  return gridCell.visible;
2362
2454
  },
2363
2455
  get visibleCount() {
2364
- return gridCell.visibleCount;
2456
+ return gridCell.visibleCount ?? 0;
2365
2457
  },
2366
2458
  };
2367
2459
  });
@@ -2377,6 +2469,14 @@ You need to define at least one Layout!`);
2377
2469
  isSelected: gridCell.rowNode.displayed,
2378
2470
  count: gridCell.count,
2379
2471
  tooltip: false,
2472
+ level: 0,
2473
+ get children() {
2474
+ if (!gridCell.children) {
2475
+ return undefined;
2476
+ }
2477
+ return gridCell.children.map((gridCell) => mapFn(gridCell, 1));
2478
+ },
2479
+ leafChildrenCount: gridCell.leafChildrenCount ?? 0,
2380
2480
  get visible() {
2381
2481
  return gridCell.visible;
2382
2482
  },
@@ -2397,14 +2497,7 @@ You need to define at least one Layout!`);
2397
2497
  }
2398
2498
  return customInFilterValuesResult;
2399
2499
  }
2400
- // No distinct values so lets return unique grid cells
2401
- const values = getCurrentGridCells().map((gridCell) => {
2402
- const inFilterValue = {
2403
- value: gridCell.rawValue,
2404
- label: gridCell.displayValue,
2405
- };
2406
- return inFilterValue;
2407
- });
2500
+ const values = getCurrentGridCells().map((gridCell) => mapFn(gridCell));
2408
2501
  return { values };
2409
2502
  }
2410
2503
  async getDistinctEditValuesForColumn(options) {
@@ -2454,6 +2547,218 @@ You need to define at least one Layout!`);
2454
2547
  return result;
2455
2548
  });
2456
2549
  }
2550
+ getDistinctGridCellsForGroupedColumn(rowNodes) {
2551
+ const groupedColumns = this.api.columnApi.getRowGroupedColumns();
2552
+ const treeMode = this.api.gridApi.isTreeDataGrid();
2553
+ // if we're not in tree mode, return if there are no grouped columns
2554
+ // but in tree mode, we have to continue, even if there are no grouped columns
2555
+ if (!groupedColumns.length && !treeMode) {
2556
+ return [];
2557
+ }
2558
+ let prevLevel = -1;
2559
+ const currentGroupKey = [];
2560
+ const currentParentGridCells = [];
2561
+ const topLevelGridCells = [];
2562
+ const includeLeafNodes = treeMode || !!this.agGridAdapter.getAgGridApi().getColumnDef(AG_GRID_GROUPED_COLUMN)?.field;
2563
+ const rowNodeCallback = (rowNode) => {
2564
+ if (!rowNode.group && !includeLeafNodes) {
2565
+ return;
2566
+ }
2567
+ const level = rowNode.level;
2568
+ const key = rowNode.key;
2569
+ if (level <= prevLevel) {
2570
+ currentGroupKey.length = level;
2571
+ currentParentGridCells.length = level;
2572
+ }
2573
+ prevLevel = level;
2574
+ // for non-tree mode
2575
+ // or for tree mode, if the rowNode has data - so it's not a filler group
2576
+ if (!treeMode || (treeMode && rowNode.data)) {
2577
+ currentGroupKey.push(key);
2578
+ }
2579
+ const parentGridCell = currentParentGridCells[currentParentGridCells.length - 1];
2580
+ const gridCell = this.addDistinctColumnValue(rowNode, AG_GRID_GROUPED_COLUMN, false);
2581
+ // for tree-mode filler nodes, we might end up without a gridCell
2582
+ // so we need to make sure it's defined
2583
+ if (gridCell) {
2584
+ gridCell.leafChildrenCount = rowNode.allLeafChildren?.length ?? 0;
2585
+ currentParentGridCells.push(gridCell);
2586
+ if (parentGridCell) {
2587
+ parentGridCell.children = parentGridCell.children || [];
2588
+ parentGridCell.children.push(gridCell);
2589
+ }
2590
+ if (level === 0 && gridCell) {
2591
+ topLevelGridCells.push(gridCell);
2592
+ }
2593
+ }
2594
+ };
2595
+ if (rowNodes) {
2596
+ rowNodes.forEach(rowNodeCallback);
2597
+ }
2598
+ else {
2599
+ this.agGridAdapter.getAgGridApi().forEachNode(rowNodeCallback);
2600
+ }
2601
+ const column = this.api.columnApi.getColumnWithColumnId(AG_GRID_GROUPED_COLUMN);
2602
+ return this.getUniqueGridCells(column, topLevelGridCells);
2603
+ }
2604
+ getDistinctGridCellsForDateColumn(column, rowNodes) {
2605
+ const topLevelGridCells = [];
2606
+ const treeDeepMap = new DeepMap();
2607
+ const isPivotResultColumn = column.isGeneratedPivotResultColumn;
2608
+ const includeTime = this.api.predicateApi.internalApi.shouldEvaluateInPredicateUsingTime(column.columnId);
2609
+ const colId = column.columnId;
2610
+ const rowNodeCallback = (rowNode) => {
2611
+ if (!rowNode) {
2612
+ return;
2613
+ }
2614
+ const initialCell = this.addDistinctColumnValue(rowNode, column.columnId, isPivotResultColumn);
2615
+ if (initialCell) {
2616
+ const value = initialCell.rawValue;
2617
+ // we want to filter out empty values
2618
+ if (value === '' || value === null || value === undefined) {
2619
+ return;
2620
+ }
2621
+ const dateInstance = parseDateValue(value);
2622
+ if (!(dateInstance instanceof Date)) {
2623
+ return;
2624
+ }
2625
+ const year = dateInstance.getFullYear();
2626
+ const month = dateInstance.getMonth() + 1;
2627
+ const day = dateInstance.getDate();
2628
+ const yearRawValue = `${year}`;
2629
+ const monthRawValue = `${year}-${`${month}`.padStart(2, '0')}`;
2630
+ const dayRawValue = `${monthRawValue}-${`${day}`.padStart(2, '0')}`;
2631
+ const yearCells = treeDeepMap.get([year]) || [];
2632
+ const yearCell = this.createGridCell(rowNode, colId, {
2633
+ rawValue: yearRawValue,
2634
+ displayValue: yearRawValue,
2635
+ normalisedValue: yearRawValue,
2636
+ });
2637
+ yearCells.push(yearCell);
2638
+ treeDeepMap.set([year], yearCells);
2639
+ const monthCells = treeDeepMap.get([year, month]) || [];
2640
+ const monthCell = this.createGridCell(rowNode, colId, {
2641
+ rawValue: monthRawValue,
2642
+ displayValue: DateFormatter(`${monthRawValue}-01`, { Pattern: 'LLLL' }),
2643
+ normalisedValue: monthRawValue,
2644
+ });
2645
+ monthCells.push(monthCell);
2646
+ treeDeepMap.set([year, month], monthCells);
2647
+ const dayCells = treeDeepMap.get([year, month, day]) || [];
2648
+ const dayCell = this.createGridCell(rowNode, colId, {
2649
+ rawValue: dayRawValue,
2650
+ displayValue: `${day}`.padStart(2, '0'),
2651
+ normalisedValue: dayRawValue,
2652
+ });
2653
+ dayCells.push(dayCell);
2654
+ treeDeepMap.set([year, month, day], dayCells);
2655
+ if (includeTime) {
2656
+ const timeCells = treeDeepMap.get([year, month, day, dateInstance.getTime()]) || [];
2657
+ // if the value is a string, let's use it as the final raw value
2658
+ const timeRawValue = typeof value === 'string' ? value : `${dateInstance.toISOString()}`;
2659
+ let timeDisplayValue = typeof value === 'string'
2660
+ ? value
2661
+ : [dateInstance.getHours(), dateInstance.getMinutes(), dateInstance.getSeconds()]
2662
+ .map((v) => `${v}`.padStart(2, '0'))
2663
+ .join(':')
2664
+ .concat(dateInstance.getMilliseconds()
2665
+ ? `.${dateInstance.getMilliseconds().toString().padStart(3, '0')}`
2666
+ : '');
2667
+ const timeCell = this.createGridCell(rowNode, colId, {
2668
+ rawValue: timeRawValue,
2669
+ displayValue: timeDisplayValue,
2670
+ normalisedValue: timeRawValue,
2671
+ });
2672
+ timeCells.push(timeCell);
2673
+ treeDeepMap.set([year, month, day, dateInstance.getTime()], timeCells);
2674
+ }
2675
+ }
2676
+ };
2677
+ if (rowNodes) {
2678
+ rowNodes.forEach(rowNodeCallback);
2679
+ }
2680
+ else {
2681
+ this.agGridAdapter.getAgGridApi().forEachNode(rowNodeCallback);
2682
+ }
2683
+ const years = treeDeepMap.getKeysStartingWith([], {
2684
+ excludeSelf: true,
2685
+ depthLimit: 1,
2686
+ });
2687
+ for (const keys of years) {
2688
+ const [year] = keys;
2689
+ const yearCells = treeDeepMap.get([year]) || [];
2690
+ // should only be one item in the uniqueYearCells array
2691
+ const uniqueYearCell = this.getUniqueGridCells(column, yearCells)[0];
2692
+ if (!uniqueYearCell) {
2693
+ continue;
2694
+ }
2695
+ uniqueYearCell.children = [];
2696
+ topLevelGridCells.push(uniqueYearCell);
2697
+ const keysForYear = treeDeepMap.getKeysStartingWith([year], {
2698
+ depthLimit: 1,
2699
+ excludeSelf: true,
2700
+ });
2701
+ for (const keys of keysForYear) {
2702
+ const [_, month] = keys;
2703
+ const monthCells = treeDeepMap.get([year, month]) || [];
2704
+ const uniqueMonthCell = this.getUniqueGridCells(column, monthCells)[0];
2705
+ if (!uniqueMonthCell) {
2706
+ continue;
2707
+ }
2708
+ uniqueMonthCell.children = [];
2709
+ uniqueYearCell.children.push(uniqueMonthCell);
2710
+ // those are all the days for which there are values in this year/month
2711
+ const keysForMonth = treeDeepMap.getKeysStartingWith([year, month], {
2712
+ depthLimit: 1,
2713
+ excludeSelf: true,
2714
+ });
2715
+ for (const keys of keysForMonth) {
2716
+ const [_, __, day] = keys;
2717
+ const dayCells = treeDeepMap.get([year, month, day]) || [];
2718
+ const uniqueDayCell = this.getUniqueGridCells(column, dayCells)[0];
2719
+ if (!uniqueDayCell) {
2720
+ continue;
2721
+ }
2722
+ uniqueMonthCell.children.push(uniqueDayCell);
2723
+ if (includeTime) {
2724
+ uniqueDayCell.children = [];
2725
+ const keysForDay = treeDeepMap.getKeysStartingWith([year, month, day], {
2726
+ depthLimit: 1,
2727
+ excludeSelf: true,
2728
+ });
2729
+ for (const keys of keysForDay) {
2730
+ const [_, __, ___, time] = keys;
2731
+ const timeCells = treeDeepMap.get([year, month, day, time]) || [];
2732
+ const uniqueTimeCell = this.getUniqueGridCells(column, timeCells)[0];
2733
+ if (!uniqueTimeCell) {
2734
+ continue;
2735
+ }
2736
+ uniqueDayCell.children.push(uniqueTimeCell);
2737
+ }
2738
+ uniqueDayCell.leafChildrenCount =
2739
+ treeDeepMap.getKeysForLeafNodesStartingWith([year, month, day]).length;
2740
+ uniqueDayCell.children.sort((dayCell1, dayCell2) => {
2741
+ return dayCell1.rawValue.localeCompare(dayCell2.rawValue);
2742
+ });
2743
+ }
2744
+ }
2745
+ uniqueMonthCell.leafChildrenCount =
2746
+ treeDeepMap.getKeysForLeafNodesStartingWith([year, month]).length;
2747
+ uniqueMonthCell.children.sort((monthCell1, monthCell2) => {
2748
+ return monthCell1.rawValue.localeCompare(monthCell2.rawValue);
2749
+ });
2750
+ }
2751
+ uniqueYearCell.leafChildrenCount =
2752
+ treeDeepMap.getKeysForLeafNodesStartingWith([year]).length;
2753
+ uniqueYearCell.children.sort((monthCell1, monthCell2) => {
2754
+ return monthCell1.rawValue.localeCompare(monthCell2.rawValue);
2755
+ });
2756
+ }
2757
+ topLevelGridCells.sort((yearCell1, yearCell2) => {
2758
+ return yearCell1.rawValue.localeCompare(yearCell2.rawValue);
2759
+ });
2760
+ return topLevelGridCells;
2761
+ }
2457
2762
  getDistinctGridCellsForColumn(column, rowNodes) {
2458
2763
  let gridCells = [];
2459
2764
  const isPivotResultColumn = column.isGeneratedPivotResultColumn;
@@ -2490,10 +2795,17 @@ You need to define at least one Layout!`);
2490
2795
  // see https://www.ag-grid.com/javascript-data-grid/tree-data-paths/#filler-groups
2491
2796
  return;
2492
2797
  }
2798
+ // if (columnId !== AG_GRID_GROUPED_COLUMN) {
2799
+ // return;
2800
+ // }
2801
+ return this.getGridCellFromRowNode(rowNode, columnId);
2493
2802
  }
2494
2803
  else {
2495
2804
  // for normal Table Columns we do NOT return the values of the aggregates
2496
- return;
2805
+ if (columnId !== AG_GRID_GROUPED_COLUMN) {
2806
+ return;
2807
+ }
2808
+ return this.getGridCellFromRowNode(rowNode, columnId);
2497
2809
  }
2498
2810
  }
2499
2811
  if (isPivotResultColumn) {
@@ -2507,14 +2819,12 @@ You need to define at least one Layout!`);
2507
2819
  }
2508
2820
  }
2509
2821
  const returnValue = this.getGridCellFromRowNode(rowNode, columnId);
2510
- if (Helper.objectExists(returnValue)) {
2511
- return returnValue;
2512
- }
2822
+ return returnValue;
2513
2823
  }
2514
2824
  getUniqueGridCells(column, gridCells) {
2515
2825
  let gridCellsToUse = gridCells;
2516
2826
  const cache = new Map();
2517
- const lowercase = this.api.predicateApi.useCaseSensitivity();
2827
+ const lowercase = this.api.predicateApi.useCaseSensitivity(column.columnId);
2518
2828
  const getter = (dataItem) => {
2519
2829
  let value = dataItem.rawValue;
2520
2830
  if (value instanceof Date) {
@@ -3260,6 +3570,7 @@ You need to define at least one Layout!`);
3260
3570
  const prevLayout = this._prevLayout;
3261
3571
  this._prevLayout = layout;
3262
3572
  const perfSetLayout = this.logger.beginPerf(`setLayout(${layout.Name})`);
3573
+ const setLayoutMarker = getMarker(this.adaptableOptions.adaptableId).track.Runtime.label.SetLayout.start();
3263
3574
  const isPivot = isPivotLayout(layout);
3264
3575
  // update the header name for all columns
3265
3576
  this.agGridAdapter
@@ -3311,6 +3622,22 @@ You need to define at least one Layout!`);
3311
3622
  }
3312
3623
  });
3313
3624
  perfSetLayout.end();
3625
+ setLayoutMarker.end({
3626
+ details: [
3627
+ {
3628
+ name: 'Layout name',
3629
+ value: layout.Name,
3630
+ },
3631
+ {
3632
+ name: 'Type',
3633
+ value: isPivot ? 'Pivot' : 'Table',
3634
+ },
3635
+ {
3636
+ name: isPivot ? 'Pivot Columns' : 'Table Columns',
3637
+ value: isPivot ? layout.PivotColumns.join(', ') : layout.TableColumns.join(', '),
3638
+ },
3639
+ ],
3640
+ });
3314
3641
  }
3315
3642
  getActiveAdaptableAggFuncForCol(columnId) {
3316
3643
  if (!columnId) {
@@ -3619,7 +3946,7 @@ You need to define at least one Layout!`);
3619
3946
  return hasPivotTotals(one) || hasPivotTotals(other);
3620
3947
  }
3621
3948
  onLayoutChange(layout) {
3622
- this.refreshAdaptableAfterLayoutChange(layout);
3949
+ layout = this.refreshAdaptableAfterLayoutChange(layout);
3623
3950
  this.api.layoutApi.createOrUpdateLayout(layout);
3624
3951
  }
3625
3952
  refreshAdaptableAfterLayoutChange(layout) {
@@ -3627,6 +3954,15 @@ You need to define at least one Layout!`);
3627
3954
  const prevLayoutForRefresh = this.__prevLayoutForRefresh || this.api.layoutApi.getCurrentLayout();
3628
3955
  // see #on-regroup-expect-group-column-to-be-recomputed-and-setup-properly
3629
3956
  const rowGroupsChanged = this.isRowGroupDifferentInLayout(prevLayoutForRefresh, layout);
3957
+ // when grouping changes, if we have a filter on the grouped column, we need to remove it
3958
+ // as it is no longer valid
3959
+ if (rowGroupsChanged && layout.ColumnFilters) {
3960
+ const newFilters = layout.ColumnFilters.filter((filter) => filter.ColumnId !== AG_GRID_GROUPED_COLUMN);
3961
+ if (newFilters.length != layout.ColumnFilters.length) {
3962
+ layout = { ...layout };
3963
+ layout.ColumnFilters = newFilters;
3964
+ }
3965
+ }
3630
3966
  const hasPivotTotalsInLayout = this.hasPivotTotalsInLayout(prevLayoutForRefresh, layout);
3631
3967
  const pivotColsChanged = JSON.stringify(layout.PivotColumns) !== JSON.stringify(prevLayoutForRefresh.PivotColumns);
3632
3968
  if (rowGroupsChanged || pivotColsChanged || hasPivotTotalsInLayout) {
@@ -3636,6 +3972,7 @@ You need to define at least one Layout!`);
3636
3972
  this.deriveAdaptableColumnStateFromAgGrid();
3637
3973
  }
3638
3974
  this.__prevLayoutForRefresh = layout;
3975
+ return layout;
3639
3976
  }
3640
3977
  validateColumnDefTypes(columnDefs) {
3641
3978
  // in Adaptable version 20 we switched from colDef.type to colDef.cellDataType
@@ -2,12 +2,14 @@ import { DoesFilterPassParams, FilterHandler, FilterHandlerParams } from 'ag-gri
2
2
  import { AdaptableApi } from '../Api/AdaptableApi';
3
3
  import { ColumnSetupInfo } from '../AdaptableState/Common/ColumnSetupInfo';
4
4
  import { InFilterValueResult } from '../AdaptableOptions/FilterOptions';
5
+ import { ColumnFilter } from '../types';
5
6
  export declare class AdaptableFilterHandler implements FilterHandler {
6
7
  private adaptableApi;
7
8
  readonly colId: string;
8
9
  private filterDisplayValuesResult;
9
10
  private previousFilterDisplayValuesResult;
10
11
  constructor(adaptableApi: AdaptableApi, columnSetup: ColumnSetupInfo);
12
+ getCurrentColumnFilters(): ColumnFilter[];
11
13
  doesFilterPass(params: DoesFilterPassParams): boolean;
12
14
  getCachedFilterDisplayValues(): InFilterValueResult | undefined;
13
15
  getLastCachedFilterDisplayValues(): InFilterValueResult | undefined;
@@ -21,6 +23,6 @@ export declare class AdaptableFilterHandler implements FilterHandler {
21
23
  onAnyFilterChanged(): void;
22
24
  resetFilterDisplayValues(): void;
23
25
  refreshFilterDisplayValues(): Promise<InFilterValueResult>;
24
- refresh(params: FilterHandlerParams<any, any, any, any>): void;
26
+ refresh(_params: FilterHandlerParams<any, any, any, any>): void;
25
27
  destroy(): void;
26
28
  }
@@ -3,6 +3,17 @@ export class AdaptableFilterHandler {
3
3
  this.adaptableApi = adaptableApi;
4
4
  this.colId = columnSetup.colId;
5
5
  }
6
+ getCurrentColumnFilters() {
7
+ const columnFilters = this.adaptableApi.filterApi.columnFilterApi
8
+ .getActiveColumnFilters()
9
+ .filter((columnFilter) => this.adaptableApi.filterApi.columnFilterApi.isColumnFilterActive(columnFilter))
10
+ .filter((columnFilter) => columnFilter.ColumnId === this.colId)
11
+ .filter((columnFilter) => {
12
+ const shouldEvaluateFilterOnClient = this.adaptableApi.expressionApi.internalApi.shouldEvaluatePredicatesInAdaptableQL('ColumnFilter', columnFilter, columnFilter.Predicates);
13
+ return shouldEvaluateFilterOnClient;
14
+ });
15
+ return columnFilters;
16
+ }
6
17
  doesFilterPass(params) {
7
18
  try {
8
19
  const rowNode = params.node;
@@ -11,15 +22,11 @@ export class AdaptableFilterHandler {
11
22
  if (!isRowFilterable) {
12
23
  return true;
13
24
  }
14
- const columnFilters = this.adaptableApi.filterApi.columnFilterApi
15
- .getActiveColumnFilters()
16
- .filter((columnFilter) => this.adaptableApi.filterApi.columnFilterApi.isColumnFilterActive(columnFilter))
17
- .filter((columnFilter) => columnFilter.ColumnId === this.colId)
18
- .filter((columnFilter) => {
19
- const shouldEvaluateFilterOnClient = this.adaptableApi.expressionApi.internalApi.shouldEvaluatePredicatesInAdaptableQL('ColumnFilter', columnFilter, columnFilter.Predicates);
20
- return shouldEvaluateFilterOnClient;
25
+ const columnFilters = this.getCurrentColumnFilters();
26
+ const anyFilterFailed = columnFilters.some((columnFilter) => {
27
+ const result = !this.adaptableApi.filterApi.columnFilterApi.internalApi.evaluateColumnFilter(columnFilter, rowNode);
28
+ return result;
21
29
  });
22
- const anyFilterFailed = columnFilters.some((columnFilter) => !this.adaptableApi.filterApi.columnFilterApi.internalApi.evaluateColumnFilter(columnFilter, rowNode));
23
30
  return anyFilterFailed ? false : true;
24
31
  }
25
32
  catch (ex) {
@@ -77,10 +84,7 @@ export class AdaptableFilterHandler {
77
84
  this.resetFilterDisplayValues();
78
85
  return this.getFromCacheOrFetchFilterDisplayValues({ currentSearchValue: '' });
79
86
  }
80
- refresh(params) {
81
- // No specific refresh logic needed for this handler
82
- // The filter display values will be reset on new rows loaded or any filter changed
83
- }
87
+ refresh(_params) { }
84
88
  destroy() {
85
89
  this.filterDisplayValuesResult = undefined;
86
90
  this.previousFilterDisplayValuesResult = undefined;