diff --git a/cypress/e2e/mobile.cy.js b/cypress/e2e/mobile.cy.js
index 7203edebc30..7610a62441b 100644
--- a/cypress/e2e/mobile.cy.js
+++ b/cypress/e2e/mobile.cy.js
@@ -9,10 +9,10 @@ describe('Mobile UI', () => {
});
describe('Infinite Scroll', () => {
- it.only('should load more items when scrolling to the bottom of the page', () => {
+ it('should load more items when scrolling to the bottom of the page', () => {
ListPagePosts.navigate();
+ cy.contains('Fusce massa lorem').should('exist');
cy.contains('Sed quo et et fugiat modi').should('not.exist');
- cy.scrollTo('bottom');
cy.wait(500);
cy.scrollTo('bottom');
cy.contains('Sed quo et et fugiat modi');
diff --git a/packages/ra-ui-materialui/src/list/filter/FilterButton.stories.tsx b/packages/ra-ui-materialui/src/list/filter/FilterButton.stories.tsx
index 55a09d3fed5..4e62312de47 100644
--- a/packages/ra-ui-materialui/src/list/filter/FilterButton.stories.tsx
+++ b/packages/ra-ui-materialui/src/list/filter/FilterButton.stories.tsx
@@ -1,4 +1,5 @@
import * as React from 'react';
+import { Chip } from '@mui/material';
import { ListBase, memoryStore } from 'ra-core';
import {
Admin,
@@ -13,6 +14,7 @@ import {
TopToolbar,
SearchInput,
FilterButtonProps,
+ InputProps,
} from 'react-admin';
import fakerestDataProvider from 'ra-data-fakerest';
import {
@@ -383,6 +385,33 @@ export const WithAutoCompleteArrayInput = (args: {
);
};
+const QuickFilter = ({ label }: InputProps) => ;
+
+export const WithComplexValueFilter = (args: {
+ disableSaveQuery?: boolean;
+}) => {
+ const postFilters: React.ReactElement[] = [
+ ,
+ ];
+ return (
+
+
+ }
+ />
+
+
+ );
+};
+
export const Variant = () => {
const postFilters: React.ReactElement[] = [
', () => {
});
});
- it('should allow to add and clear a filter with a complex object value', async () => {
+ it('should allow to add and clear a filter with a nested value', async () => {
render();
const addFilterButton = await screen.findByText('Add filter');
@@ -230,6 +232,25 @@ describe('', () => {
expect(screen.queryByLabelText('Nested')).toBeNull();
});
+ it('should hide a removed filter with a complex object value', async () => {
+ render();
+
+ const addFilterButton = await screen.findByText('Add filter');
+ fireEvent.click(addFilterButton);
+ fireEvent.click(await screen.findByText('Complex'));
+ await screen.findByText('1-7 of 7');
+ await screen.findByText('Complex', {
+ selector: `.${chipClasses.root} *`,
+ });
+ fireEvent.click(await screen.findByTitle('Remove this filter'));
+ await screen.findByText('1-10 of 13');
+ expect(
+ screen.queryByText('Complex', {
+ selector: `.${chipClasses.root} *`,
+ })
+ ).toBeNull();
+ });
+
it('should provide a FormGroupContext', async () => {
render();
diff --git a/packages/ra-ui-materialui/src/list/filter/FilterForm.tsx b/packages/ra-ui-materialui/src/list/filter/FilterForm.tsx
index 6751ad17b2b..1cf14ba1c6f 100644
--- a/packages/ra-ui-materialui/src/list/filter/FilterForm.tsx
+++ b/packages/ra-ui-materialui/src/list/filter/FilterForm.tsx
@@ -123,7 +123,7 @@ export const FilterFormBase = (props: FilterFormBaseProps) => {
return (
filterElement.props.alwaysOn ||
displayedFilters[filterElement.props.source] ||
- (filterValue !== '' && typeof filterValue !== 'undefined')
+ !isEmptyValue(filterValue)
);
});
};
@@ -301,3 +301,17 @@ const getInputValue = (
}
return get(filterValues, key, '');
};
+
+const isEmptyValue = (filterValue: unknown) => {
+ if (filterValue === '' || typeof filterValue === 'undefined') return true;
+
+ // If one of the value leaf is not empty
+ // the value is considered not empty
+ if (typeof filterValue === 'object') {
+ return Object.keys(filterValue).every(key =>
+ isEmptyValue(filterValue[key])
+ );
+ }
+
+ return false;
+};