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.
This commit is contained in:
Lucas Bordeau
2025-02-19 10:57:13 +01:00
committed by GitHub
parent 645065abba
commit 33178fa8b2
8 changed files with 65 additions and 24 deletions
@@ -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,
],
);
@@ -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 = ({
}}
>
<RecordBoard />
<RecordIndexRemoveSortingModal recordIndexId={recordBoardId} />
</RecordBoardContext.Provider>
);
};
@@ -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 (
<>
<ConfirmationModal
isOpen={isRemoveSortingModalOpen[0]}
setIsOpen={isRemoveSortingModalOpen[1]}
isOpen={isRemoveSortingModalOpen}
setIsOpen={setIsRemoveSortingModalOpen}
title={'Remove sorting?'}
subtitle={<>This is required to enable manual row reordering.</>}
onConfirmClick={() => handleRemoveClick()}
@@ -34,7 +34,7 @@ export const RecordIndexTableContainer = ({
viewBarId={viewBarId}
updateRecordMutation={updateEntity}
/>
<RecordIndexRemoveSortingModal recordTableId={recordTableId} />
<RecordIndexRemoveSortingModal recordIndexId={recordTableId} />
</>
);
};
@@ -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,
@@ -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,
@@ -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,
],
@@ -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,
],
);