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

Clean record filter and record sort #10466

Merged
merged 4 commits into from
Feb 25, 2025

Conversation

lucasbordeau
Copy link
Contributor

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)

- Removed unsaved states for view filters and view sorts
- Use record filter and record sort related hooks and utils where needed instead
Copy link
Contributor

@greptile-apps greptile-apps bot left a 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 and useDeleteCombinedViewFilters/Sorts hooks, replacing them with direct useUpsertRecordFilter/Sort and useRemoveRecordFilter/Sort operations
  • Eliminates the event-in-state pattern by removing onSortSelectComponentState in favor of direct function calls
  • Adds new utility functions like getViewSortsToCreate, getViewSortsToUpdate, and getViewSortsToDelete 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 and currentRecordSortsComponentState

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' ? (
Copy link
Contributor

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',
Copy link
Contributor

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 () => {
Copy link
Contributor

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.

Suggested change
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';
Copy link
Contributor

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.

Comment on lines 59 to 60
// TODO: this should be removed as it is not consistent across re-renders
const [fieldId] = useState(v4());
Copy link
Contributor

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.

Comment on lines 116 to +120
useEffect(() => {
currentViewWithSavedFiltersAndSorts?.viewFields.forEach((viewField) => {
currentView?.viewFields.forEach((viewField) => {
setViewFieldAggregateOperation(viewField);
});
}, [
currentViewWithSavedFiltersAndSorts?.viewFields,
setViewFieldAggregateOperation,
]);
}, [currentView, setViewFieldAggregateOperation]);
Copy link
Contributor

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.

Comment on lines 26 to 31
}, [
applyViewFiltersToCurrentRecordFilters,
getFiltersFromQueryParams,
hasFiltersQueryParams,
resetUnsavedViewStates,
setUnsavedViewFilter,
]);
Copy link
Contributor

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

Suggested change
}, [
applyViewFiltersToCurrentRecordFilters,
getFiltersFromQueryParams,
hasFiltersQueryParams,
resetUnsavedViewStates,
setUnsavedViewFilter,
]);
}, [
applyViewFiltersToCurrentRecordFilters,
getFiltersFromQueryParams,
hasFiltersQueryParams,
]);

Comment on lines +35 to 36
if (!advancedRecordFilterIds) {
throw new Error('No advanced view filters to remove');
Copy link
Contributor

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.

Comment on lines 49 to 57
const { selectedRecordIds } = jsonRelationFilterValueSchema
.catch({
isCurrentWorkspaceMemberSelected: false,
selectedRecordIds: simpleRelationFilterValueSchema.parse(
viewFilterUsedInDropdown?.value,
recordFilterUsedInDropdown?.value,
),
})
.parse(viewFilterUsedInDropdown?.value);
.parse(recordFilterUsedInDropdown?.value);

Copy link
Contributor

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.

Suggested change
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);

Comment on lines +68 to 72
const recordFilterSelectedRecords = isNonEmptyString(
recordFilterUsedInDropdown?.value,
)
? JSON.parse(viewFilterUsedInDropdown.value)
? JSON.parse(recordFilterUsedInDropdown.value)
: [];
Copy link
Contributor

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.

Suggested change
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' ? (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we avoid it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll try yes

@lucasbordeau lucasbordeau enabled auto-merge (squash) February 25, 2025 13:53
@lucasbordeau lucasbordeau merged commit 2247d3f into main Feb 25, 2025
45 checks passed
@lucasbordeau lucasbordeau deleted the refactor/record-filter-and-sort-cleanup branch February 25, 2025 14:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants