@adaptabletools/adaptable 21.0.12 → 21.1.0-canary.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/base.css +1811 -2336
- package/base.css.map +1 -1
- package/index.css +1768 -1413
- package/index.css.map +1 -1
- package/package.json +3 -3
- package/src/AdaptableInterfaces/IAdaptable.d.ts +2 -1
- package/src/AdaptableOptions/FilterOptions.d.ts +7 -0
- package/src/AdaptableOptions/PredicateOptions.d.ts +4 -3
- package/src/AdaptableState/Common/AdaptableColumn.d.ts +1 -1
- package/src/AdaptableState/Common/AdaptablePredicate.d.ts +12 -0
- package/src/AdaptableState/Common/AdaptablePredicate.js +132 -18
- package/src/AdaptableState/Selection/GridCell.d.ts +10 -0
- package/src/Api/Implementation/ExportApiImpl.js +2 -8
- package/src/Api/Implementation/PredicateApiImpl.d.ts +3 -1
- package/src/Api/Implementation/PredicateApiImpl.js +25 -2
- package/src/Api/Internal/AdaptableInternalApi.d.ts +2 -1
- package/src/Api/Internal/AdaptableInternalApi.js +6 -0
- package/src/Api/Internal/PredicateInternalApi.d.ts +3 -1
- package/src/Api/Internal/PredicateInternalApi.js +14 -0
- package/src/Api/PredicateApi.d.ts +1 -1
- package/src/Redux/Store/AdaptableStore.js +111 -3
- package/src/Utilities/Helpers/Helper.js +26 -2
- package/src/Utilities/Hooks/index.d.ts +4 -0
- package/src/Utilities/Hooks/index.js +4 -0
- package/src/Utilities/Hooks/useAdaptableColumn.d.ts +2 -0
- package/src/Utilities/Hooks/useAdaptableColumn.js +6 -0
- package/src/Utilities/Hooks/useAdaptableOptions.d.ts +2 -0
- package/src/Utilities/Hooks/useAdaptableOptions.js +5 -0
- package/src/Utilities/Hooks/useAdaptableState.d.ts +3 -0
- package/src/Utilities/Hooks/useAdaptableState.js +39 -0
- package/src/Utilities/Services/ModuleService.js +1 -1
- package/src/Utilities/adaptableQlUtils.js +3 -0
- package/src/View/AdaptableComputedCSSVarsContext.d.ts +12 -0
- package/src/View/AdaptableComputedCSSVarsContext.js +25 -0
- package/src/View/Components/AdaptableInput/AdaptableDateInlineInput.d.ts +1 -1
- package/src/View/Components/ColumnFilter/FloatingFilter.js +5 -1
- package/src/View/Components/ColumnFilter/components/FloatingFilterInputList.js +1 -1
- package/src/View/Components/ColumnFilter/components/FloatingFilterValues.js +34 -9
- package/src/View/Components/FilterForm/ListBoxFilterForm.d.ts +1 -0
- package/src/View/Components/FilterForm/ListBoxFilterForm.js +93 -16
- package/src/View/Layout/Wizard/sections/ColumnsSection.js +1 -1
- package/src/View/renderWithAdaptableContext.js +3 -1
- package/src/agGrid/AdaptableAgGrid.d.ts +3 -1
- package/src/agGrid/AdaptableAgGrid.js +361 -24
- package/src/agGrid/AdaptableFilterHandler.d.ts +3 -1
- package/src/agGrid/AdaptableFilterHandler.js +16 -12
- package/src/agGrid/AgGridAdapter.js +9 -5
- package/src/agGrid/AgGridColumnAdapter.js +14 -12
- package/src/components/OverlayTrigger/index.js +1 -1
- package/src/components/Select/Select.js +22 -22
- package/src/components/Tree/TreeDropdown/index.d.ts +27 -0
- package/src/components/Tree/TreeDropdown/index.js +250 -0
- package/src/components/Tree/TreeList/index.d.ts +25 -0
- package/src/components/Tree/TreeList/index.js +35 -0
- package/src/devTools/DevToolsTracks.d.ts +31 -0
- package/src/devTools/DevToolsTracks.js +31 -0
- package/src/devTools/PerfMarker.d.ts +12 -0
- package/src/devTools/PerfMarker.js +1 -0
- package/src/devTools/index.d.ts +102 -0
- package/src/devTools/index.js +159 -0
- package/src/env.js +2 -2
- package/src/layout-manager/src/index.d.ts +2 -0
- package/src/layout-manager/src/index.js +24 -0
- package/src/metamodel/adaptable.metamodel.d.ts +6 -0
- package/src/metamodel/adaptable.metamodel.js +1 -1
- package/tsconfig.esm.tsbuildinfo +1 -1
|
@@ -24,7 +24,7 @@ export class AgGridAdapter {
|
|
|
24
24
|
const ColumnDefFactory_Prototye_preWireBeans = ColumnDefFactory_Prototype.preWireBeans;
|
|
25
25
|
ColumnDefFactory_Prototype.preWireBeans = function (beans) {
|
|
26
26
|
ColumnDefFactory_Prototye_preWireBeans?.apply(this, arguments);
|
|
27
|
-
const gridId = beans?.context?.
|
|
27
|
+
const gridId = beans?.context?.getId();
|
|
28
28
|
if (!gridId) {
|
|
29
29
|
console.error('CRITICAL: No gridId found in beans, this should never happen!');
|
|
30
30
|
}
|
|
@@ -137,7 +137,8 @@ export class AgGridAdapter {
|
|
|
137
137
|
}
|
|
138
138
|
const pivotColumnFilters = self.adaptableApi.filterApi.columnFilterApi
|
|
139
139
|
.getActiveColumnFilters()
|
|
140
|
-
.filter((columnFilter) => self.adaptableApi.columnApi.isPivotResultColumn(columnFilter.ColumnId)
|
|
140
|
+
.filter((columnFilter) => self.adaptableApi.columnApi.isPivotResultColumn(columnFilter.ColumnId) ||
|
|
141
|
+
self.adaptableApi.columnApi.isAutoRowGroupColumnForSingle(columnFilter.ColumnId));
|
|
141
142
|
try {
|
|
142
143
|
if (pivotColumnFilters.length > 0) {
|
|
143
144
|
for (const columnFilter of pivotColumnFilters) {
|
|
@@ -160,7 +161,8 @@ export class AgGridAdapter {
|
|
|
160
161
|
agGridColumnFilterService.doFiltersPass = this.DANGER_doFiltersPassMonkeyPatcher;
|
|
161
162
|
this.DANGER_isAggFilterPresentMonkeyPatcher = function () {
|
|
162
163
|
const columnFilters = self.adaptableApi.filterApi.columnFilterApi.getActiveColumnFilters();
|
|
163
|
-
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));
|
|
164
166
|
};
|
|
165
167
|
agGridColumnFilterService.isAggFilterPresent = this.DANGER_isAggFilterPresentMonkeyPatcher;
|
|
166
168
|
}
|
|
@@ -484,8 +486,10 @@ export class AgGridAdapter {
|
|
|
484
486
|
this.logger.warn(`Column is undefined, returning 'text' for Type`);
|
|
485
487
|
return 'text';
|
|
486
488
|
}
|
|
487
|
-
if (this.adaptableApi.columnApi.isAutoRowGroupColumnForSingle(agColumn.getId())
|
|
488
|
-
|
|
489
|
+
if (this.adaptableApi.columnApi.isAutoRowGroupColumnForSingle(agColumn.getId())) {
|
|
490
|
+
return 'groupColumn';
|
|
491
|
+
}
|
|
492
|
+
if (this.adaptableApi.columnApi.isSelectionColumn(agColumn.getId())) {
|
|
489
493
|
return 'unknown';
|
|
490
494
|
}
|
|
491
495
|
if (this.adaptableApi.columnApi.isAutoRowGroupColumnForMulti(agColumn.getId())) {
|
|
@@ -592,31 +592,33 @@ export class AgGridColumnAdapter {
|
|
|
592
592
|
});
|
|
593
593
|
}
|
|
594
594
|
else {
|
|
595
|
+
// TODO only set auto group column as filterable if at least one group columns is filterable
|
|
595
596
|
this.setColDefProperty(col, 'filter', () => {
|
|
596
597
|
return 'agGroupColumnFilter';
|
|
597
598
|
});
|
|
598
599
|
}
|
|
599
|
-
|
|
600
|
+
if (this.adaptableApi.columnApi.isAutoRowGroupColumnForMulti(colId)) {
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
600
603
|
}
|
|
601
604
|
// setup "normal" column filter
|
|
602
605
|
this.setColDefProperty(col, 'filter', (original_filter) => {
|
|
603
|
-
|
|
604
|
-
return;
|
|
605
|
-
}
|
|
606
|
+
const pivotMode = this.adaptableInstance.isInPivotMode();
|
|
606
607
|
if (!useAdaptableFilter) {
|
|
607
608
|
return original_filter;
|
|
608
609
|
}
|
|
609
|
-
if (
|
|
610
|
-
|
|
610
|
+
if (!colDef.filter) {
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
if (typeof original_filter !== 'boolean' &&
|
|
611
614
|
typeof original_filter?.handler !== 'function' &&
|
|
612
|
-
!
|
|
615
|
+
!pivotMode) {
|
|
613
616
|
this.adaptableApi.consoleError(`Column '${colId}' has a custom filter defined in colDef.filter, but Adaptable Filtering accepts only the TRUE/FALSE values!`);
|
|
614
617
|
return false;
|
|
615
618
|
}
|
|
616
619
|
return {
|
|
617
620
|
component: AgGridFilterAdapterFactory(this.adaptableInstance),
|
|
618
|
-
|
|
619
|
-
handler: (params) => new AdaptableFilterHandler(this.adaptableApi, columnSetup),
|
|
621
|
+
handler: () => new AdaptableFilterHandler(this.adaptableApi, columnSetup),
|
|
620
622
|
};
|
|
621
623
|
});
|
|
622
624
|
}
|
|
@@ -633,7 +635,7 @@ export class AgGridColumnAdapter {
|
|
|
633
635
|
!colDef.floatingFilter ||
|
|
634
636
|
!this.adaptableOptions.filterOptions.useAdaptableFiltering ||
|
|
635
637
|
!this.adaptableApi.filterApi.columnFilterApi.isQuickFilterVisible();
|
|
636
|
-
if (this.adaptableApi.columnApi.
|
|
638
|
+
if (this.adaptableApi.columnApi.isAutoRowGroupColumnForMulti(col.getColId())) {
|
|
637
639
|
this.setColDefProperty(col, 'floatingFilter', (original_floatingFilter) => {
|
|
638
640
|
// the floating filter for the group column is "inherited" from the base column
|
|
639
641
|
// via the colDef.filter = 'agGroupColumnFilter'
|
|
@@ -644,7 +646,7 @@ export class AgGridColumnAdapter {
|
|
|
644
646
|
});
|
|
645
647
|
this.setColDefProperty(col, 'suppressFloatingFilterButton', () => {
|
|
646
648
|
// hide button for multi column groups
|
|
647
|
-
return
|
|
649
|
+
return true;
|
|
648
650
|
});
|
|
649
651
|
return;
|
|
650
652
|
}
|
|
@@ -654,7 +656,7 @@ export class AgGridColumnAdapter {
|
|
|
654
656
|
}
|
|
655
657
|
return AgGridFloatingFilterAdapterFactory(this.adaptableInstance);
|
|
656
658
|
});
|
|
657
|
-
this.setColDefProperty(col, 'floatingFilter', (
|
|
659
|
+
this.setColDefProperty(col, 'floatingFilter', () => {
|
|
658
660
|
if (isFloatingFilterDisabled) {
|
|
659
661
|
return;
|
|
660
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
|
|
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,
|
|
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 {
|
|
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(
|
|
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
|
-
|
|
63
|
-
|
|
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
|
|
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':
|
|
112
|
-
'--ab-cmp-select-menu__min-width':
|
|
113
|
-
'--ab-cmp-select-menu__max-height':
|
|
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
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|