-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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
Clean record filter and record sort #10466
Conversation
- Removed unsaved states for view filters and view sorts - Use record filter and record sort related hooks and utils where needed instead
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.
PR Summary
This PR refactors the record filtering and sorting system by removing the legacy combined filter/sort implementation in favor of using currentRecordFilters and currentRecordSorts directly throughout the codebase.
- Removes all
useUpsertCombinedViewFilters/Sorts
anduseDeleteCombinedViewFilters/Sorts
hooks, replacing them with directuseUpsertRecordFilter/Sort
anduseRemoveRecordFilter/Sort
operations - Eliminates the event-in-state pattern by removing
onSortSelectComponentState
in favor of direct function calls - Adds new utility functions like
getViewSortsToCreate
,getViewSortsToUpdate
, andgetViewSortsToDelete
with comprehensive test coverage - Implements
useSaveRecordSortsToViewSorts
to handle synchronization between record sorts and view sorts - Simplifies component implementations by accessing filter/sort state directly through
currentRecordFiltersComponentState
andcurrentRecordSortsComponentState
64 file(s) reviewed, 11 comment(s)
Edit PR Review Bot Settings | Greptile
@@ -49,7 +49,7 @@ export const AdvancedFilterRootLevelViewFilterGroup = ({ | |||
return ( | |||
<StyledContainer> | |||
{childViewFiltersAndViewFilterGroups.map((child, i) => | |||
child.__typename === 'ViewFilterGroup' ? ( | |||
(child as any).__typename === 'ViewFilterGroup' ? ( |
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.
style: Using as any
type assertion bypasses TypeScript's type checking. Consider creating a proper type guard function or interface to check if the object is a ViewFilterGroup instead.
const childViewFilters = childViewFiltersAndViewFilterGroups.filter( | ||
(child) => child.__typename === 'ViewFilter', | ||
(child) => (child as any).__typename === 'ViewFilter', |
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.
style: Using (child as any).__typename
is a type safety workaround. Consider defining a proper type for the child elements to avoid using any
.
|
||
const currentRecordFilter = currentRecordFilters.find( | ||
(recordFilter) => recordFilter.id === viewFilterId, | ||
); | ||
|
||
const handleRemove = async () => { |
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.
style: Function is marked as async but doesn't use await anywhere.
const handleRemove = async () => { | |
const handleRemove = () => { |
@@ -3,12 +3,12 @@ import { availableFieldMetadataItemsForFilterFamilySelector } from '@/object-met | |||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; | |||
import { useUpsertCombinedViewFilterGroup } from '@/object-record/advanced-filter/hooks/useUpsertCombinedViewFilterGroup'; |
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.
style: This hook useUpsertCombinedViewFilterGroup
still has 'Combined' in its name while other combined hooks are being removed. Consider renaming for consistency with the PR's goal of removing combined filter/sort implementations.
// TODO: this should be removed as it is not consistent across re-renders | ||
const [fieldId] = useState(v4()); |
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.
style: This TODO comment about fieldId being inconsistent across re-renders remains unaddressed in this PR. Consider replacing this with a more stable ID generation approach.
useEffect(() => { | ||
currentViewWithSavedFiltersAndSorts?.viewFields.forEach((viewField) => { | ||
currentView?.viewFields.forEach((viewField) => { | ||
setViewFieldAggregateOperation(viewField); | ||
}); | ||
}, [ | ||
currentViewWithSavedFiltersAndSorts?.viewFields, | ||
setViewFieldAggregateOperation, | ||
]); | ||
}, [currentView, setViewFieldAggregateOperation]); |
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.
style: This effect now depends on currentView
instead of currentViewWithSavedFiltersAndSorts?.viewFields
. Make sure this doesn't cause unnecessary re-renders if other properties of currentView
change but viewFields
doesn't.
}, [ | ||
applyViewFiltersToCurrentRecordFilters, | ||
getFiltersFromQueryParams, | ||
hasFiltersQueryParams, | ||
resetUnsavedViewStates, | ||
setUnsavedViewFilter, | ||
]); |
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.
logic: resetUnsavedViewStates is included in the dependency array but not used in the effect
}, [ | |
applyViewFiltersToCurrentRecordFilters, | |
getFiltersFromQueryParams, | |
hasFiltersQueryParams, | |
resetUnsavedViewStates, | |
setUnsavedViewFilter, | |
]); | |
}, [ | |
applyViewFiltersToCurrentRecordFilters, | |
getFiltersFromQueryParams, | |
hasFiltersQueryParams, | |
]); |
if (!advancedRecordFilterIds) { | ||
throw new Error('No advanced view filters to remove'); |
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.
style: The error message still refers to 'advanced view filters' but the code is now checking for 'advancedRecordFilterIds'. Consider updating the error message to 'No advanced record filters to remove' for consistency.
const { selectedRecordIds } = jsonRelationFilterValueSchema | ||
.catch({ | ||
isCurrentWorkspaceMemberSelected: false, | ||
selectedRecordIds: simpleRelationFilterValueSchema.parse( | ||
viewFilterUsedInDropdown?.value, | ||
recordFilterUsedInDropdown?.value, | ||
), | ||
}) | ||
.parse(viewFilterUsedInDropdown?.value); | ||
.parse(recordFilterUsedInDropdown?.value); | ||
|
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.
logic: This code assumes recordFilterUsedInDropdown could be undefined when parsing its value. If currentRecordFilters is empty, this will cause a runtime error when trying to parse undefined.
const { selectedRecordIds } = jsonRelationFilterValueSchema | |
.catch({ | |
isCurrentWorkspaceMemberSelected: false, | |
selectedRecordIds: simpleRelationFilterValueSchema.parse( | |
viewFilterUsedInDropdown?.value, | |
recordFilterUsedInDropdown?.value, | |
), | |
}) | |
.parse(viewFilterUsedInDropdown?.value); | |
.parse(recordFilterUsedInDropdown?.value); | |
const { selectedRecordIds } = jsonRelationFilterValueSchema | |
.catch({ | |
isCurrentWorkspaceMemberSelected: false, | |
selectedRecordIds: simpleRelationFilterValueSchema.parse( | |
recordFilterUsedInDropdown?.value, | |
), | |
}) | |
.parse(recordFilterUsedInDropdown?.value ?? null); |
const recordFilterSelectedRecords = isNonEmptyString( | ||
recordFilterUsedInDropdown?.value, | ||
) | ||
? JSON.parse(viewFilterUsedInDropdown.value) | ||
? JSON.parse(recordFilterUsedInDropdown.value) | ||
: []; |
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.
logic: Similar issue here - if recordFilterUsedInDropdown is undefined, attempting to access recordFilterUsedInDropdown.value on line 71 will cause a runtime error.
const recordFilterSelectedRecords = isNonEmptyString( | |
recordFilterUsedInDropdown?.value, | |
) | |
? JSON.parse(viewFilterUsedInDropdown.value) | |
? JSON.parse(recordFilterUsedInDropdown.value) | |
: []; | |
const recordFilterSelectedRecords = isNonEmptyString( | |
recordFilterUsedInDropdown?.value, | |
) | |
? JSON.parse(recordFilterUsedInDropdown?.value ?? '') | |
: []; |
@@ -49,7 +49,7 @@ export const AdvancedFilterRootLevelViewFilterGroup = ({ | |||
return ( | |||
<StyledContainer> | |||
{childViewFiltersAndViewFilterGroups.map((child, i) => | |||
child.__typename === 'ViewFilterGroup' ? ( | |||
(child as any).__typename === 'ViewFilterGroup' ? ( |
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.
can we avoid it?
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'll try yes
- Fixed bug with aggregate not taking current record filters
This PR removes what's left from record filter and record sort previous logic to handle CRUD and state management with view.
So everything that is named combinedFilter and combinedSort is removed here.
We implement currentRecordFilters and currentRecordSorts everywhere.
We also remove the event in a state onSortSelectComponentState. (a pattern we want to avoid)