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:
@ -1,7 +1,7 @@
|
|||||||
import styled from '@emotion/styled';
|
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 { 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 { useContext, useRef } from 'react';
|
||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
||||||
import { Key } from 'ts-key-enum';
|
import { Key } from 'ts-key-enum';
|
||||||
|
|
||||||
import { useActionMenu } from '@/action-menu/hooks/useActionMenu';
|
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 { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
|
||||||
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
|
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
|
||||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
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 { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
||||||
import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
|
import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
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 { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||||
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
||||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||||
|
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||||
import { ViewType } from '@/views/types/ViewType';
|
import { ViewType } from '@/views/types/ViewType';
|
||||||
import { useScrollRestoration } from '~/hooks/useScrollRestoration';
|
import { useScrollRestoration } from '~/hooks/useScrollRestoration';
|
||||||
|
|
||||||
@ -142,11 +144,26 @@ export const RecordBoard = () => {
|
|||||||
ActionBarHotkeyScope.ActionBar,
|
ActionBarHotkeyScope.ActionBar,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { currentViewWithCombinedFiltersAndSorts } =
|
||||||
|
useGetCurrentView(recordBoardId);
|
||||||
|
|
||||||
|
const setIsRemoveSortingModalOpen = useSetRecoilState(
|
||||||
|
isRemoveSortingModalOpenState,
|
||||||
|
);
|
||||||
|
|
||||||
const handleDragEnd: OnDragEndResponder = useRecoilCallback(
|
const handleDragEnd: OnDragEndResponder = useRecoilCallback(
|
||||||
({ snapshot }) =>
|
({ snapshot }) =>
|
||||||
(result) => {
|
(result) => {
|
||||||
if (!result.destination) return;
|
if (!result.destination) return;
|
||||||
|
|
||||||
|
const viewSorts =
|
||||||
|
currentViewWithCombinedFiltersAndSorts?.viewSorts || [];
|
||||||
|
|
||||||
|
if (viewSorts.length > 0) {
|
||||||
|
setIsRemoveSortingModalOpen(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const draggedRecordId = result.draggableId;
|
const draggedRecordId = result.draggableId;
|
||||||
const sourceRecordGroupId = result.source.droppableId;
|
const sourceRecordGroupId = result.source.droppableId;
|
||||||
const destinationRecordGroupId = result.destination.droppableId;
|
const destinationRecordGroupId = result.destination.droppableId;
|
||||||
@ -201,6 +218,8 @@ export const RecordBoard = () => {
|
|||||||
recordIndexRecordIdsByGroupFamilyState,
|
recordIndexRecordIdsByGroupFamilyState,
|
||||||
selectFieldMetadataItem,
|
selectFieldMetadataItem,
|
||||||
updateOneRecord,
|
updateOneRecord,
|
||||||
|
setIsRemoveSortingModalOpen,
|
||||||
|
currentViewWithCombinedFiltersAndSorts,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
|
|||||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||||
import { RecordBoard } from '@/object-record/record-board/components/RecordBoard';
|
import { RecordBoard } from '@/object-record/record-board/components/RecordBoard';
|
||||||
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
|
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';
|
import { recordIndexKanbanFieldMetadataIdState } from '@/object-record/record-index/states/recordIndexKanbanFieldMetadataIdState';
|
||||||
|
|
||||||
type RecordIndexBoardContainerProps = {
|
type RecordIndexBoardContainerProps = {
|
||||||
@ -50,6 +51,7 @@ export const RecordIndexBoardContainer = ({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RecordBoard />
|
<RecordBoard />
|
||||||
|
<RecordIndexRemoveSortingModal recordIndexId={recordBoardId} />
|
||||||
</RecordBoardContext.Provider>
|
</RecordBoardContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -6,22 +6,21 @@ import { useDeleteCombinedViewSorts } from '@/views/hooks/useDeleteCombinedViewS
|
|||||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||||
|
|
||||||
export const RecordIndexRemoveSortingModal = ({
|
export const RecordIndexRemoveSortingModal = ({
|
||||||
recordTableId,
|
recordIndexId,
|
||||||
}: {
|
}: {
|
||||||
recordTableId: string;
|
recordIndexId: string;
|
||||||
}) => {
|
}) => {
|
||||||
const { currentViewWithCombinedFiltersAndSorts } =
|
const { currentViewWithCombinedFiltersAndSorts } =
|
||||||
useGetCurrentView(recordTableId);
|
useGetCurrentView(recordIndexId);
|
||||||
|
|
||||||
const viewSorts = currentViewWithCombinedFiltersAndSorts?.viewSorts || [];
|
const viewSorts = currentViewWithCombinedFiltersAndSorts?.viewSorts || [];
|
||||||
const fieldMetadataIds = viewSorts.map(
|
const fieldMetadataIds = viewSorts.map(
|
||||||
(viewSort) => viewSort.fieldMetadataId,
|
(viewSort) => viewSort.fieldMetadataId,
|
||||||
);
|
);
|
||||||
const isRemoveSortingModalOpen = useRecoilState(
|
const [isRemoveSortingModalOpen, setIsRemoveSortingModalOpen] =
|
||||||
isRemoveSortingModalOpenState,
|
useRecoilState(isRemoveSortingModalOpenState);
|
||||||
);
|
|
||||||
|
|
||||||
const { deleteCombinedViewSort } = useDeleteCombinedViewSorts(recordTableId);
|
const { deleteCombinedViewSort } = useDeleteCombinedViewSorts(recordIndexId);
|
||||||
|
|
||||||
const handleRemoveClick = () => {
|
const handleRemoveClick = () => {
|
||||||
fieldMetadataIds.forEach((id) => {
|
fieldMetadataIds.forEach((id) => {
|
||||||
@ -32,8 +31,8 @@ export const RecordIndexRemoveSortingModal = ({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ConfirmationModal
|
<ConfirmationModal
|
||||||
isOpen={isRemoveSortingModalOpen[0]}
|
isOpen={isRemoveSortingModalOpen}
|
||||||
setIsOpen={isRemoveSortingModalOpen[1]}
|
setIsOpen={setIsRemoveSortingModalOpen}
|
||||||
title={'Remove sorting?'}
|
title={'Remove sorting?'}
|
||||||
subtitle={<>This is required to enable manual row reordering.</>}
|
subtitle={<>This is required to enable manual row reordering.</>}
|
||||||
onConfirmClick={() => handleRemoveClick()}
|
onConfirmClick={() => handleRemoveClick()}
|
||||||
|
|||||||
@ -34,7 +34,7 @@ export const RecordIndexTableContainer = ({
|
|||||||
viewBarId={viewBarId}
|
viewBarId={viewBarId}
|
||||||
updateRecordMutation={updateEntity}
|
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 { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
||||||
import { useCurrentRecordGroupDefinition } from '@/object-record/record-group/hooks/useCurrentRecordGroupDefinition';
|
import { useCurrentRecordGroupDefinition } from '@/object-record/record-group/hooks/useCurrentRecordGroupDefinition';
|
||||||
import { useRecordGroupFilter } from '@/object-record/record-group/hooks/useRecordGroupFilter';
|
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 { tableViewFilterGroupsComponentState } from '@/object-record/record-table/states/tableViewFilterGroupsComponentState';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
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 = (
|
export const useFindManyRecordIndexTableParams = (
|
||||||
objectNameSingular: string,
|
objectNameSingular: string,
|
||||||
@ -28,11 +30,18 @@ export const useFindManyRecordIndexTableParams = (
|
|||||||
recordTableId,
|
recordTableId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const tableSorts = useRecoilComponentValueV2(
|
const { currentViewWithCombinedFiltersAndSorts } =
|
||||||
tableSortsComponentState,
|
useGetCurrentView(recordTableId);
|
||||||
|
|
||||||
|
const availableSortDefinitions = useRecoilComponentValueV2(
|
||||||
|
availableSortDefinitionsComponentState,
|
||||||
recordTableId,
|
recordTableId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const viewSorts = currentViewWithCombinedFiltersAndSorts?.viewSorts ?? [];
|
||||||
|
|
||||||
|
const sorts = mapViewSortsToSorts(viewSorts, availableSortDefinitions);
|
||||||
|
|
||||||
const currentRecordFilters = useRecoilComponentValueV2(
|
const currentRecordFilters = useRecoilComponentValueV2(
|
||||||
currentRecordFiltersComponentState,
|
currentRecordFiltersComponentState,
|
||||||
);
|
);
|
||||||
@ -46,7 +55,7 @@ export const useFindManyRecordIndexTableParams = (
|
|||||||
tableViewFilterGroups,
|
tableViewFilterGroups,
|
||||||
);
|
);
|
||||||
|
|
||||||
const orderBy = turnSortsIntoOrderBy(objectMetadataItem, tableSorts);
|
const orderBy = turnSortsIntoOrderBy(objectMetadataItem, sorts);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
|
|||||||
@ -10,10 +10,12 @@ import { currentRecordFiltersComponentState } from '@/object-record/record-filte
|
|||||||
import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter';
|
||||||
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
|
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
|
||||||
import { useRecordBoardRecordGqlFields } from '@/object-record/record-index/hooks/useRecordBoardRecordGqlFields';
|
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 { recordIndexViewFilterGroupsState } from '@/object-record/record-index/states/recordIndexViewFilterGroupsState';
|
||||||
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
|
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
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';
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
type UseLoadRecordIndexBoardProps = {
|
type UseLoadRecordIndexBoardProps = {
|
||||||
@ -45,7 +47,16 @@ export const useLoadRecordIndexBoardColumn = ({
|
|||||||
const currentRecordFilters = useRecoilComponentValueV2(
|
const currentRecordFilters = useRecoilComponentValueV2(
|
||||||
currentRecordFiltersComponentState,
|
currentRecordFiltersComponentState,
|
||||||
);
|
);
|
||||||
const recordIndexSorts = useRecoilValue(recordIndexSortsState);
|
|
||||||
|
const { currentViewWithCombinedFiltersAndSorts } = useGetCurrentView();
|
||||||
|
|
||||||
|
const viewsorts = currentViewWithCombinedFiltersAndSorts?.viewSorts ?? [];
|
||||||
|
|
||||||
|
const sortDefinitions = useRecoilComponentValueV2(
|
||||||
|
availableSortDefinitionsComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const sorts = mapViewSortsToSorts(viewsorts, sortDefinitions);
|
||||||
|
|
||||||
const { filterValueDependencies } = useFilterValueDependencies();
|
const { filterValueDependencies } = useFilterValueDependencies();
|
||||||
|
|
||||||
@ -55,7 +66,8 @@ export const useLoadRecordIndexBoardColumn = ({
|
|||||||
objectMetadataItem?.fields ?? [],
|
objectMetadataItem?.fields ?? [],
|
||||||
recordIndexViewFilterGroups,
|
recordIndexViewFilterGroups,
|
||||||
);
|
);
|
||||||
const orderBy = turnSortsIntoOrderBy(objectMetadataItem, recordIndexSorts);
|
|
||||||
|
const orderBy = turnSortsIntoOrderBy(objectMetadataItem, sorts);
|
||||||
|
|
||||||
const recordGqlFields = useRecordBoardRecordGqlFields({
|
const recordGqlFields = useRecordBoardRecordGqlFields({
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
|
|||||||
@ -33,7 +33,7 @@ export const RecordTableBodyDragDropContextProvider = ({
|
|||||||
|
|
||||||
const viewSorts = currentViewWithCombinedFiltersAndSorts?.viewSorts || [];
|
const viewSorts = currentViewWithCombinedFiltersAndSorts?.viewSorts || [];
|
||||||
|
|
||||||
const setIsRemoveSortingModalOpenState = useSetRecoilState(
|
const setIsRemoveSortingModalOpen = useSetRecoilState(
|
||||||
isRemoveSortingModalOpenState,
|
isRemoveSortingModalOpenState,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ export const RecordTableBodyDragDropContextProvider = ({
|
|||||||
({ snapshot }) =>
|
({ snapshot }) =>
|
||||||
(result: DropResult) => {
|
(result: DropResult) => {
|
||||||
if (viewSorts.length > 0) {
|
if (viewSorts.length > 0) {
|
||||||
setIsRemoveSortingModalOpenState(true);
|
setIsRemoveSortingModalOpen(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ export const RecordTableBodyDragDropContextProvider = ({
|
|||||||
},
|
},
|
||||||
[
|
[
|
||||||
recordIndexAllRecordIdsSelector,
|
recordIndexAllRecordIdsSelector,
|
||||||
setIsRemoveSortingModalOpenState,
|
setIsRemoveSortingModalOpen,
|
||||||
updateOneRow,
|
updateOneRow,
|
||||||
viewSorts.length,
|
viewSorts.length,
|
||||||
],
|
],
|
||||||
|
|||||||
@ -26,7 +26,7 @@ export const RecordTableBodyRecordGroupDragDropContextProvider = ({
|
|||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
});
|
});
|
||||||
|
|
||||||
const setIsRemoveSortingModalOpenState = useSetRecoilState(
|
const setIsRemoveSortingModalOpen = useSetRecoilState(
|
||||||
isRemoveSortingModalOpenState,
|
isRemoveSortingModalOpenState,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ export const RecordTableBodyRecordGroupDragDropContextProvider = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (indexSorts.length > 0) {
|
if (indexSorts.length > 0) {
|
||||||
setIsRemoveSortingModalOpenState(true);
|
setIsRemoveSortingModalOpen(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +129,7 @@ export const RecordTableBodyRecordGroupDragDropContextProvider = ({
|
|||||||
objectMetadataItem.fields,
|
objectMetadataItem.fields,
|
||||||
recordIdsByGroupFamilyState,
|
recordIdsByGroupFamilyState,
|
||||||
updateOneRow,
|
updateOneRow,
|
||||||
setIsRemoveSortingModalOpenState,
|
setIsRemoveSortingModalOpen,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user