Deprecate ViewSort typing (#14476)

Continuing the work to deprecate the old ViewSorts and leverage types
that are available in graphql.tsx codegen as we have migrated views to
codegen
This commit is contained in:
Charles Bochet
2025-09-14 17:17:35 +02:00
committed by GitHub
parent f46d67f9f3
commit 72da21217f
40 changed files with 375 additions and 314 deletions
+1 -1
View File
@@ -62,7 +62,7 @@ const jestConfig = {
coverageThreshold: {
global: {
statements: 53,
lines: 53,
lines: 52,
functions: 42,
},
},
@@ -10,10 +10,6 @@ import { selectedRecordSortDirectionComponentState } from '@/object-record/objec
import { visibleRecordFieldsComponentSelector } from '@/object-record/record-field/states/visibleRecordFieldsComponentSelector';
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
import { useUpsertRecordSort } from '@/object-record/record-sort/hooks/useUpsertRecordSort';
import {
RECORD_SORT_DIRECTIONS,
type RecordSortDirection,
} from '@/object-record/record-sort/types/RecordSortDirection';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
@@ -38,6 +34,7 @@ import { findByProperty } from 'twenty-shared/utils';
import { IconX, useIcons } from 'twenty-ui/display';
import { MenuItem } from 'twenty-ui/navigation';
import { v4 } from 'uuid';
import { ViewSortDirection } from '~/generated/graphql';
export const ObjectSortDropdownButton = () => {
const { resetRecordSortDropdownSearchInput } =
@@ -136,7 +133,7 @@ export const ObjectSortDropdownButton = () => {
isRecordSortDirectionDropdownMenuUnfoldedComponentState,
);
const handleSortDirectionClick = (sortDirection: RecordSortDirection) => {
const handleSortDirectionClick = (sortDirection: ViewSortDirection) => {
setSelectedRecordSortDirection(sortDirection);
setIsRecordSortDirectionMenuUnfolded(false);
};
@@ -190,21 +187,24 @@ export const ObjectSortDropdownButton = () => {
</DropdownMenuHeader>
<DropdownMenuInnerSelect
dropdownId="record-sort-direction-dropdown"
options={RECORD_SORT_DIRECTIONS.map((sortDirection) => ({
value: sortDirection,
label: sortDirection === 'asc' ? t`Ascending` : t`Descending`,
}))}
options={[ViewSortDirection.ASC, ViewSortDirection.DESC].map(
(sortDirection) => ({
value: sortDirection,
label:
sortDirection === ViewSortDirection.ASC
? t`Ascending`
: t`Descending`,
}),
)}
selectedOption={{
value: selectedRecordSortDirection,
label:
selectedRecordSortDirection === 'asc'
selectedRecordSortDirection === ViewSortDirection.ASC
? t`Ascending`
: t`Descending`,
}}
onChange={(sortDirection) =>
handleSortDirectionClick(
sortDirection.value as RecordSortDirection,
)
handleSortDirectionClick(sortDirection.value as ViewSortDirection)
}
widthInPixels={GenericDropdownContentWidth.ExtraLarge}
/>
@@ -1,6 +1,7 @@
import { isRecordSortDirectionDropdownMenuUnfoldedComponentState } from '@/object-record/object-sort-dropdown/states/isRecordSortDirectionDropdownMenuUnfoldedComponentState';
import { selectedRecordSortDirectionComponentState } from '@/object-record/object-sort-dropdown/states/selectedRecordSortDirectionComponentState';
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
import { ViewSortDirection } from '~/generated/graphql';
export const useResetSortDropdown = () => {
const setIsRecordSortDirectionDropdownMenuUnfolded =
@@ -14,7 +15,7 @@ export const useResetSortDropdown = () => {
const resetSortDropdown = () => {
setIsRecordSortDirectionDropdownMenuUnfolded(false);
setSelectedRecordSortDirection('asc');
setSelectedRecordSortDirection(ViewSortDirection.ASC);
};
return {
@@ -1,10 +1,10 @@
import { ObjectSortDropdownComponentInstanceContext } from '@/object-record/object-sort-dropdown/states/context/ObjectSortDropdownComponentInstanceContext';
import { type RecordSortDirection } from '@/object-record/record-sort/types/RecordSortDirection';
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
import { ViewSortDirection } from '~/generated/graphql';
export const selectedRecordSortDirectionComponentState =
createComponentState<RecordSortDirection>({
createComponentState<ViewSortDirection>({
key: 'selectedRecordSortDirectionComponentState',
defaultValue: 'asc',
defaultValue: ViewSortDirection.ASC,
componentInstanceContext: ObjectSortDropdownComponentInstanceContext,
});
@@ -4,7 +4,10 @@ import { type RecordGqlOperationOrderBy } from '@/object-record/graphql/types/Re
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
import { type RecordSort } from '@/object-record/record-sort/types/RecordSort';
import { type EachTestingContext } from 'twenty-shared/testing';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import {
FieldMetadataType,
ViewSortDirection,
} from '~/generated-metadata/graphql';
const fields = [
{
@@ -81,7 +84,7 @@ const turnSortsIntoOrderByTestUseCases: TurnSortsIntoOrderTestContext[] = [
{
id: 'id',
fieldMetadataId: 'field1',
direction: 'asc',
direction: ViewSortDirection.ASC,
},
],
expected: [{ field1: 'AscNullsFirst' }, { position: 'AscNullsFirst' }],
@@ -98,12 +101,12 @@ const turnSortsIntoOrderByTestUseCases: TurnSortsIntoOrderTestContext[] = [
{
id: 'id',
fieldMetadataId: 'field1',
direction: 'asc',
direction: ViewSortDirection.ASC,
},
{
id: 'id',
fieldMetadataId: 'field2',
direction: 'desc',
direction: ViewSortDirection.DESC,
},
],
expected: [
@@ -121,7 +124,7 @@ const turnSortsIntoOrderByTestUseCases: TurnSortsIntoOrderTestContext[] = [
{
id: 'id',
fieldMetadataId: 'invalidField',
direction: 'asc',
direction: ViewSortDirection.ASC,
},
],
expected: [{ position: 'AscNullsFirst' }],
@@ -135,7 +138,7 @@ const turnSortsIntoOrderByTestUseCases: TurnSortsIntoOrderTestContext[] = [
{
id: 'id',
fieldMetadataId: 'invalidField',
direction: 'asc',
direction: ViewSortDirection.ASC,
},
],
expected: [],
@@ -10,6 +10,7 @@ import { hasObjectMetadataItemPositionField } from '@/object-metadata/utils/hasO
import { type RecordSort } from '@/object-record/record-sort/types/RecordSort';
import { type OrderBy } from '@/types/OrderBy';
import { isDefined } from 'twenty-shared/utils';
import { ViewSortDirection } from '~/generated/graphql';
export const turnSortsIntoOrderBy = (
objectMetadataItem: ObjectMetadataItem,
@@ -29,7 +30,9 @@ export const turnSortsIntoOrderBy = (
}
const direction: OrderBy =
sort.direction === 'asc' ? 'AscNullsFirst' : 'DescNullsLast';
sort.direction === ViewSortDirection.ASC
? 'AscNullsFirst'
: 'DescNullsLast';
return getOrderByForFieldMetadataType(correspondingField, direction);
})
@@ -6,6 +6,7 @@ import { useUpsertRecordSort } from '@/object-record/record-sort/hooks/useUpsert
import { type RecordSort } from '@/object-record/record-sort/types/RecordSort';
import { isDefined } from 'twenty-shared/utils';
import { v4 } from 'uuid';
import { ViewSortDirection } from '~/generated/graphql';
type UseHandleToggleColumnSortProps = {
objectMetadataItemId: string;
@@ -35,7 +36,7 @@ export const useHandleToggleColumnSort = ({
const newSort: RecordSort = {
id: v4(),
fieldMetadataId,
direction: 'asc',
direction: ViewSortDirection.ASC,
};
upsertRecordSort(newSort);
@@ -1,7 +1,7 @@
import { type RecordSortDirection } from '@/object-record/record-sort/types/RecordSortDirection';
import { type ViewSortDirection } from '~/generated/graphql';
export type RecordSort = {
id: string;
fieldMetadataId: string;
direction: RecordSortDirection;
direction: ViewSortDirection;
};
@@ -1,3 +0,0 @@
export const RECORD_SORT_DIRECTIONS = ['asc', 'desc'] as const;
export type RecordSortDirection = (typeof RECORD_SORT_DIRECTIONS)[number];
@@ -4,6 +4,7 @@ import { useUpsertRecordSort } from '@/object-record/record-sort/hooks/useUpsert
import { type RecordSort } from '@/object-record/record-sort/types/RecordSort';
import { SortOrFilterChip } from '@/views/components/SortOrFilterChip';
import { IconArrowDown, IconArrowUp } from 'twenty-ui/display';
import { ViewSortDirection } from '~/generated/graphql';
type EditableSortChipProps = {
recordSort: RecordSort;
@@ -25,9 +26,11 @@ export const EditableSortChip = ({ recordSort }: EditableSortChipProps) => {
const handleClick = () => {
const newSort: RecordSort = {
...recordSort,
direction: recordSort.direction === 'asc' ? 'desc' : 'asc',
direction:
recordSort.direction === ViewSortDirection.ASC
? ViewSortDirection.DESC
: ViewSortDirection.ASC,
};
upsertRecordSort(newSort);
};
@@ -36,7 +39,11 @@ export const EditableSortChip = ({ recordSort }: EditableSortChipProps) => {
key={recordSort.fieldMetadataId}
testId={recordSort.fieldMetadataId}
labelValue={fieldMetadataItem.label}
Icon={recordSort.direction === 'desc' ? IconArrowDown : IconArrowUp}
Icon={
recordSort.direction === ViewSortDirection.DESC
? IconArrowDown
: IconArrowUp
}
onRemove={handleRemoveClick}
onClick={handleClick}
type="sort"
@@ -6,7 +6,6 @@ import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/ho
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
import { hasInitializedCurrentRecordSortsComponentFamilyState } from '@/views/states/hasInitializedCurrentRecordSortsComponentFamilyState';
import { coreViewFromViewIdFamilySelector } from '@/views/states/selectors/coreViewFromViewIdFamilySelector';
import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts';
import { useEffect } from 'react';
import { useRecoilValue } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
@@ -45,7 +44,7 @@ export const ViewBarRecordSortEffect = () => {
}
if (isDefined(currentView)) {
setCurrentRecordSorts(mapViewSortsToSorts(currentView.viewSorts));
setCurrentRecordSorts(currentView.viewSorts);
setHasInitializedCurrentRecordSorts(true);
}
}
@@ -1,19 +1,17 @@
import { act, renderHook } from '@testing-library/react';
import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState';
import { type RecordSort } from '@/object-record/record-sort/types/RecordSort';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { type ViewSort } from '@/views/types/ViewSort';
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
import { coreViewsState } from '@/views/states/coreViewState';
import { type CoreViewSortEssential } from '@/views/types/CoreViewSortEssential';
import { type CoreViewWithRelations } from '@/views/types/CoreViewWithRelations';
import { type View } from '@/views/types/View';
import { isDefined } from 'twenty-shared/utils';
import { ViewSortDirection, type CoreViewSort } from '~/generated/graphql';
import { ViewSortDirection } from '~/generated/graphql';
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper';
import {
mockedCoreViewsData,
@@ -43,24 +41,21 @@ describe('useApplyCurrentViewSortsToCurrentRecordSorts', () => {
throw new Error('Missing mock field metadata item with type TEXT');
}
const mockViewSort: ViewSort = {
__typename: 'ViewSort',
const mockViewSort: CoreViewSortEssential = {
id: 'sort-1',
fieldMetadataId: mockFieldMetadataItem.id,
direction: 'asc',
direction: ViewSortDirection.ASC,
viewId: 'view-1',
};
const allCompaniesView = mockedViewsData[0];
const allCompaniesCoreView = mockedCoreViewsData[0];
const mockCoreViewSort: Omit<CoreViewSort, 'workspaceId'> = {
__typename: 'CoreViewSort',
const mockCoreViewSort: CoreViewSortEssential = {
id: 'sort-1',
fieldMetadataId: mockFieldMetadataItem.id,
direction: ViewSortDirection.ASC,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
viewId: allCompaniesCoreView.id,
viewId: 'view-1',
};
const mockView = {
@@ -111,7 +106,7 @@ describe('useApplyCurrentViewSortsToCurrentRecordSorts', () => {
id: mockViewSort.id,
fieldMetadataId: mockViewSort.fieldMetadataId,
direction: mockViewSort.direction,
} satisfies RecordSort,
},
]);
});
@@ -1,13 +1,13 @@
import { act, renderHook } from '@testing-library/react';
import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState';
import { type RecordSort } from '@/object-record/record-sort/types/RecordSort';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { type ViewSort } from '@/views/types/ViewSort';
import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems';
import { type CoreViewSortEssential } from '@/views/types/CoreViewSortEssential';
import { isDefined } from 'twenty-shared/utils';
import { ViewSortDirection } from '~/generated/graphql';
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper';
import { useApplyViewSortsToCurrentRecordSorts } from '../useApplyViewSortsToCurrentRecordSorts';
@@ -32,11 +32,11 @@ describe('useApplyViewSortsToCurrentRecordSorts', () => {
throw new Error(`Missing mock field metadata Name`);
}
const mockViewSort: ViewSort = {
__typename: 'ViewSort',
const mockViewSort: CoreViewSortEssential = {
id: 'sort-1',
fieldMetadataId: mockFieldMetadataItem.id,
direction: 'asc',
direction: ViewSortDirection.ASC,
viewId: 'view-1',
};
it('should apply view sorts to current record sorts', () => {
@@ -70,7 +70,7 @@ describe('useApplyViewSortsToCurrentRecordSorts', () => {
id: mockViewSort.id,
fieldMetadataId: mockViewSort.fieldMetadataId,
direction: mockViewSort.direction,
} satisfies RecordSort,
},
]);
});
@@ -1,39 +1,26 @@
import { useCallback } from 'react';
import { triggerCreateRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect';
import { triggerDestroyRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerDestroyRecordsOptimisticEffect';
import { triggerUpdateRecordOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerUpdateRecordOptimisticEffect';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordFromCache';
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
import { CREATE_CORE_VIEW_SORT } from '@/views/graphql/mutations/createCoreViewSort';
import { DESTROY_CORE_VIEW_SORT } from '@/views/graphql/mutations/destroyCoreViewSort';
import { UPDATE_CORE_VIEW_SORT } from '@/views/graphql/mutations/updateCoreViewSort';
import { useTriggerViewSortOptimisticEffect } from '@/views/optimistic-effects/hooks/useTriggerViewSortOptimisticEffect';
import { type CoreViewSortEssential } from '@/views/types/CoreViewSortEssential';
import { type GraphQLView } from '@/views/types/GraphQLView';
import { type ViewSort } from '@/views/types/ViewSort';
import { convertViewSortDirectionToCore } from '@/views/utils/convertViewSortDirectionToCore';
import { useApolloClient } from '@apollo/client';
import { isNull } from '@sniptt/guards';
import { isDefined } from 'twenty-shared/utils';
import { type CoreViewSort } from '~/generated/graphql';
export const usePersistViewSortRecords = () => {
const { objectMetadataItem } = useObjectMetadataItem({
objectNameSingular: CoreObjectNameSingular.ViewSort,
});
const getRecordFromCache = useGetRecordFromCache({
objectNameSingular: CoreObjectNameSingular.ViewSort,
});
const { objectMetadataItems } = useObjectMetadataItems();
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
const apolloClient = useApolloClient();
const { triggerViewSortOptimisticEffect } =
useTriggerViewSortOptimisticEffect();
const createCoreViewSortRecords = useCallback(
(viewSortsToCreate: ViewSort[], view: Pick<GraphQLView, 'id'>) => {
(
viewSortsToCreate: CoreViewSortEssential[],
view: Pick<GraphQLView, 'id'>,
) => {
if (!viewSortsToCreate.length) return;
return Promise.all(
viewSortsToCreate.map((viewSort) =>
@@ -44,35 +31,26 @@ export const usePersistViewSortRecords = () => {
id: viewSort.id,
fieldMetadataId: viewSort.fieldMetadataId,
viewId: view.id,
direction: convertViewSortDirectionToCore(viewSort.direction),
direction: viewSort.direction,
} satisfies Partial<CoreViewSort>,
},
update: (cache, { data }) => {
const record = data?.['createCoreViewSort'];
if (!isDefined(record)) return;
update: (_cache, { data }) => {
const createdViewSort = data?.createCoreViewSort;
if (!isDefined(createdViewSort)) return;
triggerCreateRecordsOptimisticEffect({
cache,
objectMetadataItem,
recordsToCreate: [record],
objectMetadataItems,
objectPermissionsByObjectMetadataId,
triggerViewSortOptimisticEffect({
createdViewSorts: [createdViewSort],
});
},
}),
),
);
},
[
apolloClient,
objectMetadataItem,
objectMetadataItems,
objectPermissionsByObjectMetadataId,
],
[apolloClient, triggerViewSortOptimisticEffect],
);
const updateCoreViewSortRecords = useCallback(
(viewSortsToUpdate: ViewSort[]) => {
(viewSortsToUpdate: CoreViewSortEssential[]) => {
if (!viewSortsToUpdate.length) return;
return Promise.all(
viewSortsToUpdate.map((viewSort) =>
@@ -81,66 +59,44 @@ export const usePersistViewSortRecords = () => {
variables: {
id: viewSort.id,
input: {
direction: convertViewSortDirectionToCore(viewSort.direction),
direction: viewSort.direction,
} satisfies Partial<CoreViewSort>,
},
update: (cache, { data }) => {
const record = data?.['updateCoreViewSort'];
if (!isDefined(record)) return;
update: (_cache, { data }) => {
const updatedViewSort = data?.updateCoreViewSort;
if (!isDefined(updatedViewSort)) return;
const cachedRecord = getRecordFromCache<ViewSort>(
record.id,
cache,
);
if (isNull(cachedRecord)) return;
triggerUpdateRecordOptimisticEffect({
cache,
objectMetadataItem,
currentRecord: cachedRecord,
updatedRecord: record,
objectMetadataItems,
triggerViewSortOptimisticEffect({
updatedViewSorts: [updatedViewSort],
});
},
}),
),
);
},
[apolloClient, getRecordFromCache, objectMetadataItem, objectMetadataItems],
[apolloClient, triggerViewSortOptimisticEffect],
);
const deleteCoreViewSortRecords = useCallback(
(viewSortIdsToDelete: string[]) => {
if (!viewSortIdsToDelete.length) return;
(viewSortsToDelete: Pick<CoreViewSortEssential, 'id' | 'viewId'>[]) => {
if (!viewSortsToDelete.length) return;
return Promise.all(
viewSortIdsToDelete.map((viewSortId) =>
viewSortsToDelete.map((viewSort) =>
apolloClient.mutate({
mutation: DESTROY_CORE_VIEW_SORT,
variables: {
id: viewSortId,
id: viewSort.id,
},
update: (cache, { data }) => {
const record = data?.['destroyCoreViewSort'];
if (!isDefined(record)) return;
const cachedRecord = getRecordFromCache<ViewSort>(
record.id,
cache,
);
if (isNull(cachedRecord)) return;
triggerDestroyRecordsOptimisticEffect({
cache,
objectMetadataItem,
recordsToDestroy: [cachedRecord],
objectMetadataItems,
update: (_cache) => {
triggerViewSortOptimisticEffect({
deletedViewSorts: [viewSort],
});
},
}),
),
);
},
[apolloClient, getRecordFromCache, objectMetadataItem, objectMetadataItems],
[apolloClient, triggerViewSortOptimisticEffect],
);
return {
@@ -3,7 +3,6 @@ import { currentRecordSortsComponentState } from '@/object-record/record-sort/st
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
import { coreViewFromViewIdFamilySelector } from '@/views/states/selectors/coreViewFromViewIdFamilySelector';
import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts';
import { useRecoilValue } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
@@ -24,7 +23,11 @@ export const useApplyCurrentViewSortsToCurrentRecordSorts = () => {
const applyCurrentViewSortsToCurrentRecordSorts = () => {
if (isDefined(currentView)) {
setCurrentRecordSorts(mapViewSortsToSorts(currentView.viewSorts));
const recordSorts = currentView.viewSorts.map((viewSort) => {
const { viewId: _viewId, ...recordSort } = viewSort;
return recordSort;
});
setCurrentRecordSorts(recordSorts);
}
};
@@ -1,17 +1,20 @@
import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState';
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
import { type ViewSort } from '@/views/types/ViewSort';
import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts';
import { type CoreViewSortEssential } from '@/views/types/CoreViewSortEssential';
export const useApplyViewSortsToCurrentRecordSorts = () => {
const setCurrentRecordSorts = useSetRecoilComponentState(
currentRecordSortsComponentState,
);
const applyViewSortsToCurrentRecordSorts = (viewSorts: ViewSort[]) => {
const recordSortsToApply = mapViewSortsToSorts(viewSorts);
setCurrentRecordSorts(recordSortsToApply);
const applyViewSortsToCurrentRecordSorts = (
viewSorts: CoreViewSortEssential[],
) => {
const recordSorts = viewSorts.map((viewSort) => {
const { viewId: _viewId, ...recordSort } = viewSort;
return recordSort;
});
setCurrentRecordSorts(recordSorts);
};
return {
@@ -6,6 +6,7 @@ import { getViewSortsToDelete } from '@/views/utils/getViewSortsToDelete';
import { getViewSortsToUpdate } from '@/views/utils/getViewSortsToUpdate';
import { mapRecordSortToViewSort } from '@/views/utils/mapRecordSortToViewSort';
import { useMemo } from 'react';
import { isDefined } from 'twenty-shared/utils';
export const useAreViewSortsDifferentFromRecordSorts = () => {
const { currentView } = useGetCurrentViewOnly();
@@ -15,8 +16,11 @@ export const useAreViewSortsDifferentFromRecordSorts = () => {
const viewSortsAreDifferentFromRecordSorts = useMemo(() => {
const currentViewSorts = currentView?.viewSorts ?? [];
if (!isDefined(currentView)) {
return false;
}
const viewSortsFromCurrentRecordSorts = currentRecordSorts.map(
mapRecordSortToViewSort,
(recordSort) => mapRecordSortToViewSort(recordSort, currentView.id),
);
const viewSortsToCreate = getViewSortsToCreate(
@@ -17,7 +17,6 @@ import { isPersistingViewFieldsState } from '@/views/states/isPersistingViewFiel
import { coreViewFromViewIdFamilySelector } from '@/views/states/selectors/coreViewFromViewIdFamilySelector';
import { type GraphQLView } from '@/views/types/GraphQLView';
import { type ViewGroup } from '@/views/types/ViewGroup';
import { type ViewSort } from '@/views/types/ViewSort';
import { ViewType } from '@/views/types/ViewType';
import { convertViewOpenRecordInToCore } from '@/views/utils/convertViewOpenRecordInToCore';
import { convertViewTypeToCore } from '@/views/utils/convertViewTypeToCore';
@@ -206,14 +205,11 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
});
const viewSortsToCreate = currentRecordSorts
.map(mapRecordSortToViewSort)
.map(
(viewSort) =>
({
...viewSort,
id: v4(),
}) satisfies ViewSort,
);
.map((recordSort) => mapRecordSortToViewSort(recordSort, newViewId))
.map((viewSort) => ({
...viewSort,
id: v4(),
}));
await createViewFilterGroupRecords(viewFilterGroupsToCreate, {
id: newViewId,
@@ -9,7 +9,6 @@ import { getFilterableFieldsWithVectorSearch } from '@/views/utils/getFilterable
import { mapViewFieldToRecordField } from '@/views/utils/mapViewFieldToRecordField';
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts';
import { useRecoilCallback } from 'recoil';
import { isDefined, removePropertiesFromRecord } from 'twenty-shared/utils';
import { useFindManyCoreViewsLazyQuery } from '~/generated/graphql';
@@ -121,7 +120,7 @@ export const useRefreshCoreViewsByObjectMetadataId = () => {
view.id,
),
}),
mapViewSortsToSorts(view.viewSorts),
view.viewSorts,
);
}
}
@@ -37,7 +37,9 @@ export const useSaveRecordSortsToViewSorts = () => {
currentRecordSortsCallbackState,
);
const newViewSorts = currentRecordSorts.map(mapRecordSortToViewSort);
const newViewSorts = currentRecordSorts.map((recordSort) =>
mapRecordSortToViewSort(recordSort, currentView.id),
);
const viewSortsToCreate = getViewSortsToCreate(
currentViewSorts,
@@ -54,13 +56,9 @@ export const useSaveRecordSortsToViewSorts = () => {
newViewSorts,
);
const viewSortIdsToDelete = viewSortsToDelete.map(
(viewSort) => viewSort.id,
);
await createViewSortRecords(viewSortsToCreate, currentView);
await updateViewSortRecords(viewSortsToUpdate);
await deleteViewSortRecords(viewSortIdsToDelete);
await deleteViewSortRecords(viewSortsToDelete);
},
[
currentView,
@@ -0,0 +1,141 @@
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { coreViewsState } from '@/views/states/coreViewState';
import { type CoreViewWithRelations } from '@/views/types/CoreViewWithRelations';
import { useApolloClient } from '@apollo/client';
import { useRecoilCallback } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { type CoreViewSort } from '~/generated/graphql';
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
export const useTriggerViewSortOptimisticEffect = () => {
const apolloClient = useApolloClient();
const cache = apolloClient.cache;
const triggerViewSortOptimisticEffect = useRecoilCallback(
({ set, snapshot }) =>
({
createdViewSorts = [],
updatedViewSorts = [],
deletedViewSorts = [],
}: {
createdViewSorts?: Omit<CoreViewSort, 'workspaceId'>[];
updatedViewSorts?: Omit<CoreViewSort, 'workspaceId'>[];
deletedViewSorts?: Pick<CoreViewSort, 'id' | 'viewId'>[];
}) => {
const coreViews = getSnapshotValue(snapshot, coreViewsState);
let newCoreViews = [...coreViews];
createdViewSorts.forEach((createdViewSort) => {
cache.modify<CoreViewWithRelations>({
id: cache.identify({
__typename: 'CoreView',
id: createdViewSort.viewId,
}),
fields: {
viewSorts: (existingViewSorts, { toReference }) => [
...(existingViewSorts ?? []),
toReference(createdViewSort),
],
},
});
const toBeModifiedCoreView = newCoreViews.find(
(coreView) => coreView.id === createdViewSort.viewId,
);
if (isDefined(toBeModifiedCoreView)) {
newCoreViews = [
...newCoreViews.filter(
(coreView) => coreView.id !== createdViewSort.viewId,
),
{
...toBeModifiedCoreView,
viewSorts: [...toBeModifiedCoreView.viewSorts, createdViewSort],
},
];
}
});
updatedViewSorts.forEach((updatedViewSort) => {
cache.modify<CoreViewWithRelations>({
id: cache.identify({
__typename: 'CoreView',
id: updatedViewSort.viewId,
}),
fields: {
viewSorts: (existingViewSorts, { readField, toReference }) =>
existingViewSorts.map((viewSort) => {
const viewSortId = readField<string>('id', viewSort);
if (viewSortId === updatedViewSort.id) {
return toReference(updatedViewSort);
}
return viewSort;
}),
},
});
const toBeModifiedCoreView = newCoreViews.find(
(coreView) => coreView.id === updatedViewSort.viewId,
);
if (isDefined(toBeModifiedCoreView)) {
newCoreViews = [
...newCoreViews.filter(
(coreView) => coreView.id !== updatedViewSort.viewId,
),
{
...toBeModifiedCoreView,
viewSorts: [
...toBeModifiedCoreView.viewSorts.filter(
(viewSort) => viewSort.id !== updatedViewSort.id,
),
updatedViewSort,
],
},
];
}
});
deletedViewSorts.forEach(
(deletedViewSort: Pick<CoreViewSort, 'id' | 'viewId'>) => {
cache.modify<CoreViewWithRelations>({
id: cache.identify({
__typename: 'CoreView',
id: deletedViewSort.viewId,
}),
fields: {
viewSorts: (existingViewSorts, { readField }) =>
existingViewSorts.filter(
(viewSort) =>
readField('id', viewSort) !== deletedViewSort.id,
),
},
});
const toBeModifiedCoreView = newCoreViews.find(
(coreView) => coreView.id === deletedViewSort.viewId,
);
if (isDefined(toBeModifiedCoreView)) {
newCoreViews = [
...newCoreViews.filter(
(coreView) => coreView.id !== deletedViewSort.viewId,
),
{
...toBeModifiedCoreView,
viewSorts: toBeModifiedCoreView.viewSorts.filter(
(viewSort) => viewSort.id !== deletedViewSort.id,
),
},
];
}
},
);
if (!isDeeplyEqual(coreViews, newCoreViews)) {
set(coreViewsState, newCoreViews);
}
},
[cache],
);
return {
triggerViewSortOptimisticEffect,
};
};
@@ -0,0 +1,6 @@
import { type CoreViewSort } from '~/generated/graphql';
export type CoreViewSortEssential = Pick<
CoreViewSort,
'id' | 'fieldMetadataId' | 'direction' | 'viewId'
>;
@@ -1,10 +1,10 @@
import { type CoreViewSortEssential } from '@/views/types/CoreViewSortEssential';
import {
type AggregateOperations,
type CoreViewField,
type CoreViewFilter,
type CoreViewFilterGroup,
type CoreViewGroup,
type CoreViewSort,
type ViewKey,
type ViewOpenRecordIn,
type ViewType,
@@ -27,7 +27,7 @@ export type CoreViewWithRelations = {
CoreViewFilterGroup,
'workspaceId' | 'createdAt' | 'updatedAt'
>[];
viewSorts: Omit<CoreViewSort, 'workspaceId' | 'createdAt' | 'updatedAt'>[];
viewSorts: CoreViewSortEssential[];
kanbanAggregateOperation?: AggregateOperations | null;
kanbanAggregateOperationFieldMetadataId?: string | null;
position: number;
@@ -1,11 +1,11 @@
import { type AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations';
import { type CoreViewSortEssential } from '@/views/types/CoreViewSortEssential';
import { type ViewField } from '@/views/types/ViewField';
import { type ViewFilter } from '@/views/types/ViewFilter';
import { type ViewFilterGroup } from '@/views/types/ViewFilterGroup';
import { type ViewGroup } from '@/views/types/ViewGroup';
import { type ViewKey } from '@/views/types/ViewKey';
import { type ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
import { type ViewSort } from '@/views/types/ViewSort';
import { type ViewType } from '@/views/types/ViewType';
export type GraphQLView = {
@@ -25,7 +25,7 @@ export type GraphQLView = {
viewFields: ViewField[];
viewFilters: ViewFilter[];
viewFilterGroups?: ViewFilterGroup[];
viewSorts: ViewSort[];
viewSorts: CoreViewSortEssential[];
viewGroups: ViewGroup[];
position: number;
icon: string;
@@ -1,11 +1,11 @@
import { type AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations';
import { type CoreViewSortEssential } from '@/views/types/CoreViewSortEssential';
import { type ViewField } from '@/views/types/ViewField';
import { type ViewFilter } from '@/views/types/ViewFilter';
import { type ViewFilterGroup } from '@/views/types/ViewFilterGroup';
import { type ViewGroup } from '@/views/types/ViewGroup';
import { type ViewKey } from '@/views/types/ViewKey';
import { type ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
import { type ViewSort } from '@/views/types/ViewSort';
import { type ViewType } from '@/views/types/ViewType';
export type View = {
@@ -19,7 +19,7 @@ export type View = {
viewGroups: ViewGroup[];
viewFilters: ViewFilter[];
viewFilterGroups?: ViewFilterGroup[];
viewSorts: ViewSort[];
viewSorts: CoreViewSortEssential[];
/**
* @deprecated Use `viewGroups.fieldMetadataId` instead.
*/
@@ -1,8 +0,0 @@
import { type RecordSortDirection } from '@/object-record/record-sort/types/RecordSortDirection';
export type ViewSort = {
__typename: 'ViewSort';
id: string;
fieldMetadataId: string;
direction: RecordSortDirection;
};
@@ -1,13 +1,16 @@
import { type RecordSortDirection } from '@/object-record/record-sort/types/RecordSortDirection';
import { type ViewSort } from '@/views/types/ViewSort';
import { areViewSortsEqual } from '@/views/utils/areViewSortsEqual';
import { type CoreViewSort, ViewSortDirection } from '~/generated/graphql';
describe('areViewSortsEqual', () => {
const baseSort: ViewSort = {
__typename: 'ViewSort',
const baseSort: CoreViewSort = {
__typename: 'CoreViewSort',
id: 'sort-1',
fieldMetadataId: 'field-1',
direction: 'asc',
direction: ViewSortDirection.ASC,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
viewId: 'view-1',
workspaceId: 'workspace-1',
};
it('should return true when all comparable properties are equal', () => {
@@ -19,7 +22,7 @@ describe('areViewSortsEqual', () => {
it('should return false when displayValue is different', () => {
const sortA = { ...baseSort };
const sortB = { ...baseSort, direction: 'desc' as RecordSortDirection };
const sortB = { ...baseSort, direction: 'desc' as ViewSortDirection };
expect(areViewSortsEqual(sortA, sortB)).toBe(false);
});
@@ -1,23 +1,24 @@
import { type ViewSort } from '@/views/types/ViewSort';
import { type CoreViewSortEssential } from '@/views/types/CoreViewSortEssential';
import { ViewSortDirection } from '~/generated/graphql';
import { getViewSortsToCreate } from '../getViewSortsToCreate';
describe('getViewSortsToCreate', () => {
const baseSort: ViewSort = {
__typename: 'ViewSort',
const baseSort: CoreViewSortEssential = {
id: 'sort-1',
fieldMetadataId: 'field-1',
direction: 'asc',
direction: ViewSortDirection.ASC,
viewId: 'view-1',
};
it('should return all sorts when current sorts array is empty', () => {
const currentViewSorts: ViewSort[] = [];
const newViewSorts: ViewSort[] = [
const currentViewSorts: CoreViewSortEssential[] = [];
const newViewSorts: CoreViewSortEssential[] = [
{ ...baseSort },
{
...baseSort,
id: 'sort-2',
fieldMetadataId: 'field-2',
} satisfies ViewSort,
} satisfies CoreViewSortEssential,
];
const result = getViewSortsToCreate(currentViewSorts, newViewSorts);
@@ -26,8 +27,8 @@ describe('getViewSortsToCreate', () => {
});
it('should return empty array when new sorts array is empty', () => {
const currentViewSorts: ViewSort[] = [baseSort];
const newViewSorts: ViewSort[] = [];
const currentViewSorts: CoreViewSortEssential[] = [baseSort];
const newViewSorts: CoreViewSortEssential[] = [];
const result = getViewSortsToCreate(currentViewSorts, newViewSorts);
@@ -40,11 +41,11 @@ describe('getViewSortsToCreate', () => {
...baseSort,
id: 'sort-2',
fieldMetadataId: 'field-2',
} satisfies ViewSort;
} satisfies CoreViewSortEssential;
const currentViewSorts: ViewSort[] = [existingSort];
const currentViewSorts: CoreViewSortEssential[] = [existingSort];
const newViewSorts: ViewSort[] = [
const newViewSorts: CoreViewSortEssential[] = [
existingSort,
newSortWithDifferentFieldMetadataId,
];
@@ -55,8 +56,8 @@ describe('getViewSortsToCreate', () => {
});
it('should handle empty arrays for both inputs', () => {
const currentViewSorts: ViewSort[] = [];
const newViewSorts: ViewSort[] = [];
const currentViewSorts: CoreViewSortEssential[] = [];
const newViewSorts: CoreViewSortEssential[] = [];
const result = getViewSortsToCreate(currentViewSorts, newViewSorts);
@@ -1,17 +1,18 @@
import { type ViewSort } from '@/views/types/ViewSort';
import { type CoreViewSortEssential } from '@/views/types/CoreViewSortEssential';
import { ViewSortDirection } from '~/generated/graphql';
import { getViewSortsToDelete } from '../getViewSortsToDelete';
describe('getViewSortsToDelete', () => {
const baseSort: ViewSort = {
__typename: 'ViewSort',
const baseSort: CoreViewSortEssential = {
id: 'sort-1',
fieldMetadataId: 'field-1',
direction: 'asc',
direction: ViewSortDirection.ASC,
viewId: 'view-1',
};
it('should return empty array when current sorts array is empty', () => {
const currentViewSorts: ViewSort[] = [];
const newViewSorts: ViewSort[] = [baseSort];
const currentViewSorts: CoreViewSortEssential[] = [];
const newViewSorts: CoreViewSortEssential[] = [baseSort];
const result = getViewSortsToDelete(currentViewSorts, newViewSorts);
@@ -20,8 +21,8 @@ describe('getViewSortsToDelete', () => {
it('should return all current sorts when new sorts array is empty', () => {
const existingSort = { ...baseSort };
const currentViewSorts: ViewSort[] = [existingSort];
const newViewSorts: ViewSort[] = [];
const currentViewSorts: CoreViewSortEssential[] = [existingSort];
const newViewSorts: CoreViewSortEssential[] = [];
const result = getViewSortsToDelete(currentViewSorts, newViewSorts);
@@ -32,12 +33,15 @@ describe('getViewSortsToDelete', () => {
const sortToDelete = { ...baseSort };
const sortToKeep = {
...baseSort,
id: 'filter-2',
id: 'sort-2',
fieldMetadataId: 'field-2',
} satisfies ViewSort;
};
const currentViewSorts: ViewSort[] = [sortToDelete, sortToKeep];
const newViewSorts: ViewSort[] = [sortToKeep];
const currentViewSorts: CoreViewSortEssential[] = [
sortToDelete,
sortToKeep,
];
const newViewSorts: CoreViewSortEssential[] = [sortToKeep];
const result = getViewSortsToDelete(currentViewSorts, newViewSorts);
@@ -45,8 +49,8 @@ describe('getViewSortsToDelete', () => {
});
it('should handle empty arrays for both inputs', () => {
const currentViewSorts: ViewSort[] = [];
const newViewSorts: ViewSort[] = [];
const currentViewSorts: CoreViewSortEssential[] = [];
const newViewSorts: CoreViewSortEssential[] = [];
const result = getViewSortsToDelete(currentViewSorts, newViewSorts);
@@ -56,14 +60,14 @@ describe('getViewSortsToDelete', () => {
it('should not delete sorts that match in both fieldMetadataId and direction', () => {
const existingSort = { ...baseSort };
const matchingSort = {
__typename: 'ViewSort',
id: 'sort-2',
fieldMetadataId: 'field-1',
direction: 'asc',
} satisfies ViewSort;
direction: ViewSortDirection.ASC,
viewId: 'view-1',
};
const currentViewSorts: ViewSort[] = [existingSort];
const newViewSorts: ViewSort[] = [matchingSort];
const currentViewSorts: CoreViewSortEssential[] = [existingSort];
const newViewSorts: CoreViewSortEssential[] = [matchingSort];
const result = getViewSortsToDelete(currentViewSorts, newViewSorts);
@@ -1,18 +1,18 @@
import { type RecordSortDirection } from '@/object-record/record-sort/types/RecordSortDirection';
import { type ViewSort } from '@/views/types/ViewSort';
import { type CoreViewSortEssential } from '@/views/types/CoreViewSortEssential';
import { ViewSortDirection } from '~/generated/graphql';
import { getViewSortsToUpdate } from '../getViewSortsToUpdate';
describe('getViewSortsToUpdate', () => {
const baseSort: ViewSort = {
__typename: 'ViewSort',
const baseSort: CoreViewSortEssential = {
id: 'sort-1',
fieldMetadataId: 'field-1',
direction: 'asc' as RecordSortDirection,
direction: ViewSortDirection.ASC,
viewId: 'view-1',
};
it('should return empty array when current sorts array is empty', () => {
const currentViewSorts: ViewSort[] = [];
const newViewSorts: ViewSort[] = [baseSort];
const currentViewSorts: CoreViewSortEssential[] = [];
const newViewSorts: CoreViewSortEssential[] = [baseSort];
const result = getViewSortsToUpdate(currentViewSorts, newViewSorts);
@@ -20,8 +20,8 @@ describe('getViewSortsToUpdate', () => {
});
it('should return empty array when new sorts array is empty', () => {
const currentViewSorts: ViewSort[] = [baseSort];
const newViewSorts: ViewSort[] = [];
const currentViewSorts: CoreViewSortEssential[] = [baseSort];
const newViewSorts: CoreViewSortEssential[] = [];
const result = getViewSortsToUpdate(currentViewSorts, newViewSorts);
@@ -32,11 +32,11 @@ describe('getViewSortsToUpdate', () => {
const existingSort = { ...baseSort };
const updatedSort = {
...baseSort,
direction: 'desc',
} satisfies ViewSort;
direction: ViewSortDirection.DESC,
} satisfies CoreViewSortEssential;
const currentViewSorts: ViewSort[] = [existingSort];
const newViewSorts: ViewSort[] = [updatedSort];
const currentViewSorts: CoreViewSortEssential[] = [existingSort];
const newViewSorts: CoreViewSortEssential[] = [updatedSort];
const result = getViewSortsToUpdate(currentViewSorts, newViewSorts);
@@ -47,8 +47,8 @@ describe('getViewSortsToUpdate', () => {
const existingSort = { ...baseSort };
const sameSort = { ...baseSort };
const currentViewSorts: ViewSort[] = [existingSort];
const newViewSorts: ViewSort[] = [sameSort];
const currentViewSorts: CoreViewSortEssential[] = [existingSort];
const newViewSorts: CoreViewSortEssential[] = [sameSort];
const result = getViewSortsToUpdate(currentViewSorts, newViewSorts);
@@ -56,8 +56,8 @@ describe('getViewSortsToUpdate', () => {
});
it('should handle empty arrays for both inputs', () => {
const currentViewSorts: ViewSort[] = [];
const newViewSorts: ViewSort[] = [];
const currentViewSorts: CoreViewSortEssential[] = [];
const newViewSorts: CoreViewSortEssential[] = [];
const result = getViewSortsToUpdate(currentViewSorts, newViewSorts);
@@ -1,14 +1,11 @@
import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldMetadata';
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
import { type RecordSort } from '@/object-record/record-sort/types/RecordSort';
import { type ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
import { type ViewField } from '@/views/types/ViewField';
import { type ViewFilter } from '@/views/types/ViewFilter';
import { type ViewSort } from '@/views/types/ViewSort';
import { mapColumnDefinitionsToViewFields } from '@/views/utils/mapColumnDefinitionToViewField';
import { mapViewFieldsToColumnDefinitions } from '@/views/utils/mapViewFieldsToColumnDefinitions';
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts';
import { ViewFilterOperand } from 'twenty-shared/types';
import { FieldMetadataType } from '~/generated-metadata/graphql';
@@ -22,27 +19,6 @@ const baseFieldMetadataItem = {
type: FieldMetadataType.FULL_NAME,
};
describe('mapViewSortsToSorts', () => {
it('should map each ViewSort object to a corresponding Sort object', () => {
const viewSorts: ViewSort[] = [
{
__typename: 'ViewSort',
id: 'id',
fieldMetadataId: '05731f68-6e7a-4903-8374-c0b6a9063482',
direction: 'asc',
},
];
const expectedSorts: RecordSort[] = [
{
id: 'id',
fieldMetadataId: '05731f68-6e7a-4903-8374-c0b6a9063482',
direction: 'asc',
},
];
expect(mapViewSortsToSorts(viewSorts)).toEqual(expectedSorts);
});
});
describe('mapViewFiltersToFilters', () => {
it('should map each ViewFilter object to a corresponding Filter object', () => {
const viewFilters: ViewFilter[] = [
@@ -1,16 +1,23 @@
import { type ViewSort } from '@/views/types/ViewSort';
import { type CoreViewSort } from '~/generated/graphql';
import { compareStrictlyExceptForNullAndUndefined } from '~/utils/compareStrictlyExceptForNullAndUndefined';
export const areViewSortsEqual = (viewSortA: ViewSort, viewSortB: ViewSort) => {
const propertiesToCompare: (keyof ViewSort)[] = [
'fieldMetadataId',
'direction',
];
export const areViewSortsEqual = (
viewSortA: Pick<CoreViewSort, 'fieldMetadataId' | 'direction'>,
viewSortB: Pick<CoreViewSort, 'fieldMetadataId' | 'direction'>,
) => {
const propertiesToCompare: (keyof Pick<
CoreViewSort,
'fieldMetadataId' | 'direction'
>)[] = ['fieldMetadataId', 'direction'];
return propertiesToCompare.every((property) =>
compareStrictlyExceptForNullAndUndefined(
viewSortA[property],
viewSortB[property],
viewSortA[
property as keyof Pick<CoreViewSort, 'fieldMetadataId' | 'direction'>
],
viewSortB[
property as keyof Pick<CoreViewSort, 'fieldMetadataId' | 'direction'>
],
),
);
};
@@ -1,14 +0,0 @@
import { type ViewSort } from '@/views/types/ViewSort';
import { type CoreViewSort, ViewSortDirection } from '~/generated/graphql';
export const convertCoreViewSortToViewSort = (
coreViewSort: Pick<CoreViewSort, 'id' | 'fieldMetadataId' | 'direction'>,
): ViewSort => {
return {
__typename: 'ViewSort',
id: coreViewSort.id,
fieldMetadataId: coreViewSort.fieldMetadataId,
direction:
coreViewSort.direction === ViewSortDirection.ASC ? 'asc' : 'desc',
};
};
@@ -6,7 +6,6 @@ import { convertCoreViewFilterToViewFilter } from '@/views/utils/convertCoreView
import { convertCoreViewGroupToViewGroup } from '@/views/utils/convertCoreViewGroupToViewGroup';
import { convertCoreViewKeyToViewKey } from '@/views/utils/convertCoreViewKeyToViewKey';
import { convertCoreViewOpenRecordInToViewOpenRecordIn } from '@/views/utils/convertCoreViewOpenRecordInToViewOpenRecordIn';
import { convertCoreViewSortToViewSort } from '@/views/utils/convertCoreViewSortToViewSort';
import { convertCoreViewTypeToViewType } from '@/views/utils/convertCoreViewTypeToViewType';
export const convertCoreViewToView = (
@@ -37,9 +36,7 @@ export const convertCoreViewToView = (
viewFilterGroups: coreView.viewFilterGroups?.map(
convertCoreViewFilterGroupToViewFilterGroup,
),
viewSorts: coreView.viewSorts.map((viewSort) =>
convertCoreViewSortToViewSort(viewSort),
),
viewSorts: coreView.viewSorts,
kanbanFieldMetadataId: '',
kanbanAggregateOperation: coreView.kanbanAggregateOperation ?? null,
kanbanAggregateOperationFieldMetadataId:
@@ -1,9 +0,0 @@
import { ViewSortDirection } from '~/generated/graphql';
export const convertViewSortDirectionToCore = (
viewSortDirection: string,
): ViewSortDirection => {
return viewSortDirection === 'asc'
? ViewSortDirection.ASC
: ViewSortDirection.DESC;
};
@@ -1,9 +1,10 @@
import { type ViewSort } from '@/views/types/ViewSort';
import { type CoreViewSortEssential } from '@/views/types/CoreViewSortEssential';
import { isDefined } from 'twenty-shared/utils';
import { type CoreViewSort } from '~/generated/graphql';
export const getViewSortsToCreate = (
currentViewSorts: ViewSort[],
newViewSorts: ViewSort[],
currentViewSorts: Pick<CoreViewSort, 'fieldMetadataId'>[],
newViewSorts: CoreViewSortEssential[],
) => {
return newViewSorts.filter((newViewSort) => {
const correspondingViewSort = currentViewSorts.find(
@@ -1,8 +1,8 @@
import { type ViewSort } from '@/views/types/ViewSort';
import { type CoreViewSortEssential } from '@/views/types/CoreViewSortEssential';
export const getViewSortsToDelete = (
currentViewSorts: ViewSort[],
newViewSorts: ViewSort[],
currentViewSorts: CoreViewSortEssential[],
newViewSorts: Pick<CoreViewSortEssential, 'fieldMetadataId'>[],
) => {
return currentViewSorts.filter(
(currentViewSort) =>
@@ -1,10 +1,13 @@
import { type ViewSort } from '@/views/types/ViewSort';
import { type CoreViewSortEssential } from '@/views/types/CoreViewSortEssential';
import { areViewSortsEqual } from '@/views/utils/areViewSortsEqual';
import { isDefined } from 'twenty-shared/utils';
export const getViewSortsToUpdate = (
currentViewSorts: ViewSort[],
newViewSorts: ViewSort[],
currentViewSorts: Pick<
CoreViewSortEssential,
'fieldMetadataId' | 'direction'
>[],
newViewSorts: CoreViewSortEssential[],
) => {
return newViewSorts.filter((newViewSort) => {
const correspondingViewSort = currentViewSorts.find(
@@ -1,9 +1,12 @@
import { type RecordSort } from '@/object-record/record-sort/types/RecordSort';
import { type ViewSort } from '@/views/types/ViewSort';
import { type CoreViewSort } from '~/generated/graphql';
export const mapRecordSortToViewSort = (recordSort: RecordSort): ViewSort => {
export const mapRecordSortToViewSort = (
recordSort: RecordSort,
viewId: string,
): Pick<CoreViewSort, 'id' | 'fieldMetadataId' | 'direction' | 'viewId'> => {
return {
__typename: 'ViewSort',
...recordSort,
} satisfies ViewSort;
viewId,
};
};
@@ -1,15 +0,0 @@
import { type RecordSort } from '@/object-record/record-sort/types/RecordSort';
import { type ViewSort } from '../types/ViewSort';
import { isDefined } from 'twenty-shared/utils';
export const mapViewSortsToSorts = (viewSorts: ViewSort[]): RecordSort[] => {
return viewSorts
.map((viewSort) => {
return {
id: viewSort.id,
fieldMetadataId: viewSort.fieldMetadataId,
direction: viewSort.direction,
};
})
.filter(isDefined);
};