From 33178fa8b2a4d89f4d0f47e1add6254b05f5f139 Mon Sep 17 00:00:00 2001 From: Lucas Bordeau Date: Wed, 19 Feb 2025 10:57:13 +0100 Subject: [PATCH] Fix sorts on table and board (#10311) This PR fixes sorts on table and board. The sorts were not taken into account due to the recent view refactor that had the side effect of removing the synchronization between recordSortsState and changing the state. The fix was to use combined view sorts instead, which are currently the source of truth for sorts. Also added a confirmation modal for manual sorting on board. --- .../record-board/components/RecordBoard.tsx | 21 ++++++++++++++++++- .../components/RecordIndexBoardContainer.tsx | 2 ++ .../RecordIndexRemoveSortingModal.tsx | 17 +++++++-------- .../components/RecordIndexTableContainer.tsx | 2 +- .../useFindManyRecordIndexTableParams.ts | 17 +++++++++++---- .../hooks/useLoadRecordIndexBoardColumn.ts | 18 +++++++++++++--- ...RecordTableBodyDragDropContextProvider.tsx | 6 +++--- ...BodyRecordGroupDragDropContextProvider.tsx | 6 +++--- 8 files changed, 65 insertions(+), 24 deletions(-) diff --git a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx index 9214b4f54..33e4dc242 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx @@ -1,7 +1,7 @@ import styled from '@emotion/styled'; import { DragDropContext, OnDragEndResponder } from '@hello-pangea/dnd'; // Atlassian dnd does not support StrictMode from RN 18, so we use a fork @hello-pangea/dnd https://github.com/atlassian/react-beautiful-dnd/issues/2350 import { useContext, useRef } from 'react'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilCallback, useSetRecoilState } from 'recoil'; import { Key } from 'ts-key-enum'; import { useActionMenu } from '@/action-menu/hooks/useActionMenu'; @@ -21,6 +21,7 @@ import { visibleRecordGroupIdsComponentFamilySelector } from '@/object-record/re import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState'; import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { isRemoveSortingModalOpenState } from '@/object-record/record-table/states/isRemoveSortingModalOpenState'; import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope'; import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect'; import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; @@ -31,6 +32,7 @@ import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2'; import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2'; import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useGetCurrentView } from '@/views/hooks/useGetCurrentView'; import { ViewType } from '@/views/types/ViewType'; import { useScrollRestoration } from '~/hooks/useScrollRestoration'; @@ -142,11 +144,26 @@ export const RecordBoard = () => { ActionBarHotkeyScope.ActionBar, ); + const { currentViewWithCombinedFiltersAndSorts } = + useGetCurrentView(recordBoardId); + + const setIsRemoveSortingModalOpen = useSetRecoilState( + isRemoveSortingModalOpenState, + ); + const handleDragEnd: OnDragEndResponder = useRecoilCallback( ({ snapshot }) => (result) => { if (!result.destination) return; + const viewSorts = + currentViewWithCombinedFiltersAndSorts?.viewSorts || []; + + if (viewSorts.length > 0) { + setIsRemoveSortingModalOpen(true); + return; + } + const draggedRecordId = result.draggableId; const sourceRecordGroupId = result.source.droppableId; const destinationRecordGroupId = result.destination.droppableId; @@ -201,6 +218,8 @@ export const RecordBoard = () => { recordIndexRecordIdsByGroupFamilyState, selectFieldMetadataItem, updateOneRecord, + setIsRemoveSortingModalOpen, + currentViewWithCombinedFiltersAndSorts, ], ); diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardContainer.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardContainer.tsx index 73c2f372e..63e9323ba 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardContainer.tsx @@ -6,6 +6,7 @@ import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord'; import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; import { RecordBoard } from '@/object-record/record-board/components/RecordBoard'; import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext'; +import { RecordIndexRemoveSortingModal } from '@/object-record/record-index/components/RecordIndexRemoveSortingModal'; import { recordIndexKanbanFieldMetadataIdState } from '@/object-record/record-index/states/recordIndexKanbanFieldMetadataIdState'; type RecordIndexBoardContainerProps = { @@ -50,6 +51,7 @@ export const RecordIndexBoardContainer = ({ }} > + ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRemoveSortingModal.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRemoveSortingModal.tsx index 1a16e7fee..9f3d0e82a 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRemoveSortingModal.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRemoveSortingModal.tsx @@ -6,22 +6,21 @@ import { useDeleteCombinedViewSorts } from '@/views/hooks/useDeleteCombinedViewS import { useGetCurrentView } from '@/views/hooks/useGetCurrentView'; export const RecordIndexRemoveSortingModal = ({ - recordTableId, + recordIndexId, }: { - recordTableId: string; + recordIndexId: string; }) => { const { currentViewWithCombinedFiltersAndSorts } = - useGetCurrentView(recordTableId); + useGetCurrentView(recordIndexId); const viewSorts = currentViewWithCombinedFiltersAndSorts?.viewSorts || []; const fieldMetadataIds = viewSorts.map( (viewSort) => viewSort.fieldMetadataId, ); - const isRemoveSortingModalOpen = useRecoilState( - isRemoveSortingModalOpenState, - ); + const [isRemoveSortingModalOpen, setIsRemoveSortingModalOpen] = + useRecoilState(isRemoveSortingModalOpenState); - const { deleteCombinedViewSort } = useDeleteCombinedViewSorts(recordTableId); + const { deleteCombinedViewSort } = useDeleteCombinedViewSorts(recordIndexId); const handleRemoveClick = () => { fieldMetadataIds.forEach((id) => { @@ -32,8 +31,8 @@ export const RecordIndexRemoveSortingModal = ({ return ( <> This is required to enable manual row reordering.} onConfirmClick={() => handleRemoveClick()} diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainer.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainer.tsx index 9d3d588c3..290b2bdbb 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainer.tsx @@ -34,7 +34,7 @@ export const RecordIndexTableContainer = ({ viewBarId={viewBarId} updateRecordMutation={updateEntity} /> - + ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useFindManyRecordIndexTableParams.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useFindManyRecordIndexTableParams.ts index 4e69c157a..f3fa29b29 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useFindManyRecordIndexTableParams.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useFindManyRecordIndexTableParams.ts @@ -5,9 +5,11 @@ import { currentRecordFiltersComponentState } from '@/object-record/record-filte import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter'; import { useCurrentRecordGroupDefinition } from '@/object-record/record-group/hooks/useCurrentRecordGroupDefinition'; import { useRecordGroupFilter } from '@/object-record/record-group/hooks/useRecordGroupFilter'; -import { tableSortsComponentState } from '@/object-record/record-table/states/tableSortsComponentState'; import { tableViewFilterGroupsComponentState } from '@/object-record/record-table/states/tableViewFilterGroupsComponentState'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import { useGetCurrentView } from '@/views/hooks/useGetCurrentView'; +import { availableSortDefinitionsComponentState } from '@/views/states/availableSortDefinitionsComponentState'; +import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts'; export const useFindManyRecordIndexTableParams = ( objectNameSingular: string, @@ -28,11 +30,18 @@ export const useFindManyRecordIndexTableParams = ( recordTableId, ); - const tableSorts = useRecoilComponentValueV2( - tableSortsComponentState, + const { currentViewWithCombinedFiltersAndSorts } = + useGetCurrentView(recordTableId); + + const availableSortDefinitions = useRecoilComponentValueV2( + availableSortDefinitionsComponentState, recordTableId, ); + const viewSorts = currentViewWithCombinedFiltersAndSorts?.viewSorts ?? []; + + const sorts = mapViewSortsToSorts(viewSorts, availableSortDefinitions); + const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); @@ -46,7 +55,7 @@ export const useFindManyRecordIndexTableParams = ( tableViewFilterGroups, ); - const orderBy = turnSortsIntoOrderBy(objectMetadataItem, tableSorts); + const orderBy = turnSortsIntoOrderBy(objectMetadataItem, sorts); return { objectNameSingular, diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoardColumn.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoardColumn.ts index d83eecfb7..66df519c6 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoardColumn.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoardColumn.ts @@ -10,10 +10,12 @@ import { currentRecordFiltersComponentState } from '@/object-record/record-filte import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter'; import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState'; import { useRecordBoardRecordGqlFields } from '@/object-record/record-index/hooks/useRecordBoardRecordGqlFields'; -import { recordIndexSortsState } from '@/object-record/record-index/states/recordIndexSortsState'; import { recordIndexViewFilterGroupsState } from '@/object-record/record-index/states/recordIndexViewFilterGroupsState'; import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import { useGetCurrentView } from '@/views/hooks/useGetCurrentView'; +import { availableSortDefinitionsComponentState } from '@/views/states/availableSortDefinitionsComponentState'; +import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts'; import { isDefined } from 'twenty-shared'; type UseLoadRecordIndexBoardProps = { @@ -45,7 +47,16 @@ export const useLoadRecordIndexBoardColumn = ({ const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); - const recordIndexSorts = useRecoilValue(recordIndexSortsState); + + const { currentViewWithCombinedFiltersAndSorts } = useGetCurrentView(); + + const viewsorts = currentViewWithCombinedFiltersAndSorts?.viewSorts ?? []; + + const sortDefinitions = useRecoilComponentValueV2( + availableSortDefinitionsComponentState, + ); + + const sorts = mapViewSortsToSorts(viewsorts, sortDefinitions); const { filterValueDependencies } = useFilterValueDependencies(); @@ -55,7 +66,8 @@ export const useLoadRecordIndexBoardColumn = ({ objectMetadataItem?.fields ?? [], recordIndexViewFilterGroups, ); - const orderBy = turnSortsIntoOrderBy(objectMetadataItem, recordIndexSorts); + + const orderBy = turnSortsIntoOrderBy(objectMetadataItem, sorts); const recordGqlFields = useRecordBoardRecordGqlFields({ objectMetadataItem, diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyDragDropContextProvider.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyDragDropContextProvider.tsx index f59a39023..a332c0626 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyDragDropContextProvider.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyDragDropContextProvider.tsx @@ -33,7 +33,7 @@ export const RecordTableBodyDragDropContextProvider = ({ const viewSorts = currentViewWithCombinedFiltersAndSorts?.viewSorts || []; - const setIsRemoveSortingModalOpenState = useSetRecoilState( + const setIsRemoveSortingModalOpen = useSetRecoilState( isRemoveSortingModalOpenState, ); @@ -41,7 +41,7 @@ export const RecordTableBodyDragDropContextProvider = ({ ({ snapshot }) => (result: DropResult) => { if (viewSorts.length > 0) { - setIsRemoveSortingModalOpenState(true); + setIsRemoveSortingModalOpen(true); return; } @@ -101,7 +101,7 @@ export const RecordTableBodyDragDropContextProvider = ({ }, [ recordIndexAllRecordIdsSelector, - setIsRemoveSortingModalOpenState, + setIsRemoveSortingModalOpen, updateOneRow, viewSorts.length, ], diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyRecordGroupDragDropContextProvider.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyRecordGroupDragDropContextProvider.tsx index 4054c2825..a5024e329 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyRecordGroupDragDropContextProvider.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyRecordGroupDragDropContextProvider.tsx @@ -26,7 +26,7 @@ export const RecordTableBodyRecordGroupDragDropContextProvider = ({ objectNameSingular, }); - const setIsRemoveSortingModalOpenState = useSetRecoilState( + const setIsRemoveSortingModalOpen = useSetRecoilState( isRemoveSortingModalOpenState, ); @@ -69,7 +69,7 @@ export const RecordTableBodyRecordGroupDragDropContextProvider = ({ } if (indexSorts.length > 0) { - setIsRemoveSortingModalOpenState(true); + setIsRemoveSortingModalOpen(true); return; } @@ -129,7 +129,7 @@ export const RecordTableBodyRecordGroupDragDropContextProvider = ({ objectMetadataItem.fields, recordIdsByGroupFamilyState, updateOneRow, - setIsRemoveSortingModalOpenState, + setIsRemoveSortingModalOpen, ], );