-
-
Notifications
You must be signed in to change notification settings - Fork 5.3k
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
Introduce <FilterLiveForm>
#10344
Introduce <FilterLiveForm>
#10344
Conversation
…tFilterForm to only submit on real changes
@@ -30,35 +24,45 @@ import { FilterFormInput } from './FilterFormInput'; | |||
import { FilterContext } from '../FilterContext'; | |||
|
|||
export const FilterForm = (props: FilterFormProps) => { | |||
const { defaultValues, filters: filtersProps, ...rest } = props; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
defaultValues
is not used in all RA's code, and I tested it and it does not work, so I removed it to reduce tech debt. Shouldn't be a BC since it does not currently work.
const mergedInitialValuesWithDefaultValues = | ||
mergeInitialValuesWithDefaultValues( | ||
defaultValues || filterValues, | ||
filters | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This whole call is actually useless, because:
defaultValues
don't workmergeInitialValuesWithDefaultValues
actually does nothing, since there is a runtime check to prevent having bothalwaysOn
anddefaultValue
. It's probably a historic tech debt, that's why I removed it.
@@ -270,7 +252,7 @@ const getInputValue = ( | |||
filterValues: Record<string, any> | |||
) => { | |||
if (formValues[key] === undefined || formValues[key] === null) { | |||
return ''; | |||
return get(filterValues, key, ''); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same, historic bug (see updated unit test)
resolver, | ||
validate, | ||
children, | ||
component: Component, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why don't you provide a default value here and avoid the ternary at L124?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't know how to do it, but now I know! Thanks!
packages/ra-ui-materialui/src/list/filter/FilterListWrapper.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot reviewed 13 out of 28 changed files in this pull request and generated no suggestions.
Files not reviewed (15)
- docs/navigation.html: Language not supported
- docs/Reference.md: Evaluated as low risk
- packages/ra-core/src/util/index.ts: Evaluated as low risk
- packages/ra-ui-materialui/src/list/filter/FilterList.stories.tsx: Evaluated as low risk
- packages/ra-ui-materialui/src/list/filter/FilterForm.spec.tsx: Evaluated as low risk
- packages/ra-ui-materialui/src/list/filter/FilterList.tsx: Evaluated as low risk
- packages/ra-core/src/controller/list/index.ts: Evaluated as low risk
- packages/ra-ui-materialui/src/list/filter/FilterForm.tsx: Evaluated as low risk
- packages/ra-core/src/controller/list/filter/index.ts: Evaluated as low risk
- packages/ra-core/src/controller/list/filter/AutoSubmitFilterForm.tsx: Evaluated as low risk
- packages/ra-ui-materialui/src/input/SearchInput.spec.tsx: Evaluated as low risk
- docs/FilteringTutorial.md: Evaluated as low risk
- docs/FilterList.md: Evaluated as low risk
- docs/FilterLiveSearch.md: Evaluated as low risk
- packages/ra-ui-materialui/src/input/SearchInput.stories.tsx: Evaluated as low risk
import { Box, BoxProps, Typography } from '@mui/material'; | ||
import { useTranslate } from 'ra-core'; | ||
|
||
export const FilterListWrapper = (props: FilterListWrapperProps) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would name this FilterListSection
docs/FilterLiveSearch.md
Outdated
@@ -12,7 +12,7 @@ title: "The FilterLiveSearch Component" | |||
</video> | |||
|
|||
|
|||
The filter sidebar is not a form. Therefore, if your users need to enter complex filters, you'll have to recreate a filter form using react-hook-form (see the [Building a custom filter](./FilteringTutorial.md#building-a-custom-filter) for an example). However, if you only need one text input with a filter-as-you-type behavior, you'll find the `<FilterLiveSearch>` component convenient. | |||
The filter sidebar is not a form. Therefore, if your users need to enter complex filters, you'll have to recreate a filter form. This can easily be done thanks to the [`<AutoSubmitFilterForm>`](./AutoSubmitFilterForm.md) component. However, if you only need one text input with a filter-as-you-type behavior, you'll find the `<FilterLiveSearch>` component even more convenient. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The filter sidebar is not a form. Therefore, if your users need to enter complex filters, you'll have to recreate a filter form. This can easily be done thanks to the [`<AutoSubmitFilterForm>`](./AutoSubmitFilterForm.md) component. However, if you only need one text input with a filter-as-you-type behavior, you'll find the `<FilterLiveSearch>` component even more convenient. | |
The filter sidebar is not a form. Therefore, if your users need to enter complex filters, you'll have to recreate a filter form. This can be done thanks to the [`<AutoSubmitFilterForm>`](./AutoSubmitFilterForm.md) component. However, if you only need one text input with a filter-as-you-type behavior, you'll find the `<FilterLiveSearch>` component even more convenient. |
export const useDebouncedEvent = (callback, delay: number) => { | ||
// Create a ref that stores the debounced callback | ||
const debouncedCallbackRef = useRef(debounce(callback, delay)); | ||
|
||
// Whenever callback or delay changes, we need to update the debounced callback | ||
useEffect(() => { | ||
debouncedCallbackRef.current = debounce(callback, delay); | ||
}, [callback, delay]); | ||
|
||
// The function returned by useCallback will invoke the debounced callback | ||
// Its dependencies array is empty, so it never changes across re-renders | ||
return useCallback((...args) => debouncedCallbackRef.current(...args), []); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't have the checks we do in useEvent
to prevent calling the callback inside a render. I'm not really sure of the consequences but the react team has made it a strong limitation of useEvent
(see its code in our repo)
const { | ||
debounce = 500, | ||
resolver, | ||
validate, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When you have a non validated input you can't submit. But if you submit your FilterList
in a same time, it will reset your AutoSubmitForm
to the last validated state.
Do we need to consider it as an issue or as a normal way of work @fzaninotto @djhi ?
Capture.video.2024-11-18.11.19.16.mp4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO this isn't a bug
Such a really nice job 🦾 |
ProblemWith a It can easily happens when your app need to increase a bit the debounce. Moreover, when it happens, your input seems to be empty… it’s confusing SolutionMake the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only reviewed documentation so far
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome!
packages/ra-core/src/controller/list/filter/AutoSubmitFilterForm.tsx
Outdated
Show resolved
Hide resolved
packages/ra-core/src/controller/list/filter/AutoSubmitFilterForm.tsx
Outdated
Show resolved
Hide resolved
const { | ||
debounce = 500, | ||
resolver, | ||
validate, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO this isn't a bug
packages/ra-core/src/controller/list/filter/AutoSubmitFilterForm.tsx
Outdated
Show resolved
Hide resolved
packages/ra-ui-materialui/src/list/filter/FilterListWrapper.tsx
Outdated
Show resolved
Hide resolved
packages/ra-ui-materialui/src/list/filter/FilterLiveSearch.stories.tsx
Outdated
Show resolved
Hide resolved
Reproduced. However, I don't see how I could fix it. The Clear Filters button is outside the AutoSubmitFilterForm, and has no way of canceling the debounced event. Fortunately, this really an edge case, the default debounce of 500 ms makes it rather unlikely to happen, and clicking the Clear Filters button a second time (or navigating away and back) fixes all issues. |
// Whenever callback or delay changes, we need to update the debounced callback | ||
useLayoutEffect(() => { | ||
debouncedCallbackRef.current = debounce(stableCallback, delay); | ||
}, [stableCallback, delay]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need the stableCallback
dependency anymore: it's a ref so it will never change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah it's because ESLint is not aware that stableCallback
is a ref. NVM then
Problem
The
FilterList
is designed for buttons - not inputs. We provide theFilterLiveSearch
component, which is aTextInput
inside a form that submits on change. But some users want to be able to add custom form inputs (e.g. to select an author from a resource using an autocomplete), and re-writing the form wrapper is cumbersome.Solution
Introduce a new component to wrap form inputs in that case:
This PR also fixes #5591 🎉
Todo
<AutoSubmitFilterForm>
<FilterListWrapper>
to make it look nicer next to<FilterList>
FilterLiveSearch
keeps applying old valueAutoSubmitFilterForm
inFilterForm
to keep the code more consistentAutoSubmitFilterForm
inFilterLiveSearch
to keep the code more consistentHow To Test
<FilterLiveForm>
logic: http://localhost:9010/?path=/story/ra-core-controller-list-filter-filterliveform--basic<FilterLiveForm>
UI: http://localhost:9010/?path=/story/ra-ui-materialui-list-filter-filterliveform--full-app<FilterListSection>
: http://localhost:9010/?path=/story/ra-ui-materialui-list-filter-filterlistsection--basic<FilterLiveSearch>
old value bug: http://localhost:9010/?path=/story/ra-ui-materialui-list-filter-filterlivesearch--full-app<FilterLiveSearch>
Additional Checks
master
for a bugfix, ornext
for a featureAlso, please make sure to read the contributing guidelines.