@adaptabletools/adaptable 21.0.0-canary.1 → 21.0.0-canary.3

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 (43) hide show
  1. package/package.json +1 -1
  2. package/src/AdaptableInterfaces/IAdaptable.d.ts +3 -2
  3. package/src/AdaptableOptions/DefaultAdaptableOptions.js +0 -1
  4. package/src/AdaptableOptions/EditOptions.d.ts +6 -1
  5. package/src/AdaptableOptions/FilterOptions.d.ts +20 -8
  6. package/src/AdaptableOptions/LayoutOptions.d.ts +3 -0
  7. package/src/AdaptableState/Common/AdaptableColumn.d.ts +2 -2
  8. package/src/Api/ColumnFilterApi.d.ts +5 -5
  9. package/src/Api/Implementation/ColumnApiImpl.js +1 -1
  10. package/src/Api/Implementation/ColumnFilterApiImpl.d.ts +3 -3
  11. package/src/Api/Implementation/ColumnFilterApiImpl.js +6 -6
  12. package/src/Api/Internal/ColumnFilterInternalApi.d.ts +3 -3
  13. package/src/Api/Internal/ColumnFilterInternalApi.js +19 -24
  14. package/src/Api/Internal/ColumnInternalApi.js +1 -1
  15. package/src/Api/Internal/GridInternalApi.d.ts +3 -2
  16. package/src/Api/Internal/GridInternalApi.js +3 -2
  17. package/src/Api/Internal/PredicateInternalApi.js +0 -1
  18. package/src/Redux/Store/AdaptableStore.js +0 -2
  19. package/src/Strategy/ColumnFilterModule.js +8 -1
  20. package/src/Utilities/adaptableQlUtils.js +1 -1
  21. package/src/View/Components/ColumnFilter/components/FloatingFilterValues.d.ts +5 -1
  22. package/src/View/Components/ColumnFilter/components/FloatingFilterValues.js +52 -16
  23. package/src/View/Components/ColumnFilter/utils.js +0 -1
  24. package/src/View/Components/FilterForm/ListBoxFilterForm.js +1 -1
  25. package/src/View/Components/PredicateEditor/PredicateEditor.js +14 -0
  26. package/src/View/Components/Selectors/PermittedValuesSelector.d.ts +2 -4
  27. package/src/View/Components/Selectors/PermittedValuesSelector.js +6 -5
  28. package/src/agGrid/AdaptableAgGrid.d.ts +3 -2
  29. package/src/agGrid/AdaptableAgGrid.js +20 -10
  30. package/src/agGrid/AdaptableFilterHandler.d.ts +12 -4
  31. package/src/agGrid/AdaptableFilterHandler.js +38 -11
  32. package/src/agGrid/AgGridColumnAdapter.js +5 -2
  33. package/src/agGrid/AgGridExportAdapter.js +2 -4
  34. package/src/agGrid/AgGridModulesAdapter.js +5 -1
  35. package/src/agGrid/agGridDataTypeDefinitions.js +1 -8
  36. package/src/components/Select/Select.d.ts +1 -0
  37. package/src/components/Select/Select.js +5 -4
  38. package/src/env.js +2 -2
  39. package/src/metamodel/adaptable.metamodel.d.ts +15 -0
  40. package/src/metamodel/adaptable.metamodel.js +1 -1
  41. package/src/migration/VersionUpgrade20.js +1 -2
  42. package/src/types.d.ts +2 -2
  43. package/tsconfig.esm.tsbuildinfo +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adaptabletools/adaptable",
3
- "version": "21.0.0-canary.1",
3
+ "version": "21.0.0-canary.3",
4
4
  "description": "Powerful data-agnostic HTML5 AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements",
5
5
  "keywords": [
6
6
  "web-components",
@@ -10,7 +10,7 @@ import { SelectedCellInfo } from '../AdaptableState/Selection/SelectedCellInfo';
10
10
  import { AdaptableTheme } from '../AdaptableState/ThemeState';
11
11
  import { IAdaptableStore } from '../Redux/Store/Interface/IAdaptableStore';
12
12
  import { IModuleCollection } from '../Strategy/Interface/IModule';
13
- import { AdaptableMenuItem, AdaptableOptions, AdaptablePlugin, AdaptableState, ChartDefinition, InFilterValue, SelectedRowInfo } from '../types';
13
+ import { AdaptableMenuItem, AdaptableOptions, AdaptablePlugin, AdaptableState, ChartDefinition, InFilterValueResult, SelectedRowInfo } from '../types';
14
14
  import { ICalculatedColumnExpressionService } from '../Utilities/Services/Interface/ICalculatedColumnExpressionService';
15
15
  import { IDataService } from '../Utilities/Services/Interface/IDataService';
16
16
  import { AnnotationsService } from '../Utilities/Services/AnnotationsService';
@@ -183,7 +183,8 @@ export interface IAdaptable {
183
183
  getDistinctFilterValuesForColumn(options: {
184
184
  column: AdaptableColumn;
185
185
  currentSearchValue: string;
186
- }): Promise<InFilterValue[]>;
186
+ previousResult: InFilterValueResult | undefined;
187
+ }): Promise<InFilterValueResult>;
187
188
  getGridCellFromRowNode(rowNode: IRowNode, columnId: string): GridCell | undefined;
188
189
  getRawValueFromRowNode(rowNode: IRowNode, columnId: string): any;
189
190
  getDisplayValueFromRowNode(rowNode: IRowNode, columnId: string): string | undefined;
@@ -150,7 +150,6 @@ const DefaultAdaptableOptions = {
150
150
  columnFilterOptions: {
151
151
  indicateFilteredColumns: true,
152
152
  autoApplyColumnFilter: true,
153
- cacheInFilterValues: true,
154
153
  defaultNumericColumnFilter: 'Equals',
155
154
  defaultTextColumnFilter: 'Contains',
156
155
  defaultDateColumnFilter: 'On',
@@ -58,7 +58,12 @@ export interface EditColumnValueInfo {
58
58
  value: any;
59
59
  label?: string;
60
60
  }
61
- export interface CustomEditColumnValueInfo extends EditColumnValueInfo {
61
+ /**
62
+ * Information about items in the custom Edit Controls
63
+ */
64
+ export interface CustomEditColumnValueInfo {
65
+ value: any;
66
+ label?: string;
62
67
  }
63
68
  /**
64
69
  * Used for Server Validation ie. after an edit in AG Grid which must be checked on Server
@@ -30,7 +30,7 @@ export interface FilterOptions<TData = any> {
30
30
  * @param context
31
31
  * @returns
32
32
  */
33
- customInFilterValues?: (context: CustomInFilterValuesContext<TData>) => Promise<InFilterValueInfo[]> | InFilterValueInfo[];
33
+ customInFilterValues?: (context: CustomInFilterValuesContext<TData>) => Promise<InFilterValueResult> | InFilterValueResult;
34
34
  /**
35
35
  * When to re-filter grid after data changes: 'Always', 'Never' or 'Throttle' (with a delay value)
36
36
  *
@@ -86,13 +86,6 @@ export interface ColumnFilterOptions<TData = any> {
86
86
  * @noCodeItem
87
87
  */
88
88
  autoApplyColumnFilter?: boolean | ((context: AdaptableColumnContext) => boolean);
89
- /**
90
- * Whether to cache the values in the IN Filter component
91
- * @defaultValue true
92
- * @gridInfoItem
93
- * @noCodeItem
94
- */
95
- cacheInFilterValues?: boolean | ((context: AdaptableColumnContext) => boolean);
96
89
  /**
97
90
  * Default filter type for numeric Columns
98
91
  *
@@ -212,6 +205,20 @@ export interface InFilterValue<ValueType = any> {
212
205
  */
213
206
  tooltip?: boolean | string;
214
207
  }
208
+ /**
209
+ * Result when providing custom values for the IN Column Filter
210
+ */
211
+ export type InFilterValueResult = {
212
+ /**
213
+ * List of Items to display in the IN Column Filter
214
+ */
215
+ values: InFilterValue[];
216
+ /**
217
+ * When TRUE, displays the provided values without any filtering.
218
+ * When FALSE, the values are filtered based on the current search text.
219
+ */
220
+ skipDefaultSearch?: boolean;
221
+ };
215
222
  /**
216
223
  * Information about items in the IN Column Filter
217
224
  */
@@ -253,6 +260,11 @@ export interface CustomInFilterValuesContext<TData = any> extends AdaptableColum
253
260
  * Search text in the IN Filter component - used when filtering on server
254
261
  */
255
262
  currentSearchValue: string;
263
+ /**
264
+ * Memoized result from previous invocation. Helps avoid expensive recomputations,
265
+ * especially for async operations (e.g. server-side filtering).
266
+ */
267
+ previousFilterResult?: InFilterValueResult;
256
268
  }
257
269
  /**
258
270
  * List of Editors that can be used when creating the Grid Filter
@@ -122,5 +122,8 @@ export interface DefaultLayoutProperties {
122
122
  * Context for `LayoutOptions.defaultLayoutProperties` function
123
123
  */
124
124
  export interface DefaultLayoutPropertiesContext extends BaseContext {
125
+ /**
126
+ * Type of Layout ('table' | 'pivot')
127
+ */
125
128
  layoutType: 'table' | 'pivot';
126
129
  }
@@ -1,11 +1,11 @@
1
1
  import { AdaptableObject } from './AdaptableObject';
2
- import { BaseCellDataType, ColDef } from 'ag-grid-enterprise';
2
+ import { ColDef } from 'ag-grid-enterprise';
3
3
  import { UniqueGridCell } from '../Selection/GridCell';
4
4
  import { ColumnFilter } from './ColumnFilter';
5
5
  /**
6
6
  * Defines data type of a Column; can be an AG Grid BaseCellDataType or an AdapTable array-related one
7
7
  */
8
- export type AdaptableColumnDataType = BaseCellDataType | 'textArray' | 'numberArray' | 'tupleArray' | 'objectArray' | 'unknown';
8
+ export type AdaptableColumnDataType = 'text' | 'number' | 'boolean' | 'date' | 'object' | 'textArray' | 'numberArray' | 'tupleArray' | 'objectArray' | 'unknown';
9
9
  /**
10
10
  * Column Types recognised by AdapTable; to be set in GridOptions
11
11
  */
@@ -1,4 +1,4 @@
1
- import { AdaptableColumn, ColumnFilter, ColumnFilterPredicate, InFilterValue, InFilterValueInfo } from '../types';
1
+ import { AdaptableColumn, ColumnFilter, ColumnFilterPredicate, InFilterValueInfo, InFilterValueResult } from '../types';
2
2
  import { AdaptablePredicateDef, ColumnFilterDef } from '../AdaptableState/Common/AdaptablePredicate';
3
3
  /**
4
4
  * Provides run-time access to Filter section of Adaptable State.
@@ -138,16 +138,16 @@ export interface ColumnFilterApi {
138
138
  * @param columnId - the ID of the Column for which to refresh filter values.
139
139
  * @return a Promise that resolves to the list of filter values, each represented as an object with `value` and `label` properties.
140
140
  */
141
- refreshFilterValues(columnId: string): Promise<InFilterValue[]>;
141
+ refreshFilterValues(columnId: string): Promise<InFilterValueResult>;
142
142
  /**
143
143
  * Refreshes (reloads) the filter values for ALL Columns (for `IN` Filter).
144
144
  *
145
145
  * @returns A Promise that resolves to a map where:
146
146
  * - keys are column IDs (string)
147
- * - values are arrays of filter values for the corresponding column
148
- * Each filter value contains a `value` and display `label` property
147
+ * - values are objects with a `values` property, which is an array of values for the corresponding column
148
+ * Each item in the array contains a `value` and display `label` property
149
149
  */
150
- refreshAllFilterValues(): Promise<Record<string, InFilterValue[]>>;
150
+ refreshAllFilterValues(): Promise<Record<string, InFilterValueResult>>;
151
151
  /**
152
152
  * Reset(clear cache) the filter values for a given Column (for `IN` Filter).
153
153
  * @param columnId - the ID of the Column for which to reset filter values.
@@ -414,7 +414,7 @@ export class ColumnApiImpl extends ApiBase {
414
414
  return this.getUIAvailableColumns().filter((c) => c.dataType === 'textArray');
415
415
  }
416
416
  getDateColumns() {
417
- return this.getUIAvailableColumns().filter((c) => c.dataType === 'date' || c.dataType === 'dateString');
417
+ return this.getUIAvailableColumns().filter((c) => c.dataType === 'date');
418
418
  }
419
419
  getBooleanColumns() {
420
420
  return this.getUIAvailableColumns().filter((c) => c.dataType === 'boolean');
@@ -1,7 +1,7 @@
1
1
  import { ApiBase } from './ApiBase';
2
2
  import { AdaptablePredicateDef, ColumnFilterDef } from '../../AdaptableState/Common/AdaptablePredicate';
3
3
  import { AdaptableColumn } from '../../AdaptableState/Common/AdaptableColumn';
4
- import { ColumnFilter, ColumnFilterPredicate, InFilterValueInfo, InFilterValue } from '../../types';
4
+ import { ColumnFilter, ColumnFilterPredicate, InFilterValueInfo, InFilterValueResult } from '../../types';
5
5
  import { IAdaptable } from '../../AdaptableInterfaces/IAdaptable';
6
6
  import { ColumnFilterInternalApi } from '../Internal/ColumnFilterInternalApi';
7
7
  import { ColumnFilterApi } from '../ColumnFilterApi';
@@ -44,8 +44,8 @@ export declare class ColumnFilterApiImpl extends ApiBase implements ColumnFilter
44
44
  suspendAllColumnFilters(): void;
45
45
  unSuspendAllColumnFilters(): void;
46
46
  addBlanksToInFilterValues(columnDistinctValues: InFilterValueInfo[]): InFilterValueInfo[];
47
- refreshFilterValues(columnId: string): Promise<InFilterValue[]>;
48
- refreshAllFilterValues(): Promise<Record<string, InFilterValue[]>>;
47
+ refreshFilterValues(columnId: string): Promise<InFilterValueResult>;
48
+ refreshAllFilterValues(): Promise<Record<string, InFilterValueResult>>;
49
49
  resetFilterValues(columnId: string): void;
50
50
  resetAllFilterValues(): void;
51
51
  }
@@ -214,19 +214,19 @@ export class ColumnFilterApiImpl extends ApiBase {
214
214
  async refreshAllFilterValues() {
215
215
  const allFilterHandlers = this.internalApi.getAllAdaptableFilterHandlers();
216
216
  const handlerPromises = allFilterHandlers.map(async (handler) => {
217
- let values = [];
217
+ let result = { values: [] };
218
218
  if (typeof handler.refreshFilterDisplayValues === 'function') {
219
- values = await handler.refreshFilterDisplayValues();
219
+ result = await handler.refreshFilterDisplayValues();
220
220
  }
221
221
  else {
222
222
  this.logWarn(`No refresh function for filter handler: ${handler.colId}`);
223
- values = [];
223
+ result = { values: [] };
224
224
  }
225
- return { columnId: handler.colId, values };
225
+ return { columnId: handler.colId, result };
226
226
  });
227
227
  return Promise.all(handlerPromises).then((results) => {
228
- return results.reduce((acc, { columnId, values }) => {
229
- acc[columnId] = values;
228
+ return results.reduce((acc, { columnId, result }) => {
229
+ acc[columnId] = result;
230
230
  return acc;
231
231
  }, {});
232
232
  });
@@ -5,7 +5,7 @@ import { AdaptablePredicateDef } from '../../AdaptableState/Common/AdaptablePred
5
5
  import { ColumnFilter } from '../../AdaptableState/Common/ColumnFilter';
6
6
  import { GridCell } from '../../AdaptableState/Selection/GridCell';
7
7
  import { LayoutColumnFilterAction } from '../../Redux/ActionsReducers/LayoutRedux';
8
- import { InFilterValue } from '../../types';
8
+ import { InFilterValueResult } from '../../types';
9
9
  import { ApiBase } from '../Implementation/ApiBase';
10
10
  import { AdaptableFilterHandler } from '../../agGrid/AdaptableFilterHandler';
11
11
  export declare class ColumnFilterInternalApi extends ApiBase {
@@ -53,8 +53,8 @@ export declare class ColumnFilterInternalApi extends ApiBase {
53
53
  getColumnFilterValues(options: {
54
54
  columnId: string;
55
55
  currentSearchValue: string;
56
- }): Promise<InFilterValue[]>;
56
+ }): Promise<InFilterValueResult>;
57
57
  shouldAutoApplyColumnFilter(columnId: string): boolean;
58
- shouldCacheColumnFilterValues(columnId: string): boolean;
58
+ getAdaptableFilterHandler(columnId: string): AdaptableFilterHandler | undefined;
59
59
  getAllAdaptableFilterHandlers(): AdaptableFilterHandler[];
60
60
  }
@@ -240,20 +240,28 @@ export class ColumnFilterInternalApi extends ApiBase {
240
240
  * Only if the FilterHandler is not available we fallback to the GridApi method
241
241
  */
242
242
  async getColumnFilterValues(options) {
243
- const shouldUseCachedValues = this.shouldCacheColumnFilterValues(options.columnId);
244
- if (!shouldUseCachedValues) {
245
- return this.getGridApi().internalApi.getDistinctFilterDisplayValuesForColumn(options);
246
- }
243
+ const filterOptions = this.getOptionsApi().getFilterOptions();
244
+ const newOptions = {
245
+ columnId: options.columnId,
246
+ get currentSearchValue() {
247
+ // we need this in order to keep it lazy
248
+ return options.currentSearchValue;
249
+ },
250
+ previousResult: undefined,
251
+ };
247
252
  const columnFilterHandler = this.getAgGridApi().getColumnFilterHandler(options.columnId);
248
253
  if (!columnFilterHandler) {
249
254
  this.logWarn(`No ColumnFilterHandler found for columnId: ${options.columnId}!`);
250
- return this.getGridApi().internalApi.getDistinctFilterDisplayValuesForColumn(options);
255
+ return this.getGridApi().internalApi.getDistinctFilterDisplayValuesForColumn(newOptions);
256
+ }
257
+ if (typeof columnFilterHandler.getFromCacheOrFetchFilterDisplayValues !== 'function') {
258
+ this.logWarn(`ColumnFilterHandler for columnId: ${options.columnId} does not have getFromCacheOrFetchFilterDisplayValues method!`);
259
+ return this.getGridApi().internalApi.getDistinctFilterDisplayValuesForColumn(newOptions);
251
260
  }
252
- if (typeof columnFilterHandler.getFilterDisplayValues !== 'function') {
253
- this.logWarn(`ColumnFilterHandler for columnId: ${options.columnId} does not have getFilterDisplayValues method!`);
254
- return this.getGridApi().internalApi.getDistinctFilterDisplayValuesForColumn(options);
261
+ if (filterOptions.customInFilterValues) {
262
+ return columnFilterHandler.fetchFilterDisplayValues(newOptions);
255
263
  }
256
- return columnFilterHandler.getFilterDisplayValues(options.currentSearchValue);
264
+ return columnFilterHandler.getFromCacheOrFetchFilterDisplayValues(newOptions);
257
265
  }
258
266
  shouldAutoApplyColumnFilter(columnId) {
259
267
  const autoApplyColumnFilterOpt = this.getOptionsApi().getFilterOptions().columnFilterOptions?.autoApplyColumnFilter;
@@ -271,21 +279,8 @@ export class ColumnFilterInternalApi extends ApiBase {
271
279
  // fallback, should never happen
272
280
  return true;
273
281
  }
274
- shouldCacheColumnFilterValues(columnId) {
275
- const cacheColumnFilterValuesOpt = this.getOptionsApi().getFilterOptions().columnFilterOptions?.cacheInFilterValues;
276
- if (typeof cacheColumnFilterValuesOpt === 'boolean') {
277
- return cacheColumnFilterValuesOpt;
278
- }
279
- if (typeof cacheColumnFilterValuesOpt === 'function') {
280
- const column = this.getColumnApi().getColumnWithColumnId(columnId);
281
- const context = {
282
- column,
283
- ...this.getAdaptableApi().internalApi.buildBaseContext(),
284
- };
285
- return cacheColumnFilterValuesOpt(context);
286
- }
287
- // fallback, should never happen
288
- return true;
282
+ getAdaptableFilterHandler(columnId) {
283
+ return this.getAgGridApi().getColumnFilterHandler(columnId);
289
284
  }
290
285
  getAllAdaptableFilterHandlers() {
291
286
  const allFilterableColumns = this.getColumnApi().getFilterableColumns();
@@ -296,6 +296,6 @@ export class ColumnInternalApi extends ApiBase {
296
296
  }
297
297
  getColumnDateTypes() {
298
298
  // this is required because Adaptable uses 'date' type for all AG Grid date types: 'date', 'dateString'
299
- return ['date', 'dateString'];
299
+ return ['date'];
300
300
  }
301
301
  }
@@ -5,7 +5,7 @@ import { SpecialColumnSettings } from '../../AdaptableState/Common/SpecialColumn
5
5
  import { GridCell } from '../../AdaptableState/Selection/GridCell';
6
6
  import { SelectedCellInfo } from '../../AdaptableState/Selection/SelectedCellInfo';
7
7
  import { SelectedRowInfo } from '../../AdaptableState/Selection/SelectedRowInfo';
8
- import { InFilterValue } from '../../types';
8
+ import { InFilterValueResult } from '../../types';
9
9
  import { ApiBase } from '../Implementation/ApiBase';
10
10
  import { EditColumnValueInfo } from '../../AdaptableOptions/EditOptions';
11
11
  export declare class GridInternalApi extends ApiBase {
@@ -29,7 +29,8 @@ export declare class GridInternalApi extends ApiBase {
29
29
  getDistinctFilterDisplayValuesForColumn(options: {
30
30
  columnId: string;
31
31
  currentSearchValue: string;
32
- }): Promise<InFilterValue[]>;
32
+ previousResult: InFilterValueResult | undefined;
33
+ }): Promise<InFilterValueResult>;
33
34
  getDistinctValuesForColumn(columnId: string): Promise<GridCell[]> | undefined;
34
35
  getDistinctEditDisplayValuesForColumn(options: {
35
36
  columnId: string;
@@ -35,15 +35,16 @@ export class GridInternalApi extends ApiBase {
35
35
  async getDistinctFilterDisplayValuesForColumn(options) {
36
36
  const abColumn = this.getColumnApi().getColumnWithColumnId(options.columnId);
37
37
  if (abColumn == undefined) {
38
- return [];
38
+ return { values: [] };
39
39
  }
40
40
  const inFilterValues = await this._adaptable.getDistinctFilterValuesForColumn({
41
41
  column: abColumn,
42
42
  get currentSearchValue() {
43
43
  return options.currentSearchValue;
44
44
  },
45
+ previousResult: options.previousResult,
45
46
  });
46
- return inFilterValues || [];
47
+ return inFilterValues || { values: [] };
47
48
  }
48
49
  async getDistinctValuesForColumn(columnId) {
49
50
  const abColumn = this.getColumnApi().getColumnWithColumnId(columnId);
@@ -106,7 +106,6 @@ export class PredicateInternalApi extends ApiBase {
106
106
  predicateId = 'Equals';
107
107
  break;
108
108
  case 'date':
109
- case 'dateString':
110
109
  predicateId = 'On';
111
110
  break;
112
111
  case 'text':
@@ -892,8 +892,6 @@ const adaptableMiddleware = (adaptable) => (function(middlewareAPI) {
892
892
  const newLayout = (newLayoutState.Layouts || []).find((l) => l.Name == newLayoutState.CurrentLayout) ||
893
893
  newLayoutState.Layouts[0] ||
894
894
  ERROR_LAYOUT;
895
- const changedColumnSorts = adaptable.api.layoutApi.internalApi.getChangedColumnSorts(oldLayout.ColumnSorts, newLayout.ColumnSorts);
896
- changedColumnSorts.forEach((columnId) => adaptable.api.filterApi.columnFilterApi.resetFilterValues(columnId));
897
895
  let refreshColumnFilters = false;
898
896
  if (adaptable.api.filterApi.columnFilterApi.internalApi.areColumnFiltersDifferent(oldLayout.ColumnFilters, newLayout.ColumnFilters)) {
899
897
  refreshColumnFilters = true;
@@ -30,11 +30,18 @@ export class ColumnFilterModule extends AdaptableModuleBase {
30
30
  // we reset the filter cache on sort change, because we might have columns
31
31
  // with "In" filters, with custom values, which use `context.orderedValues`
32
32
  // customInFilterValues: (context: CustomInFilterValuesContext<Car>) => {
33
- // return context.orderedValues;
33
+ // return {values: context.orderedValues};
34
34
  // }
35
35
  // and that order will most likely change when sorting happens
36
36
  // so we need to reset the cached filter values when sorting changes
37
37
  this.api.eventApi.on('GridSorted', () => {
38
+ const filterOptions = this.api.optionsApi.getFilterOptions();
39
+ if (!filterOptions.customInFilterValues) {
40
+ // no-one is using context.sortedValues/context.orderedValues
41
+ // or a custom property from a value, like value.count or value.visible
42
+ // so no need to reset the filter display values
43
+ return;
44
+ }
38
45
  this.api.filterApi.columnFilterApi.resetAllFilterValues();
39
46
  });
40
47
  }
@@ -8,7 +8,7 @@ export const mapColumnDataTypeToExpressionFunctionType = (dataType) => {
8
8
  if (dataType === 'text') {
9
9
  return 'text';
10
10
  }
11
- if (dataType === 'date' || dataType === 'dateString') {
11
+ if (dataType === 'date') {
12
12
  return 'date';
13
13
  }
14
14
  if (dataType === 'numberArray') {
@@ -25,6 +25,7 @@ export declare function useDistinctFilterColumnValues(options: {
25
25
  label: string;
26
26
  }[];
27
27
  dataLoadIsComplete: boolean;
28
+ skipDefaultSearch: boolean;
28
29
  searchValueUsedInFilterValue: boolean;
29
30
  };
30
31
  setQuickFilterValues: React.Dispatch<React.SetStateAction<{
@@ -33,9 +34,12 @@ export declare function useDistinctFilterColumnValues(options: {
33
34
  label: string;
34
35
  }[];
35
36
  dataLoadIsComplete: boolean;
37
+ skipDefaultSearch: boolean;
36
38
  searchValueUsedInFilterValue: boolean;
37
39
  }>>;
38
- triggerValuesLoad: () => void;
40
+ triggerValuesLoad: (options?: {
41
+ usePrevious: boolean;
42
+ }) => void;
39
43
  };
40
44
  /**
41
45
  * This component was ported and modified to not know about colum filter and predicates.
@@ -20,10 +20,18 @@ export function useDistinctFilterColumnValues(options) {
20
20
  const { columnId, searchValueRef } = options;
21
21
  const { api } = useAdaptable();
22
22
  const [valuesLoadTrigger, setValuesLoadTrigger] = React.useState(0);
23
- const triggerValuesLoad = React.useCallback(() => {
23
+ const usePreviousValuesProbablyBecauseOfAGGridUnnecessaryFilterRemountRef = React.useRef(false);
24
+ const triggerValuesLoad = React.useCallback((options) => {
25
+ usePreviousValuesProbablyBecauseOfAGGridUnnecessaryFilterRemountRef.current =
26
+ !!options?.usePrevious;
24
27
  setValuesLoadTrigger((prev) => prev + 1);
25
28
  }, []);
26
- const [quickFilterValues, setQuickFilterValues] = React.useState({ values: [], dataLoadIsComplete: false, searchValueUsedInFilterValue: false });
29
+ const [quickFilterValues, setQuickFilterValues] = React.useState({
30
+ values: [],
31
+ dataLoadIsComplete: false,
32
+ skipDefaultSearch: false,
33
+ searchValueUsedInFilterValue: false,
34
+ });
27
35
  const [isDistinctColumnValuesLoading, setIsDistinctColumnValuesLoading] = React.useState(false);
28
36
  useEffect(() => {
29
37
  if (valuesLoadTrigger === 0) {
@@ -33,21 +41,35 @@ export function useDistinctFilterColumnValues(options) {
33
41
  let ignore = false;
34
42
  setIsDistinctColumnValuesLoading(true);
35
43
  let searchValueUsedInFilterValue = false;
36
- api.filterApi.columnFilterApi.internalApi
37
- .getColumnFilterValues({
38
- columnId,
39
- get currentSearchValue() {
40
- searchValueUsedInFilterValue = true;
41
- return searchValueRef ? searchValueRef.current : '';
42
- },
43
- })
44
- .then((distinctFilterDisplayValues) => {
44
+ const columnFilterinternalApi = api.filterApi.columnFilterApi.internalApi;
45
+ let promise = undefined;
46
+ if (usePreviousValuesProbablyBecauseOfAGGridUnnecessaryFilterRemountRef.current) {
47
+ const previousResult = columnFilterinternalApi
48
+ .getAdaptableFilterHandler(columnId)
49
+ ?.getLastCachedFilterDisplayValues();
50
+ if (previousResult) {
51
+ promise = Promise.resolve(previousResult);
52
+ }
53
+ }
54
+ usePreviousValuesProbablyBecauseOfAGGridUnnecessaryFilterRemountRef.current = false;
55
+ if (!promise) {
56
+ promise = columnFilterinternalApi.getColumnFilterValues({
57
+ columnId,
58
+ get currentSearchValue() {
59
+ searchValueUsedInFilterValue = true;
60
+ return searchValueRef ? searchValueRef.current : '';
61
+ },
62
+ });
63
+ }
64
+ promise.then((distinctFilterDisplayValues) => {
45
65
  if (ignore) {
46
66
  return;
47
67
  }
68
+ const values = distinctFilterDisplayValues.values;
48
69
  setQuickFilterValues({
49
- values: distinctFilterDisplayValues,
70
+ values,
50
71
  dataLoadIsComplete: true,
72
+ skipDefaultSearch: !!distinctFilterDisplayValues.skipDefaultSearch,
51
73
  searchValueUsedInFilterValue,
52
74
  });
53
75
  setIsDistinctColumnValuesLoading(false);
@@ -84,9 +106,15 @@ export const FloatingFilterValues = (props) => {
84
106
  if (!value || !Array.isArray(value) || value.length === 0) {
85
107
  return;
86
108
  }
109
+ // see 😅 usePreviousValuesProbablyBecauseOfAGGridUnnecessaryFilterRemountRef 😅
110
+ const usePrevious = !!api.filterApi.columnFilterApi.internalApi
111
+ .getAdaptableFilterHandler(props.columnId)
112
+ ?.getLastCachedFilterDisplayValues();
87
113
  // however, if the `value` prop is a non-empty array, we need to load the values
88
114
  // so we know which labels to show
89
- triggerValuesLoad();
115
+ triggerValuesLoad({
116
+ usePrevious,
117
+ });
90
118
  }, []);
91
119
  const quickFilterValuesRef = React.useRef(quickFilterValues);
92
120
  quickFilterValuesRef.current = quickFilterValues;
@@ -116,16 +144,19 @@ export const FloatingFilterValues = (props) => {
116
144
  const onMenuOpen = triggerValuesLoad;
117
145
  const onInputChange = React.useCallback((value) => {
118
146
  searchValueRef.current = value;
119
- if (quickFilterValues.searchValueUsedInFilterValue) {
147
+ const quickFilterValues = quickFilterValuesRef.current;
148
+ if (quickFilterValues.searchValueUsedInFilterValue || quickFilterValues.skipDefaultSearch) {
120
149
  triggerValuesLoad();
121
150
  }
122
- }, [quickFilterValues.searchValueUsedInFilterValue]);
151
+ }, []);
152
+ const { skipDefaultSearch } = quickFilterValues;
123
153
  return (React.createElement(ColumnValuesSelect, { selectProps: props.inline
124
154
  ? {
125
155
  ...props.selectProps,
126
156
  'data-name': 'Select Values',
127
157
  renderMultipleValues,
128
158
  isClearable: false,
159
+ skipDefaultFiltering: skipDefaultSearch,
129
160
  styles: {
130
161
  dropdownIndicator: {
131
162
  display: 'none',
@@ -154,5 +185,10 @@ export const FloatingFilterValues = (props) => {
154
185
  onMenuOpen,
155
186
  onInputChange,
156
187
  }
157
- : { ...props.selectProps, onMenuOpen, onInputChange }, disabled: props.disabled, isLoading: isDistinctColumnValuesLoading, column: currentColumn, dataType: currentColumn.dataType, options: quickFilterValues.values, value: props.value, onChange: props.onChange }));
188
+ : {
189
+ ...props.selectProps,
190
+ skipDefaultFiltering: skipDefaultSearch,
191
+ onMenuOpen,
192
+ onInputChange,
193
+ }, disabled: props.disabled, isLoading: isDistinctColumnValuesLoading, column: currentColumn, dataType: currentColumn.dataType, options: quickFilterValues.values, value: props.value, onChange: props.onChange }));
158
194
  };
@@ -133,7 +133,6 @@ export const mapColumnFilterToQlPredicate = (columnFilter, abColumn, qlPredicate
133
133
  : { operator: 'Contains', args: [] };
134
134
  break;
135
135
  case 'date':
136
- case 'dateString':
137
136
  let defaultQlDatePredicate;
138
137
  const defaultDateColumnFilter = columnFilterOptions.defaultDateColumnFilter;
139
138
  if (defaultDateColumnFilter) {
@@ -9,7 +9,7 @@ export const ColumnValuesSelect = (props) => {
9
9
  const column = props.column;
10
10
  const selectedColumnValues = props.value || [];
11
11
  const value = [];
12
- const options = props.options.filter((distinctValue, index) => {
12
+ const options = (Array.isArray(props.options) ? props.options : []).filter((distinctValue) => {
13
13
  let isActive = selectedColumnValues.indexOf(distinctValue.value) >= 0;
14
14
  // special case for date objects, need to check against string values
15
15
  if (!isActive && distinctValue.value && distinctValue.value instanceof Date) {
@@ -45,13 +45,25 @@ export const PredicateEditor = (props) => {
45
45
  const adaptable = useAdaptable();
46
46
  const columnId = props.columnId;
47
47
  const column = adaptable.api.columnApi.getColumnWithColumnId(columnId);
48
+ const searchValueRef = React.useRef('');
48
49
  const { quickFilterValues, isDistinctColumnValuesLoading, triggerValuesLoad } = useDistinctFilterColumnValues({
49
50
  columnId,
51
+ searchValueRef,
50
52
  });
53
+ const quickFilterValuesRef = React.useRef(quickFilterValues);
54
+ quickFilterValuesRef.current = quickFilterValues;
51
55
  useEffect(triggerValuesLoad, []);
52
56
  const onMenuOpen = () => {
53
57
  triggerValuesLoad();
54
58
  };
59
+ const onInputChange = React.useCallback((value) => {
60
+ searchValueRef.current = value;
61
+ const quickFilterValues = quickFilterValuesRef.current;
62
+ if (quickFilterValues.searchValueUsedInFilterValue || quickFilterValues.skipDefaultSearch) {
63
+ triggerValuesLoad();
64
+ }
65
+ }, []);
66
+ const { skipDefaultSearch } = quickFilterValues;
55
67
  return (React.createElement(Box, { className: baseClassName },
56
68
  React.createElement(Flex, { justifyContent: "stretch", alignItems: "center" },
57
69
  icon && React.createElement(Tag, { mr: 2 }, icon),
@@ -70,5 +82,7 @@ export const PredicateEditor = (props) => {
70
82
  adaptable.api.predicateApi.internalApi.IsInorNotInPredicateDef(currentPredicateDef) && (React.createElement(Box, { mt: 2 },
71
83
  React.createElement(ColumnValuesSelect, { isLoading: isDistinctColumnValuesLoading, column: column, options: quickFilterValues.values, selectProps: {
72
84
  onMenuOpen,
85
+ onInputChange,
86
+ skipDefaultFiltering: skipDefaultSearch,
73
87
  }, dataType: column.dataType, value: props.predicate.Inputs, onChange: handlePredicateValuesChange })))));
74
88
  };
@@ -1,5 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { SelectProps } from '../../../components/Select';
3
+ import { InFilterValue } from '../../../AdaptableOptions/FilterOptions';
3
4
  export type ValueType = number | string | Date;
4
5
  interface PermittedValuesSelectorProps<Value extends ValueType, IsMulti extends boolean> {
5
6
  searchable?: false | 'inline' | 'menulist';
@@ -17,10 +18,7 @@ interface PermittedValuesSelectorProps<Value extends ValueType, IsMulti extends
17
18
  menuPortalTarget?: HTMLElement;
18
19
  loadValues?: (options: {
19
20
  currentSearchValue: string;
20
- }) => Promise<{
21
- value: any;
22
- label: string;
23
- }[]>;
21
+ }) => Promise<InFilterValue[]>;
24
22
  }
25
23
  export declare const PermittedValuesSelector: <Value extends ValueType, IsMulti extends boolean = false>(props: PermittedValuesSelectorProps<Value, IsMulti>) => React.JSX.Element;
26
24
  export {};