From 0ed7907b0fcdf4a4101245a53e9dbc051c5ff305 Mon Sep 17 00:00:00 2001 From: Gildas Garcia <1122076+djhi@users.noreply.github.com> Date: Fri, 27 Jan 2023 10:46:32 +0100 Subject: [PATCH 1/2] Fix AutocompleteInput flickers inside ReferenceInput --- .../controller/input/useReferenceArrayInputController.ts | 7 ++++++- packages/ra-core/src/dataProvider/useGetManyAggregate.ts | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/ra-core/src/controller/input/useReferenceArrayInputController.ts b/packages/ra-core/src/controller/input/useReferenceArrayInputController.ts index b529f39d12a..aee3e20ae76 100644 --- a/packages/ra-core/src/controller/input/useReferenceArrayInputController.ts +++ b/packages/ra-core/src/controller/input/useReferenceArrayInputController.ts @@ -107,7 +107,12 @@ export const useReferenceArrayInputController = < filter: { ...params.filter, ...filter }, meta, }, - { retry: false, enabled: isGetMatchingEnabled, ...otherQueryOptions } + { + retry: false, + enabled: isGetMatchingEnabled, + keepPreviousData: true, + ...otherQueryOptions, + } ); // We merge the currently selected records with the matching ones, otherwise diff --git a/packages/ra-core/src/dataProvider/useGetManyAggregate.ts b/packages/ra-core/src/dataProvider/useGetManyAggregate.ts index a3efc92ff9a..beb93924c70 100644 --- a/packages/ra-core/src/dataProvider/useGetManyAggregate.ts +++ b/packages/ra-core/src/dataProvider/useGetManyAggregate.ts @@ -121,6 +121,7 @@ export const useGetManyAggregate = ( }); }, retry: false, + keepPreviousData: true, ...options, } ); From d349459380028d084372336b145bd49722de3dc1 Mon Sep 17 00:00:00 2001 From: Gildas Garcia <1122076+djhi@users.noreply.github.com> Date: Fri, 27 Jan 2023 11:29:24 +0100 Subject: [PATCH 2/2] Add test --- .../src/dataProvider/useGetManyAggregate.ts | 1 - .../src/input/AutocompleteArrayInput.spec.tsx | 57 +++++++++++++++++++ .../src/input/AutocompleteInput.stories.tsx | 2 +- 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/packages/ra-core/src/dataProvider/useGetManyAggregate.ts b/packages/ra-core/src/dataProvider/useGetManyAggregate.ts index beb93924c70..a3efc92ff9a 100644 --- a/packages/ra-core/src/dataProvider/useGetManyAggregate.ts +++ b/packages/ra-core/src/dataProvider/useGetManyAggregate.ts @@ -121,7 +121,6 @@ export const useGetManyAggregate = ( }); }, retry: false, - keepPreviousData: true, ...options, } ); diff --git a/packages/ra-ui-materialui/src/input/AutocompleteArrayInput.spec.tsx b/packages/ra-ui-materialui/src/input/AutocompleteArrayInput.spec.tsx index 527a0bc26a9..38f0796f355 100644 --- a/packages/ra-ui-materialui/src/input/AutocompleteArrayInput.spec.tsx +++ b/packages/ra-ui-materialui/src/input/AutocompleteArrayInput.spec.tsx @@ -11,6 +11,7 @@ import { AdminContext } from '../AdminContext'; import { SimpleForm } from '../form'; import { AutocompleteArrayInput } from './AutocompleteArrayInput'; import { useCreateSuggestionContext } from './useSupportCreateSuggestion'; +import { InsideReferenceArrayInput } from './AutocompleteArrayInput.stories'; describe('', () => { const defaultProps = { @@ -931,4 +932,60 @@ describe('', () => { ); expect(screen.queryAllByRole('option')).toHaveLength(2); }); + + it('should display "No options" and not throw any error inside a ReferenceArrayInput field when referenced list is empty', async () => { + render(); + // Give time for the (previously thrown) error to happen + await new Promise(resolve => setTimeout(resolve, 1000)); + await waitFor(() => { + screen.getByText('Author'); + }); + screen.getByRole('textbox').focus(); + fireEvent.click(screen.getByLabelText('Clear value')); + fireEvent.change(screen.getByRole('textbox'), { + target: { value: 'plop' }, + }); + await waitFor( + () => { + screen.getByText('No options'); + }, + { timeout: 2000 } + ); + }); + + it('should not display "No options" inside a ReferenceArrayInput field when referenced list loading', async () => { + render(); + // Give time for the (previously thrown) error to happen + await new Promise(resolve => setTimeout(resolve, 1000)); + await waitFor(() => { + screen.getByText('Author'); + }); + screen.getByRole('textbox').focus(); + fireEvent.click(screen.getByLabelText('Clear value')); + fireEvent.change(screen.getByRole('textbox'), { + target: { value: 'Vic' }, + }); + + // As the No options message might only be displayed after a small delay, + // we need to check for its presence for a few seconds. + // This test failed before the fix + const noOptionsAppeared = await new Promise(resolve => { + let noOptionsAppeared = false; + const checkForNoOptions = () => { + noOptionsAppeared = screen.queryByText('No options') != null; + if (noOptionsAppeared) { + clearInterval(interval); + resolve(noOptionsAppeared); + } + }; + + const interval = setInterval(checkForNoOptions, 100); + setTimeout(() => { + clearInterval(interval); + resolve(noOptionsAppeared); + }, 2000); + }); + + expect(noOptionsAppeared).toBe(false); + }); }); diff --git a/packages/ra-ui-materialui/src/input/AutocompleteInput.stories.tsx b/packages/ra-ui-materialui/src/input/AutocompleteInput.stories.tsx index 4c509e26a62..633fc66898f 100644 --- a/packages/ra-ui-materialui/src/input/AutocompleteInput.stories.tsx +++ b/packages/ra-ui-materialui/src/input/AutocompleteInput.stories.tsx @@ -819,7 +819,7 @@ const FanList = props => { return data ? ( <> {data.map(fan => ( - +