UNPKG

@adaptabletools/adaptable

Version:

Powerful data-agnostic HTML5 AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements

294 lines (293 loc) 13 kB
import * as LayoutRedux from '../../Redux/ActionsReducers/LayoutRedux'; import * as ModuleConstants from '../../Utilities/Constants/ModuleConstants'; import ArrayExtensions, { areArraysEqual } from '../../Utilities/Extensions/ArrayExtensions'; import StringExtensions from '../../Utilities/Extensions/StringExtensions'; import { COLUMN_FILTER_WINDOW } from '../../View/Components/Popups/WindowPopups/windowFactory'; import { ApiBase } from '../Implementation/ApiBase'; import { AdaptableFilterHandler } from '../../agGrid/AdaptableFilterHandler'; export class ColumnFilterInternalApi extends ApiBase { /** * Returns Predicate Definition for given Column and Quick Filter shortcut * @param shortcut Quick Filter shortcut to lookup * @param column AdapTable Column being Filtered */ findPredicateDefByShortcut(shortcut, column) { return this.getColumnFilterApi() .getFilterPredicateDefsForColumn(column) .find((predicateDef) => this.getPredicateDefShortcuts(predicateDef)?.includes(shortcut)); } /** * Creates an Equality Filter based on given Grid Cells * @param gridCells cells to create Filter for */ createValuesColumnFilterForCells(gridCells) { if (!gridCells) { return null; } const filter = { ColumnId: gridCells[0].column.columnId, Predicates: [ { PredicateId: 'In', Inputs: [...new Set(gridCells.map((gc) => gc.displayValue))], }, ], }; const [savedFilter] = this.getColumnFilterApi().setColumnFilters([filter]) || [null]; return savedFilter; } /** * Creates an Equality Filter based on given Grid Cell * @param gridCell cell to create Filter for */ createEqualityColumnFilterForCell(gridCell) { if (!gridCell) { return null; } const column = gridCell.column; const filter = { ColumnId: column.columnId, Predicates: [ { PredicateId: this.getPredicateApi().internalApi.getEqualityPredicateForDataType(column.dataType), Inputs: [...new Set([gridCell.rawValue])], }, ], }; const [savedFilter] = this.getColumnFilterApi().setColumnFilters([filter]) || [null]; return savedFilter; } /** * Calls AdapTableQL to evaluate Filter for given Row * @param columnFilter Column Filter to use * @param node Row Node to evaluate */ evaluateColumnFilter(columnFilter, node) { if (!columnFilter.Predicates.length) { return true; } const someInputsAreEmpty = columnFilter.Predicates.some((predicate) => predicate.Inputs?.some((input) => { if (typeof input === 'string') { return StringExtensions.IsNullOrEmpty(input); } if (typeof input === 'number') { return isNaN(input); } return !input; })); if (someInputsAreEmpty) { return true; } const column = this.getColumnApi().getColumnWithColumnId(columnFilter.ColumnId); if (!column) { return true; } const gridCell = this.getGridApi().getGridCellFromRowNode(node, columnFilter.ColumnId); if (!gridCell) { return true; } let value = gridCell.normalisedValue; const predicateDefHandlerContext = { value: value, oldValue: null, displayValue: gridCell.displayValue, node, column, predicatesOperator: columnFilter.PredicatesOperator, ...this.getAdaptableInternalApi().buildBaseContext(), }; return this.getPredicateApi().handlePredicates(columnFilter.Predicates, predicateDefHandlerContext, true); } /** * Checks if the filter action should trigger Column Filtering * * @param action Filtering Action */ shouldNewColumnFilterTriggerColumnFiltering(action) { // trigger filter change only: // - new -> new filter is active // - clear -> previous filters was active // - clearAll -> a filter was active // - edit -> same => input change // - edit -> different & new is active // - edit -> different & old was active // - set -> new filter is active // filter -> suspend changes const isNewAndActive = action.type === LayoutRedux.LAYOUT_COLUMN_FILTER_ADD && this.getColumnFilterApi().isColumnFilterActive(action.columnFilter); const isClearAndPreviousWasActive = action.type === LayoutRedux.LAYOUT_COLUMN_FILTER_CLEAR && this.getColumnFilterApi().isColumnFilterActiveForColumn(action.columnId); const isClearAllAtLeastOneActiveFilter = action.type === LayoutRedux.LAYOUT_COLUMN_FILTER_CLEAR_ALL && this.getColumnFilterApi() .getColumnFilters() .some((columnFilter) => this.getColumnFilterApi().isColumnFilterActive(columnFilter)); let isEditTrigger = false; if (action.type === LayoutRedux.LAYOUT_COLUMN_FILTER_EDIT) { const newFilter = action.columnFilter; const previous = this.getColumnFilterApi().getColumnFilterForColumn(newFilter.ColumnId); // same filter edit, so always trigger if (previous && newFilter && // same predicates areArraysEqual(previous.Predicates.map((p) => p.PredicateId), newFilter.Predicates.map((p) => p.PredicateId))) { isEditTrigger = true; // new filter is active } else if (this.getColumnFilterApi().isColumnFilterActive(newFilter)) { isEditTrigger = true; } else if (this.getColumnFilterApi().isColumnFilterActive(previous)) { // previous filter was active isEditTrigger = true; } } const isSetAndActive = action.type === LayoutRedux.LAYOUT_COLUMN_FILTER_SET && this.getColumnFilterApi().isColumnFilterActive(action.columnFilter); const isSuspendChanged = [ LayoutRedux.LAYOUT_COLUMN_FILTER_SUSPEND, LayoutRedux.LAYOUT_COLUMN_FILTER_SUSPEND_ALL, LayoutRedux.LAYOUT_COLUMN_FILTER_UNSUSPEND, LayoutRedux.LAYOUT_COLUMN_FILTER_UNSUSPEND_ALL, ].includes(action.type); return (isNewAndActive || isClearAndPreviousWasActive || isClearAllAtLeastOneActiveFilter || isEditTrigger || isSetAndActive || isSuspendChanged); } /** * Compares to sets of Column Filters to see if they are identical * @param filters1 * @param filters2 */ areColumnFiltersDifferent(oldFilters, newFilters) { if (ArrayExtensions.IsNullOrEmpty(oldFilters) && ArrayExtensions.IsNullOrEmpty(newFilters)) { return false; } return !ArrayExtensions.areArraysEqualWithCustomComparator(oldFilters, newFilters, (filter1, filter2) => { // Compare basic properties if (filter1.ColumnId !== filter2.ColumnId) { return false; } if ((filter1.PredicatesOperator || 'AND') !== (filter2.PredicatesOperator || 'AND')) { return false; } if ((filter1.IsSuspended || false) !== (filter2.IsSuspended || false)) { return false; } // Compare predicates (regardless of order) return ArrayExtensions.areArraysEqualWithCustomComparator(filter1.Predicates, filter2.Predicates, (pred1, pred2) => { if (pred1.PredicateId !== pred2.PredicateId) { return false; } // Compare inputs array (might be primitives or objects) return ArrayExtensions.areArraysEqualWithCustomComparator(pred1.Inputs, pred2.Inputs, (input1, input2) => { if (input1 === input2) { return true; } if (typeof input1 !== typeof input2) { return false; } // For object inputs, use JSON comparison if (typeof input1 === 'object' && input1 !== null && input2 !== null) { return JSON.stringify(input1) === JSON.stringify(input2); } return input1 === input2; }); }); }); } getPredicateDefShortcuts(predicateDef) { const shortcuts = this.getFilterOptions().columnFilterOptions.quickFilterWildcards; let predicateShortcuts = predicateDef.shortcuts; const predicateId = predicateDef.id; if (shortcuts?.[predicateId] && Array.isArray(shortcuts[predicateId])) { predicateShortcuts = shortcuts[predicateId]; } return predicateShortcuts; } showQuickFilterDropdown(columnId) { const hideQuickFilterDropdownFunction = this.getFilterOptions().columnFilterOptions.hideQuickFilterDropdown; if (hideQuickFilterDropdownFunction) { const column = this.getColumnApi().getColumnWithColumnId(columnId); const columnColumnContext = { column: column, ...this.getAdaptableInternalApi().buildBaseContext(), }; return !hideQuickFilterDropdownFunction(columnColumnContext); } return true; } openColumnFilterPopup(columnId, popupProps) { this.getAdaptableInternalApi().showPopupWindow({ id: COLUMN_FILTER_WINDOW, title: ModuleConstants.ColumnFilterFriendlyName, icon: 'filter', factoryId: COLUMN_FILTER_WINDOW, popupProps: { value: columnId, size: { width: 380, height: 450, }, ...popupProps, }, }); } /** * First we try to get the cached values from the FilterHandler * Only if the FilterHandler is not available we fallback to the GridApi method */ async getColumnFilterValues(options) { const filterOptions = this.getOptionsApi().getFilterOptions(); const newOptions = { columnId: options.columnId, get currentSearchValue() { // we need this in order to keep it lazy return options.currentSearchValue; }, previousResult: undefined, }; const columnFilterHandler = this.getAgGridApi().getColumnFilterHandler(options.columnId); if (!columnFilterHandler) { this.logWarn(`No ColumnFilterHandler found for columnId: ${options.columnId}!`); return this.getGridApi().internalApi.getDistinctFilterDisplayValuesForColumn(newOptions); } if (typeof columnFilterHandler.getFromCacheOrFetchFilterDisplayValues !== 'function') { this.logWarn(`ColumnFilterHandler for columnId: ${options.columnId} does not have getFromCacheOrFetchFilterDisplayValues method!`); return this.getGridApi().internalApi.getDistinctFilterDisplayValuesForColumn(newOptions); } if (filterOptions.customInFilterValues) { return columnFilterHandler.fetchFilterDisplayValues(newOptions); } return columnFilterHandler.getFromCacheOrFetchFilterDisplayValues(newOptions); } shouldManuallyApplyColumnFilter(columnId) { const manuallyApplyColumnFilterOpt = this.getOptionsApi().getFilterOptions().columnFilterOptions?.manuallyApplyColumnFilter; if (typeof manuallyApplyColumnFilterOpt === 'boolean') { return manuallyApplyColumnFilterOpt; } if (typeof manuallyApplyColumnFilterOpt === 'function') { const column = this.getColumnApi().getColumnWithColumnId(columnId); const context = { column, ...this.getAdaptableApi().internalApi.buildBaseContext(), }; return manuallyApplyColumnFilterOpt(context); } // fallback, should never happen return false; } getAdaptableFilterHandler(columnId) { return this.getAgGridApi().getColumnFilterHandler(columnId); } getAllAdaptableFilterHandlers() { const allFilterableColumns = this.getColumnApi().getFilterableColumns(); const filterHandlers = allFilterableColumns .map((column) => this.getAgGridApi().getColumnFilterHandler(column.columnId)) .filter(Boolean) .filter((handler) => handler instanceof AdaptableFilterHandler); return filterHandlers; } }