@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,6 +8,7 @@ import { agGridDataTypeDefinitions, ALL_ADAPTABLE_DATA_TYPES } from './agGridDat
8
8
  import { isPivotGrandTotal } from '../Api/Implementation/ColumnApiImpl';
9
9
  import { isPivotColumnTotal } from '../layout-manager/src/isPivotColumnTotal';
10
10
  import { isPivotAggTotalColumn } from '../layout-manager/src/isPivotAggTotalColumn';
11
+ import { isWeightedAverageAggFuncName } from '../AdaptableState/Common/AggregationColumns';
11
12
  // AG GRID obfuscates its internals, this is (currently) the best way to get hold of its internal services
12
13
  const DANGER_AG_GRID_BEANS_MAP = {};
13
14
  const getColumnApiModule = () => ColumnApiModule;
@@ -23,7 +24,7 @@ export class AgGridAdapter {
23
24
  const ColumnDefFactory_Prototye_preWireBeans = ColumnDefFactory_Prototype.preWireBeans;
24
25
  ColumnDefFactory_Prototype.preWireBeans = function (beans) {
25
26
  ColumnDefFactory_Prototye_preWireBeans?.apply(this, arguments);
26
- const gridId = beans?.context?.getGridId();
27
+ const gridId = beans?.context?.getId();
27
28
  if (!gridId) {
28
29
  console.error('CRITICAL: No gridId found in beans, this should never happen!');
29
30
  }
@@ -136,7 +137,8 @@ export class AgGridAdapter {
136
137
  }
137
138
  const pivotColumnFilters = self.adaptableApi.filterApi.columnFilterApi
138
139
  .getActiveColumnFilters()
139
- .filter((columnFilter) => self.adaptableApi.columnApi.isPivotResultColumn(columnFilter.ColumnId));
140
+ .filter((columnFilter) => self.adaptableApi.columnApi.isPivotResultColumn(columnFilter.ColumnId) ||
141
+ self.adaptableApi.columnApi.isAutoRowGroupColumnForSingle(columnFilter.ColumnId));
140
142
  try {
141
143
  if (pivotColumnFilters.length > 0) {
142
144
  for (const columnFilter of pivotColumnFilters) {
@@ -159,7 +161,8 @@ export class AgGridAdapter {
159
161
  agGridColumnFilterService.doFiltersPass = this.DANGER_doFiltersPassMonkeyPatcher;
160
162
  this.DANGER_isAggFilterPresentMonkeyPatcher = function () {
161
163
  const columnFilters = self.adaptableApi.filterApi.columnFilterApi.getActiveColumnFilters();
162
- return columnFilters.some((colFilter) => self.adaptableApi.columnApi.isPivotResultColumn(colFilter.ColumnId));
164
+ return columnFilters.some((colFilter) => self.adaptableApi.columnApi.isPivotResultColumn(colFilter.ColumnId) ||
165
+ self.adaptableApi.columnApi.isAutoRowGroupColumnForSingle(colFilter.ColumnId));
163
166
  };
164
167
  agGridColumnFilterService.isAggFilterPresent = this.DANGER_isAggFilterPresentMonkeyPatcher;
165
168
  }
@@ -483,8 +486,10 @@ export class AgGridAdapter {
483
486
  this.logger.warn(`Column is undefined, returning 'text' for Type`);
484
487
  return 'text';
485
488
  }
486
- if (this.adaptableApi.columnApi.isAutoRowGroupColumnForSingle(agColumn.getId()) ||
487
- this.adaptableApi.columnApi.isSelectionColumn(agColumn.getId())) {
489
+ if (this.adaptableApi.columnApi.isAutoRowGroupColumnForSingle(agColumn.getId())) {
490
+ return 'groupColumn';
491
+ }
492
+ if (this.adaptableApi.columnApi.isSelectionColumn(agColumn.getId())) {
488
493
  return 'unknown';
489
494
  }
490
495
  if (this.adaptableApi.columnApi.isAutoRowGroupColumnForMulti(agColumn.getId())) {
@@ -608,9 +613,10 @@ export class AgGridAdapter {
608
613
  return false;
609
614
  }
610
615
  getColumnAggregationFunctions(colDef) {
611
- const result = colDef.allowedAggFuncs || ['sum', 'min', 'max', 'count', 'avg', 'first', 'last']; // those are the default fns aggrid supports out-of-the-box
616
+ let result = [].concat(colDef.allowedAggFuncs || ['sum', 'min', 'max', 'count', 'avg', 'first', 'last']); // those are the default fns aggrid supports out-of-the-box
612
617
  const gridOptionsAggFuncs = this.adaptableApi.agGridApi.getGridOption('aggFuncs') || {};
613
618
  result.push(...Object.keys(gridOptionsAggFuncs));
619
+ result = result.filter((func) => !isWeightedAverageAggFuncName(func));
614
620
  return [...new Set(result)];
615
621
  }
616
622
  isTreeColumn(isGeneratedRowGroupColumn) {
@@ -17,6 +17,7 @@ import { AdaptableFilterHandler } from './AdaptableFilterHandler';
17
17
  import { AgGridFilterAdapterFactory } from './AgGridFilterAdapter';
18
18
  import { AgGridFloatingFilterAdapterFactory } from './AgGridFloatingFilterAdapter';
19
19
  import { errorOnce } from './AdaptableLogger';
20
+ import { isWeightedAverageAggFuncName } from '../AdaptableState/Common/AggregationColumns';
20
21
  export function getEditorForColumnDataType(columnDataType, variant) {
21
22
  if (columnDataType === 'number') {
22
23
  return variant === 'react' ? AdaptableReactNumberEditor : AdaptableNumberEditor;
@@ -516,7 +517,10 @@ export class AgGridColumnAdapter {
516
517
  }
517
518
  setupColumnAllowedAggFuncs({ col, abColumn }) {
518
519
  this.setColDefProperty(col, 'allowedAggFuncs', () => {
519
- return abColumn.availableAggregationFunctions;
520
+ if (!abColumn.availableAggregationFunctions) {
521
+ return undefined;
522
+ }
523
+ return abColumn.availableAggregationFunctions.filter((func) => !isWeightedAverageAggFuncName(func));
520
524
  });
521
525
  }
522
526
  setupColumnType(columnSetupInfo) {
@@ -588,31 +592,33 @@ export class AgGridColumnAdapter {
588
592
  });
589
593
  }
590
594
  else {
595
+ // TODO only set auto group column as filterable if at least one group columns is filterable
591
596
  this.setColDefProperty(col, 'filter', () => {
592
597
  return 'agGroupColumnFilter';
593
598
  });
594
599
  }
595
- return;
600
+ if (this.adaptableApi.columnApi.isAutoRowGroupColumnForMulti(colId)) {
601
+ return;
602
+ }
596
603
  }
597
604
  // setup "normal" column filter
598
605
  this.setColDefProperty(col, 'filter', (original_filter) => {
599
- if (!colDef.filter) {
600
- return;
601
- }
606
+ const pivotMode = this.adaptableInstance.isInPivotMode();
602
607
  if (!useAdaptableFilter) {
603
608
  return original_filter;
604
609
  }
605
- if (useAdaptableFilter &&
606
- typeof original_filter !== 'boolean' &&
610
+ if (!colDef.filter) {
611
+ return;
612
+ }
613
+ if (typeof original_filter !== 'boolean' &&
607
614
  typeof original_filter?.handler !== 'function' &&
608
- !this.adaptableInstance.isInPivotMode()) {
615
+ !pivotMode) {
609
616
  this.adaptableApi.consoleError(`Column '${colId}' has a custom filter defined in colDef.filter, but Adaptable Filtering accepts only the TRUE/FALSE values!`);
610
617
  return false;
611
618
  }
612
619
  return {
613
620
  component: AgGridFilterAdapterFactory(this.adaptableInstance),
614
- // doesFilterPass,
615
- handler: (params) => new AdaptableFilterHandler(this.adaptableApi, columnSetup),
621
+ handler: () => new AdaptableFilterHandler(this.adaptableApi, columnSetup),
616
622
  };
617
623
  });
618
624
  }
@@ -629,7 +635,7 @@ export class AgGridColumnAdapter {
629
635
  !colDef.floatingFilter ||
630
636
  !this.adaptableOptions.filterOptions.useAdaptableFiltering ||
631
637
  !this.adaptableApi.filterApi.columnFilterApi.isQuickFilterVisible();
632
- if (this.adaptableApi.columnApi.isAutoRowGroupColumn(col.getColId())) {
638
+ if (this.adaptableApi.columnApi.isAutoRowGroupColumnForMulti(col.getColId())) {
633
639
  this.setColDefProperty(col, 'floatingFilter', (original_floatingFilter) => {
634
640
  // the floating filter for the group column is "inherited" from the base column
635
641
  // via the colDef.filter = 'agGroupColumnFilter'
@@ -640,7 +646,7 @@ export class AgGridColumnAdapter {
640
646
  });
641
647
  this.setColDefProperty(col, 'suppressFloatingFilterButton', () => {
642
648
  // hide button for multi column groups
643
- return this.adaptableApi.columnApi.isAutoRowGroupColumnForMulti(col.getColId());
649
+ return true;
644
650
  });
645
651
  return;
646
652
  }
@@ -650,7 +656,7 @@ export class AgGridColumnAdapter {
650
656
  }
651
657
  return AgGridFloatingFilterAdapterFactory(this.adaptableInstance);
652
658
  });
653
- this.setColDefProperty(col, 'floatingFilter', (original_floatingFilter) => {
659
+ this.setColDefProperty(col, 'floatingFilter', () => {
654
660
  if (isFloatingFilterDisabled) {
655
661
  return;
656
662
  }
@@ -193,7 +193,7 @@ const OverlayTrigger = React.forwardRef((givenProps, ref) => {
193
193
  clearAllOverlays();
194
194
  hideOverlay('overlay-trigger');
195
195
  }
196
- } }, props.render({ targetWidth: targetWidth })));
196
+ } }, props.render({ targetWidth })));
197
197
  let preparedConstrainTo;
198
198
  if (constrainTo) {
199
199
  preparedConstrainTo = getConstrainElement(targetRef.current, constrainTo);
@@ -4,13 +4,14 @@ import ReactSelect, { components, } from 'react-select';
4
4
  import CreatableSelect from 'react-select/creatable';
5
5
  import { Icon } from '../icons';
6
6
  import { Box, Flex } from 'rebass';
7
- import { DataSource, InfiniteTable, components as InfiniteTableComponents, } from '@infinite-table/infinite-react';
7
+ import { DataSource, InfiniteTable, } from '@infinite-table/infinite-react';
8
8
  import { useCallback, useMemo, useState } from 'react';
9
9
  import join from '../utils/join';
10
10
  import { Resizable } from 're-resizable';
11
11
  import Tooltip from '../Tooltip';
12
12
  import { ensurePortalElement } from '../OverlayTrigger';
13
- import { CSSNumericVariableWatch } from './CSSNumericVariableWatch';
13
+ import { CheckBox } from '../CheckBox';
14
+ import { useAdaptableComputedCSSVars } from '../../View/AdaptableComputedCSSVarsContext';
14
15
  const resizableDirections = {
15
16
  right: true,
16
17
  bottom: true,
@@ -52,15 +53,27 @@ const INFINITE_COLUMNS_WITH_CHECKBOX = {
52
53
  renderSelectionCheckBox: (params) => {
53
54
  // disable reacting to onChange
54
55
  // as we handle selection change in the onCellClick
55
- return React.createElement(InfiniteTableComponents.CheckBox, { checked: params.rowInfo?.rowSelected ?? false });
56
+ return React.createElement(CheckBox, { mx: 1, checked: params.rowInfo?.rowSelected ?? false });
56
57
  },
57
58
  renderHeaderSelectionCheckBox: true,
58
59
  className: 'ab-Select-CheckboxColumn',
59
60
  renderValue,
60
61
  renderHeader: (headerParams) => {
62
+ const selected = headerParams.allRowsSelected
63
+ ? true
64
+ : headerParams.someRowsSelected
65
+ ? null
66
+ : false;
67
+ const { api } = headerParams;
61
68
  return (React.createElement(React.Fragment, null,
62
- headerParams.renderBag.selectionCheckBox,
63
- headerParams.allRowsSelected ? '(Deselect All)' : '(Select All)'));
69
+ React.createElement(CheckBox, { mx: 1, checked: selected, onChange: (selected) => {
70
+ if (selected) {
71
+ api.rowSelectionApi.selectAll();
72
+ }
73
+ else {
74
+ api.rowSelectionApi.deselectAll();
75
+ }
76
+ } }, headerParams.allRowsSelected ? '(Deselect All)' : '(Select All)')));
64
77
  },
65
78
  renderMenuIcon: false,
66
79
  },
@@ -102,15 +115,11 @@ const doesOptionMatchValue = function (value) {
102
115
  };
103
116
  export const Select = function (props) {
104
117
  let maxLabelLength = 0;
105
- const cssVarsValuesRef = React.useRef({
106
- '--ab-cmp-select-menu__max-width': 0,
107
- '--ab-cmp-select-menu__min-width': 0,
108
- '--ab-cmp-select-menu__max-height': 0,
109
- });
118
+ const computedCSSVars = useAdaptableComputedCSSVars();
110
119
  const CSS_VARS_VALUES = {
111
- '--ab-cmp-select-menu__max-width': cssVarsValuesRef.current['--ab-cmp-select-menu__max-width'] || '60vw',
112
- '--ab-cmp-select-menu__min-width': cssVarsValuesRef.current['--ab-cmp-select-menu__min-width'] || 150,
113
- '--ab-cmp-select-menu__max-height': cssVarsValuesRef.current['--ab-cmp-select-menu__max-height'] || '60vh',
120
+ '--ab-cmp-select-menu__max-width': computedCSSVars['--ab-cmp-select-menu__max-width'] || '60vw',
121
+ '--ab-cmp-select-menu__min-width': computedCSSVars['--ab-cmp-select-menu__min-width'] || 150,
122
+ '--ab-cmp-select-menu__max-height': computedCSSVars['--ab-cmp-select-menu__max-height'] || '60vh',
114
123
  };
115
124
  const searchableInMenulist = props.searchable === 'menulist';
116
125
  const searchableInline = props.searchable === 'inline';
@@ -513,15 +522,6 @@ export const Select = function (props) {
513
522
  props.onInputChange?.(value);
514
523
  }, [props.onInputChange, isMulti]);
515
524
  return (React.createElement(React.Fragment, null,
516
- React.createElement(CSSNumericVariableWatch, { varName: "--ab-cmp-select-menu__max-width", onChange: (value) => {
517
- cssVarsValuesRef.current['--ab-cmp-select-menu__max-width'] = value;
518
- } }),
519
- React.createElement(CSSNumericVariableWatch, { varName: "--ab-cmp-select-menu__min-width", onChange: (value) => {
520
- cssVarsValuesRef.current['--ab-cmp-select-menu__min-width'] = value;
521
- } }),
522
- React.createElement(CSSNumericVariableWatch, { varName: "--ab-cmp-select-menu__max-height", onChange: (value) => {
523
- cssVarsValuesRef.current['--ab-cmp-select-menu__max-height'] = value;
524
- } }),
525
525
  React.createElement(SelectComponent, { ref: ref, openMenuOnClick: searchableInMenulist ? false : undefined, openMenuOnFocus: searchableInMenulist ? false : undefined, menuIsOpen: searchableInMenulist ? isSelectMenuOpen : undefined, isSearchable: searchableInline, "aria-label": props['aria-label'], onKeyDown: props.onKeyDown, inputValue: inputValue, onInputChange: onInputChange, onFocus: onFocus, onBlur: onBlur, onMenuOpen: props.onMenuOpen, isLoading: props.isLoading, options: props.options, className: join(props.className, 'ab-Select'), isDisabled: disabled, menuPlacement: props.menuPlacement ?? 'auto', hideSelectedOptions: false, isMulti: isMulti, value: selectedOption, blurInputOnSelect: false, menuPosition: props.menuPosition ?? 'absolute',
526
526
  // This needed so the menu is not clipped by overflow: hidden
527
527
  menuPortalTarget: ensurePortalElement(), isClearable: props.isClearable, closeMenuOnSelect: props.closeMenuOnSelect, onChange: (option) => {
@@ -0,0 +1,27 @@
1
+ import * as React from 'react';
2
+ import { TreeListItem, TreeListProps } from '../TreeList';
3
+ export type TreeDropdownProps<T extends TreeListItem<any>> = {
4
+ placeholder?: string;
5
+ style?: React.CSSProperties;
6
+ fieldStyle?: React.CSSProperties;
7
+ listSizeConstraints?: {
8
+ minWidth?: number | string;
9
+ maxWidth?: number | string;
10
+ minHeight?: number | string;
11
+ maxHeight?: number | string;
12
+ };
13
+ options: TreeListProps<T>['options'];
14
+ labelField?: string;
15
+ primaryKey?: keyof T;
16
+ value?: any[][] | string[];
17
+ defaultValue?: any[][] | string[];
18
+ toDisplayValue?: (value: any[][] | string[]) => string;
19
+ onChange: (value: any[][] | string[]) => void;
20
+ onMenuOpen?: () => void;
21
+ onMenuClose?: () => void;
22
+ onMouseDown?: (e: React.MouseEvent<HTMLDivElement>) => void;
23
+ resizable?: boolean;
24
+ clearable?: boolean;
25
+ };
26
+ export declare function toDisplayValueDefault(value: any[][] | string[]): string;
27
+ export declare function TreeDropdown<T extends TreeListItem<any>>(props: TreeDropdownProps<T>): React.JSX.Element;
@@ -0,0 +1,250 @@
1
+ import * as React from 'react';
2
+ import FieldWrap from '../../FieldWrap';
3
+ import { TreeList } from '../TreeList';
4
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
5
+ import OverlayTrigger from '../../OverlayTrigger';
6
+ import { Box, Flex } from 'rebass';
7
+ import NotifyResize from '../../NotifyResize';
8
+ import Input from '../../Input';
9
+ import { TreeSelectionState, withSelectedLeafNodesOnly, } from '../../InfiniteTable';
10
+ import SimpleButton from '../../SimpleButton';
11
+ import { CheckBox } from '../../CheckBox';
12
+ import { useLatest } from '../../utils/useLatest';
13
+ import { Resizable } from 're-resizable';
14
+ import { useAdaptableComputedCSSVars } from '../../../View/AdaptableComputedCSSVarsContext';
15
+ const resizableDirections = {
16
+ right: true,
17
+ bottom: true,
18
+ bottomRight: true,
19
+ };
20
+ export function toDisplayValueDefault(value) {
21
+ if (!Array.isArray(value)) {
22
+ return `${value}`;
23
+ }
24
+ return value.map((v) => (Array.isArray(v) ? v.join('-') : v)).join(', ');
25
+ }
26
+ const getLabelColumn = (field) => {
27
+ return {
28
+ field,
29
+ defaultFlex: 1,
30
+ renderTreeIcon: true,
31
+ defaultSortable: false,
32
+ resizable: false,
33
+ renderSelectionCheckBox: ({ rowInfo, dataSourceApi, api }) => {
34
+ if (!rowInfo.isTreeNode) {
35
+ return null;
36
+ }
37
+ return (React.createElement(CheckBox, { mx: 1, checked: rowInfo?.rowSelected, onChange: (checked) => {
38
+ dataSourceApi.treeApi.setNodeSelection(rowInfo.nodePath, checked);
39
+ api.focus();
40
+ } }));
41
+ },
42
+ renderHeader: ({ dataSourceApi, api, allRowsSelected, someRowsSelected }) => {
43
+ const { treeApi } = dataSourceApi;
44
+ const allFirstLevelCollapsed = dataSourceApi
45
+ .getOriginalDataArray()
46
+ .every((item) => !treeApi.isNodeExpanded([item.id]));
47
+ return (React.createElement(Flex, { flexDirection: 'row', alignItems: 'center', width: '100%', onMouseDown: (e) => {
48
+ // so we can keep the focus on the Grid
49
+ e.preventDefault();
50
+ } },
51
+ React.createElement(CheckBox, { checked: someRowsSelected && !allRowsSelected ? null : allRowsSelected, mr: 2, onChange: () => {
52
+ if (allRowsSelected) {
53
+ dataSourceApi.treeApi.deselectAll();
54
+ }
55
+ else {
56
+ dataSourceApi.treeApi.selectAll();
57
+ }
58
+ api.focus();
59
+ } }),
60
+ React.createElement(Flex, { flex: 1 }),
61
+ React.createElement(SimpleButton, { label: "toggle-expand-collapse", icon: allFirstLevelCollapsed ? 'expand-all' : 'collapse-all', onMouseDown: () => {
62
+ if (allFirstLevelCollapsed) {
63
+ dataSourceApi.treeApi.expandAll();
64
+ }
65
+ else {
66
+ dataSourceApi.treeApi.collapseAll();
67
+ }
68
+ }, iconPosition: "end" }, allFirstLevelCollapsed ? 'Expand All' : 'Collapse All')));
69
+ },
70
+ };
71
+ };
72
+ const sizeFull = {
73
+ width: '100%',
74
+ height: '100%',
75
+ };
76
+ function getRowCount(options) {
77
+ return options.reduce((acc, option) => {
78
+ if (Array.isArray(option.children)) {
79
+ return acc + getRowCount(option.children) + 1;
80
+ }
81
+ return acc + 1;
82
+ }, 0);
83
+ }
84
+ export function TreeDropdown(props) {
85
+ const [visible, doSetVisible] = useState(false);
86
+ const overlayDOMRef = useRef(null);
87
+ const getProps = useLatest(props);
88
+ const computedCSSVars = useAdaptableComputedCSSVars();
89
+ const [treeExpandState, setTreeExpandState] = useState(undefined);
90
+ const [searchValue, setSearchValue] = useState('');
91
+ const labelField = props.labelField ?? 'label';
92
+ const columns = useMemo(() => {
93
+ return {
94
+ label: getLabelColumn(labelField),
95
+ };
96
+ }, [labelField]);
97
+ const [stateValue, setStateValue] = useState(props.value !== undefined ? props.value : props.defaultValue || []);
98
+ const onChange = useCallback((value) => {
99
+ const paths = value instanceof TreeSelectionState
100
+ ? value.getState().selectedPaths
101
+ : value.selectedPaths || [];
102
+ if (props.value === undefined) {
103
+ setStateValue(paths);
104
+ }
105
+ props.onChange?.(paths);
106
+ }, [props.onChange, props.value]);
107
+ const value = props.value !== undefined ? props.value : stateValue;
108
+ const treeSelection = useMemo(() => {
109
+ const selection = {
110
+ defaultSelection: false,
111
+ selectedPaths: value,
112
+ };
113
+ return selection;
114
+ }, [value]);
115
+ const rowCount = useMemo(() => {
116
+ return getRowCount(props.options);
117
+ }, [props.options]);
118
+ const [size, setSize] = useState({
119
+ width: 0,
120
+ height: rowCount * 35,
121
+ });
122
+ const setHeight = useCallback((height) => {
123
+ setSize((s) => {
124
+ return {
125
+ ...s,
126
+ height,
127
+ };
128
+ });
129
+ }, []);
130
+ const setWidth = useCallback((width) => {
131
+ setSize((s) => {
132
+ return {
133
+ ...s,
134
+ width,
135
+ };
136
+ });
137
+ }, []);
138
+ const getSize = useLatest(size);
139
+ useEffect(() => {
140
+ if (!getSize().height) {
141
+ setHeight(rowCount * 35);
142
+ }
143
+ }, [rowCount]);
144
+ const setVisible = (visible) => {
145
+ if (visible) {
146
+ const { onMenuOpen } = getProps();
147
+ if (onMenuOpen) {
148
+ onMenuOpen();
149
+ }
150
+ requestAnimationFrame(() => {
151
+ doSetVisible(visible);
152
+ });
153
+ }
154
+ else {
155
+ const { onMenuClose } = getProps();
156
+ if (onMenuClose) {
157
+ onMenuClose();
158
+ }
159
+ doSetVisible(visible);
160
+ }
161
+ };
162
+ const [treeListApi, setTreeListApi] = useState(null);
163
+ const { listSizeConstraints } = props;
164
+ const nodeMatches = useCallback(({ data }) => {
165
+ return !searchValue
166
+ ? data
167
+ : `${data[labelField]}`.toLowerCase().includes(searchValue.toLowerCase());
168
+ }, [searchValue]);
169
+ const filterFunction = useCallback(({ data, filterTreeNode }) => {
170
+ if (!Array.isArray(data.children)) {
171
+ return nodeMatches({ data });
172
+ }
173
+ // allow non-leaf nodes to match
174
+ if (nodeMatches({ data })) {
175
+ return data;
176
+ }
177
+ return filterTreeNode(data);
178
+ }, [nodeMatches]);
179
+ return (React.createElement(Flex, { flexDirection: 'row', className: "ab-TreeDropdown", style: {
180
+ width: '100%',
181
+ ...props.style,
182
+ }, onMouseDown: props.onMouseDown, onBlur: (e) => {
183
+ const { relatedTarget } = e;
184
+ const overlayDOMNode = overlayDOMRef.current;
185
+ if ((overlayDOMNode && relatedTarget == overlayDOMNode) ||
186
+ overlayDOMNode?.contains(relatedTarget)) {
187
+ return;
188
+ }
189
+ setVisible(false);
190
+ } },
191
+ React.createElement(NotifyResize, { onResize: (newSize) => {
192
+ setWidth(newSize.width);
193
+ } }),
194
+ React.createElement(OverlayTrigger, { visible: visible, targetOffset: 20, render: () => {
195
+ const minWidth = listSizeConstraints?.minWidth ||
196
+ computedCSSVars['--ab-cmp-select-menu__min-width'] ||
197
+ 240;
198
+ const maxWidth = listSizeConstraints?.maxWidth ||
199
+ computedCSSVars['--ab-cmp-select-menu__max-width'] ||
200
+ '60vw';
201
+ const minHeight = listSizeConstraints?.minHeight || 200;
202
+ const maxHeight = listSizeConstraints?.maxHeight ||
203
+ computedCSSVars['--ab-cmp-select-menu__max-height'] ||
204
+ '50vh';
205
+ const resizable = getProps().resizable;
206
+ const treeList = (React.createElement(TreeList, { primaryKey: props.primaryKey ?? 'id', treeFilterFunction: filterFunction, columnHeaderHeight: 40, onReady: ({ api }) => {
207
+ setTreeListApi(api);
208
+ api.focus();
209
+ }, defaultTreeExpandState: treeExpandState, onTreeExpandStateChange: setTreeExpandState, columns: columns, options: props.options, treeSelection: treeSelection, onTreeSelectionChange: withSelectedLeafNodesOnly(onChange), style: resizable
210
+ ? sizeFull
211
+ : {
212
+ width: size.width,
213
+ height: size.height,
214
+ maxWidth,
215
+ minHeight,
216
+ maxHeight,
217
+ minWidth,
218
+ } }));
219
+ let children = (React.createElement(Flex, { flexDirection: 'column', height: '100%' },
220
+ React.createElement(Flex, { backgroundColor: 'defaultbackground', p: 1, alignItems: 'center', justifyContent: 'stretch', justifyItems: 'stretch' },
221
+ React.createElement(Input, { "data-name": "menulist-search-input", placeholder: "Search...", style: { width: '100%' }, value: searchValue, onChange: (e) => setSearchValue(e.target.value) })),
222
+ treeList));
223
+ if (resizable) {
224
+ const onResizeStop = (_e, _direction, ref) => {
225
+ const newSize = {
226
+ width: ref.style.width,
227
+ height: ref.style.height,
228
+ };
229
+ setSize(newSize);
230
+ };
231
+ children = (React.createElement(Resizable, { enable: resizableDirections, minWidth: minWidth, maxWidth: maxWidth, minHeight: minHeight, maxHeight: maxHeight, defaultSize: size, onResizeStop: onResizeStop, onResizeStart: (e) => {
232
+ // in order to prevent focus from being lost
233
+ e.preventDefault();
234
+ } }, children));
235
+ }
236
+ return (React.createElement(Box, { ref: overlayDOMRef, className: "ab-TreeDropdownOverlay", "data-name": "menu-container" }, children));
237
+ } },
238
+ React.createElement(FieldWrap, { style: { width: '100%', ...props.fieldStyle } },
239
+ React.createElement(Input, { type: "text", readOnly: true, "data-name": "Select Values", placeholder: props.placeholder ?? 'Select a value', style: {
240
+ width: '100%',
241
+ }, pr: props.clearable ? 0 : undefined, value: props.toDisplayValue ? props.toDisplayValue(value) : toDisplayValueDefault(value), onFocus: () => {
242
+ if (!visible) {
243
+ setVisible(true);
244
+ }
245
+ treeListApi?.focus();
246
+ } }),
247
+ props.clearable && (React.createElement(SimpleButton, { style: {
248
+ visibility: Array.isArray(value) && value.length > 0 ? 'visible' : 'hidden',
249
+ }, variant: "text", icon: "close", onClick: () => onChange({ selectedPaths: [] }) }))))));
250
+ }
@@ -0,0 +1,25 @@
1
+ import * as React from 'react';
2
+ import { DataSourcePropOnTreeSelectionChange_MultiNode, InfiniteTableProps, TreeDataSourceProps } from '../../InfiniteTable';
3
+ export type TreeListItem<T = any> = {
4
+ id: string | number;
5
+ label: string;
6
+ children?: TreeListItem<T>[];
7
+ };
8
+ export type TreeListProps<T extends TreeListItem<T>> = {
9
+ options: T[];
10
+ debugId?: string;
11
+ primaryKey?: keyof T;
12
+ domProps?: InfiniteTableProps<T>['domProps'];
13
+ style?: React.CSSProperties;
14
+ rowHeight?: number | string;
15
+ treeSelection?: TreeDataSourceProps<T>['treeSelection'];
16
+ defaultTreeSelection?: TreeDataSourceProps<T>['defaultTreeSelection'];
17
+ onTreeSelectionChange?: DataSourcePropOnTreeSelectionChange_MultiNode;
18
+ defaultTreeExpandState?: TreeDataSourceProps<T>['defaultTreeExpandState'];
19
+ onTreeExpandStateChange?: TreeDataSourceProps<T>['onTreeExpandStateChange'];
20
+ columns?: InfiniteTableProps<T>['columns'];
21
+ columnHeaderHeight?: number | string;
22
+ onReady?: InfiniteTableProps<T>['onReady'];
23
+ treeFilterFunction?: TreeDataSourceProps<T>['treeFilterFunction'];
24
+ };
25
+ export declare function TreeList<T extends TreeListItem<T>>(props: TreeListProps<T>): React.JSX.Element;
@@ -0,0 +1,35 @@
1
+ import * as React from 'react';
2
+ import { TreeDataSource, TreeGrid, } from '../../InfiniteTable';
3
+ import { Flex } from 'rebass';
4
+ import join from '../../../../../adaptable-react-aggrid/src/utils/join';
5
+ const columns = {
6
+ label: {
7
+ field: 'label',
8
+ header: 'Label',
9
+ defaultFlex: 1,
10
+ renderTreeIcon: true,
11
+ renderSelectionCheckBox: true,
12
+ defaultSortable: false,
13
+ },
14
+ };
15
+ const domProps = {
16
+ style: {
17
+ height: '100%',
18
+ flex: 1,
19
+ },
20
+ className: 'ab-TreeList',
21
+ };
22
+ const DEFAULT_TREE_EXPAND_STATE = {
23
+ expandedPaths: [],
24
+ defaultExpanded: false,
25
+ };
26
+ export function TreeList(props) {
27
+ return (React.createElement(Flex, { flex: 1, flexDirection: 'column', className: "ab-TreeList", style: props.style },
28
+ React.createElement(TreeDataSource, { data: props.options, primaryKey: props.primaryKey ?? 'id', defaultTreeSelection: props.defaultTreeSelection, treeSelection: props.treeSelection, onTreeSelectionChange: props.onTreeSelectionChange, treeFilterFunction: props.treeFilterFunction, onTreeExpandStateChange: props.onTreeExpandStateChange, defaultTreeExpandState: props.defaultTreeExpandState ?? DEFAULT_TREE_EXPAND_STATE },
29
+ React.createElement(TreeGrid, { defaultActiveRowIndex: 0, onReady: props.onReady, debugId: props.debugId, keyboardSelection: true, rowHeight: props.rowHeight ?? '--ab-grid-row-height', keyboardNavigation: "row", columnHeaderHeight: props.columnHeaderHeight, domProps: {
30
+ ...domProps,
31
+ ...props.domProps,
32
+ className: join(domProps.className, props.domProps?.className),
33
+ style: { ...domProps.style, ...props.domProps?.style },
34
+ }, columns: props.columns ?? columns, showZebraRows: false }))));
35
+ }
@@ -0,0 +1,31 @@
1
+ export declare const DevToolsTracks: {
2
+ readonly Init: {
3
+ readonly track: "Initialisation";
4
+ readonly labels: {
5
+ readonly Init: "Init";
6
+ readonly InitStore: "Init store";
7
+ readonly LoadStore: "Loading store";
8
+ readonly InitAGGrid: "AG Grid init";
9
+ };
10
+ };
11
+ readonly LayoutManager: {
12
+ readonly track: "Layout Manager";
13
+ readonly labels: {
14
+ readonly SetLayout: "Setting layout";
15
+ readonly ApplyPivotLayout: "Apply pivot layout";
16
+ readonly ApplyTableLayout: "Apply table layout";
17
+ };
18
+ };
19
+ readonly Runtime: {
20
+ readonly track: "Runtime";
21
+ readonly labels: {
22
+ readonly SetLayout: "Setting layout";
23
+ };
24
+ };
25
+ readonly Redux: {
26
+ readonly track: "Redux";
27
+ readonly labels: {
28
+ readonly Action: "Action";
29
+ };
30
+ };
31
+ };
@@ -0,0 +1,31 @@
1
+ export const DevToolsTracks = {
2
+ Init: {
3
+ track: 'Initialisation',
4
+ labels: {
5
+ Init: 'Init',
6
+ InitStore: 'Init store',
7
+ LoadStore: 'Loading store',
8
+ InitAGGrid: 'AG Grid init',
9
+ },
10
+ },
11
+ LayoutManager: {
12
+ track: 'Layout Manager',
13
+ labels: {
14
+ SetLayout: 'Setting layout',
15
+ ApplyPivotLayout: 'Apply pivot layout',
16
+ ApplyTableLayout: 'Apply table layout',
17
+ },
18
+ },
19
+ Runtime: {
20
+ track: 'Runtime',
21
+ labels: {
22
+ SetLayout: 'Setting layout',
23
+ },
24
+ },
25
+ Redux: {
26
+ track: 'Redux',
27
+ labels: {
28
+ Action: 'Action',
29
+ },
30
+ },
31
+ };
@@ -0,0 +1,12 @@
1
+ export type PerfMarkerDetails = {
2
+ name: string;
3
+ value: string | number | boolean;
4
+ }[];
5
+ export interface PerfMarker {
6
+ start(options?: {
7
+ details?: PerfMarkerDetails;
8
+ }): PerfMarker;
9
+ end(options?: {
10
+ details?: PerfMarkerDetails;
11
+ }): PerfMarker;
12
+ }