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

Add initialization of new record sorts state and added remove record sorts util #10358

Merged
merged 1 commit into from
Feb 20, 2025

Conversation

lucasbordeau
Copy link
Contributor

This PR adds the same synchronization utils and hooks from view to record sorts, as we did with view and record filters.

The goal is to apply what's in the view sorts only when needed.

Also added tests for those utils and hooks.

We also add useRemoveRecordSorts.

- Added useApplyCurrentViewSortsToCurrentRecordSorts
- Added useApplyViewSortsToCurrentRecordSorts
- Added unit tests
- Renamed to isRecordSortDirectionDropdownMenuUnfoldedComponentState
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 introduces synchronization between view sorts and record sorts, mirroring the existing pattern used for view and record filters synchronization.

  • Added new useApplyViewSortsToCurrentRecordSorts and useApplyCurrentViewSortsToCurrentRecordSorts hooks in /packages/twenty-front/src/modules/views/hooks/ to manage sort state synchronization
  • Added useRemoveRecordSort hook in /packages/twenty-front/src/modules/object-record/record-sort/hooks/useRemoveRecordSort.ts for consistent sort removal
  • Renamed state from isRecordSortDirectionMenuUnfolded to isRecordSortDirectionDropdownMenuUnfolded for better clarity
  • Added comprehensive test coverage in /packages/twenty-front/src/modules/views/hooks/__tests__/ for new sort synchronization hooks

12 file(s) reviewed, 8 comment(s)
Edit PR Review Bot Settings | Greptile

Comment on lines +19 to +23
const hasFoundRecordSortInCurrentRecordSorts = currentRecordSorts.some(
(existingSort) => existingSort.fieldMetadataId === fieldMetadataId,
);

if (hasFoundRecordSortInCurrentRecordSorts) {
Copy link
Contributor

Choose a reason for hiding this comment

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

style: Redundant check - the findIndex operation on line 27 already performs this check. This creates unnecessary iteration over the array.

Suggested change
const hasFoundRecordSortInCurrentRecordSorts = currentRecordSorts.some(
(existingSort) => existingSort.fieldMetadataId === fieldMetadataId,
);
if (hasFoundRecordSortInCurrentRecordSorts) {
const indexOfSortToRemove = currentRecordSorts.findIndex(
(existingSort) => existingSort.fieldMetadataId === fieldMetadataId,
);
if (indexOfSortToRemove >= 0) {

Comment on lines 31 to +32
const handleToggleColumnSort = useCallback(
(fieldMetadataId: string) => {
async (fieldMetadataId: string) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: Function is now async but callers may not be prepared to handle the Promise return type. Check all usage sites.

Comment on lines 51 to +53
upsertRecordSort(newSort);

await upsertCombinedViewSort(newSort);
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: No error handling for upsertCombinedViewSort failure. Record sort could be left in inconsistent state if view sort fails.

Comment on lines +48 to +50
const currentSorts = useRecoilComponentValueV2(
currentRecordSortsComponentState,
);
Copy link
Contributor

Choose a reason for hiding this comment

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

style: Verify initial state of currentSorts before applying changes to ensure clean test environment.

Comment on lines +37 to +39
if (!isDefined(mockFieldMetadataItem)) {
throw new Error('Missing mock field metadata item with type TEXT');
}
Copy link
Contributor

Choose a reason for hiding this comment

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

syntax: Error message mentions 'type TEXT' but the field is actually filtered by 'name'

Suggested change
if (!isDefined(mockFieldMetadataItem)) {
throw new Error('Missing mock field metadata item with type TEXT');
}
if (!isDefined(mockFieldMetadataItem)) {
throw new Error('Missing mock field metadata item with name "name"');
}

Comment on lines +108 to +148
it('should not apply sorts when current view is not found', () => {
const { result } = renderHook(
() => {
const { applyCurrentViewSortsToCurrentRecordSorts } =
useApplyCurrentViewSortsToCurrentRecordSorts();

const currentSorts = useRecoilComponentValueV2(
currentRecordSortsComponentState,
);

return {
applyCurrentViewSortsToCurrentRecordSorts,
currentSorts,
};
},
{
wrapper: getJestMetadataAndApolloMocksAndActionMenuWrapper({
apolloMocks: [],
componentInstanceId: 'instanceId',
contextStoreCurrentObjectMetadataNameSingular:
mockObjectMetadataItemNameSingular,
onInitializeRecoilSnapshot: (snapshot) => {
snapshot.set(
contextStoreCurrentViewIdComponentState.atomFamily({
instanceId: 'instanceId',
}),
mockView.id,
);

snapshot.set(prefetchViewsState, []);
},
}),
},
);

act(() => {
result.current.applyCurrentViewSortsToCurrentRecordSorts();
});

expect(result.current.currentSorts).toEqual([]);
});
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: Test sets view ID but empty prefetch state - could lead to inconsistent state. Consider testing with non-existent view ID instead


const currentView = useRecoilValue(
prefetchViewFromViewIdFamilySelector({
viewId: currentViewId ?? '',
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: Empty string fallback could cause unnecessary prefetch calls when currentViewId is null

Comment on lines +31 to +41
const applyCurrentViewSortsToCurrentRecordSorts = () => {
const sortDefinitions = formatFieldMetadataItemsAsSortDefinitions({
fields: sortableFieldMetadataItems,
});

if (isDefined(currentView)) {
setCurrentRecordSorts(
mapViewSortsToSorts(currentView.viewSorts, sortDefinitions),
);
}
};
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: No cleanup of record sorts when currentView is undefined - could leave stale sorts

Suggested change
const applyCurrentViewSortsToCurrentRecordSorts = () => {
const sortDefinitions = formatFieldMetadataItemsAsSortDefinitions({
fields: sortableFieldMetadataItems,
});
if (isDefined(currentView)) {
setCurrentRecordSorts(
mapViewSortsToSorts(currentView.viewSorts, sortDefinitions),
);
}
};
const applyCurrentViewSortsToCurrentRecordSorts = () => {
const sortDefinitions = formatFieldMetadataItemsAsSortDefinitions({
fields: sortableFieldMetadataItems,
});
if (isDefined(currentView)) {
setCurrentRecordSorts(
mapViewSortsToSorts(currentView.viewSorts, sortDefinitions),
);
} else {
setCurrentRecordSorts([]);
}
};

@lucasbordeau lucasbordeau merged commit 3c80e26 into main Feb 20, 2025
47 checks passed
@lucasbordeau lucasbordeau deleted the refactor/apply-view-sorts-to-record-sorts branch February 20, 2025 15:24
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