Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DataGrid] Improve the invalid sortModel and filterModel warnings #3671

Merged
merged 32 commits into from
Feb 15, 2022
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
543c8bc
[DataGrid] Improve the invalid sortModel and filterModel warnings
flaviendelangle Jan 20, 2022
15b5740
Work
flaviendelangle Jan 20, 2022
a968078
Work
flaviendelangle Jan 20, 2022
6dfe952
Fix
flaviendelangle Jan 20, 2022
23bb123
Fix
flaviendelangle Jan 20, 2022
f6cc332
Merge branch 'master' into sort-filter-warning
flaviendelangle Jan 21, 2022
73dc09f
Merge
flaviendelangle Jan 26, 2022
53b666a
Merge
flaviendelangle Jan 28, 2022
3cc6527
Fix
flaviendelangle Jan 28, 2022
e83d42b
Merge
flaviendelangle Feb 1, 2022
e540e08
Work
flaviendelangle Feb 1, 2022
74c5fd2
Work
flaviendelangle Feb 9, 2022
a2688d6
Merge
flaviendelangle Feb 9, 2022
787645b
Fix
flaviendelangle Feb 9, 2022
d89d6dd
Merge branch 'master' into sort-filter-warning
flaviendelangle Feb 11, 2022
f6fd020
Work
flaviendelangle Feb 11, 2022
b3c2b3c
Work
flaviendelangle Feb 11, 2022
b76c436
Update packages/grid/_modules_/grid/hooks/features/sorting/gridSortin…
flaviendelangle Feb 14, 2022
55c58fd
Update packages/grid/_modules_/grid/hooks/features/filter/gridFilterU…
flaviendelangle Feb 14, 2022
57726b8
Update packages/grid/x-data-grid/src/tests/sorting.DataGrid.test.tsx
flaviendelangle Feb 14, 2022
e5ba2ec
Code review: Matheus
flaviendelangle Feb 14, 2022
b20cfa0
Worké
flaviendelangle Feb 14, 2022
16ab9ab
Fix
flaviendelangle Feb 14, 2022
7dbaa63
Work
flaviendelangle Feb 14, 2022
ed671d8
Merge branch 'master' into sort-filter-warning
flaviendelangle Feb 15, 2022
9307f89
Code review: Matheus (prepare for operatorValue requirement)
flaviendelangle Feb 15, 2022
7ec1516
Fix
flaviendelangle Feb 15, 2022
8ab1b3d
Work
flaviendelangle Feb 15, 2022
3d93892
Work
flaviendelangle Feb 15, 2022
92fa1ae
Fix
flaviendelangle Feb 15, 2022
1bb99f0
Empty
flaviendelangle Feb 15, 2022
a5b545b
Empty
flaviendelangle Feb 15, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions docs/data/data-grid/components/CustomSortIcons.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,7 @@ export default function CustomSortIcons() {
<DataGrid
columns={columns}
rows={rows}
sortModel={[
{ field: 'name', sort: 'asc' },
{ field: 'stars', sort: 'desc' },
]}
sortModel={[{ field: 'name', sort: 'asc' }]}
components={{
ColumnSortedDescendingIcon: SortedDescendingIcon,
ColumnSortedAscendingIcon: SortedAscendingIcon,
Expand Down
5 changes: 1 addition & 4 deletions docs/data/data-grid/components/CustomSortIcons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,7 @@ export default function CustomSortIcons() {
<DataGrid
columns={columns}
rows={rows}
sortModel={[
{ field: 'name', sort: 'asc' },
{ field: 'stars', sort: 'desc' },
]}
sortModel={[{ field: 'name', sort: 'asc' }]}
components={{
ColumnSortedDescendingIcon: SortedDescendingIcon,
ColumnSortedAscendingIcon: SortedAscendingIcon,
Expand Down
5 changes: 1 addition & 4 deletions docs/data/data-grid/components/CustomSortIcons.tsx.preview
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
<DataGrid
columns={columns}
rows={rows}
sortModel={[
{ field: 'name', sort: 'asc' },
{ field: 'stars', sort: 'desc' },
]}
sortModel={[{ field: 'name', sort: 'asc' }]}
components={{
ColumnSortedDescendingIcon: SortedDescendingIcon,
ColumnSortedAscendingIcon: SortedAscendingIcon,
Expand Down
1 change: 1 addition & 0 deletions docs/data/data-grid/filtering/CustomInputComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ RatingInputValue.propTypes = {
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
/**
* The name of the operator we want to apply.
* Will become required on `@mui/x-data-grid@6.X`.
*/
operatorValue: PropTypes.string,
/**
Expand Down
1 change: 1 addition & 0 deletions docs/data/data-grid/filtering/CustomMultiValueOperator.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ InputNumberInterval.propTypes = {
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
/**
* The name of the operator we want to apply.
* Will become required on `@mui/x-data-grid@6.X`.
*/
operatorValue: PropTypes.string,
/**
Expand Down
1 change: 1 addition & 0 deletions docs/data/data-grid/filtering/CustomRatingOperator.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ RatingInputValue.propTypes = {
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
/**
* The name of the operator we want to apply.
* Will become required on `@mui/x-data-grid@6.X`.
*/
operatorValue: PropTypes.string,
/**
Expand Down
7 changes: 6 additions & 1 deletion docs/pages/api-docs/data-grid/data-grid.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@
"type": { "name": "enum", "description": "'client'<br>&#124;&nbsp;'server'" },
"default": "\"client\""
},
"filterModel": { "type": { "name": "custom", "description": "any" } },
"filterModel": {
"type": {
"name": "shape",
"description": "{ items: Array&lt;{ columnField: string, id?: number<br>&#124;&nbsp;string, operatorValue?: string, value?: any }&gt;, linkOperator?: 'and'<br>&#124;&nbsp;'or' }"
}
},
"getCellClassName": { "type": { "name": "func" } },
"getDetailPanelContent": { "type": { "name": "func" } },
"getRowClassName": { "type": { "name": "func" } },
Expand Down
2 changes: 1 addition & 1 deletion docs/pages/api-docs/data-grid/grid-filter-item.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ import { GridFilterItem } from '@mui/x-data-grid';
| :---------------------------------------------------------------------------------------------- | :---------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------- |
| <span class="prop-name">columnField</span> | <span class="prop-type">string</span> | The column from which we want to filter the rows. |
| <span class="prop-name optional">id<sup><abbr title="optional">?</abbr></sup></span> | <span class="prop-type">number \| string</span> | Must be unique.<br />Only useful when the model contains several items. |
| <span class="prop-name optional">operatorValue<sup><abbr title="optional">?</abbr></sup></span> | <span class="prop-type">string</span> | The name of the operator we want to apply. |
| <span class="prop-name optional">operatorValue<sup><abbr title="optional">?</abbr></sup></span> | <span class="prop-type">string</span> | The name of the operator we want to apply.<br />Will become required on `@mui/x-data-grid@6.X`. |
| <span class="prop-name optional">value<sup><abbr title="optional">?</abbr></sup></span> | <span class="prop-type">any</span> | The filtering value.<br />The operator filtering function will decide for each row if the row values is correct compared to this value. |
7 changes: 6 additions & 1 deletion docs/pages/x/api/data-grid/data-grid.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@
"type": { "name": "enum", "description": "'client'<br>&#124;&nbsp;'server'" },
"default": "\"client\""
},
"filterModel": { "type": { "name": "custom", "description": "any" } },
"filterModel": {
"type": {
"name": "shape",
"description": "{ items: Array&lt;{ columnField: string, id?: number<br>&#124;&nbsp;string, operatorValue?: string, value?: any }&gt;, linkOperator?: 'and'<br>&#124;&nbsp;'or' }"
}
},
"getCellClassName": { "type": { "name": "func" } },
"getDetailPanelContent": { "type": { "name": "func" } },
"getRowClassName": { "type": { "name": "func" } },
Expand Down
2 changes: 1 addition & 1 deletion docs/pages/x/api/data-grid/grid-filter-item.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ import { GridFilterItem } from '@mui/x-data-grid';
| :---------------------------------------------------------------------------------------------- | :---------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------- |
| <span class="prop-name">columnField</span> | <span class="prop-type">string</span> | The column from which we want to filter the rows. |
| <span class="prop-name optional">id<sup><abbr title="optional">?</abbr></sup></span> | <span class="prop-type">number \| string</span> | Must be unique.<br />Only useful when the model contains several items. |
| <span class="prop-name optional">operatorValue<sup><abbr title="optional">?</abbr></sup></span> | <span class="prop-type">string</span> | The name of the operator we want to apply. |
| <span class="prop-name optional">operatorValue<sup><abbr title="optional">?</abbr></sup></span> | <span class="prop-type">string</span> | The name of the operator we want to apply.<br />Will become required on `@mui/x-data-grid@6.X`. |
| <span class="prop-name optional">value<sup><abbr title="optional">?</abbr></sup></span> | <span class="prop-type">any</span> | The filtering value.<br />The operator filtering function will decide for each row if the row values is correct compared to this value. |
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,21 @@ import { GridFilterItem, GridFilterModel, GridLinkOperator, GridRowId } from '..
import { GridApiCommunity } from '../../../models/api/gridApiCommunity';
import { GridStateCommunity } from '../../../models/gridStateCommunity';
import { GridAggregatedFilterItemApplier } from './gridFilterState';
import { buildWarning } from '../../../utils/warning';

type GridFilterItemApplier = {
fn: (rowId: GridRowId) => boolean;
item: GridFilterItem;
};

export const mergeStateWithFilterModel = (
filterModel: GridFilterModel,
disableMultipleColumnsFiltering: boolean,
) => {
const cleanFilterModel = { ...filterModel };
if (cleanFilterModel.items.length > 1 && disableMultipleColumnsFiltering) {
cleanFilterModel.items = [cleanFilterModel.items[0]];
}

return (state: GridStateCommunity): GridStateCommunity => ({
...state,
filter: {
...state.filter,
filterModel,
},
});
};

/**
* 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 = (
const cleanFilterItem = (
item: GridFilterItem,
apiRef: React.MutableRefObject<GridApiCommunity>,
) => {
Expand All @@ -53,6 +36,82 @@ export const cleanFilterItem = (
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.',
flaviendelangle marked this conversation as resolved.
Show resolved Hide resolved
'This property will become required on `@mui/x-data-grid@6.X`.',
]);

export const sanitizeFilterModel = (
model: GridFilterModel,
disableMultipleColumnsFiltering: boolean,
apiRef: React.MutableRefObject<GridApiCommunity>,
) => {
const hasSeveralItems = model.items.length > 1;

let items: GridFilterItem[];
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 {
...model,
items: items.map((item) => cleanFilterItem(item, apiRef)),
};
}

if (model.items !== items) {
return {
...model,
items,
};
}

return model;
};

export const mergeStateWithFilterModel =
(
filterModel: GridFilterModel,
disableMultipleColumnsFiltering: boolean,
apiRef: React.MutableRefObject<GridApiCommunity>,
) =>
(state: GridStateCommunity): GridStateCommunity => ({
...state,
filter: {
...state.filter,
filterModel: sanitizeFilterModel(filterModel, disableMultipleColumnsFiltering, apiRef),
},
});

/**
* 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.
Expand Down
46 changes: 14 additions & 32 deletions packages/grid/_modules_/grid/hooks/features/filter/useGridFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import {
GridFilteringMethod,
GridFilteringMethodCollection,
} from './gridFilterState';
import { GridFilterModel } from '../../../models/gridFilterModel';
import { gridFilterModelSelector, gridVisibleSortedRowEntriesSelector } from './gridFilterSelector';
import { useGridStateInit } from '../../utils/useGridStateInit';
import { useFirstRender } from '../../utils/useFirstRender';
Expand All @@ -25,21 +24,10 @@ import { GridPreProcessor, useGridRegisterPreProcessor } from '../../core/prePro
import { useGridRegisterFilteringMethod } from './useGridRegisterFilteringMethod';
import {
buildAggregatedFilterApplier,
cleanFilterItem,
sanitizeFilterModel,
mergeStateWithFilterModel,
} from './gridFilterUtils';

const checkFilterModelValidity = (model: GridFilterModel) => {
if (model.items.length > 1) {
const hasItemsWithoutIds = model.items.find((item) => item.id == null);
if (hasItemsWithoutIds) {
throw new Error(
"MUI: The 'id' field is required on `filterModel.items` when you use multiple filters.",
);
}
}
};

/**
* @requires useGridColumns (state, method, event)
* @requires useGridParamsApi (method)
Expand All @@ -61,17 +49,17 @@ export const useGridFilter = (
const lastFilteringMethodApplied = React.useRef<GridFilteringMethod | null>(null);

useGridStateInit(apiRef, (state) => {
if (props.filterModel) {
checkFilterModelValidity(props.filterModel);
}
const filterModel =
props.filterModel ?? props.initialState?.filter?.filterModel ?? getDefaultGridFilterModel();

return {
...state,
filter: {
filterModel:
props.filterModel ??
props.initialState?.filter?.filterModel ??
getDefaultGridFilterModel(),
filterModel: sanitizeFilterModel(
filterModel,
props.disableMultipleColumnsFiltering,
apiRef,
),
visibleRowsLookup: {},
filteredDescendantCountLookup: {},
},
Expand Down Expand Up @@ -125,11 +113,10 @@ export const useGridFilter = (
const filterModel = gridFilterModelSelector(apiRef);
const items = [...filterModel.items];
const itemIndex = items.findIndex((filterItem) => filterItem.id === item.id);
const newItem = cleanFilterItem(item, apiRef);
if (itemIndex === -1) {
items.push(newItem);
items.push(item);
} else {
items[itemIndex] = newItem;
items[itemIndex] = item;
}
apiRef.current.setFilterModel({ ...filterModel, items });
},
Expand Down Expand Up @@ -165,12 +152,9 @@ export const useGridFilter = (
if (filterItemOnTarget) {
newFilterItems = filterItemsWithValue;
} else if (props.disableMultipleColumnsFiltering) {
newFilterItems = [cleanFilterItem({ columnField: targetColumnField }, apiRef)];
newFilterItems = [{ columnField: targetColumnField }];
} else {
newFilterItems = [
...filterItemsWithValue,
cleanFilterItem({ columnField: targetColumnField }, apiRef),
];
newFilterItems = [...filterItemsWithValue, { columnField: targetColumnField }];
}

apiRef.current.setFilterModel({
Expand Down Expand Up @@ -206,11 +190,9 @@ export const useGridFilter = (
(model) => {
const currentModel = gridFilterModelSelector(apiRef);
if (currentModel !== model) {
checkFilterModelValidity(model);

logger.debug('Setting filter model');
apiRef.current.setState(
mergeStateWithFilterModel(model, props.disableMultipleColumnsFiltering),
mergeStateWithFilterModel(model, props.disableMultipleColumnsFiltering, apiRef),
);
apiRef.current.unstable_applyFilters();
}
Expand Down Expand Up @@ -266,7 +248,7 @@ export const useGridFilter = (
return params;
}
apiRef.current.setState(
mergeStateWithFilterModel(filterModel, props.disableMultipleColumnsFiltering),
mergeStateWithFilterModel(filterModel, props.disableMultipleColumnsFiltering, apiRef),
);

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
GridSortModel,
GridSortCellParams,
} from '../../../models/gridSortModel';
import { buildWarning } from '../../../utils/warning';

type GridSortingFieldComparator = {
getSortCellParams: (id: GridRowId) => GridSortCellParams;
Expand All @@ -20,13 +21,30 @@ interface GridParsedSortItem {
getSortCellParams: (id: GridRowId) => GridSortCellParams;
}

const sortModelDisableMultiColumnsSortingWarning = buildWarning(
[
'MUI: The `sortModel` can only contain a single item when the `disableMultipleColumnsSorting` prop is set to `true`.',
'If you are using the community version of the `DataGrid`, this prop is always `true`.',
],
'error',
);

export const sanitizeSortModel = (model: GridSortModel, disableMultipleColumnsSorting: boolean) => {
if (disableMultipleColumnsSorting && model.length > 1) {
sortModelDisableMultiColumnsSortingWarning();
return [model[0]];
}

return model;
};

export const mergeStateWithSortModel =
(sortModel: GridSortModel) =>
(sortModel: GridSortModel, disableMultipleColumnsSorting: boolean) =>
(state: GridStateCommunity): GridStateCommunity => ({
...state,
sorting: {
...state.sorting,
sortModel,
sortModel: sanitizeSortModel(sortModel, disableMultipleColumnsSorting),
},
});

Expand Down
Loading