@mui/x-data-grid
Version:
The community edition of the data grid component (MUI X).
276 lines (224 loc) • 10.8 kB
JavaScript
import _extends from "@babel/runtime/helpers/esm/extends";
import { GridLinkOperator } from '../../../models';
import { getDefaultGridFilterModel } from './gridFilterState';
import { buildWarning } from '../../../utils/warning';
import { gridColumnFieldsSelector, gridColumnLookupSelector } from '../columns';
/**
* Adds default values to the optional fields of a filter items.
* @param {GridFilterItem} item The raw filter item.
* @param {React.MutableRefObject<GridApiCommunity>} apiRef The API of the grid.
* @return {GridFilterItem} The clean filter item with an uniq ID and an always-defined operatorValue.
* TODO: Make the typing reflect the different between GridFilterInputItem and GridFilterItem.
*/
export const cleanFilterItem = (item, apiRef) => {
const cleanItem = _extends({}, item);
if (cleanItem.id == null) {
cleanItem.id = Math.round(Math.random() * 1e5);
}
if (cleanItem.operatorValue == null) {
// Selects a default operator
// We don't use `apiRef.current.getColumn` because it is not ready during state initialization
const column = gridColumnLookupSelector(apiRef)[cleanItem.columnField];
cleanItem.operatorValue = column && column.filterOperators[0].value;
}
return cleanItem;
};
const filterModelDisableMultiColumnsFilteringWarning = buildWarning(['MUI: The `filterModel` can only contain a single item when the `disableMultipleColumnsFiltering` prop is set to `true`.', 'If you are using the community version of the `DataGrid`, this prop is always `true`.'], 'error');
const filterModelMissingItemIdWarning = buildWarning("MUI: The 'id' field is required on `filterModel.items` when you use multiple filters.", 'error');
const filterModelMissingItemOperatorWarning = buildWarning(['MUI: One of your filtering item have no `operatorValue` provided.', 'This property will become required on `@mui/x-data-grid@6.X`.']);
export const sanitizeFilterModel = (model, disableMultipleColumnsFiltering, apiRef) => {
const hasSeveralItems = model.items.length > 1;
let items;
if (hasSeveralItems && disableMultipleColumnsFiltering) {
filterModelDisableMultiColumnsFilteringWarning();
items = [model.items[0]];
} else {
items = model.items;
}
const hasItemsWithoutIds = hasSeveralItems && items.some(item => item.id == null);
const hasItemWithoutOperator = items.some(item => item.operatorValue == null);
if (hasItemsWithoutIds) {
filterModelMissingItemIdWarning();
}
if (hasItemWithoutOperator) {
filterModelMissingItemOperatorWarning();
}
if (hasItemWithoutOperator || hasItemsWithoutIds) {
return _extends({}, model, {
items: items.map(item => cleanFilterItem(item, apiRef))
});
}
if (model.items !== items) {
return _extends({}, model, {
items
});
}
return model;
};
export const mergeStateWithFilterModel = (filterModel, disableMultipleColumnsFiltering, apiRef) => filteringState => _extends({}, filteringState, {
filterModel: sanitizeFilterModel(filterModel, disableMultipleColumnsFiltering, apiRef)
});
const getFilterCallbackFromItem = (filterItem, apiRef) => {
if (!filterItem.columnField || !filterItem.operatorValue) {
return null;
}
const column = apiRef.current.getColumn(filterItem.columnField);
if (!column) {
return null;
}
let parsedValue;
if (column.valueParser) {
var _filterItem$value;
const parser = column.valueParser;
parsedValue = Array.isArray(filterItem.value) ? (_filterItem$value = filterItem.value) == null ? void 0 : _filterItem$value.map(x => parser(x)) : parser(filterItem.value);
} else {
parsedValue = filterItem.value;
}
const newFilterItem = _extends({}, filterItem, {
value: parsedValue
});
const filterOperators = column.filterOperators;
if (!(filterOperators != null && filterOperators.length)) {
throw new Error(`MUI: No filter operators found for column '${column.field}'.`);
}
const filterOperator = filterOperators.find(operator => operator.value === newFilterItem.operatorValue);
if (!filterOperator) {
throw new Error(`MUI: No filter operator found for column '${column.field}' and operator value '${newFilterItem.operatorValue}'.`);
}
const applyFilterOnRow = filterOperator.getApplyFilterFn(newFilterItem, column);
if (typeof applyFilterOnRow !== 'function') {
return null;
}
const fn = rowId => {
const cellParams = apiRef.current.getCellParams(rowId, newFilterItem.columnField);
return applyFilterOnRow(cellParams);
};
return {
fn,
item: newFilterItem
};
};
/**
* Generates a method to easily check if a row is matching the current filter model.
* @param {GridFilterModel} filterModel The model with which we want to filter the rows.
* @param {React.MutableRefObject<GridApiCommunity>} apiRef The API of the grid.
* @returns {GridAggregatedFilterItemApplier | null} A method that checks if a row is matching the current filter model. If `null`, we consider that all the rows are matching the filters.
*/
export const buildAggregatedFilterItemsApplier = (filterModel, apiRef) => {
const {
items
} = filterModel;
const appliers = items.map(item => getFilterCallbackFromItem(item, apiRef)).filter(callback => !!callback);
if (appliers.length === 0) {
return null;
}
return (rowId, shouldApplyFilter) => {
const resultPerItemId = {};
const filteredAppliers = shouldApplyFilter ? appliers.filter(applier => shouldApplyFilter(applier.item.columnField)) : appliers;
filteredAppliers.forEach(applier => {
resultPerItemId[applier.item.id] = applier.fn(rowId);
});
return resultPerItemId;
};
};
/**
* Generates a method to easily check if a row is matching the current quick filter.
* @param {any[]} values The model with which we want to filter the rows.
* @param {React.MutableRefObject<GridApiCommunity>} apiRef The API of the grid.
* @returns {GridAggregatedFilterItemApplier | null} A method that checks if a row is matching the current filter model. If `null`, we consider that all the rows are matching the filters.
*/
export const buildAggregatedQuickFilterApplier = (filterModel, apiRef) => {
const {
quickFilterValues = []
} = filterModel;
if (quickFilterValues.length === 0) {
return null;
}
const columnsFields = gridColumnFieldsSelector(apiRef);
const appliersPerColumnField = {};
columnsFields.forEach(field => {
const column = apiRef.current.getColumn(field);
const getApplyQuickFilterFn = column == null ? void 0 : column.getApplyQuickFilterFn;
if (!getApplyQuickFilterFn) {
return;
}
appliersPerColumnField[field] = quickFilterValues.map(value => getApplyQuickFilterFn(value, column, apiRef));
}); // If some value does not have an applier we ignore them
const sanitizedQuickFilterValues = quickFilterValues.filter((value, index) => Object.keys(appliersPerColumnField).some(field => appliersPerColumnField[field][index] != null));
if (sanitizedQuickFilterValues.length === 0) {
return null;
}
return (rowId, shouldApplyFilter) => {
const usedCellParams = {};
const columnsFieldsToFilter = [];
Object.keys(appliersPerColumnField).forEach(columnField => {
if (!shouldApplyFilter || shouldApplyFilter(columnField)) {
usedCellParams[columnField] = apiRef.current.getCellParams(rowId, columnField);
columnsFieldsToFilter.push(columnField);
}
});
const quickFilterValueResult = {};
sanitizedQuickFilterValues.forEach((value, index) => {
const isPassing = columnsFieldsToFilter.some(field => {
var _appliersPerColumnFie, _appliersPerColumnFie2;
if (appliersPerColumnField[field][index] == null) {
return false;
}
return (_appliersPerColumnFie = (_appliersPerColumnFie2 = appliersPerColumnField[field])[index]) == null ? void 0 : _appliersPerColumnFie.call(_appliersPerColumnFie2, usedCellParams[field]);
});
quickFilterValueResult[value] = isPassing;
});
return quickFilterValueResult;
};
};
export const buildAggregatedFilterApplier = (filterModel, apiRef) => {
const isRowMatchingFilterItems = buildAggregatedFilterItemsApplier(filterModel, apiRef);
const isRowMatchingQuickFilter = buildAggregatedQuickFilterApplier(filterModel, apiRef);
return (rowId, shouldApplyFilter) => ({
passingFilterItems: isRowMatchingFilterItems && isRowMatchingFilterItems(rowId, shouldApplyFilter),
passingQuickFilterValues: isRowMatchingQuickFilter && isRowMatchingQuickFilter(rowId, shouldApplyFilter)
});
};
export const passFilterLogic = (allFilterItemResults, allQuickFilterResults, filterModel, apiRef) => {
var _filterModel$quickFil, _filterModel$linkOper;
const cleanedFilterItems = filterModel.items.filter(item => getFilterCallbackFromItem(item, apiRef) !== null);
const cleanedAllFilterItemResults = allFilterItemResults.filter(result => result != null);
const cleanedAllQuickFilterResults = allQuickFilterResults.filter(result => result != null); // Defaultize operators
const quickFilterLogicOperator = (_filterModel$quickFil = filterModel.quickFilterLogicOperator) != null ? _filterModel$quickFil : getDefaultGridFilterModel().quickFilterLogicOperator;
const linkOperator = (_filterModel$linkOper = filterModel.linkOperator) != null ? _filterModel$linkOper : getDefaultGridFilterModel().linkOperator; // get result for filter items model
if (cleanedAllFilterItemResults.length > 0) {
// Return true if the item pass with one of the rows
const filterItemPredicate = item => {
return cleanedAllFilterItemResults.some(filterItemResult => filterItemResult[item.id]);
};
if (linkOperator === GridLinkOperator.And) {
const passesAllFilters = cleanedFilterItems.every(filterItemPredicate);
if (!passesAllFilters) {
return false;
}
} else {
const passesSomeFilters = cleanedFilterItems.some(filterItemPredicate);
if (!passesSomeFilters) {
return false;
}
}
} // get result for quick filter model
if (cleanedAllQuickFilterResults.length > 0 && filterModel.quickFilterValues != null) {
// Return true if the item pass with one of the rows
const quickFilterValuePredicate = value => {
return cleanedAllQuickFilterResults.some(quickFilterValueResult => quickFilterValueResult[value]);
};
if (quickFilterLogicOperator === GridLinkOperator.And) {
const passesAllQuickFilterValues = filterModel.quickFilterValues.every(quickFilterValuePredicate);
if (!passesAllQuickFilterValues) {
return false;
}
} else {
const passesSomeQuickFilterValues = filterModel.quickFilterValues.some(quickFilterValuePredicate);
if (!passesSomeQuickFilterValues) {
return false;
}
}
}
return true;
};