@adaptabletools/adaptable 23.0.20 → 23.0.22
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/package.json +1 -1
- package/src/AdaptableOptions/FilterOptions.d.ts +26 -0
- package/src/AdaptableOptions/LayoutOptions.d.ts +1 -8
- package/src/AdaptableState/InitialState.d.ts +1 -1
- package/src/Api/GridApi.d.ts +5 -1
- package/src/Api/Implementation/FormatColumnApiImpl.d.ts +1 -0
- package/src/Api/Implementation/FormatColumnApiImpl.js +15 -0
- package/src/Api/Implementation/FreeTextColumnApiImpl.js +0 -3
- package/src/Api/Implementation/GridApiImpl.d.ts +1 -0
- package/src/Api/Implementation/GridApiImpl.js +22 -1
- package/src/Api/Implementation/StateApiImpl.d.ts +2 -0
- package/src/Api/Implementation/StateApiImpl.js +15 -0
- package/src/Api/Internal/ColumnFilterInternalApi.d.ts +7 -1
- package/src/Api/Internal/ColumnFilterInternalApi.js +3 -0
- package/src/Api/Internal/FormatColumnInternalApi.d.ts +5 -0
- package/src/Api/Internal/FormatColumnInternalApi.js +22 -0
- package/src/Api/Internal/StateInternalApi.d.ts +6 -1
- package/src/Api/Internal/StateInternalApi.js +44 -0
- package/src/Api/StateApi.d.ts +20 -0
- package/src/Redux/Store/AdaptableReduxMerger.js +24 -6
- package/src/Redux/Store/AdaptableStore.js +1 -1
- package/src/Utilities/Helpers/DisplayFormatHelper.js +16 -4
- package/src/Utilities/Helpers/SettingsPanelHelper.js +2 -2
- package/src/View/Components/ColumnFilter/components/FloatingFilterValues.d.ts +9 -0
- package/src/View/Components/ColumnFilter/components/FloatingFilterValues.js +21 -41
- package/src/View/Components/FilterForm/ListBoxFilterForm.js +16 -14
- package/src/View/Components/PredicateEditor/PredicateEditor.js +7 -1
- package/src/View/FormatColumn/Wizard/FormatColumnFormatWizardSection.js +6 -2
- package/src/agGrid/AdaptableAgGrid.d.ts +1 -0
- package/src/agGrid/AdaptableAgGrid.js +15 -0
- package/src/agGrid/AdaptableFilterHandler.d.ts +5 -1
- package/src/agGrid/AdaptableFilterHandler.js +44 -0
- package/src/components/Combobox/comboboxUtils.d.ts +6 -0
- package/src/components/Combobox/comboboxUtils.js +1 -1
- package/src/components/Combobox/index.d.ts +11 -0
- package/src/components/Combobox/index.js +16 -5
- package/src/components/Tree/TreeDropdown/index.d.ts +11 -0
- package/src/components/Tree/TreeDropdown/index.js +6 -3
- package/src/env.js +2 -2
- package/tsconfig.esm.tsbuildinfo +1 -1
|
@@ -118,6 +118,7 @@ export function useDistinctFilterColumnValues(options) {
|
|
|
118
118
|
skipDefaultSearch: !!result.skipDefaultSearch,
|
|
119
119
|
searchValueUsedInFilterValue: prev.searchValueUsedInFilterValue || searchValueUsedInFilterValue,
|
|
120
120
|
hasMore: !!result.hasMore,
|
|
121
|
+
renderInputValues: result.renderInputValues,
|
|
121
122
|
dataLoadIsComplete: true,
|
|
122
123
|
}));
|
|
123
124
|
})
|
|
@@ -171,6 +172,7 @@ export function useDistinctFilterColumnValues(options) {
|
|
|
171
172
|
skipDefaultSearch: !!distinctFilterDisplayValues.skipDefaultSearch,
|
|
172
173
|
searchValueUsedInFilterValue,
|
|
173
174
|
hasMore: !!distinctFilterDisplayValues.hasMore,
|
|
175
|
+
renderInputValues: distinctFilterDisplayValues.renderInputValues,
|
|
174
176
|
});
|
|
175
177
|
lastRequestedOffsetRef.current = 0;
|
|
176
178
|
setIsDistinctColumnValuesLoading(false);
|
|
@@ -183,17 +185,17 @@ export function useDistinctFilterColumnValues(options) {
|
|
|
183
185
|
if (!quickFilterValues.hasMore || !quickFilterValues.dataLoadIsComplete) {
|
|
184
186
|
return;
|
|
185
187
|
}
|
|
186
|
-
let scrollEl = null;
|
|
187
188
|
let debounceTimer;
|
|
188
|
-
const onScroll = () => {
|
|
189
|
+
const onScroll = (event) => {
|
|
190
|
+
const target = event.target;
|
|
191
|
+
if (!(target instanceof Element) || !target.matches(FILTER_VALUES_SCROLL_SELECTOR)) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
189
194
|
if (debounceTimer) {
|
|
190
195
|
clearTimeout(debounceTimer);
|
|
191
196
|
}
|
|
192
197
|
debounceTimer = setTimeout(() => {
|
|
193
|
-
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
const el = scrollEl;
|
|
198
|
+
const el = target;
|
|
197
199
|
const remaining = el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
198
200
|
if (remaining > NEAR_END_PX) {
|
|
199
201
|
return;
|
|
@@ -201,45 +203,14 @@ export function useDistinctFilterColumnValues(options) {
|
|
|
201
203
|
loadMoreValues();
|
|
202
204
|
}, SCROLL_DEBOUNCE_MS);
|
|
203
205
|
};
|
|
204
|
-
|
|
205
|
-
scrollEl = document.querySelector(FILTER_VALUES_SCROLL_SELECTOR);
|
|
206
|
-
if (scrollEl) {
|
|
207
|
-
scrollEl.addEventListener('scroll', onScroll, { passive: true });
|
|
208
|
-
return true;
|
|
209
|
-
}
|
|
210
|
-
return false;
|
|
211
|
-
};
|
|
212
|
-
let attached = tryAttach();
|
|
213
|
-
const raf = attached
|
|
214
|
-
? undefined
|
|
215
|
-
: requestAnimationFrame(() => {
|
|
216
|
-
attached = tryAttach();
|
|
217
|
-
});
|
|
218
|
-
const timeout = attached
|
|
219
|
-
? undefined
|
|
220
|
-
: setTimeout(() => {
|
|
221
|
-
tryAttach();
|
|
222
|
-
}, 50);
|
|
206
|
+
document.addEventListener('scroll', onScroll, { capture: true, passive: true });
|
|
223
207
|
return () => {
|
|
224
|
-
if (raf != null) {
|
|
225
|
-
cancelAnimationFrame(raf);
|
|
226
|
-
}
|
|
227
|
-
if (timeout != null) {
|
|
228
|
-
clearTimeout(timeout);
|
|
229
|
-
}
|
|
230
208
|
if (debounceTimer) {
|
|
231
209
|
clearTimeout(debounceTimer);
|
|
232
210
|
}
|
|
233
|
-
|
|
234
|
-
scrollEl.removeEventListener('scroll', onScroll);
|
|
235
|
-
}
|
|
211
|
+
document.removeEventListener('scroll', onScroll, { capture: true });
|
|
236
212
|
};
|
|
237
|
-
}, [
|
|
238
|
-
quickFilterValues.hasMore,
|
|
239
|
-
quickFilterValues.dataLoadIsComplete,
|
|
240
|
-
quickFilterValues.values.length,
|
|
241
|
-
loadMoreValues,
|
|
242
|
-
]);
|
|
213
|
+
}, [quickFilterValues.hasMore, quickFilterValues.dataLoadIsComplete, loadMoreValues]);
|
|
243
214
|
useEffect(() => {
|
|
244
215
|
if (!hasMoreRef.current ||
|
|
245
216
|
!quickFilterValues.dataLoadIsComplete ||
|
|
@@ -366,7 +337,10 @@ export const FloatingFilterValues = (props) => {
|
|
|
366
337
|
triggerValuesLoad();
|
|
367
338
|
}
|
|
368
339
|
}, []);
|
|
369
|
-
const { skipDefaultSearch } = quickFilterValues;
|
|
340
|
+
const { skipDefaultSearch, renderInputValues } = quickFilterValues;
|
|
341
|
+
const renderComboboxInputValues = React.useMemo(() => renderInputValues
|
|
342
|
+
? (items) => renderInputValues({ selectedValues: items, selectedCount: items.length })
|
|
343
|
+
: undefined, [renderInputValues]);
|
|
370
344
|
if (props.columnId === AG_GRID_GROUPED_COLUMN) {
|
|
371
345
|
if (Array.isArray(props.value) && !props.value.every((value) => Array.isArray(value))) {
|
|
372
346
|
logOnce(`All the inputs for the IN predicate for the column "${props.columnId}" need to be arrays. Example:
|
|
@@ -389,11 +363,17 @@ export const FloatingFilterValues = (props) => {
|
|
|
389
363
|
...props.selectProps,
|
|
390
364
|
'data-name': 'Select Values',
|
|
391
365
|
showSelectedCount: true,
|
|
366
|
+
...(renderComboboxInputValues
|
|
367
|
+
? { renderInputValues: renderComboboxInputValues }
|
|
368
|
+
: {}),
|
|
392
369
|
filter: skipDefaultSearch ? null : undefined,
|
|
393
370
|
onInputValueChange: onInputChange,
|
|
394
371
|
}
|
|
395
372
|
: {
|
|
396
373
|
...props.selectProps,
|
|
374
|
+
...(renderComboboxInputValues
|
|
375
|
+
? { renderInputValues: renderComboboxInputValues }
|
|
376
|
+
: {}),
|
|
397
377
|
filter: skipDefaultSearch ? null : undefined,
|
|
398
378
|
onInputValueChange: onInputChange,
|
|
399
379
|
}, disabled: props.disabled, onMenuOpen: onMenuOpen, isLoading: isDistinctColumnValuesLoading, column: currentColumn, dataType: currentColumn.dataType, options: quickFilterValues.values, value: props.value, onChange: props.onChange }));
|
|
@@ -10,6 +10,7 @@ import { useMemo } from 'react';
|
|
|
10
10
|
import { GridFilterCombobox } from '../../../components/Combobox';
|
|
11
11
|
import { isEmbeddedColumnFilterLocation } from '../ColumnFilter/columnFilterLocation';
|
|
12
12
|
import { useColumnFilterLocation } from '../ColumnFilter/AdaptableColumnFilter';
|
|
13
|
+
import { useAdaptable } from '../../AdaptableContext';
|
|
13
14
|
import { GridFilterTreeDropdown } from '../../../components/Tree/TreeDropdown';
|
|
14
15
|
const baseClassName = 'ab-ListBoxFilterForm';
|
|
15
16
|
function toDateDisplayValue(values) {
|
|
@@ -29,9 +30,11 @@ const dateOnChangeParser = (value) => {
|
|
|
29
30
|
const EMPTY_ARRAY = [];
|
|
30
31
|
export const ColumnValuesSelect = (props) => {
|
|
31
32
|
const location = useColumnFilterLocation();
|
|
33
|
+
const adaptable = useAdaptable();
|
|
32
34
|
const column = props.column;
|
|
33
35
|
let selectedColumnValues = props.value || EMPTY_ARRAY;
|
|
34
36
|
const rawOptionsFromProps = Array.isArray(props.options) ? props.options : EMPTY_ARRAY;
|
|
37
|
+
const lookupItems = adaptable?.api.filterApi.columnFilterApi.internalApi.getRememberedLazyInFilterValues(column.columnId) ?? EMPTY_ARRAY;
|
|
35
38
|
const optionsFromProps = useMemo(() => {
|
|
36
39
|
if (rawOptionsFromProps === EMPTY_ARRAY) {
|
|
37
40
|
return rawOptionsFromProps;
|
|
@@ -88,19 +91,18 @@ export const ColumnValuesSelect = (props) => {
|
|
|
88
91
|
}
|
|
89
92
|
const options = column.dataType === 'date' || column.columnId === AG_GRID_GROUPED_COLUMN
|
|
90
93
|
? dateOptions
|
|
91
|
-
: optionsFromProps
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
: optionsFromProps;
|
|
95
|
+
if (column.dataType !== 'date' && column.columnId !== AG_GRID_GROUPED_COLUMN) {
|
|
96
|
+
for (const selected of selectedColumnValues) {
|
|
97
|
+
if (options.some((option) => option.value === selected)) {
|
|
98
|
+
value.push(selected);
|
|
99
|
+
continue;
|
|
95
100
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
return true;
|
|
103
|
-
});
|
|
101
|
+
const dateOption = options.find((option) => option.value instanceof Date &&
|
|
102
|
+
isEqual(parseDateValue(selected), parseDateValue(option.value)));
|
|
103
|
+
value.push(dateOption ? dateOption.value : selected);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
104
106
|
const treeDropdownToDisplayValue = React.useMemo(() => {
|
|
105
107
|
if (column.dataType === 'date') {
|
|
106
108
|
return toDateDisplayValue;
|
|
@@ -115,9 +117,9 @@ export const ColumnValuesSelect = (props) => {
|
|
|
115
117
|
}
|
|
116
118
|
}
|
|
117
119
|
: undefined;
|
|
118
|
-
const component = column.dataType === 'date' || column.columnId === AG_GRID_GROUPED_COLUMN ? (_jsx(GridFilterTreeDropdown, { toDisplayValue: treeDropdownToDisplayValue, resizable: true, onValueChange: column.dataType === 'date'
|
|
120
|
+
const component = column.dataType === 'date' || column.columnId === AG_GRID_GROUPED_COLUMN ? (_jsx(GridFilterTreeDropdown, { toDisplayValue: treeDropdownToDisplayValue, renderInputValues: selectProps.renderInputValues, resizable: true, onValueChange: column.dataType === 'date'
|
|
119
121
|
? (value) => props.onChange(dateOnChangeParser(value))
|
|
120
|
-
: props.onChange, items: options, value: selectedColumnValues, "data-name": "Select Values", primaryKey: 'value', isLoading: props.isLoading, onOpenChange: onOpenChange, showClear: isEmbeddedColumnFilterLocation(location) })) : (_jsx(GridFilterCombobox, { disabled: props.disabled, ...selectProps, onOpenChange: onOpenChange, items: options, value: value, isLoading: props.isLoading, onValueChange: props.onChange, showClear: isEmbeddedColumnFilterLocation(location) }, "select"));
|
|
122
|
+
: props.onChange, items: options, value: selectedColumnValues, "data-name": "Select Values", primaryKey: 'value', isLoading: props.isLoading, onOpenChange: onOpenChange, showClear: isEmbeddedColumnFilterLocation(location) })) : (_jsx(GridFilterCombobox, { disabled: props.disabled, ...selectProps, onOpenChange: onOpenChange, items: options, value: value, lookupItems: lookupItems, isLoading: props.isLoading, onValueChange: props.onChange, showClear: isEmbeddedColumnFilterLocation(location) }, "select"));
|
|
121
123
|
return (_jsx("div", { className: join(baseClassName, 'twa:relative', props.isLoading && `${baseClassName}--loading`, !value.length && `${baseClassName}--empty`), onKeyDownCapture: (e) => {
|
|
122
124
|
if (e.key === 'Tab') {
|
|
123
125
|
e.stopPropagation();
|
|
@@ -64,7 +64,10 @@ export const PredicateEditor = (props) => {
|
|
|
64
64
|
triggerValuesLoad();
|
|
65
65
|
}
|
|
66
66
|
}, []);
|
|
67
|
-
const { skipDefaultSearch } = quickFilterValues;
|
|
67
|
+
const { skipDefaultSearch, renderInputValues } = quickFilterValues;
|
|
68
|
+
const renderComboboxInputValues = React.useMemo(() => renderInputValues
|
|
69
|
+
? (items) => renderInputValues({ selectedValues: items, selectedCount: items.length })
|
|
70
|
+
: undefined, [renderInputValues]);
|
|
68
71
|
return (_jsxs(Box, { className: baseClassName, children: [_jsxs(Flex, { alignItems: "center", className: "twa:justify-stretch", children: [icon && _jsx(Tag, { className: "twa:mr-2", children: icon }), _jsx(SingleSelect, { items: predicateDefsOptions, "data-name": "select-predicate", placeholder: "Select Rule", value: props.predicate?.PredicateId ?? null, onValueChange: (value) => {
|
|
69
72
|
const option = predicateDefsOptions.find((x) => x.value === value);
|
|
70
73
|
props.onChange({
|
|
@@ -75,5 +78,8 @@ export const PredicateEditor = (props) => {
|
|
|
75
78
|
} })] }), _jsx(Flex, { children: currentPredicateDef?.inputs?.map((predicateDefInput, index) => (_jsxs(_Fragment, { children: [index > 0 && _jsx(HelpBlock, { className: "twa:m-2", children: "AND" }), _jsx(Flex, { className: "twa:flex-1", flexDirection: "column", children: _jsx(AdaptableInput, { "data-name": `predicate-input-${index}`, className: "twa:mt-2", type: predicateDefInput.type, autoFocus: index === 0, value: props.predicate.Inputs?.[index] ?? '', onChange: (e) => handlePredicateInputChange(e, index) }) }, index)] }))) }), adaptable.api.predicateApi.internalApi.IsInOrNotInPredicateDef(currentPredicateDef) && (_jsx(Box, { className: "twa:mt-2", children: _jsx(ColumnValuesSelect, { isLoading: isDistinctColumnValuesLoading, column: column, options: quickFilterValues.values, onMenuOpen: onMenuOpen, selectProps: {
|
|
76
79
|
onInputValueChange: onInputChange,
|
|
77
80
|
filter: skipDefaultSearch ? null : undefined,
|
|
81
|
+
...(renderComboboxInputValues
|
|
82
|
+
? { renderInputValues: renderComboboxInputValues }
|
|
83
|
+
: {}),
|
|
78
84
|
}, dataType: column.dataType, value: props.predicate.Inputs, onChange: handlePredicateValuesChange }) }))] }));
|
|
79
85
|
};
|
|
@@ -71,7 +71,7 @@ const appendNumberFormatOptions = (items, options) => {
|
|
|
71
71
|
});
|
|
72
72
|
}
|
|
73
73
|
appendDisplayFormatItem(items, 'Content', options.Content);
|
|
74
|
-
if (options.Multiplier != null && options.Multiplier !== 1) {
|
|
74
|
+
if (options.Multiplier != null && options.Multiplier !== 0 && options.Multiplier !== 1) {
|
|
75
75
|
items.push({ label: 'Multiplier', value: String(options.Multiplier) });
|
|
76
76
|
}
|
|
77
77
|
appendDisplayFormatItem(items, 'Parentheses', options.Parentheses);
|
|
@@ -342,7 +342,11 @@ const renderNumberFormat = (data, onChange, setFormatOption, scopedCustomFormatt
|
|
|
342
342
|
? clamp(Number(e.currentTarget.value), 0, 20)
|
|
343
343
|
: undefined) }) }), _jsx(FormRow, { label: "Integer Digits", children: _jsx(Input, { className: NUMBER_FORMAT_INPUT_CLASS, "data-name": "integer-digits", type: "number", min: "0", value: resolved.Options.IntegerDigits, onChange: (e) => setFormatOption('IntegerDigits', StringExtensions.IsNumeric(e.currentTarget.value)
|
|
344
344
|
? clamp(Number(e.currentTarget.value), 0, 20)
|
|
345
|
-
: undefined) }) }), _jsx(FormRow, { label: "Fraction Separator", children: _jsx(Input, { className: NUMBER_FORMAT_INPUT_CLASS, "data-name": "fraction-separator", value: resolved.Options.FractionSeparator ?? '', onChange: (e) => setFormatOption('FractionSeparator', e.currentTarget.value) }) }), _jsx(FormRow, { label: "Integer Separator", children: _jsx(Input, { className: NUMBER_FORMAT_INPUT_CLASS, "data-name": "integer-separator", value: resolved.Options.IntegerSeparator ?? '', onChange: (e) => setFormatOption('IntegerSeparator', e.currentTarget.value) }) })] }), _jsxs(FormLayout, { sizes: NUMBER_FORMAT_VALUE_FORM_SIZES, columns: [NUMBER_FORMAT_LABEL_COLUMN, NUMBER_FORMAT_VALUE_CHILDREN_COLUMN], className: "twa:mr-5 twa:shrink-0", children: [_jsx(FormRow, { label: "Multiplier", children: _jsx(Input, { className: NUMBER_FORMAT_INPUT_CLASS, "data-name": "multiplier", type: "number", value: resolved.Options.Multiplier
|
|
345
|
+
: undefined) }) }), _jsx(FormRow, { label: "Fraction Separator", children: _jsx(Input, { className: NUMBER_FORMAT_INPUT_CLASS, "data-name": "fraction-separator", value: resolved.Options.FractionSeparator ?? '', onChange: (e) => setFormatOption('FractionSeparator', e.currentTarget.value) }) }), _jsx(FormRow, { label: "Integer Separator", children: _jsx(Input, { className: NUMBER_FORMAT_INPUT_CLASS, "data-name": "integer-separator", value: resolved.Options.IntegerSeparator ?? '', onChange: (e) => setFormatOption('IntegerSeparator', e.currentTarget.value) }) })] }), _jsxs(FormLayout, { sizes: NUMBER_FORMAT_VALUE_FORM_SIZES, columns: [NUMBER_FORMAT_LABEL_COLUMN, NUMBER_FORMAT_VALUE_CHILDREN_COLUMN], className: "twa:mr-5 twa:shrink-0", children: [_jsx(FormRow, { label: "Multiplier", children: _jsx(Input, { className: NUMBER_FORMAT_INPUT_CLASS, "data-name": "multiplier", type: "number", value: typeof resolved.Options.Multiplier === 'number'
|
|
346
|
+
? resolved.Options.Multiplier
|
|
347
|
+
: '', onChange: (e) => setFormatOption('Multiplier', StringExtensions.IsNumeric(e.currentTarget.value)
|
|
348
|
+
? Number(e.currentTarget.value)
|
|
349
|
+
: undefined) }) }), _jsx(FormRow, { label: "Prefix", children: _jsx(Input, { className: NUMBER_FORMAT_INPUT_CLASS, "data-name": "prefix", value: resolved.Options.Prefix ?? '', onChange: (e) => setFormatOption('Prefix', e.currentTarget.value) }) }), _jsx(FormRow, { label: "Suffix", children: _jsx(Input, { className: NUMBER_FORMAT_INPUT_CLASS, "data-name": "suffix", value: resolved.Options.Suffix ?? '', onChange: (e) => setFormatOption('Suffix', e.currentTarget.value) }) }), _jsx(FormRow, { label: "Zero Display", children: _jsx(Input, { className: NUMBER_FORMAT_INPUT_CLASS, "data-name": "zero-display", value: resolved.Options.ZeroDisplay === undefined ||
|
|
346
350
|
resolved.Options.ZeroDisplay === '0'
|
|
347
351
|
? '0'
|
|
348
352
|
: resolved.Options.ZeroDisplay, onChange: (e) => {
|
|
@@ -291,6 +291,7 @@ export declare class AdaptableAgGrid implements IAdaptable {
|
|
|
291
291
|
autoSizeColumns(columnIds?: string[]): void;
|
|
292
292
|
autoSizeAllColumns(): void;
|
|
293
293
|
getDistinctValuesForColumn(column: AdaptableColumn): Promise<GridCell[]>;
|
|
294
|
+
private getSelectedInFilterValues;
|
|
294
295
|
getDistinctFilterValuesForColumn(options: {
|
|
295
296
|
column: AdaptableColumn;
|
|
296
297
|
currentSearchValue: string;
|
|
@@ -2372,6 +2372,18 @@ export class AdaptableAgGrid {
|
|
|
2372
2372
|
async getDistinctValuesForColumn(column) {
|
|
2373
2373
|
return this.getDistinctGridCellsForColumn(column);
|
|
2374
2374
|
}
|
|
2375
|
+
getSelectedInFilterValues(column) {
|
|
2376
|
+
const columnFilterApi = this.api.filterApi.columnFilterApi;
|
|
2377
|
+
const columnFilter = columnFilterApi.getColumnFilterForColumn(column.columnId);
|
|
2378
|
+
const filterHandler = columnFilterApi.internalApi.getAdaptableFilterHandler(column.columnId);
|
|
2379
|
+
const inputs = (columnFilter?.Predicates ?? [])
|
|
2380
|
+
.filter((predicate) => predicate.PredicateId === 'In' || predicate.PredicateId === 'NotIn')
|
|
2381
|
+
.flatMap((predicate) => (Array.isArray(predicate.Inputs) ? predicate.Inputs : []));
|
|
2382
|
+
return inputs.map((value) => {
|
|
2383
|
+
const known = filterHandler?.getRememberedLazyInFilterValue(value);
|
|
2384
|
+
return known ?? { value, label: value == null ? '' : String(value) };
|
|
2385
|
+
});
|
|
2386
|
+
}
|
|
2375
2387
|
async getDistinctFilterValuesForColumn(options) {
|
|
2376
2388
|
const { column, previousResult } = options;
|
|
2377
2389
|
const offset = options.offset ?? 0;
|
|
@@ -2426,6 +2438,9 @@ export class AdaptableAgGrid {
|
|
|
2426
2438
|
previousFilterResult: previousResult,
|
|
2427
2439
|
offset,
|
|
2428
2440
|
limit,
|
|
2441
|
+
get selectedValues() {
|
|
2442
|
+
return self.getSelectedInFilterValues(column);
|
|
2443
|
+
},
|
|
2429
2444
|
get currentSearchValue() {
|
|
2430
2445
|
return options.currentSearchValue;
|
|
2431
2446
|
},
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { DoesFilterPassParams, FilterHandler, FilterHandlerParams } from 'ag-grid-enterprise';
|
|
2
2
|
import { AdaptableApi } from '../Api/AdaptableApi';
|
|
3
|
-
import { InFilterValueResult } from '../AdaptableOptions/FilterOptions';
|
|
3
|
+
import { InFilterValue, InFilterValueResult } from '../AdaptableOptions/FilterOptions';
|
|
4
4
|
import { ColumnFilter } from '../types';
|
|
5
5
|
export declare class AdaptableFilterHandler implements FilterHandler<any, any, ColumnFilter> {
|
|
6
6
|
private adaptableApi;
|
|
7
7
|
colId: string;
|
|
8
8
|
private filterDisplayValuesResult;
|
|
9
9
|
private previousFilterDisplayValuesResult;
|
|
10
|
+
private rememberedInFilterValues;
|
|
10
11
|
constructor(adaptableApi: AdaptableApi);
|
|
11
12
|
init(params: FilterHandlerParams): void;
|
|
12
13
|
doesFilterPass(params: DoesFilterPassParams<any, any, ColumnFilter>): boolean;
|
|
@@ -22,6 +23,9 @@ export declare class AdaptableFilterHandler implements FilterHandler<any, any, C
|
|
|
22
23
|
offset?: number;
|
|
23
24
|
limit?: number;
|
|
24
25
|
}): Promise<InFilterValueResult>;
|
|
26
|
+
private rememberSelectedLazyInFilterValues;
|
|
27
|
+
getRememberedLazyInFilterValues(): InFilterValue[];
|
|
28
|
+
getRememberedLazyInFilterValue(value: any): InFilterValue | undefined;
|
|
25
29
|
onNewRowsLoaded(): void;
|
|
26
30
|
onAnyFilterChanged(): void;
|
|
27
31
|
resetFilterDisplayValues(): void;
|
|
@@ -3,6 +3,7 @@ export class AdaptableFilterHandler {
|
|
|
3
3
|
colId;
|
|
4
4
|
filterDisplayValuesResult;
|
|
5
5
|
previousFilterDisplayValuesResult;
|
|
6
|
+
rememberedInFilterValues = new Map();
|
|
6
7
|
constructor(adaptableApi) {
|
|
7
8
|
this.adaptableApi = adaptableApi;
|
|
8
9
|
}
|
|
@@ -44,6 +45,7 @@ export class AdaptableFilterHandler {
|
|
|
44
45
|
return this.fetchFilterDisplayValues(options);
|
|
45
46
|
}
|
|
46
47
|
async fetchFilterDisplayValues(options) {
|
|
48
|
+
this.rememberSelectedLazyInFilterValues(undefined);
|
|
47
49
|
return this.adaptableApi.gridApi.internalApi
|
|
48
50
|
.getDistinctFilterDisplayValuesForColumn({
|
|
49
51
|
columnId: this.colId,
|
|
@@ -55,10 +57,51 @@ export class AdaptableFilterHandler {
|
|
|
55
57
|
limit: options.limit,
|
|
56
58
|
})
|
|
57
59
|
.then((result) => {
|
|
60
|
+
this.rememberSelectedLazyInFilterValues(result);
|
|
58
61
|
this.filterDisplayValuesResult = result;
|
|
59
62
|
return result;
|
|
60
63
|
});
|
|
61
64
|
}
|
|
65
|
+
rememberSelectedLazyInFilterValues(result) {
|
|
66
|
+
if (!this.adaptableApi.optionsApi.getFilterOptions().customInFilterValues) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const paginatedResult = result ?? this.getLastCachedFilterDisplayValues();
|
|
70
|
+
if (paginatedResult?.hasMore === undefined) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const columnFilter = this.adaptableApi.filterApi.columnFilterApi.getColumnFilterForColumn(this.colId);
|
|
74
|
+
const selectedInputs = new Set((columnFilter?.Predicates ?? [])
|
|
75
|
+
.filter((predicate) => predicate.PredicateId === 'In' || predicate.PredicateId === 'NotIn')
|
|
76
|
+
.flatMap((predicate) => (Array.isArray(predicate.Inputs) ? predicate.Inputs : [])));
|
|
77
|
+
for (const value of this.rememberedInFilterValues.keys()) {
|
|
78
|
+
if (!selectedInputs.has(value)) {
|
|
79
|
+
this.rememberedInFilterValues.delete(value);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (!selectedInputs.size) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const visit = (values) => {
|
|
86
|
+
if (!values) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
for (const item of values) {
|
|
90
|
+
if (selectedInputs.has(item.value)) {
|
|
91
|
+
this.rememberedInFilterValues.set(item.value, item);
|
|
92
|
+
}
|
|
93
|
+
visit(item.children);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
visit(this.getLastCachedFilterDisplayValues()?.values);
|
|
97
|
+
visit(result?.values);
|
|
98
|
+
}
|
|
99
|
+
getRememberedLazyInFilterValues() {
|
|
100
|
+
return Array.from(this.rememberedInFilterValues.values());
|
|
101
|
+
}
|
|
102
|
+
getRememberedLazyInFilterValue(value) {
|
|
103
|
+
return this.rememberedInFilterValues.get(value);
|
|
104
|
+
}
|
|
62
105
|
onNewRowsLoaded() {
|
|
63
106
|
this.resetFilterDisplayValues();
|
|
64
107
|
}
|
|
@@ -83,5 +126,6 @@ export class AdaptableFilterHandler {
|
|
|
83
126
|
destroy() {
|
|
84
127
|
this.filterDisplayValuesResult = undefined;
|
|
85
128
|
this.previousFilterDisplayValuesResult = undefined;
|
|
129
|
+
this.rememberedInFilterValues.clear();
|
|
86
130
|
}
|
|
87
131
|
}
|
|
@@ -57,6 +57,12 @@ export type ComboboxCommonProps<T extends ComboboxItemType> = {
|
|
|
57
57
|
* is cleared on close and every open starts from the full list.
|
|
58
58
|
*/
|
|
59
59
|
persistFilterOnReopen?: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Extra items used only to resolve selected values that are not in `items`
|
|
62
|
+
* (e.g. selected In Filter values hidden by the current search page).
|
|
63
|
+
* Not shown in the dropdown list.
|
|
64
|
+
*/
|
|
65
|
+
lookupItems?: T[];
|
|
60
66
|
/**
|
|
61
67
|
* Custom filter function, or `null` to disable built-in filtering
|
|
62
68
|
* (e.g. when options are already filtered server-side).
|
|
@@ -17,7 +17,7 @@ export function valueToItem(stringValue, lookup) {
|
|
|
17
17
|
export function valueToItems(stringValues, lookup) {
|
|
18
18
|
if (stringValues == null)
|
|
19
19
|
return undefined;
|
|
20
|
-
return stringValues.map((v) => lookup.get(v)
|
|
20
|
+
return stringValues.map((v) => lookup.get(v) ?? { value: v, label: String(v ?? '') });
|
|
21
21
|
}
|
|
22
22
|
export function toStringValue(item) {
|
|
23
23
|
return item?.value ?? null;
|
|
@@ -33,7 +33,18 @@ export type MultiComboboxProps<T extends ComboboxItemType> = Omit<AdaptableCombo
|
|
|
33
33
|
} & ComboboxDataProps<T>;
|
|
34
34
|
export declare const MultiCombobox: <T extends ComboboxItemType>(props: MultiComboboxProps<T>) => React.JSX.Element;
|
|
35
35
|
export type GridFilterComboboxProps<T extends ComboboxItemType> = Omit<MultiComboboxProps<T>, 'showSelectAllCheckbox' | 'searchable' | 'renderInput' | 'renderInputValues'> & {
|
|
36
|
+
/**
|
|
37
|
+
* When true, prefix the selected values in the collapsed input with the
|
|
38
|
+
* selected count (e.g. `(3)`). Ignored when `renderInputValues` is provided.
|
|
39
|
+
*/
|
|
36
40
|
showSelectedCount?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Custom content for the selected values in the collapsed input (rendered inside the
|
|
43
|
+
* standard wrapper). When provided, the built-in selected count is not rendered -
|
|
44
|
+
* include one in the returned content if needed.
|
|
45
|
+
* When omitted, selected labels are joined with a comma.
|
|
46
|
+
*/
|
|
47
|
+
renderInputValues?: (items: T[]) => React.ReactNode;
|
|
37
48
|
};
|
|
38
49
|
export declare const GRID_FILTER_COMBBOX_ADJUSTMENTS_CLASSNAME: string;
|
|
39
50
|
export declare const GridFilterCombobox: <T extends ComboboxItemType>(props: GridFilterComboboxProps<T>) => React.JSX.Element;
|
|
@@ -196,9 +196,18 @@ const useGetAllItems = (props) => {
|
|
|
196
196
|
?
|
|
197
197
|
[].concat(props.items)
|
|
198
198
|
: props.items;
|
|
199
|
+
const lookupItems = props.lookupItems;
|
|
199
200
|
const itemByValue = useMemo(() => {
|
|
200
|
-
|
|
201
|
-
|
|
201
|
+
const map = new Map(allItems.map((item) => [item.value, item]));
|
|
202
|
+
if (lookupItems) {
|
|
203
|
+
for (const item of lookupItems) {
|
|
204
|
+
if (!map.has(item.value)) {
|
|
205
|
+
map.set(item.value, item);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return map;
|
|
210
|
+
}, [allItems, lookupItems]);
|
|
202
211
|
const creatableInput = useCreatable(props, allItems, itemByValue);
|
|
203
212
|
const { inputValue, onInputValueChange } = useMenulistFilterInput(props, {
|
|
204
213
|
inputValue: creatableInput.inputValue,
|
|
@@ -558,7 +567,7 @@ export const MultiCombobox = (props) => {
|
|
|
558
567
|
};
|
|
559
568
|
export const GRID_FILTER_COMBBOX_ADJUSTMENTS_CLASSNAME = cn('twa:[.ab-FloatingFilter_&]:border-none twa:[.ab-FloatingFilter_&]:inset-y-0.5 twa:[.ab-FloatingFilter_&]:inset-x-0 twa:[.ab-FloatingFilter_&]:absolute twa:[.ab-FloatingFilter_&]:shadow-none twa:[.ab-FloatingFilter_&]:min-h-auto!', 'twa:[.ab-FloatingFilter_&]:[line-height:1]', 'twa:[.ab-FloatingFilter_[data-slot=combobox-trigger]]:py-0', 'twa:[.ab-FloatingFilter_&]:[container-type:size]');
|
|
560
569
|
export const GridFilterCombobox = (props) => {
|
|
561
|
-
const { showSelectedCount = false, placeholder = 'Select...', ...comboboxProps } = props;
|
|
570
|
+
const { showSelectedCount = false, placeholder = 'Select...', renderInputValues: renderInputValuesProp, ...comboboxProps } = props;
|
|
562
571
|
const sharedProps = {
|
|
563
572
|
placeholder,
|
|
564
573
|
showSelectAllCheckbox: true,
|
|
@@ -570,11 +579,13 @@ export const GridFilterCombobox = (props) => {
|
|
|
570
579
|
showClear: false,
|
|
571
580
|
showTrigger: false,
|
|
572
581
|
renderInputValues: (items) => {
|
|
573
|
-
let children =
|
|
582
|
+
let children = renderInputValuesProp
|
|
583
|
+
? renderInputValuesProp(items)
|
|
584
|
+
: items.map((item) => getItemTextLabel(item)).join(', ');
|
|
574
585
|
if (items.length === 0) {
|
|
575
586
|
children = (_jsx("span", { "data-name": "placeholder", className: "twa:text-muted-foreground", children: placeholder }));
|
|
576
587
|
}
|
|
577
|
-
return (_jsx(_Fragment, { children: _jsxs("div", { className: "twa:text-ellipsis twa:overflow-hidden twa:whitespace-nowrap twa:flex-1000", "data-slot": "combobox-selected-values", children: [showSelectedCount && items.length > 0 && (_jsxs("span", { "data-name": "multiple-values-count",
|
|
588
|
+
return (_jsx(_Fragment, { children: _jsxs("div", { className: "twa:text-ellipsis twa:overflow-hidden twa:whitespace-nowrap twa:flex-1000", "data-slot": "combobox-selected-values", children: [showSelectedCount && !renderInputValuesProp && items.length > 0 && (_jsxs(_Fragment, { children: [_jsxs("span", { "data-name": "multiple-values-count", children: ["(", items.length, ")"] }), ' '] })), children] }) }));
|
|
578
589
|
},
|
|
579
590
|
};
|
|
580
591
|
const className = cn(GRID_FILTER_COMBBOX_ADJUSTMENTS_CLASSNAME, comboboxProps.className);
|
|
@@ -48,7 +48,18 @@ export type GridFilterTreeDropdownProps<T extends TreeListItem<any>> = Omit<NewT
|
|
|
48
48
|
/**
|
|
49
49
|
* When true, prefix the selected-values summary with `(N)` where N is the
|
|
50
50
|
* number of selected leaves. Mirrors `GridFilterCombobox.showSelectedCount`.
|
|
51
|
+
* Ignored when `renderInputValues` is provided.
|
|
51
52
|
*/
|
|
52
53
|
showSelectedCount?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Custom content for the selected values in the collapsed input (rendered inside the
|
|
56
|
+
* standard wrapper). Mirrors `GridFilterCombobox.renderInputValues`: called with one
|
|
57
|
+
* item per selected leaf (`value` is the full leaf path, `label` its display label).
|
|
58
|
+
* When provided, the built-in selected count is not rendered.
|
|
59
|
+
*/
|
|
60
|
+
renderInputValues?: (items: {
|
|
61
|
+
value: any;
|
|
62
|
+
label: string;
|
|
63
|
+
}[]) => React.ReactNode;
|
|
53
64
|
};
|
|
54
65
|
export declare function GridFilterTreeDropdown<T extends TreeListItem<any>>(props: GridFilterTreeDropdownProps<T>): React.JSX.Element;
|
|
@@ -399,17 +399,20 @@ export function TreeDropdown(props) {
|
|
|
399
399
|
return (_jsx(MultiCombobox, { ...comboboxProps }));
|
|
400
400
|
}
|
|
401
401
|
export function GridFilterTreeDropdown(props) {
|
|
402
|
-
const { showSelectedCount = false, placeholder = 'Select...', className, ...rest } = props;
|
|
402
|
+
const { showSelectedCount = false, placeholder = 'Select...', renderInputValues: renderInputValuesProp, className, ...rest } = props;
|
|
403
403
|
const renderSelectedValues = useCallback(({ selectedLeafPaths, getLabelForPath }) => {
|
|
404
404
|
let children;
|
|
405
405
|
if (selectedLeafPaths.length === 0) {
|
|
406
406
|
children = (_jsx("span", { "data-name": "placeholder", className: "twa:text-muted-foreground", children: placeholder }));
|
|
407
407
|
}
|
|
408
|
+
else if (renderInputValuesProp) {
|
|
409
|
+
children = renderInputValuesProp(selectedLeafPaths.map((path) => ({ value: path, label: getLabelForPath(path) })));
|
|
410
|
+
}
|
|
408
411
|
else {
|
|
409
412
|
children = selectedLeafPaths.map((path) => getLabelForPath(path)).join(', ');
|
|
410
413
|
}
|
|
411
|
-
return (_jsxs("div", { className: "twa:text-ellipsis twa:overflow-hidden twa:whitespace-nowrap twa:flex-1000", "data-slot": "combobox-selected-values", children: [showSelectedCount && selectedLeafPaths.length > 0 && (_jsxs("span", { "data-name": "multiple-values-count", className: "twa:mr-0.5", children: ["(", selectedLeafPaths.length, ")"] })), children] }));
|
|
412
|
-
}, [placeholder, showSelectedCount]);
|
|
414
|
+
return (_jsxs("div", { className: "twa:text-ellipsis twa:overflow-hidden twa:whitespace-nowrap twa:flex-1000", "data-slot": "combobox-selected-values", children: [showSelectedCount && !renderInputValuesProp && selectedLeafPaths.length > 0 && (_jsxs("span", { "data-name": "multiple-values-count", className: "twa:mr-0.5", children: ["(", selectedLeafPaths.length, ")"] })), children] }));
|
|
415
|
+
}, [placeholder, showSelectedCount, renderInputValuesProp]);
|
|
413
416
|
const mergedClassName = cn(GRID_FILTER_COMBBOX_ADJUSTMENTS_CLASSNAME, className);
|
|
414
417
|
return (_jsx(TreeDropdown, { ...rest, placeholder: placeholder, className: mergedClassName, showClear: rest.showClear ?? false, resizable: rest.resizable ?? true, renderSelectedValues: renderSelectedValues }));
|
|
415
418
|
}
|
package/src/env.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
NEXT_PUBLIC_INFINITE_TABLE_LICENSE_KEY: "StartDate=2021-06-29|EndDate=2030-01-01|Owner=Adaptable|Type=distribution|TS=1624971462479|C=137829811,1004007071,2756196225,1839832928,3994409405,636616862" || '',
|
|
3
|
-
PUBLISH_TIMESTAMP:
|
|
4
|
-
VERSION: "23.0.
|
|
3
|
+
PUBLISH_TIMESTAMP: 1789246590646 || Date.now(),
|
|
4
|
+
VERSION: "23.0.22" || '--current-version--',
|
|
5
5
|
};
|