@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
JavaScript
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;
}
}