@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
@@ -14,6 +14,26 @@ import { isYesterday } from 'date-fns';
14
14
  import StringExtensions from '../../Utilities/Extensions/StringExtensions';
15
15
  import { parseDateValue } from '../../Utilities/Helpers/DateHelper';
16
16
  import Helper from '../../Utilities/Helpers/Helper';
17
+ import { AG_GRID_GROUPED_COLUMN } from '../../Utilities/Constants/GeneralConstants';
18
+ function getGroupValuesForNode(config) {
19
+ const { node, value } = config;
20
+ const groupValues = node.group
21
+ ? []
22
+ : /*for the leaf node, also use its value*/ value != null
23
+ ? [value]
24
+ : [];
25
+ let currentNode = node.group ? node : node.parent;
26
+ while (currentNode && currentNode.groupData) {
27
+ if (currentNode.treeParent && !currentNode.data) {
28
+ // skip filler groups in tree mode
29
+ }
30
+ else {
31
+ groupValues.unshift(currentNode.groupData[AG_GRID_GROUPED_COLUMN]);
32
+ }
33
+ currentNode = currentNode.parent;
34
+ }
35
+ return groupValues;
36
+ }
17
37
  /**
18
38
  * Array of Predicate Defs which are shipped by AdapTable
19
39
  */
@@ -22,7 +42,10 @@ export const SystemPredicateDefs = [
22
42
  id: 'In',
23
43
  label: 'In',
24
44
  icon: { text: 'IN' },
25
- columnScope: { DataTypes: ['text', 'number', 'date', 'textArray', 'numberArray'] },
45
+ columnScope: {
46
+ DataTypes: ['text', 'number', 'date', 'textArray', 'numberArray'],
47
+ ColumnIds: [AG_GRID_GROUPED_COLUMN],
48
+ },
26
49
  moduleScope: ['columnFilter', 'flashingcell', 'formatColumn', 'alert', 'badgeStyle'],
27
50
  handler: (context) => {
28
51
  const { inputs = [], column, value, adaptableApi } = context;
@@ -59,9 +82,26 @@ export const SystemPredicateDefs = [
59
82
  if (inputs.length === 0) {
60
83
  return true;
61
84
  }
85
+ if (column.columnId === AG_GRID_GROUPED_COLUMN) {
86
+ const { node, treeSelectionState } = context;
87
+ const groupValues = getGroupValuesForNode({ node, value });
88
+ if (!treeSelectionState) {
89
+ // in case we don't have treeSelectionState
90
+ // this is another possible implementation
91
+ // though it won't be as performant as using the treeSelectionState
92
+ const currentValues = (groupValues ?? []).join('#');
93
+ return inputs.some((values) => {
94
+ const valuesString = values.join('#');
95
+ return currentValues.startsWith(valuesString);
96
+ });
97
+ }
98
+ const result = groupValues ? treeSelectionState.isNodeSelected(groupValues) : false;
99
+ // console.log('filter', groupValues, 'pass', result, treeSelectionState.getState());
100
+ return result;
101
+ }
62
102
  if (column.dataType === 'date') {
63
103
  return inputs.some((input) => {
64
- if (adaptableApi.optionsApi.getPredicateOptions().evaluateInPredicateUsingTime) {
104
+ if (adaptableApi.predicateApi.internalApi.shouldEvaluateInPredicateUsingTime(column.columnId)) {
65
105
  return isEqual(input, value);
66
106
  }
67
107
  else {
@@ -78,7 +118,7 @@ export const SystemPredicateDefs = [
78
118
  return arrayValue.includes(input);
79
119
  });
80
120
  }
81
- const useCaseSensitivity = adaptableApi.predicateApi.useCaseSensitivity();
121
+ const useCaseSensitivity = adaptableApi.predicateApi.useCaseSensitivity(column.columnId);
82
122
  if (column.dataType === 'text') {
83
123
  return useCaseSensitivity
84
124
  ? inputs
@@ -101,6 +141,80 @@ export const SystemPredicateDefs = [
101
141
  toString: ({ inputs }) => `IN (${inputs.join(', ')})`,
102
142
  shortcuts: ['#', '['],
103
143
  },
144
+ // {
145
+ // id: 'Tree',
146
+ // label: 'Tree',
147
+ // icon: { text: 'Tree' },
148
+ // columnScope: { DataTypes: ['date'] },
149
+ // moduleScope: ['columnFilter', 'flashingcell', 'formatColumn', 'alert'],
150
+ // handler: (context) => {
151
+ // const { inputs = [], column, value, adaptableApi } = context;
152
+ // const predicateInputs = (context.inputs || []).reduce<AdaptablePredicateDef[]>(
153
+ // (acc, input) => {
154
+ // const predicate = adaptableApi.predicateApi.getPredicateDefById(input);
155
+ // if (predicate) {
156
+ // acc.push(predicate);
157
+ // }
158
+ // return acc;
159
+ // },
160
+ // []
161
+ // );
162
+ // if (predicateInputs.length) {
163
+ // const nestedContext = { ...context };
164
+ // delete nestedContext.inputs;
165
+ // const predicateResult = predicateInputs.some((predicate) => {
166
+ // return adaptableApi.predicateApi.handlePredicate(
167
+ // {
168
+ // PredicateId: predicate.id,
169
+ // },
170
+ // nestedContext,
171
+ // false
172
+ // );
173
+ // });
174
+ // if (predicateResult) {
175
+ // // We want to use the only true values, to allow for multiple predicates to be used
176
+ // return predicateResult;
177
+ // }
178
+ // }
179
+ // if (inputs.length === 0) {
180
+ // return true;
181
+ // }
182
+ // if (column.dataType === 'date') {
183
+ // const treeSelectionState = new TreeSelectionState(
184
+ // {
185
+ // defaultSelection: false,
186
+ // // make sure something like
187
+ // // Predicates: [{ PredicateId: 'Tree', Inputs: [['2021', '2'], ['2022']] }],
188
+ // // is always converted to numbers
189
+ // selectedPaths: inputs
190
+ // .map((array) => {
191
+ // if (!Array.isArray(array)) {
192
+ // return null;
193
+ // }
194
+ // return array.map(Number);
195
+ // })
196
+ // .filter(Boolean),
197
+ // },
198
+ // () => {
199
+ // return {
200
+ // treeDeepMap: new DeepMap<string, any>(),
201
+ // treePaths: new DeepMap<string, any>(),
202
+ // };
203
+ // }
204
+ // );
205
+ // const currrentDate = parseDateValue(value);
206
+ // const currentYear = currrentDate.getFullYear();
207
+ // const currentMonth = currrentDate.getMonth() + 1;
208
+ // const currentDay = currrentDate.getDate();
209
+ // const result = treeSelectionState.isNodeSelected([currentYear, currentMonth, currentDay]);
210
+ // // console.log({ currentYear, currentMonth, currentDay, result, inputs: inputs.join('-') });
211
+ // return result;
212
+ // }
213
+ // return true;
214
+ // },
215
+ // toString: ({ inputs }) => `IN Tree (${inputs.join(', ')})`,
216
+ // shortcuts: ['#', '['],
217
+ // },
104
218
  {
105
219
  id: 'NotIn',
106
220
  label: 'Not In',
@@ -145,7 +259,7 @@ export const SystemPredicateDefs = [
145
259
  return true;
146
260
  }
147
261
  if (column.dataType === 'date') {
148
- if (adaptableApi.optionsApi.getPredicateOptions().evaluateInPredicateUsingTime) {
262
+ if (adaptableApi.predicateApi.useCaseSensitivity(column.columnId)) {
149
263
  return inputs.every((input) => {
150
264
  return !isEqual(input, value);
151
265
  });
@@ -166,7 +280,7 @@ export const SystemPredicateDefs = [
166
280
  });
167
281
  }
168
282
  if (column.dataType === 'text') {
169
- return adaptableApi.predicateApi.useCaseSensitivity()
283
+ return adaptableApi.predicateApi.useCaseSensitivity(column.columnId)
170
284
  ? !inputs
171
285
  .map((i) => {
172
286
  return i?.toLocaleLowerCase();
@@ -177,7 +291,7 @@ export const SystemPredicateDefs = [
177
291
  if (column.dataType === 'textArray') {
178
292
  const arrayValue = Array.isArray(value) ? value : [value];
179
293
  return inputs.every((input) => {
180
- return adaptableApi.predicateApi.useCaseSensitivity()
294
+ return adaptableApi.predicateApi.useCaseSensitivity(column.columnId)
181
295
  ? !arrayValue.map((v) => v?.toLocaleLowerCase()).includes(input?.toLocaleLowerCase())
182
296
  : !arrayValue.includes(input);
183
297
  });
@@ -333,11 +447,11 @@ export const SystemPredicateDefs = [
333
447
  columnScope: { DataTypes: ['text'] },
334
448
  moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn', 'badgeStyle'],
335
449
  inputs: [{ type: 'text' }],
336
- handler: ({ value, inputs, adaptableApi }) => {
450
+ handler: ({ value, inputs, adaptableApi, column }) => {
337
451
  if (!value) {
338
452
  return false;
339
453
  }
340
- const ignoreCase = !adaptableApi.predicateApi.useCaseSensitivity();
454
+ const ignoreCase = !adaptableApi.predicateApi.internalApi.shouldUseCaseSensitivePredicates(column);
341
455
  const v = ignoreCase ? String(value).toLocaleLowerCase() : String(value);
342
456
  const i = ignoreCase ? String(inputs[0]).toLocaleLowerCase() : String(inputs[0]);
343
457
  return v == i;
@@ -352,11 +466,11 @@ export const SystemPredicateDefs = [
352
466
  columnScope: { DataTypes: ['text'] },
353
467
  moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn', 'badgeStyle'],
354
468
  inputs: [{ type: 'text' }],
355
- handler: ({ value, inputs, adaptableApi }) => {
469
+ handler: ({ value, inputs, adaptableApi, column }) => {
356
470
  if (!value) {
357
471
  return true;
358
472
  }
359
- const ignoreCase = !adaptableApi.predicateApi.useCaseSensitivity();
473
+ const ignoreCase = !adaptableApi.predicateApi.internalApi.shouldUseCaseSensitivePredicates(column);
360
474
  const v = ignoreCase ? String(value).toLocaleLowerCase() : String(value);
361
475
  const i = ignoreCase ? String(inputs[0]).toLocaleLowerCase() : String(inputs[0]);
362
476
  return v != i;
@@ -371,11 +485,11 @@ export const SystemPredicateDefs = [
371
485
  columnScope: { DataTypes: ['text'] },
372
486
  moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn', 'badgeStyle'],
373
487
  inputs: [{ type: 'text' }],
374
- handler: ({ value, inputs, adaptableApi }) => {
488
+ handler: ({ value, inputs, adaptableApi, column }) => {
375
489
  if (!value) {
376
490
  return false;
377
491
  }
378
- const ignoreCase = !adaptableApi.predicateApi.useCaseSensitivity();
492
+ const ignoreCase = !adaptableApi.predicateApi.internalApi.shouldUseCaseSensitivePredicates(column);
379
493
  const v = ignoreCase ? String(value).toLocaleLowerCase() : String(value);
380
494
  const i = ignoreCase ? String(inputs[0]).toLocaleLowerCase() : String(inputs[0]);
381
495
  return v.indexOf(i) !== -1;
@@ -389,11 +503,11 @@ export const SystemPredicateDefs = [
389
503
  columnScope: { DataTypes: ['text'] },
390
504
  moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn', 'badgeStyle'],
391
505
  inputs: [{ type: 'text' }],
392
- handler: ({ value, inputs, adaptableApi }) => {
506
+ handler: ({ value, inputs, adaptableApi, column }) => {
393
507
  if (!value) {
394
508
  return true;
395
509
  }
396
- const ignoreCase = !adaptableApi.predicateApi.useCaseSensitivity();
510
+ const ignoreCase = !adaptableApi.predicateApi.internalApi.shouldUseCaseSensitivePredicates(column);
397
511
  const v = ignoreCase ? String(value).toLocaleLowerCase() : String(value);
398
512
  const i = ignoreCase ? String(inputs[0]).toLocaleLowerCase() : String(inputs[0]);
399
513
  return v.indexOf(i) === -1;
@@ -407,11 +521,11 @@ export const SystemPredicateDefs = [
407
521
  columnScope: { DataTypes: ['text'] },
408
522
  moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn', 'badgeStyle'],
409
523
  inputs: [{ type: 'text' }],
410
- handler: ({ value, inputs, adaptableApi }) => {
524
+ handler: ({ value, inputs, adaptableApi, column }) => {
411
525
  if (!value) {
412
526
  return false;
413
527
  }
414
- const ignoreCase = !adaptableApi.predicateApi.useCaseSensitivity();
528
+ const ignoreCase = !adaptableApi.predicateApi.internalApi.shouldUseCaseSensitivePredicates(column);
415
529
  const v = ignoreCase ? String(value).toLocaleLowerCase() : String(value);
416
530
  const i = ignoreCase ? String(inputs[0]).toLocaleLowerCase() : String(inputs[0]);
417
531
  return v.startsWith(i);
@@ -425,11 +539,11 @@ export const SystemPredicateDefs = [
425
539
  columnScope: { DataTypes: ['text'] },
426
540
  moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn', 'badgeStyle'],
427
541
  inputs: [{ type: 'text' }],
428
- handler: ({ value, inputs, adaptableApi }) => {
542
+ handler: ({ value, inputs, adaptableApi, column }) => {
429
543
  if (!value) {
430
544
  return false;
431
545
  }
432
- const ignoreCase = !adaptableApi.predicateApi.useCaseSensitivity();
546
+ const ignoreCase = !adaptableApi.predicateApi.internalApi.shouldUseCaseSensitivePredicates(column);
433
547
  const v = ignoreCase ? String(value).toLocaleLowerCase() : String(value);
434
548
  const i = ignoreCase ? String(inputs[0]).toLocaleLowerCase() : String(inputs[0]);
435
549
  return v.endsWith(i);
@@ -64,6 +64,16 @@ export interface GridCellWithCount extends GridCell {
64
64
  */
65
65
  visibleCount?: number;
66
66
  }
67
+ export interface GridCellWithChildren extends GridCell {
68
+ /**
69
+ * Children of Cell
70
+ */
71
+ children?: GridCellWithChildren[];
72
+ /**
73
+ * For the grouping scenario, how many leafs are there under this item
74
+ */
75
+ leafChildrenCount?: number;
76
+ }
67
77
  export interface UniqueGridCell<TData = any> {
68
78
  /**
69
79
  * Raw value of Cell
@@ -2,7 +2,7 @@ import * as ExportRedux from '../../Redux/ActionsReducers/ExportRedux';
2
2
  import { ApiBase } from './ApiBase';
3
3
  import * as ModuleConstants from '../../Utilities/Constants/ModuleConstants';
4
4
  import { ExportInternalApi } from '../Internal/ExportInternalApi';
5
- import { ALL_DATA_REPORT, CLIPBOARD_EXPORT_DESTINATION, DOWNLOAD_EXPORT_DESTINATION, EMPTY_STRING, SYSTEM_EXPORT_DESTINATIONS, SYSTEM_REPORT_FORMATS, SYSTEM_REPORT_NAMES, VISUAL_EXCEL_FORMAT_REPORT, } from '../../Utilities/Constants/GeneralConstants';
5
+ import { ALL_DATA_REPORT, CLIPBOARD_EXPORT_DESTINATION, DOWNLOAD_EXPORT_DESTINATION, EMPTY_STRING, SYSTEM_EXPORT_DESTINATIONS, SYSTEM_REPORT_FORMATS, SYSTEM_REPORT_NAMES, } from '../../Utilities/Constants/GeneralConstants';
6
6
  export class ExportApiImpl extends ApiBase {
7
7
  constructor(_adaptable) {
8
8
  super(_adaptable);
@@ -85,13 +85,7 @@ export class ExportApiImpl extends ApiBase {
85
85
  currentReportFormat: this.getExportApi().getCurrentReportFormat(),
86
86
  })
87
87
  : systemExportDestinationsOption;
88
- return systemExportDestinations.filter((destination) => {
89
- // VisualExcel format can't be exported to custom destinations
90
- if (this.getExportApi().getCurrentReportFormat() === VISUAL_EXCEL_FORMAT_REPORT) {
91
- return false;
92
- }
93
- return true;
94
- });
88
+ return systemExportDestinations;
95
89
  }
96
90
  getAvailableCustomDestinations() {
97
91
  const customDestinationsOption = this.getExportOptions().customDestinations;
@@ -3,6 +3,8 @@ import { PredicateApi } from '../PredicateApi';
3
3
  import { AdaptableColumnPredicate, AdaptablePredicate, AdaptablePredicateDef, PredicateDefHandlerContext, PredicateModuleScope } from '../../types';
4
4
  import { IAdaptable } from '../../AdaptableInterfaces/IAdaptable';
5
5
  import { PredicateInternalApi } from '../Internal/PredicateInternalApi';
6
+ import { TreeSelectionState } from '@infinite-table/infinite-react';
7
+ export declare const getTreeSelectionStateForPredicateInputs: (inputs: any[], cache?: WeakMap<any[], TreeSelectionState>) => TreeSelectionState<any>;
6
8
  export declare class PredicateApiImpl extends ApiBase implements PredicateApi {
7
9
  internalApi: PredicateInternalApi;
8
10
  constructor(_adaptable: IAdaptable);
@@ -22,5 +24,5 @@ export declare class PredicateApiImpl extends ApiBase implements PredicateApi {
22
24
  handleColumnPredicates(predicates: AdaptableColumnPredicate[], context: Omit<PredicateDefHandlerContext, 'adaptableApi' | 'inputs'>, defaultReturn: boolean): boolean;
23
25
  handlePredicate(predicate: AdaptablePredicate | undefined, context: Omit<PredicateDefHandlerContext, 'adaptableApi' | 'inputs'>, defaultReturn: boolean): boolean;
24
26
  handlePredicates(predicates: AdaptablePredicate[], params: Omit<PredicateDefHandlerContext, 'adaptableApi' | 'inputs'>, defaultReturn: boolean): boolean;
25
- useCaseSensitivity(): boolean;
27
+ useCaseSensitivity(columnId: string): boolean;
26
28
  }
@@ -3,6 +3,24 @@ import ArrayExtensions from '../../Utilities/Extensions/ArrayExtensions';
3
3
  import StringExtensions from '../../Utilities/Extensions/StringExtensions';
4
4
  import { PredicateInternalApi } from '../Internal/PredicateInternalApi';
5
5
  import { SystemPredicateDefs } from '../../AdaptableState/Common/AdaptablePredicate';
6
+ import { AG_GRID_GROUPED_COLUMN } from '../../Utilities/Constants/GeneralConstants';
7
+ import { TreeSelectionState } from '@infinite-table/infinite-react';
8
+ const treeSelectionStatesForPredicates = new WeakMap();
9
+ export const getTreeSelectionStateForPredicateInputs = (inputs, cache = treeSelectionStatesForPredicates) => {
10
+ const treeSelectionState = cache.get(inputs);
11
+ if (treeSelectionState) {
12
+ return treeSelectionState;
13
+ }
14
+ const newTreeSelectionState = new TreeSelectionState({
15
+ defaultSelection: false,
16
+ selectedPaths: inputs,
17
+ }, {
18
+ treePaths: inputs,
19
+ strictCheckPaths: false,
20
+ });
21
+ cache.set(inputs, newTreeSelectionState);
22
+ return newTreeSelectionState;
23
+ };
6
24
  export class PredicateApiImpl extends ApiBase {
7
25
  constructor(_adaptable) {
8
26
  super(_adaptable);
@@ -125,10 +143,15 @@ export class PredicateApiImpl extends ApiBase {
125
143
  if (predicateDef.inputs?.some((_, i) => predicate.Inputs?.[i] === undefined || predicate.Inputs?.[i] === '')) {
126
144
  return defaultReturn;
127
145
  }
146
+ let treeSelectionState;
147
+ if (context.column.columnId === AG_GRID_GROUPED_COLUMN && predicate.PredicateId === 'In') {
148
+ treeSelectionState = getTreeSelectionStateForPredicateInputs(predicate.Inputs);
149
+ }
128
150
  try {
129
151
  return predicateDef.handler({
130
152
  adaptableApi: this.getAdaptableApi(),
131
153
  inputs: predicate.Inputs,
154
+ treeSelectionState,
132
155
  ...context,
133
156
  });
134
157
  }
@@ -146,7 +169,7 @@ export class PredicateApiImpl extends ApiBase {
146
169
  }
147
170
  return predicates?.every((p) => this.handlePredicate(p, params, defaultReturn));
148
171
  }
149
- useCaseSensitivity() {
150
- return this.getPredicateOptions().caseSensitivePredicates;
172
+ useCaseSensitivity(columnId) {
173
+ return this.internalApi.shouldUseCaseSensitivePredicates(columnId);
151
174
  }
152
175
  }
@@ -23,7 +23,7 @@ import { AdaptableFrameworkComponent } from '../../agGrid/AdaptableFrameworkComp
23
23
  import { IMetamodelService } from '../../Utilities/Services/Interface/IMetamodelService';
24
24
  import { IModuleCollection } from '../../Strategy/Interface/IModule';
25
25
  import { AdaptableObjectTag, AdaptableObjectWithScope } from '../../AdaptableState/Common/AdaptableObject';
26
- import { AdaptableForm, CellSummmaryInfo, FormContext, RowDataChangeTrigger, RowDataChangedInfo } from '../../../types';
26
+ import { AdaptableForm, CellSummmaryInfo, FormContext, RowDataChangeTrigger, RowDataChangedInfo, AdaptableColumn, AdaptableColumnContext } from '../../../types';
27
27
  import { Fdc3Service } from '../../Utilities/Services/Fdc3Service';
28
28
  import { AnnotationsService } from '../../Utilities/Services/AnnotationsService';
29
29
  import { RowFormService } from '../../Utilities/Services/RowFormService';
@@ -122,6 +122,7 @@ export declare class AdaptableInternalApi extends ApiBase {
122
122
  setValueUsingField(rowData: Record<string, any>, fieldName: string, newValue: any): Record<string, any>;
123
123
  findAdaptableObjectsByLookupCriteria<T extends AdaptableObjectWithScope>({ scope, tag, ids }: AdaptableObjectLookupCriteria, specificAdaptableObjects: T[]): T[];
124
124
  buildBaseContext(): BaseContext;
125
+ buildAdaptableColumnContext(column: AdaptableColumn<any> | string): AdaptableColumnContext;
125
126
  setCellSummaryInfo(cellSummaryInfo: CellSummmaryInfo): void;
126
127
  parseDateValue(dateValue: string | Date | number): Date | undefined;
127
128
  }
@@ -437,6 +437,12 @@ export class AdaptableInternalApi extends ApiBase {
437
437
  clientTimestamp: new Date(),
438
438
  };
439
439
  }
440
+ buildAdaptableColumnContext(column) {
441
+ return {
442
+ ...this.buildBaseContext(),
443
+ column: typeof column === 'string' ? this.getColumnApi().getColumnWithColumnId(column) : column,
444
+ };
445
+ }
440
446
  setCellSummaryInfo(cellSummaryInfo) {
441
447
  this.dispatchAction(InternalRedux.SetCellSummaryInfo(cellSummaryInfo));
442
448
  }
@@ -1,7 +1,7 @@
1
1
  import { ApiBase } from '../Implementation/ApiBase';
2
2
  import { AdaptablePredicate, AdaptablePredicateDef } from '../../AdaptableState/Common/AdaptablePredicate';
3
3
  import { SystemFilterPredicateId } from '../../AdaptableState/Common/ColumnFilter';
4
- import { AdaptableColumnDataType } from '../../AdaptableState/Common/AdaptableColumn';
4
+ import { AdaptableColumn, AdaptableColumnDataType } from '../../AdaptableState/Common/AdaptableColumn';
5
5
  import { ColumnScope } from '../../types';
6
6
  export declare class PredicateInternalApi extends ApiBase {
7
7
  IsInOrNotInPredicate(predicate: AdaptablePredicate): boolean;
@@ -10,6 +10,8 @@ export declare class PredicateInternalApi extends ApiBase {
10
10
  * Get all Filter Predicate Definitions - System and Custom
11
11
  */
12
12
  getFilterPredicateDefs(scope: ColumnScope): AdaptablePredicateDef[];
13
+ shouldUseCaseSensitivePredicates(column: string | AdaptableColumn): boolean;
14
+ shouldEvaluateInPredicateUsingTime(column: string | AdaptableColumn): boolean;
13
15
  private getSystemFilterPredicateIds;
14
16
  /**
15
17
  * Get all Alert Predicate Definitions - System and Custom
@@ -12,6 +12,20 @@ export class PredicateInternalApi extends ApiBase {
12
12
  getFilterPredicateDefs(scope) {
13
13
  return this.mergeSystemAndCustomPredicates(this.getSystemFilterPredicateIds(scope)?.map((predicateId) => this.getPredicateApi().getPredicateDefById(predicateId)), this.getPredicateApi().getCustomPredicateDefs()).filter((predicateDef) => predicateDef.moduleScope.includes('columnFilter'));
14
14
  }
15
+ shouldUseCaseSensitivePredicates(column) {
16
+ const caseSensitivePredicates = this.getPredicateOptions().caseSensitivePredicates;
17
+ if (typeof caseSensitivePredicates === 'function') {
18
+ return caseSensitivePredicates(this.getAdaptableInternalApi().buildAdaptableColumnContext(column));
19
+ }
20
+ return caseSensitivePredicates;
21
+ }
22
+ shouldEvaluateInPredicateUsingTime(column) {
23
+ const evaluateInPredicateUsingTime = this.getPredicateOptions().evaluateInPredicateUsingTime;
24
+ if (typeof evaluateInPredicateUsingTime === 'function') {
25
+ return evaluateInPredicateUsingTime(this.getAdaptableInternalApi().buildAdaptableColumnContext(column));
26
+ }
27
+ return evaluateInPredicateUsingTime;
28
+ }
15
29
  getSystemFilterPredicateIds(scope) {
16
30
  const systemFilterPredicates = this.getPredicateOptions().systemFilterPredicates;
17
31
  if (typeof systemFilterPredicates === 'function') {
@@ -95,5 +95,5 @@ export interface PredicateApi {
95
95
  /**
96
96
  * Whether Predicates are evaluated using Case Sensitivity
97
97
  */
98
- useCaseSensitivity(): boolean;
98
+ useCaseSensitivity(columnId: string): boolean;
99
99
  }
@@ -38,6 +38,7 @@ import * as InternalRedux from '../ActionsReducers/InternalRedux';
38
38
  import * as TeamSharingRedux from '../ActionsReducers/TeamSharingRedux';
39
39
  import * as ThemeRedux from '../ActionsReducers/ThemeRedux';
40
40
  import * as ToolPanelRedux from '../ActionsReducers/ToolPanelRedux';
41
+ import { areAdaptableProfileTracksEnabled, getMarker } from '../../devTools';
41
42
  import { isAdaptableSharedEntity, isCustomSharedEntity, } from '../../AdaptableState/TeamSharingState';
42
43
  import { buildAdaptableStateFunctionConfig } from './buildAdaptableStateFunctionConfig';
43
44
  const INIT_STATE = 'INIT_STATE';
@@ -227,17 +228,21 @@ export class AdaptableStore {
227
228
  }
228
229
  return finalState;
229
230
  };
231
+ const devToolsActionMarkerMiddleware = createDevToolsActionMarkerMiddleware(adaptable);
230
232
  const pluginsMiddleware = [];
231
233
  adaptable.forPlugins((plugin) => {
232
234
  if (plugin.reduxMiddleware) {
233
235
  pluginsMiddleware.push(plugin.reduxMiddleware(adaptable));
234
236
  }
235
237
  });
238
+ const middlewares = [
239
+ devToolsActionMarkerMiddleware,
240
+ adaptableMiddleware(adaptable), // the main middleware that actually does stuff,
241
+ ...pluginsMiddleware, // the plugins middleware
242
+ ].filter(Boolean);
236
243
  //TODO: need to check if we want the storage to be done before or after
237
244
  //we enrich the state with the AB middleware
238
- this.TheStore = Redux.createStore(persistedReducer, composeEnhancers(Redux.applyMiddleware(adaptableMiddleware(adaptable), // the main middleware that actually does stuff,
239
- ...pluginsMiddleware // the plugins middleware
240
- )));
245
+ this.TheStore = Redux.createStore(persistedReducer, composeEnhancers(Redux.applyMiddleware(...middlewares)));
241
246
  this.storageEngine = storageEngine;
242
247
  }
243
248
  destroy() {
@@ -258,6 +263,109 @@ export class AdaptableStore {
258
263
  return Promise.resolve(true);
259
264
  }
260
265
  }
266
+ function createDevToolsActionMarkerMiddleware(adaptable) {
267
+ const adaptableId = adaptable?.adaptableOptions?.adaptableId;
268
+ if (!adaptableId) {
269
+ return null;
270
+ }
271
+ if (!areAdaptableProfileTracksEnabled(adaptableId)) {
272
+ return null;
273
+ }
274
+ return (middlewareAPI) => (next) => (action) => {
275
+ if (!isTrackableReduxAction(action)) {
276
+ return next(action);
277
+ }
278
+ const previousState = middlewareAPI.getState();
279
+ const marker = getMarker(adaptableId).track.Redux.label.Action.start();
280
+ try {
281
+ return next(action);
282
+ }
283
+ finally {
284
+ const nextState = middlewareAPI.getState();
285
+ const changedKeys = detectChangedAdaptableStateKeys(previousState, nextState);
286
+ const details = buildDevToolsActionDetails(action, changedKeys);
287
+ marker.end({
288
+ label: action.type,
289
+ tooltip: changedKeys?.length ? `State changes: ${changedKeys.join(', ')}` : undefined,
290
+ details: details.length ? details : undefined,
291
+ });
292
+ }
293
+ };
294
+ }
295
+ const MAX_MARKER_DETAILS = 6;
296
+ function buildDevToolsActionDetails(action, changedKeys) {
297
+ const details = [];
298
+ if (changedKeys && changedKeys.length > 0) {
299
+ const truncatedKeys = changedKeys.slice(0, MAX_MARKER_DETAILS);
300
+ const suffix = changedKeys.length > truncatedKeys.length
301
+ ? ` +${changedKeys.length - truncatedKeys.length} more`
302
+ : '';
303
+ details.push({
304
+ name: 'State changes',
305
+ value: `${truncatedKeys.join(', ')}${suffix}`,
306
+ });
307
+ }
308
+ if (isActionWithPayload(action)) {
309
+ const entries = Object.entries(action).filter(([key]) => key !== 'type');
310
+ for (const [key, value] of entries) {
311
+ if (details.length >= MAX_MARKER_DETAILS) {
312
+ break;
313
+ }
314
+ details.push({
315
+ name: `action.${key}`,
316
+ value: coerceMarkerDetailValue(value),
317
+ });
318
+ }
319
+ }
320
+ return details;
321
+ }
322
+ function detectChangedAdaptableStateKeys(previousState, nextState) {
323
+ if (!previousState || !nextState || previousState === nextState) {
324
+ return undefined;
325
+ }
326
+ const previous = previousState;
327
+ const next = nextState;
328
+ const keys = new Set([...Object.keys(previous), ...Object.keys(next)]);
329
+ const changed = [];
330
+ keys.forEach((key) => {
331
+ if (previous[key] !== next[key]) {
332
+ changed.push(key);
333
+ }
334
+ });
335
+ return changed.length > 0 ? changed : undefined;
336
+ }
337
+ function isTrackableReduxAction(action) {
338
+ return !!action && typeof action.type === 'string';
339
+ }
340
+ function isActionWithPayload(action) {
341
+ return !!action && typeof action === 'object';
342
+ }
343
+ function coerceMarkerDetailValue(value) {
344
+ if (value === null) {
345
+ return 'null';
346
+ }
347
+ if (value === undefined) {
348
+ return 'undefined';
349
+ }
350
+ const valueType = typeof value;
351
+ if (valueType === 'string' || valueType === 'number' || valueType === 'boolean') {
352
+ return value;
353
+ }
354
+ if (valueType === 'function') {
355
+ return '[function]';
356
+ }
357
+ try {
358
+ const json = JSON.stringify(value);
359
+ if (!json) {
360
+ return '[empty]';
361
+ }
362
+ const MAX_LENGTH = 200;
363
+ return json.length > MAX_LENGTH ? `${json.slice(0, MAX_LENGTH - 3)}...` : json;
364
+ }
365
+ catch (err) {
366
+ return '[unserializable]';
367
+ }
368
+ }
261
369
  // this is the main function for dealing with Redux Actions which require additional functionality to be triggered.
262
370
  // Please document each use case where we have to use the Store rather than a module or a popup screen
263
371
  // This should ideally be the ONLY place where we LISTEN to store changes
@@ -88,8 +88,32 @@ export async function copyToClipboard(text) {
88
88
  return true;
89
89
  }
90
90
  catch (ex) {
91
- AdaptableLogger.consoleErrorBase('Copy to clipboard failed.', ex);
92
- return false;
91
+ return copyToClipboardForOldBrowsers(text);
92
+ }
93
+ }
94
+ function copyToClipboardForOldBrowsers(text) {
95
+ if (document.queryCommandSupported && document.queryCommandSupported('copy')) {
96
+ let textarea = document.createElement('textarea');
97
+ textarea.textContent = text;
98
+ textarea.style.width = '1px';
99
+ textarea.style.height = '1px';
100
+ textarea.style.top = '0px';
101
+ textarea.style.left = '0px';
102
+ textarea.style.position = 'absolute';
103
+ textarea.style.opacity = '0.0';
104
+ document.body.appendChild(textarea);
105
+ textarea.select();
106
+ textarea.focus();
107
+ try {
108
+ return document.execCommand('copy'); // Security exception may be thrown by some browsers.
109
+ }
110
+ catch (ex) {
111
+ AdaptableLogger.consoleErrorBase('Copy to clipboard failed.', ex);
112
+ return false;
113
+ }
114
+ finally {
115
+ document.body.removeChild(textarea);
116
+ }
93
117
  }
94
118
  }
95
119
  export function returnItemCount(items, itemName) {
@@ -0,0 +1,4 @@
1
+ import { useAdaptableColumn } from './useAdaptableColumn';
2
+ import { useAdaptableOptions } from './useAdaptableOptions';
3
+ import { useAdaptableState } from './useAdaptableState';
4
+ export { useAdaptableColumn, useAdaptableOptions, useAdaptableState };
@@ -0,0 +1,4 @@
1
+ import { useAdaptableColumn } from './useAdaptableColumn';
2
+ import { useAdaptableOptions } from './useAdaptableOptions';
3
+ import { useAdaptableState } from './useAdaptableState';
4
+ export { useAdaptableColumn, useAdaptableOptions, useAdaptableState };
@@ -0,0 +1,2 @@
1
+ import { AdaptableColumn } from '../../types';
2
+ export declare function useAdaptableColumn(columnId: string): AdaptableColumn | undefined;
@@ -0,0 +1,6 @@
1
+ import { useAdaptable } from '../../View/AdaptableContext';
2
+ export function useAdaptableColumn(columnId) {
3
+ const api = useAdaptable().api;
4
+ const column = api.columnApi.getColumnWithColumnId(columnId);
5
+ return column;
6
+ }