Remove old view implementation step 1 (#14189)

Let's move forward and get rid of the past... !

Removing prefetchViewState and the prefetch view query.

Next steps:
- renaming Selectors to remove prefetch keywork
- remove old view type and coreViewToView util
- rework optimistic rendering for coreViews
This commit is contained in:
Charles Bochet
2025-09-01 10:25:16 +02:00
committed by GitHub
parent 1e9723a6b7
commit 988f6ee1fa
31 changed files with 120 additions and 1212 deletions
@@ -6,9 +6,7 @@ import { useFavorites } from '@/favorites/hooks/useFavorites';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { prefetchFavoritesState } from '@/prefetch/states/prefetchFavoritesState';
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
import { mockedViewsData } from '~/testing/mock-data/views';
import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems';
import {
initialFavorites,
@@ -27,8 +25,6 @@ describe('useFavorites', () => {
const setPrefetchFavorites = useSetRecoilState(prefetchFavoritesState);
setPrefetchFavorites(initialFavorites);
const setPrefetchViewsState = useSetRecoilState(prefetchViewsState);
setPrefetchViewsState(mockedViewsData);
const setCurrentWorkspaceMember = useSetRecoilState(
currentWorkspaceMemberState,
);
@@ -1,9 +1,7 @@
import { sortFavorites } from '@/favorites/utils/sortFavorites';
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
import { coreViewsState } from '@/views/states/coreViewState';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
import { useRecoilValue } from 'recoil';
import { FeatureFlagKey } from '~/generated/graphql';
import { useFavoritesMetadata } from './useFavoritesMetadata';
import { usePrefetchedFavoritesData } from './usePrefetchedFavoritesData';
import { usePrefetchedFavoritesFoldersData } from './usePrefetchedFavoritesFoldersData';
@@ -17,14 +15,9 @@ export const useFavoritesByFolder = () => {
favoriteRelationFields,
} = useFavoritesMetadata();
const prefetchViews = useRecoilValue(prefetchViewsState);
const coreViews = useRecoilValue(coreViewsState);
const isCoreViewEnabled = useIsFeatureEnabled(
FeatureFlagKey.IS_CORE_VIEW_ENABLED,
);
const views = isCoreViewEnabled ? coreViews : prefetchViews;
const views = coreViews.map(convertCoreViewToView);
const favoritesByFolder = favoriteFolders.map((folder) => ({
folderId: folder.id,
@@ -1,5 +1,6 @@
import { sortFavorites } from '@/favorites/utils/sortFavorites';
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
import { coreViewsState } from '@/views/states/coreViewState';
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
import { useMemo } from 'react';
import { useRecoilValue } from 'recoil';
import { useFavoritesMetadata } from './useFavoritesMetadata';
@@ -13,7 +14,7 @@ export const useSortedFavorites = () => {
favoriteRelationFields,
} = useFavoritesMetadata();
const prefetchViews = useRecoilValue(prefetchViewsState);
const coreViews = useRecoilValue(coreViewsState).map(convertCoreViewToView);
const favoritesSorted = useMemo(() => {
return sortFavorites(
@@ -21,15 +22,15 @@ export const useSortedFavorites = () => {
favoriteRelationFields,
getObjectRecordIdentifierByNameSingular,
true,
prefetchViews,
coreViews,
objectMetadataItems,
);
}, [
coreViews,
favoriteRelationFields,
favorites,
getObjectRecordIdentifierByNameSingular,
objectMetadataItems,
prefetchViews,
]);
const workspaceFavoritesSorted = useMemo(() => {
@@ -38,14 +39,14 @@ export const useSortedFavorites = () => {
favoriteRelationFields,
getObjectRecordIdentifierByNameSingular,
false,
prefetchViews,
coreViews,
objectMetadataItems,
);
}, [
workspaceFavorites,
favoriteRelationFields,
getObjectRecordIdentifierByNameSingular,
prefetchViews,
coreViews,
objectMetadataItems,
]);
@@ -4,23 +4,15 @@ import { useGetObjectRecordIdentifierByNameSingular } from '@/object-metadata/ho
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
import { coreViewsState } from '@/views/states/coreViewState';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
import { useMemo } from 'react';
import { useRecoilValue } from 'recoil';
import {
FeatureFlagKey,
FieldMetadataType,
} from '~/generated-metadata/graphql';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { usePrefetchedFavoritesData } from './usePrefetchedFavoritesData';
export const useWorkspaceFavorites = () => {
const { workspaceFavorites } = usePrefetchedFavoritesData();
const isCoreViewEnabled = useIsFeatureEnabled(
FeatureFlagKey.IS_CORE_VIEW_ENABLED,
);
const prefetchViews = useRecoilValue(prefetchViewsState);
const coreViews = useRecoilValue(coreViewsState);
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
const { objectMetadataItem: favoriteObjectMetadataItem } =
@@ -41,7 +33,7 @@ export const useWorkspaceFavorites = () => {
[favoriteObjectMetadataItem.fields],
);
const views = isCoreViewEnabled ? coreViews : prefetchViews;
const views = coreViews.map(convertCoreViewToView);
const sortedWorkspaceFavorites = useMemo(
() =>
@@ -1,28 +1,16 @@
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
import { coreViewsState } from '@/views/states/coreViewState';
import { type View } from '@/views/types/View';
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
import { extractFeatureFlagMapFromWorkspace } from '@/workspace/utils/extractFeatureFlagMapFromWorkspace';
import { selector } from 'recoil';
import { FeatureFlagKey } from '~/generated/graphql';
export const favoriteViewsWithMinimalDataSelector = selector<
Pick<View, 'id' | 'name' | 'objectMetadataId' | 'icon'>[]
>({
key: 'favoriteViewsWithMinimalDataSelector',
get: ({ get }) => {
const prefetchedViews = get(prefetchViewsState);
const coreViews = get(coreViewsState);
const currentWorkspace = get(currentWorkspaceState);
const featureFlags = extractFeatureFlagMapFromWorkspace(currentWorkspace);
const isCoreViewEnabled = featureFlags[FeatureFlagKey.IS_CORE_VIEW_ENABLED];
const views = isCoreViewEnabled
? coreViews.map(convertCoreViewToView)
: prefetchedViews;
const views = coreViews.map(convertCoreViewToView);
return views.map((view) => ({
id: view.id,
name: view.name,
@@ -7,11 +7,9 @@ import { currentUserWorkspaceState } from '@/auth/states/currentUserWorkspaceSta
import { useDefaultHomePagePath } from '@/navigation/hooks/useDefaultHomePagePath';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations';
import { arePrefetchViewsLoadedState } from '@/prefetch/states/arePrefetchViewsLoaded';
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
import { AppPath } from '@/types/AppPath';
import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
import { ViewType } from '@/views/types/ViewType';
import { coreViewsState } from '@/views/states/coreViewState';
import { ViewOpenRecordIn, ViewType } from '~/generated/graphql';
import { getMockCompanyObjectMetadataItem } from '~/testing/mock-data/companies';
import { mockedUserData } from '~/testing/mock-data/users';
import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems';
@@ -32,39 +30,33 @@ const renderHooks = ({
const setObjectMetadataItems = useSetRecoilState(
objectMetadataItemsState,
);
const setPrefetchViews = useSetRecoilState(prefetchViewsState);
const setArePrefetchViewsLoaded = useSetRecoilState(
arePrefetchViewsLoadedState,
);
const setCoreViews = useSetRecoilState(coreViewsState);
useEffect(() => {
setObjectMetadataItems(generatedMockObjectMetadataItems);
setArePrefetchViewsLoaded(true);
if (withExistingView) {
setPrefetchViews([
setCoreViews([
{
id: 'viewId',
name: 'Test View',
objectMetadataId: getMockCompanyObjectMetadataItem().id,
type: ViewType.Table,
type: ViewType.TABLE,
key: null,
isCompact: false,
openRecordIn: ViewOpenRecordInType.SIDE_PANEL,
openRecordIn: ViewOpenRecordIn.SIDE_PANEL,
viewFields: [],
viewGroups: [],
viewSorts: [],
kanbanFieldMetadataId: '',
kanbanAggregateOperation: AggregateOperations.COUNT,
icon: '',
kanbanAggregateOperationFieldMetadataId: '',
position: 0,
viewFilters: [],
__typename: 'View',
},
]);
} else {
setPrefetchViews([]);
setCoreViews([]);
}
if (withCurrentUser) {
@@ -75,8 +67,7 @@ const renderHooks = ({
setCurrentUser,
setCurrentUserWorkspace,
setObjectMetadataItems,
setPrefetchViews,
setArePrefetchViewsLoaded,
setCoreViews,
]);
return useDefaultHomePagePath();
@@ -3,37 +3,26 @@ import { lastVisitedObjectMetadataItemIdState } from '@/navigation/states/lastVi
import { type ObjectPathInfo } from '@/navigation/types/ObjectPathInfo';
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
import { arePrefetchViewsLoadedState } from '@/prefetch/states/arePrefetchViewsLoaded';
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
import { getObjectPermissionsFromMapByObjectMetadataId } from '@/settings/roles/role-permissions/objects-permissions/utils/getObjectPermissionsFromMapByObjectMetadataId';
import { AppPath } from '@/types/AppPath';
import { SettingsPath } from '@/types/SettingsPath';
import { coreViewsState } from '@/views/states/coreViewState';
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap';
import isEmpty from 'lodash.isempty';
import { useCallback, useMemo } from 'react';
import { useRecoilCallback, useRecoilValue } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { FeatureFlagKey } from '~/generated/graphql';
import { getAppPath } from '~/utils/navigation/getAppPath';
export const useDefaultHomePagePath = () => {
const currentUser = useRecoilValue(currentUserState);
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
const featureFlagsMap = useFeatureFlagsMap();
const isCoreViewEnabled =
featureFlagsMap[FeatureFlagKey.IS_CORE_VIEW_ENABLED];
const {
activeNonSystemObjectMetadataItems,
alphaSortedActiveNonSystemObjectMetadataItems,
} = useFilteredObjectMetadataItems();
const arePrefetchViewsLoaded = useRecoilValue(arePrefetchViewsLoadedState);
const readableAlphaSortedActiveNonSystemObjectMetadataItems = useMemo(() => {
return alphaSortedActiveNonSystemObjectMetadataItems.filter((item) => {
const objectPermissions = getObjectPermissionsFromMapByObjectMetadataId({
@@ -56,27 +45,18 @@ export const useDefaultHomePagePath = () => {
[activeNonSystemObjectMetadataItems],
);
const getFirstView = useRecoilCallback(
({ snapshot }) => {
return (objectMetadataItemId: string | undefined | null) => {
if (!arePrefetchViewsLoaded) {
return undefined;
}
const getFirstView = useRecoilCallback(({ snapshot }) => {
return (objectMetadataItemId: string | undefined | null) => {
const views = snapshot
.getLoadable(coreViewsState)
.getValue()
.map(convertCoreViewToView);
const views = isCoreViewEnabled
? snapshot
.getLoadable(coreViewsState)
.getValue()
.map(convertCoreViewToView)
: snapshot.getLoadable(prefetchViewsState).getValue();
return views.find(
(view) => view.objectMetadataId === objectMetadataItemId,
);
};
},
[arePrefetchViewsLoaded, isCoreViewEnabled],
);
return views.find(
(view) => view.objectMetadataId === objectMetadataItemId,
);
};
}, []);
const firstObjectPathInfo = useMemo<ObjectPathInfo | null>(() => {
const [firstObjectMetadataItem] =
@@ -132,10 +112,6 @@ export const useDefaultHomePagePath = () => {
);
const defaultHomePagePath = useMemo(() => {
if (!arePrefetchViewsLoaded) {
return undefined;
}
if (!isDefined(currentUser)) {
return AppPath.SignInUp;
}
@@ -159,7 +135,6 @@ export const useDefaultHomePagePath = () => {
viewId ? { viewId } : undefined,
);
}, [
arePrefetchViewsLoaded,
currentUser,
getDefaultObjectPathInfo,
readableAlphaSortedActiveNonSystemObjectMetadataItems,
@@ -1,7 +1,7 @@
import { lastVisitedViewPerObjectMetadataItemState } from '@/navigation/states/lastVisitedViewPerObjectMetadataItemState';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
import { type View } from '@/views/types/View';
import { coreViewsState } from '@/views/states/coreViewState';
import { type CoreViewWithRelations } from '@/views/types/CoreViewWithRelations';
import { useRecoilCallback } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
@@ -15,9 +15,11 @@ export const useSetLastVisitedViewForObjectMetadataNamePlural = () => {
objectNamePlural: string;
viewId: string;
}) => {
const views = snapshot.getLoadable(prefetchViewsState).getValue();
const views = snapshot.getLoadable(coreViewsState).getValue();
const view = views.find((view: View) => view.id === viewId);
const view = views.find(
(view: CoreViewWithRelations) => view.id === viewId,
);
const objectMetadataItems = snapshot
.getLoadable(objectMetadataItemsState)
@@ -1,12 +1,10 @@
import { PrefetchRunFavoriteQueriesEffect } from '@/prefetch/components/PrefetchRunFavoriteQueriesEffect';
import { PrefetchRunViewQueryEffect } from '@/prefetch/components/PrefetchRunViewQueryEffect';
import React from 'react';
export const PrefetchDataProvider = ({ children }: React.PropsWithChildren) => {
return (
<>
<PrefetchRunFavoriteQueriesEffect />
<PrefetchRunViewQueryEffect />
{children}
</>
);
@@ -1,64 +0,0 @@
import { useEffect } from 'react';
import { useRecoilCallback, useRecoilValue } from 'recoil';
import { currentUserState } from '@/auth/states/currentUserState';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
import { findAllViewsOperationSignatureFactory } from '@/prefetch/graphql/operation-signatures/factories/findAllViewsOperationSignatureFactory';
import { arePrefetchViewsLoadedState } from '@/prefetch/states/arePrefetchViewsLoaded';
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
import { isPersistingViewFieldsState } from '@/views/states/isPersistingViewFieldsState';
import { type View } from '@/views/types/View';
import { useIsWorkspaceActivationStatusEqualsTo } from '@/workspace/hooks/useIsWorkspaceActivationStatusEqualsTo';
import { isDefined } from 'twenty-shared/utils';
import { WorkspaceActivationStatus } from 'twenty-shared/workspace';
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
export const PrefetchRunViewQueryEffect = () => {
const currentUser = useRecoilValue(currentUserState);
const isWorkspaceActive = useIsWorkspaceActivationStatusEqualsTo(
WorkspaceActivationStatus.ACTIVE,
);
const { objectMetadataItems } = useObjectMetadataItems();
const findAllViewsOperationSignature = findAllViewsOperationSignatureFactory({
objectMetadataItem: objectMetadataItems.find(
(item) => item.nameSingular === CoreObjectNameSingular.View,
),
});
const { records } = useFindManyRecords({
objectNameSingular: CoreObjectNameSingular.View,
filter: findAllViewsOperationSignature.variables.filter,
recordGqlFields: findAllViewsOperationSignature.fields,
skip: !currentUser || !isWorkspaceActive,
});
const setPrefetchViewsState = useRecoilCallback(
({ set, snapshot }) =>
(views: View[]) => {
const existingViews = snapshot
.getLoadable(prefetchViewsState)
.getValue();
if (!isDeeplyEqual(existingViews, views)) {
set(prefetchViewsState, views);
set(arePrefetchViewsLoadedState, true);
}
},
[],
);
const isPersistingViewFields = useRecoilValue(isPersistingViewFieldsState);
useEffect(() => {
if (isDefined(records) && !isPersistingViewFields) {
setPrefetchViewsState(records as View[]);
}
}, [isPersistingViewFields, records, setPrefetchViewsState]);
return <></>;
};
@@ -1,6 +0,0 @@
import { createState } from 'twenty-ui/utilities';
export const arePrefetchViewsLoadedState = createState<boolean>({
key: 'arePrefetchViewsLoadedState',
defaultValue: false,
});
@@ -1,7 +0,0 @@
import { type View } from '@/views/types/View';
import { createState } from 'twenty-ui/utilities';
export const prefetchViewsState = createState<View[]>({
key: 'prefetchViewsState',
defaultValue: [],
});
@@ -1,11 +1,7 @@
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
import { coreViewsState } from '@/views/states/coreViewState';
import { ViewKey } from '@/views/types/ViewKey';
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
import { extractFeatureFlagMapFromWorkspace } from '@/workspace/utils/extractFeatureFlagMapFromWorkspace';
import { selectorFamily } from 'recoil';
import { FeatureFlagKey } from '~/generated/graphql';
export const prefetchIndexViewIdFromObjectMetadataItemFamilySelector =
selectorFamily<string | undefined, { objectMetadataItemId: string }>({
@@ -13,19 +9,9 @@ export const prefetchIndexViewIdFromObjectMetadataItemFamilySelector =
get:
({ objectMetadataItemId }) =>
({ get }) => {
const prefetchedViews = get(prefetchViewsState);
const coreViews = get(coreViewsState);
const currentWorkspace = get(currentWorkspaceState);
const featureFlags =
extractFeatureFlagMapFromWorkspace(currentWorkspace);
const isCoreViewEnabled =
featureFlags[FeatureFlagKey.IS_CORE_VIEW_ENABLED];
const views = isCoreViewEnabled
? coreViews.map(convertCoreViewToView)
: prefetchedViews;
const views = coreViews.map(convertCoreViewToView);
return views?.find(
(view) =>
@@ -1,11 +1,7 @@
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
import { coreViewsState } from '@/views/states/coreViewState';
import { type View } from '@/views/types/View';
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
import { extractFeatureFlagMapFromWorkspace } from '@/workspace/utils/extractFeatureFlagMapFromWorkspace';
import { selectorFamily } from 'recoil';
import { FeatureFlagKey } from '~/generated/graphql';
export const prefetchViewFromViewIdFamilySelector = selectorFamily<
View | undefined,
@@ -15,19 +11,9 @@ export const prefetchViewFromViewIdFamilySelector = selectorFamily<
get:
({ viewId }) =>
({ get }) => {
const prefetchedViews = get(prefetchViewsState);
const coreViews = get(coreViewsState);
const currentWorkspace = get(currentWorkspaceState);
const featureFlags = extractFeatureFlagMapFromWorkspace(currentWorkspace);
const isCoreViewEnabled =
featureFlags[FeatureFlagKey.IS_CORE_VIEW_ENABLED];
const views = isCoreViewEnabled
? coreViews.map(convertCoreViewToView)
: prefetchedViews;
const views = coreViews.map(convertCoreViewToView);
return views?.find((view) => view.id === viewId);
},
});
@@ -1,10 +1,6 @@
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
import { coreViewsState } from '@/views/states/coreViewState';
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
import { extractFeatureFlagMapFromWorkspace } from '@/workspace/utils/extractFeatureFlagMapFromWorkspace';
import { selectorFamily } from 'recoil';
import { FeatureFlagKey } from '~/generated/graphql';
export const prefetchViewIdsFromObjectMetadataItemFamilySelector =
selectorFamily<string[], { objectMetadataItemId: string }>({
@@ -12,19 +8,9 @@ export const prefetchViewIdsFromObjectMetadataItemFamilySelector =
get:
({ objectMetadataItemId }) =>
({ get }) => {
const prefetchedViews = get(prefetchViewsState);
const coreViews = get(coreViewsState);
const currentWorkspace = get(currentWorkspaceState);
const featureFlags =
extractFeatureFlagMapFromWorkspace(currentWorkspace);
const isCoreViewEnabled =
featureFlags[FeatureFlagKey.IS_CORE_VIEW_ENABLED];
const views = isCoreViewEnabled
? coreViews.map(convertCoreViewToView)
: prefetchedViews;
const views = coreViews.map(convertCoreViewToView);
return views
.filter((view) => view.objectMetadataId === objectMetadataItemId)
@@ -1,26 +1,11 @@
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
import { coreViewsState } from '@/views/states/coreViewState';
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
import { extractFeatureFlagMapFromWorkspace } from '@/workspace/utils/extractFeatureFlagMapFromWorkspace';
import { selector } from 'recoil';
import { FeatureFlagKey } from '~/generated/graphql';
export const prefetchViewLengthSelector = selector<number>({
key: 'prefetchViewLengthSelector',
get: ({ get }) => {
const prefetchedViews = get(prefetchViewsState);
const coreViews = get(coreViewsState);
const currentWorkspace = get(currentWorkspaceState);
const featureFlags = extractFeatureFlagMapFromWorkspace(currentWorkspace);
const isCoreViewEnabled = featureFlags[FeatureFlagKey.IS_CORE_VIEW_ENABLED];
const views = isCoreViewEnabled
? coreViews.map(convertCoreViewToView)
: prefetchedViews;
return views?.length ?? 0;
return coreViews?.length ?? 0;
},
});
@@ -1,11 +1,7 @@
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
import { coreViewsState } from '@/views/states/coreViewState';
import { type View } from '@/views/types/View';
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
import { extractFeatureFlagMapFromWorkspace } from '@/workspace/utils/extractFeatureFlagMapFromWorkspace';
import { selectorFamily } from 'recoil';
import { FeatureFlagKey } from '~/generated/graphql';
export const prefetchViewsFromObjectMetadataItemFamilySelector = selectorFamily<
View[],
@@ -15,18 +11,9 @@ export const prefetchViewsFromObjectMetadataItemFamilySelector = selectorFamily<
get:
({ objectMetadataItemId }) =>
({ get }) => {
const prefetchedViews = get(prefetchViewsState);
const coreViews = get(coreViewsState);
const currentWorkspace = get(currentWorkspaceState);
const featureFlags = extractFeatureFlagMapFromWorkspace(currentWorkspace);
const isCoreViewEnabled =
featureFlags[FeatureFlagKey.IS_CORE_VIEW_ENABLED];
const views = isCoreViewEnabled
? coreViews.map(convertCoreViewToView)
: prefetchedViews;
const views = coreViews.map(convertCoreViewToView);
const filteredViews = views.filter(
(view) => view.objectMetadataId === objectMetadataItemId,
@@ -1,11 +1,8 @@
import { useFieldMetadataItem } from '@/object-metadata/hooks/useFieldMetadataItem';
import { useGetRelationMetadata } from '@/object-metadata/hooks/useGetRelationMetadata';
import { useUpdateOneObjectMetadataItem } from '@/object-metadata/hooks/useUpdateOneObjectMetadataItem';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField';
import { useDeleteRecordFromCache } from '@/object-record/cache/hooks/useDeleteRecordFromCache';
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
import { SettingsObjectFieldActiveActionDropdown } from '@/settings/data-model/object-details/components/SettingsObjectFieldActiveActionDropdown';
import { SettingsObjectFieldInactiveActionDropdown } from '@/settings/data-model/object-details/components/SettingsObjectFieldDisabledActionDropdown';
import { settingsObjectFieldsFamilyState } from '@/settings/data-model/object-details/states/settingsObjectFieldsFamilyState';
@@ -14,12 +11,10 @@ import { SettingsPath } from '@/types/SettingsPath';
import { TableCell } from '@/ui/layout/table/components/TableCell';
import { TableRow } from '@/ui/layout/table/components/TableRow';
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
import { type View } from '@/views/types/View';
import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useMemo } from 'react';
import { useRecoilState, useRecoilValue } from 'recoil';
import { useRecoilState } from 'recoil';
import {
isDefined,
isLabelIdentifierFieldMetadataTypes,
@@ -27,7 +22,7 @@ import {
import { IconMinus, IconPlus, useIcons } from 'twenty-ui/display';
import { LightIconButton } from 'twenty-ui/input';
import { UndecoratedLink } from 'twenty-ui/navigation';
import { FeatureFlagKey, RelationType } from '~/generated-metadata/graphql';
import { RelationType } from '~/generated-metadata/graphql';
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
import { type SettingsObjectDetailTableItem } from '~/pages/settings/data-model/types/SettingsObjectDetailTableItem';
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
@@ -119,14 +114,6 @@ export const SettingsObjectFieldItemTableRow = ({
deleteMetadataField,
} = useFieldMetadataItem();
const prefetchViews = useRecoilValue(prefetchViewsState);
const deleteViewFromCache = useDeleteRecordFromCache({
objectNameSingular: CoreObjectNameSingular.View,
});
const featureFlagMap = useFeatureFlagsMap();
const isCoreViewEnabled = featureFlagMap[FeatureFlagKey.IS_CORE_VIEW_ENABLED];
const handleDisableField = async (
activeFieldMetadatItem: FieldMetadataItem,
) => {
@@ -136,19 +123,7 @@ export const SettingsObjectFieldItemTableRow = ({
);
// TODO: Add optimistic rendering for core views
const deletedViewIds = isCoreViewEnabled
? []
: (prefetchViews as View[])
.map((view) => {
// TODO: replace with viewGroups.fieldMetadataId
if (view.kanbanFieldMetadataId === activeFieldMetadatItem.id) {
deleteViewFromCache(view);
return view.id;
}
return null;
})
.filter(isDefined);
const deletedViewIds: string[] = [];
const [baseUrl, queryParams] = navigationMemorizedUrl.includes('?')
? navigationMemorizedUrl.split('?')
@@ -7,7 +7,6 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext';
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
import { ViewBarFilterDropdown } from '@/views/components/ViewBarFilterDropdown';
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
@@ -30,10 +29,7 @@ import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator';
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
import {
mockedCoreViewsData,
mockedViewsData,
} from '~/testing/mock-data/views';
import { mockedCoreViewsData } from '~/testing/mock-data/views';
import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems';
const meta: Meta<typeof ViewBarFilterDropdown> = {
@@ -51,13 +47,10 @@ const meta: Meta<typeof ViewBarFilterDropdown> = {
instanceId,
);
const setPrefetchViews = useSetRecoilState(prefetchViewsState);
const setCoreViews = useSetRecoilState(coreViewsState);
const mockView = mockedViewsData[0];
const mockCoreView = mockedCoreViewsData[0];
setPrefetchViews([mockView]);
setCoreViews([mockCoreView]);
const setCurrentViewId = useSetRecoilComponentState(
@@ -65,7 +58,7 @@ const meta: Meta<typeof ViewBarFilterDropdown> = {
MAIN_CONTEXT_STORE_INSTANCE_ID,
);
setCurrentViewId(mockView.id);
setCurrentViewId(mockCoreView.id);
const columns = companyObjectMetadataItem.fields.map(
(fieldMetadataItem, index) =>
@@ -3,7 +3,6 @@ import { renderHook } from '@testing-library/react';
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState';
import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup';
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups } from '@/views/hooks/useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups';
import { coreViewsState } from '@/views/states/coreViewState';
@@ -90,7 +89,6 @@ describe('useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups', () => {
contextStoreCurrentObjectMetadataNameSingular:
mockObjectMetadataItemNameSingular,
onInitializeRecoilSnapshot: (snapshot) => {
snapshot.set(prefetchViewsState, [mockView]);
snapshot.set(coreViewsState, [mockCoreView]);
},
}),
@@ -148,7 +146,6 @@ describe('useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups', () => {
mockView.id,
);
snapshot.set(prefetchViewsState, []);
snapshot.set(coreViewsState, []);
},
}),
@@ -191,9 +188,6 @@ describe('useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups', () => {
mockView.id,
);
snapshot.set(prefetchViewsState, [
{ ...mockView, viewFilterGroups: [] },
]);
snapshot.set(coreViewsState, [
{ ...mockCoreView, viewFilterGroups: [] },
]);
@@ -4,7 +4,6 @@ import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { coreViewsState } from '@/views/states/coreViewState';
import { type CoreViewWithRelations } from '@/views/types/CoreViewWithRelations';
@@ -86,7 +85,6 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
mockObjectMetadataItemNameSingular,
contextStoreCurrentViewId: mockView.id,
onInitializeRecoilSnapshot: (snapshot) => {
snapshot.set(prefetchViewsState, [mockView]);
snapshot.set(coreViewsState, [mockCoreView]);
},
});
@@ -159,7 +157,6 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
}),
mockView.id,
);
snapshot.set(prefetchViewsState, []);
snapshot.set(coreViewsState, []);
},
}),
@@ -201,9 +198,6 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
}),
mockView.id,
);
snapshot.set(prefetchViewsState, [
{ ...mockView, viewFilters: [] },
]);
snapshot.set(coreViewsState, [
{ ...mockCoreView, viewFilters: [] },
]);
@@ -8,7 +8,6 @@ import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/ho
import { type ViewSort } from '@/views/types/ViewSort';
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
import { coreViewsState } from '@/views/states/coreViewState';
import { type CoreViewWithRelations } from '@/views/types/CoreViewWithRelations';
@@ -97,7 +96,6 @@ describe('useApplyCurrentViewSortsToCurrentRecordSorts', () => {
mockObjectMetadataItemNameSingular,
contextStoreCurrentViewId: mockView.id,
onInitializeRecoilSnapshot: (snapshot) => {
snapshot.set(prefetchViewsState, [mockView]);
snapshot.set(coreViewsState, [mockCoreView]);
},
}),
@@ -146,7 +144,7 @@ describe('useApplyCurrentViewSortsToCurrentRecordSorts', () => {
mockView.id,
);
snapshot.set(prefetchViewsState, []);
snapshot.set(coreViewsState, []);
},
}),
},
@@ -161,7 +159,7 @@ describe('useApplyCurrentViewSortsToCurrentRecordSorts', () => {
it('should handle view with empty sorts', () => {
const viewWithNoSorts = {
...mockView,
...mockCoreView,
viewSorts: [],
};
@@ -193,7 +191,7 @@ describe('useApplyCurrentViewSortsToCurrentRecordSorts', () => {
mockView.id,
);
snapshot.set(prefetchViewsState, [viewWithNoSorts]);
snapshot.set(coreViewsState, [viewWithNoSorts]);
},
}),
},
@@ -3,28 +3,21 @@ import { v4 } from 'uuid';
import { triggerCreateRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect';
import { triggerUpdateRecordOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerUpdateRecordOptimisticEffect';
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
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 { useCreateOneRecordMutation } from '@/object-record/hooks/useCreateOneRecordMutation';
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
import { useUpdateOneRecordMutation } from '@/object-record/hooks/useUpdateOneRecordMutation';
import { CREATE_CORE_VIEW_FIELD } from '@/views/graphql/mutations/createCoreViewField';
import { UPDATE_CORE_VIEW_FIELD } from '@/views/graphql/mutations/updateCoreViewField';
import { type GraphQLView } from '@/views/types/GraphQLView';
import { type ViewField } from '@/views/types/ViewField';
import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap';
import { useApolloClient } from '@apollo/client';
import { isNull } from '@sniptt/guards';
import { isDefined } from 'twenty-shared/utils';
import { FeatureFlagKey, type CoreViewField } from '~/generated/graphql';
import { type CoreViewField } from '~/generated/graphql';
export const usePersistViewFieldRecords = () => {
const featureFlags = useFeatureFlagsMap();
const isCoreViewEnabled = featureFlags[FeatureFlagKey.IS_CORE_VIEW_ENABLED];
const { objectMetadataItem } = useObjectMetadataItem({
objectNameSingular: CoreObjectNameSingular.ViewField,
});
@@ -33,112 +26,10 @@ export const usePersistViewFieldRecords = () => {
objectNameSingular: CoreObjectNameSingular.ViewField,
});
const { createOneRecordMutation } = useCreateOneRecordMutation({
objectNameSingular: CoreObjectNameSingular.ViewField,
});
const { updateOneRecordMutation } = useUpdateOneRecordMutation({
objectNameSingular: CoreObjectNameSingular.ViewField,
});
const { objectMetadataItems } = useObjectMetadataItems();
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
const apolloCoreClient = useApolloCoreClient();
const apolloClient = useApolloClient();
const createViewFieldRecords = useCallback(
(
viewFieldsToCreate: Omit<ViewField, 'definition'>[],
view: Pick<GraphQLView, 'id'>,
) => {
if (!viewFieldsToCreate.length) return;
return Promise.all(
viewFieldsToCreate.map((viewField) =>
apolloCoreClient.mutate({
mutation: createOneRecordMutation,
variables: {
input: {
fieldMetadataId: viewField.fieldMetadataId,
viewId: view.id,
isVisible: viewField.isVisible,
position: viewField.position,
size: viewField.size,
id: v4(),
},
},
update: (cache, { data }) => {
const record = data?.['createViewField'];
if (!record) return;
triggerCreateRecordsOptimisticEffect({
cache,
objectMetadataItem,
recordsToCreate: [record],
objectMetadataItems,
objectPermissionsByObjectMetadataId,
});
},
}),
),
);
},
[
apolloCoreClient,
createOneRecordMutation,
objectMetadataItem,
objectMetadataItems,
objectPermissionsByObjectMetadataId,
],
);
const updateViewFieldRecords = useCallback(
(viewFieldsToUpdate: Omit<ViewField, 'definition'>[]) => {
if (!viewFieldsToUpdate.length) return;
return Promise.all(
viewFieldsToUpdate.map((viewField) =>
apolloCoreClient.mutate({
mutation: updateOneRecordMutation,
variables: {
id: viewField.id,
input: {
isVisible: viewField.isVisible,
position: viewField.position,
size: viewField.size,
aggregateOperation: viewField.aggregateOperation,
},
},
update: (cache, { data }) => {
const record = data?.['updateViewField'];
if (!isDefined(record)) return;
const cachedRecord = getRecordFromCache<ViewField>(
record.id,
cache,
);
if (isNull(cachedRecord)) return;
triggerUpdateRecordOptimisticEffect({
cache,
objectMetadataItem,
currentRecord: cachedRecord,
updatedRecord: record,
objectMetadataItems,
});
},
}),
),
);
},
[
apolloCoreClient,
getRecordFromCache,
objectMetadataItem,
objectMetadataItems,
updateOneRecordMutation,
],
);
const createCoreViewFieldRecords = useCallback(
(
viewFieldsToCreate: Omit<ViewField, 'definition'>[],
@@ -226,11 +117,7 @@ export const usePersistViewFieldRecords = () => {
);
return {
createViewFieldRecords: isCoreViewEnabled
? createCoreViewFieldRecords
: createViewFieldRecords,
updateViewFieldRecords: isCoreViewEnabled
? updateCoreViewFieldRecords
: updateViewFieldRecords,
createViewFieldRecords: createCoreViewFieldRecords,
updateViewFieldRecords: updateCoreViewFieldRecords,
};
};
@@ -3,30 +3,22 @@ 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 { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
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 { useCreateOneRecordMutation } from '@/object-record/hooks/useCreateOneRecordMutation';
import { useDestroyOneRecordMutation } from '@/object-record/hooks/useDestroyOneRecordMutation';
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
import { useUpdateOneRecordMutation } from '@/object-record/hooks/useUpdateOneRecordMutation';
import { CREATE_CORE_VIEW_FILTER_GROUP } from '@/views/graphql/mutations/createCoreViewFilterGroup';
import { DESTROY_CORE_VIEW_FILTER_GROUP } from '@/views/graphql/mutations/destroyCoreViewFilterGroup';
import { UPDATE_CORE_VIEW_FILTER_GROUP } from '@/views/graphql/mutations/updateCoreViewFilterGroup';
import { type GraphQLView } from '@/views/types/GraphQLView';
import { type ViewFilterGroup } from '@/views/types/ViewFilterGroup';
import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap';
import { useApolloClient } from '@apollo/client';
import { isNull } from '@sniptt/guards';
import { isDefined } from 'twenty-shared/utils';
import { type CoreViewFilterGroup, FeatureFlagKey } from '~/generated/graphql';
import { type CoreViewFilterGroup } from '~/generated/graphql';
export const usePersistViewFilterGroupRecords = () => {
const featureFlags = useFeatureFlagsMap();
const isCoreViewEnabled = featureFlags[FeatureFlagKey.IS_CORE_VIEW_ENABLED];
const { objectMetadataItem } = useObjectMetadataItem({
objectNameSingular: CoreObjectNameSingular.ViewFilterGroup,
});
@@ -35,194 +27,10 @@ export const usePersistViewFilterGroupRecords = () => {
objectNameSingular: CoreObjectNameSingular.ViewFilterGroup,
});
const { destroyOneRecordMutation } = useDestroyOneRecordMutation({
objectNameSingular: CoreObjectNameSingular.ViewFilterGroup,
});
const { createOneRecordMutation } = useCreateOneRecordMutation({
objectNameSingular: CoreObjectNameSingular.ViewFilterGroup,
});
const { updateOneRecordMutation } = useUpdateOneRecordMutation({
objectNameSingular: CoreObjectNameSingular.ViewFilterGroup,
});
const { objectMetadataItems } = useObjectMetadataItems();
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
const apolloCoreClient = useApolloCoreClient();
const apolloClient = useApolloClient();
const createViewFilterGroupRecord = useCallback(
async (viewFilterGroup: ViewFilterGroup, view: Pick<GraphQLView, 'id'>) => {
const result = await apolloCoreClient.mutate<{
createViewFilterGroup: ViewFilterGroup;
}>({
mutation: createOneRecordMutation,
variables: {
input: {
id: viewFilterGroup.id,
viewId: view.id,
parentViewFilterGroupId: viewFilterGroup.parentViewFilterGroupId,
logicalOperator: viewFilterGroup.logicalOperator,
positionInViewFilterGroup:
viewFilterGroup.positionInViewFilterGroup,
},
},
update: (cache, { data }) => {
const record = data?.createViewFilterGroup;
if (!isDefined(record)) return;
triggerCreateRecordsOptimisticEffect({
cache,
objectMetadataItem,
recordsToCreate: [record],
objectMetadataItems,
objectPermissionsByObjectMetadataId,
});
},
});
if (!result.data) {
throw new Error('Failed to create view filter group');
}
return { newRecordId: result.data.createViewFilterGroup.id };
},
[
apolloCoreClient,
createOneRecordMutation,
objectMetadataItem,
objectMetadataItems,
objectPermissionsByObjectMetadataId,
],
);
const createViewFilterGroupRecords = useCallback(
async (
viewFilterGroupsToCreate: ViewFilterGroup[],
view: Pick<GraphQLView, 'id'>,
) => {
if (!viewFilterGroupsToCreate.length) return [];
const oldToNewId = new Map<string, string>();
for (const viewFilterGroupToCreate of viewFilterGroupsToCreate) {
const newParentViewFilterGroupId = isDefined(
viewFilterGroupToCreate.parentViewFilterGroupId,
)
? (oldToNewId.get(viewFilterGroupToCreate.parentViewFilterGroupId) ??
viewFilterGroupToCreate.parentViewFilterGroupId)
: undefined;
const { newRecordId } = await createViewFilterGroupRecord(
{
...viewFilterGroupToCreate,
parentViewFilterGroupId: newParentViewFilterGroupId,
},
view,
);
oldToNewId.set(viewFilterGroupToCreate.id, newRecordId);
}
const newRecordIds = viewFilterGroupsToCreate.map((viewFilterGroup) => {
const newId = oldToNewId.get(viewFilterGroup.id);
if (!newId) {
throw new Error('Failed to create view filter group');
}
return newId;
});
return newRecordIds;
},
[createViewFilterGroupRecord],
);
const updateViewFilterGroupRecords = useCallback(
(viewFilterGroupsToUpdate: ViewFilterGroup[]) => {
if (!viewFilterGroupsToUpdate.length) return;
return Promise.all(
viewFilterGroupsToUpdate.map((viewFilterGroup) =>
apolloCoreClient.mutate<{ updateViewFilterGroup: ViewFilterGroup }>({
mutation: updateOneRecordMutation,
variables: {
id: viewFilterGroup.id,
input: {
parentViewFilterGroupId:
viewFilterGroup.parentViewFilterGroupId,
logicalOperator: viewFilterGroup.logicalOperator,
positionInViewFilterGroup:
viewFilterGroup.positionInViewFilterGroup,
},
},
update: (cache, { data }) => {
const record = data?.updateViewFilterGroup;
if (!isDefined(record)) return;
const cachedRecord = getRecordFromCache<ViewFilterGroup>(
record.id,
cache,
);
if (!isDefined(cachedRecord)) return;
triggerUpdateRecordOptimisticEffect({
cache,
objectMetadataItem,
currentRecord: cachedRecord,
updatedRecord: record,
objectMetadataItems,
});
},
}),
),
);
},
[
apolloCoreClient,
getRecordFromCache,
objectMetadataItem,
objectMetadataItems,
updateOneRecordMutation,
],
);
const deleteViewFilterGroupRecords = useCallback(
(viewFilterGroupIdsToDelete: string[]) => {
if (!viewFilterGroupIdsToDelete.length) return;
return Promise.all(
viewFilterGroupIdsToDelete.map((viewFilterGroupId) =>
apolloCoreClient.mutate<{ destroyViewFilterGroup: ViewFilterGroup }>({
mutation: destroyOneRecordMutation,
variables: {
id: viewFilterGroupId,
},
update: (cache, { data }) => {
const record = data?.destroyViewFilterGroup;
if (!isDefined(record)) return;
const cachedRecord = getRecordFromCache(record.id, cache);
if (!isDefined(cachedRecord)) return;
triggerDestroyRecordsOptimisticEffect({
cache,
objectMetadataItem,
recordsToDestroy: [cachedRecord],
objectMetadataItems,
});
},
}),
),
);
},
[
apolloCoreClient,
destroyOneRecordMutation,
getRecordFromCache,
objectMetadataItem,
objectMetadataItems,
],
);
const createCoreViewFilterGroupRecord = useCallback(
async (viewFilterGroup: ViewFilterGroup, view: Pick<GraphQLView, 'id'>) => {
const result = await apolloClient.mutate<{
@@ -382,14 +190,8 @@ export const usePersistViewFilterGroupRecords = () => {
);
return {
createViewFilterGroupRecords: isCoreViewEnabled
? createCoreViewFilterGroupRecords
: createViewFilterGroupRecords,
updateViewFilterGroupRecords: isCoreViewEnabled
? updateCoreViewFilterGroupRecords
: updateViewFilterGroupRecords,
deleteViewFilterGroupRecords: isCoreViewEnabled
? deleteCoreViewFilterGroupRecords
: deleteViewFilterGroupRecords,
createViewFilterGroupRecords: createCoreViewFilterGroupRecords,
updateViewFilterGroupRecords: updateCoreViewFilterGroupRecords,
deleteViewFilterGroupRecords: deleteCoreViewFilterGroupRecords,
};
};
@@ -3,31 +3,23 @@ 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 { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
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 { useCreateOneRecordMutation } from '@/object-record/hooks/useCreateOneRecordMutation';
import { useDestroyOneRecordMutation } from '@/object-record/hooks/useDestroyOneRecordMutation';
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
import { useUpdateOneRecordMutation } from '@/object-record/hooks/useUpdateOneRecordMutation';
import { CREATE_CORE_VIEW_FILTER } from '@/views/graphql/mutations/createCoreViewFilter';
import { DESTROY_CORE_VIEW_FILTER } from '@/views/graphql/mutations/destroyCoreViewFilter';
import { UPDATE_CORE_VIEW_FILTER } from '@/views/graphql/mutations/updateCoreViewFilter';
import { type GraphQLView } from '@/views/types/GraphQLView';
import { type ViewFilter } from '@/views/types/ViewFilter';
import { convertViewFilterOperandToCore } from '@/views/utils/convertViewFilterOperandToCore';
import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap';
import { useApolloClient } from '@apollo/client';
import { isNull } from '@sniptt/guards';
import { isDefined } from 'twenty-shared/utils';
import { type CoreViewFilter, FeatureFlagKey } from '~/generated/graphql';
import { type CoreViewFilter } from '~/generated/graphql';
export const usePersistViewFilterRecords = () => {
const featureFlags = useFeatureFlagsMap();
const isCoreViewEnabled = featureFlags[FeatureFlagKey.IS_CORE_VIEW_ENABLED];
const { objectMetadataItem } = useObjectMetadataItem({
objectNameSingular: CoreObjectNameSingular.ViewFilter,
});
@@ -36,156 +28,9 @@ export const usePersistViewFilterRecords = () => {
objectNameSingular: CoreObjectNameSingular.ViewFilter,
});
const { destroyOneRecordMutation } = useDestroyOneRecordMutation({
objectNameSingular: CoreObjectNameSingular.ViewFilter,
});
const { createOneRecordMutation } = useCreateOneRecordMutation({
objectNameSingular: CoreObjectNameSingular.ViewFilter,
});
const { updateOneRecordMutation } = useUpdateOneRecordMutation({
objectNameSingular: CoreObjectNameSingular.ViewFilter,
});
const { objectMetadataItems } = useObjectMetadataItems();
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
const apolloCoreClient = useApolloCoreClient();
const apolloClient = useApolloClient();
const createViewFilterRecords = useCallback(
(viewFiltersToCreate: ViewFilter[], view: Pick<GraphQLView, 'id'>) => {
if (viewFiltersToCreate.length === 0) return;
return Promise.all(
viewFiltersToCreate.map((viewFilter) =>
apolloCoreClient.mutate({
mutation: createOneRecordMutation,
variables: {
input: {
id: viewFilter.id,
fieldMetadataId: viewFilter.fieldMetadataId,
viewId: view.id,
value: viewFilter.value,
displayValue: viewFilter.displayValue,
operand: viewFilter.operand,
viewFilterGroupId: viewFilter.viewFilterGroupId,
positionInViewFilterGroup: viewFilter.positionInViewFilterGroup,
subFieldName: viewFilter.subFieldName ?? null,
} satisfies Partial<ViewFilter>,
},
update: (cache, { data }) => {
const record = data?.['createViewFilter'];
if (!isDefined(record)) return;
triggerCreateRecordsOptimisticEffect({
cache,
objectMetadataItem,
recordsToCreate: [record],
objectMetadataItems,
objectPermissionsByObjectMetadataId,
});
},
}),
),
);
},
[
apolloCoreClient,
createOneRecordMutation,
objectMetadataItem,
objectMetadataItems,
objectPermissionsByObjectMetadataId,
],
);
const updateViewFilterRecords = useCallback(
(viewFiltersToUpdate: ViewFilter[]) => {
if (!viewFiltersToUpdate.length) return;
return Promise.all(
viewFiltersToUpdate.map((viewFilter) =>
apolloCoreClient.mutate({
mutation: updateOneRecordMutation,
variables: {
id: viewFilter.id,
input: {
value: viewFilter.value,
displayValue: viewFilter.displayValue,
operand: viewFilter.operand,
positionInViewFilterGroup: viewFilter.positionInViewFilterGroup,
viewFilterGroupId: viewFilter.viewFilterGroupId,
subFieldName: viewFilter.subFieldName ?? null,
} satisfies Partial<ViewFilter>,
},
update: (cache, { data }) => {
const record = data?.['updateViewFilter'];
if (!isDefined(record)) return;
const cachedRecord = getRecordFromCache<ViewFilter>(
record.id,
cache,
);
if (!isDefined(cachedRecord)) return;
triggerUpdateRecordOptimisticEffect({
cache,
objectMetadataItem,
currentRecord: cachedRecord,
updatedRecord: record,
objectMetadataItems,
});
},
}),
),
);
},
[
apolloCoreClient,
getRecordFromCache,
objectMetadataItem,
objectMetadataItems,
updateOneRecordMutation,
],
);
const deleteViewFilterRecords = useCallback(
(viewFilterIdsToDelete: string[]) => {
if (!viewFilterIdsToDelete.length) return;
return Promise.all(
viewFilterIdsToDelete.map((viewFilterId) =>
apolloCoreClient.mutate({
mutation: destroyOneRecordMutation,
variables: {
id: viewFilterId,
},
update: (cache, { data }) => {
const record = data?.['destroyViewFilter'];
if (!isDefined(record)) return;
const cachedRecord = getRecordFromCache<ViewFilter>(
record.id,
cache,
);
if (!isDefined(cachedRecord)) return;
triggerDestroyRecordsOptimisticEffect({
cache,
objectMetadataItem,
recordsToDestroy: [cachedRecord],
objectMetadataItems,
});
},
}),
),
);
},
[
apolloCoreClient,
destroyOneRecordMutation,
getRecordFromCache,
objectMetadataItem,
objectMetadataItems,
],
);
const createCoreViewFilterRecords = useCallback(
(viewFiltersToCreate: ViewFilter[], view: Pick<GraphQLView, 'id'>) => {
@@ -308,14 +153,8 @@ export const usePersistViewFilterRecords = () => {
);
return {
createViewFilterRecords: isCoreViewEnabled
? createCoreViewFilterRecords
: createViewFilterRecords,
updateViewFilterRecords: isCoreViewEnabled
? updateCoreViewFilterRecords
: updateViewFilterRecords,
deleteViewFilterRecords: isCoreViewEnabled
? deleteCoreViewFilterRecords
: deleteViewFilterRecords,
createViewFilterRecords: createCoreViewFilterRecords,
updateViewFilterRecords: updateCoreViewFilterRecords,
deleteViewFilterRecords: deleteCoreViewFilterRecords,
};
};
@@ -1,17 +1,10 @@
import { useCallback } from 'react';
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { useCreateManyRecords } from '@/object-record/hooks/useCreateManyRecords';
import { useDestroyManyRecords } from '@/object-record/hooks/useDestroyManyRecords';
import { useUpdateOneRecordMutation } from '@/object-record/hooks/useUpdateOneRecordMutation';
import { CREATE_CORE_VIEW_GROUP } from '@/views/graphql/mutations/createCoreViewGroup';
import { DESTROY_CORE_VIEW_GROUP } from '@/views/graphql/mutations/destroyCoreViewGroup';
import { UPDATE_CORE_VIEW_GROUP } from '@/views/graphql/mutations/updateCoreViewGroup';
import { type ViewGroup } from '@/views/types/ViewGroup';
import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap';
import { useApolloClient } from '@apollo/client';
import { FeatureFlagKey } from '~/generated/graphql';
type CreateViewGroupRecordsArgs = {
viewGroupsToCreate: ViewGroup[];
@@ -19,96 +12,8 @@ type CreateViewGroupRecordsArgs = {
};
export const usePersistViewGroupRecords = () => {
const featureFlags = useFeatureFlagsMap();
const isCoreViewEnabled = featureFlags[FeatureFlagKey.IS_CORE_VIEW_ENABLED];
const apolloCoreClient = useApolloCoreClient();
const apolloClient = useApolloClient();
const { createManyRecords } = useCreateManyRecords({
objectNameSingular: CoreObjectNameSingular.ViewGroup,
shouldMatchRootQueryFilter: true,
});
const { updateOneRecordMutation } = useUpdateOneRecordMutation({
objectNameSingular: CoreObjectNameSingular.ViewGroup,
});
const { destroyManyRecords } = useDestroyManyRecords({
objectNameSingular: CoreObjectNameSingular.ViewGroup,
});
const createViewGroupRecords = useCallback(
({ viewGroupsToCreate, viewId }: CreateViewGroupRecordsArgs) => {
if (viewGroupsToCreate.length === 0) return;
return createManyRecords({
recordsToCreate: viewGroupsToCreate.map((viewGroup) => ({
...viewGroup,
viewId,
})),
});
},
[createManyRecords],
);
const updateViewGroupRecords = useCallback(
async (viewGroupsToUpdate: ViewGroup[]) => {
if (!viewGroupsToUpdate.length) return;
const mutationPromises = viewGroupsToUpdate.map((viewGroup) =>
apolloCoreClient.mutate<{ updateViewGroup: ViewGroup }>({
mutation: updateOneRecordMutation,
variables: {
id: viewGroup.id,
input: {
isVisible: viewGroup.isVisible,
position: viewGroup.position,
},
},
// Avoid cache being updated with stale data
fetchPolicy: 'no-cache',
}),
);
const mutationResults = await Promise.all(mutationPromises);
// FixMe: Using useUpdateOneRecord hook that call triggerUpdateRecordsOptimisticEffect is actaully causing multiple records to be created
// This is a temporary fix
mutationResults.forEach(({ data }) => {
const record = data?.['updateViewGroup'];
if (!record) return;
apolloCoreClient.cache.modify({
id: apolloCoreClient.cache.identify({
__typename: 'ViewGroup',
id: record.id,
}),
fields: {
isVisible: () => record.isVisible,
position: () => record.position,
},
});
});
},
[apolloCoreClient, updateOneRecordMutation],
);
const deleteViewGroupRecords = useCallback(
async (viewGroupsToDelete: ViewGroup[]) => {
if (!viewGroupsToDelete.length) return;
const recordIdsToDestroy = viewGroupsToDelete.map(
(viewGroup) => viewGroup.id,
);
return destroyManyRecords({
recordIdsToDestroy,
});
},
[destroyManyRecords],
);
const createCoreViewGroupRecords = useCallback(
({ viewGroupsToCreate, viewId }: CreateViewGroupRecordsArgs) => {
if (viewGroupsToCreate.length === 0) return;
@@ -196,14 +101,8 @@ export const usePersistViewGroupRecords = () => {
);
return {
createViewGroupRecords: isCoreViewEnabled
? createCoreViewGroupRecords
: createViewGroupRecords,
updateViewGroupRecords: isCoreViewEnabled
? updateCoreViewGroupRecords
: updateViewGroupRecords,
deleteViewGroupRecords: isCoreViewEnabled
? deleteCoreViewGroupRecords
: deleteViewGroupRecords,
createViewGroupRecords: createCoreViewGroupRecords,
updateViewGroupRecords: updateCoreViewGroupRecords,
deleteViewGroupRecords: deleteCoreViewGroupRecords,
};
};
@@ -3,31 +3,23 @@ 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 { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
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 { useCreateOneRecordMutation } from '@/object-record/hooks/useCreateOneRecordMutation';
import { useDestroyOneRecordMutation } from '@/object-record/hooks/useDestroyOneRecordMutation';
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
import { useUpdateOneRecordMutation } from '@/object-record/hooks/useUpdateOneRecordMutation';
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 { type GraphQLView } from '@/views/types/GraphQLView';
import { type ViewSort } from '@/views/types/ViewSort';
import { convertViewSortDirectionToCore } from '@/views/utils/convertViewSortDirectionToCore';
import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap';
import { useApolloClient } from '@apollo/client';
import { isNull } from '@sniptt/guards';
import { isDefined } from 'twenty-shared/utils';
import { type CoreViewSort, FeatureFlagKey } from '~/generated/graphql';
import { type CoreViewSort } from '~/generated/graphql';
export const usePersistViewSortRecords = () => {
const featureFlags = useFeatureFlagsMap();
const isCoreViewEnabled = featureFlags[FeatureFlagKey.IS_CORE_VIEW_ENABLED];
const { objectMetadataItem } = useObjectMetadataItem({
objectNameSingular: CoreObjectNameSingular.ViewSort,
});
@@ -36,145 +28,9 @@ export const usePersistViewSortRecords = () => {
objectNameSingular: CoreObjectNameSingular.ViewSort,
});
const { destroyOneRecordMutation } = useDestroyOneRecordMutation({
objectNameSingular: CoreObjectNameSingular.ViewSort,
});
const { createOneRecordMutation } = useCreateOneRecordMutation({
objectNameSingular: CoreObjectNameSingular.ViewSort,
});
const { updateOneRecordMutation } = useUpdateOneRecordMutation({
objectNameSingular: CoreObjectNameSingular.ViewSort,
});
const { objectMetadataItems } = useObjectMetadataItems();
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
const apolloCoreClient = useApolloCoreClient();
const apolloClient = useApolloClient();
const createViewSortRecords = useCallback(
(viewSortsToCreate: ViewSort[], view: Pick<GraphQLView, 'id'>) => {
if (!viewSortsToCreate.length) return;
return Promise.all(
viewSortsToCreate.map((viewSort) =>
apolloCoreClient.mutate({
mutation: createOneRecordMutation,
variables: {
input: {
fieldMetadataId: viewSort.fieldMetadataId,
viewId: view.id,
direction: viewSort.direction,
id: viewSort.id,
},
},
update: (cache, { data }) => {
const record = data?.['createViewSort'];
if (!isDefined(record)) return;
triggerCreateRecordsOptimisticEffect({
cache,
objectMetadataItem,
recordsToCreate: [record],
objectMetadataItems,
objectPermissionsByObjectMetadataId,
});
},
}),
),
);
},
[
apolloCoreClient,
createOneRecordMutation,
objectMetadataItem,
objectMetadataItems,
objectPermissionsByObjectMetadataId,
],
);
const updateViewSortRecords = useCallback(
(viewSortsToUpdate: ViewSort[]) => {
if (!viewSortsToUpdate.length) return;
return Promise.all(
viewSortsToUpdate.map((viewSort) =>
apolloCoreClient.mutate({
mutation: updateOneRecordMutation,
variables: {
id: viewSort.id,
input: {
direction: viewSort.direction,
},
},
update: (cache, { data }) => {
const record = data?.['updateViewSort'];
if (!isDefined(record)) return;
const cachedRecord = getRecordFromCache<ViewSort>(
record.id,
cache,
);
if (!isDefined(cachedRecord)) return;
triggerUpdateRecordOptimisticEffect({
cache,
objectMetadataItem,
currentRecord: cachedRecord,
updatedRecord: record,
objectMetadataItems,
});
},
}),
),
);
},
[
apolloCoreClient,
getRecordFromCache,
objectMetadataItem,
objectMetadataItems,
updateOneRecordMutation,
],
);
const deleteViewSortRecords = useCallback(
(viewSortIdsToDelete: string[]) => {
if (!viewSortIdsToDelete.length) return;
return Promise.all(
viewSortIdsToDelete.map((viewSortId) =>
apolloCoreClient.mutate({
mutation: destroyOneRecordMutation,
variables: {
id: viewSortId,
},
update: (cache, { data }) => {
const record = data?.['destroyViewSort'];
if (!isDefined(record)) return;
const cachedRecord = getRecordFromCache<ViewSort>(
record.id,
cache,
);
if (!isDefined(cachedRecord)) return;
triggerDestroyRecordsOptimisticEffect({
cache,
objectMetadataItem,
recordsToDestroy: [cachedRecord],
objectMetadataItems,
});
},
}),
),
);
},
[
apolloCoreClient,
destroyOneRecordMutation,
getRecordFromCache,
objectMetadataItem,
objectMetadataItems,
],
);
const createCoreViewSortRecords = useCallback(
(viewSortsToCreate: ViewSort[], view: Pick<GraphQLView, 'id'>) => {
@@ -288,14 +144,8 @@ export const usePersistViewSortRecords = () => {
);
return {
createViewSortRecords: isCoreViewEnabled
? createCoreViewSortRecords
: createViewSortRecords,
updateViewSortRecords: isCoreViewEnabled
? updateCoreViewSortRecords
: updateViewSortRecords,
deleteViewSortRecords: isCoreViewEnabled
? deleteCoreViewSortRecords
: deleteViewSortRecords,
createViewSortRecords: createCoreViewSortRecords,
updateViewSortRecords: updateCoreViewSortRecords,
deleteViewSortRecords: deleteCoreViewSortRecords,
};
};
@@ -1,7 +1,4 @@
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
import { useLazyFindManyRecords } from '@/object-record/hooks/useLazyFindManyRecords';
import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState';
import { anyFieldFilterValueComponentState } from '@/object-record/record-filter/states/anyFieldFilterValueComponentState';
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
@@ -19,7 +16,6 @@ import { usePersistViewSortRecords } from '@/views/hooks/internal/usePersistView
import { useRefreshCoreViews } from '@/views/hooks/useRefreshCoreViews';
import { isPersistingViewFieldsState } from '@/views/states/isPersistingViewFieldsState';
import { type GraphQLView } from '@/views/types/GraphQLView';
import { type View } from '@/views/types/View';
import { type ViewGroup } from '@/views/types/ViewGroup';
import { type ViewSort } from '@/views/types/ViewSort';
import { ViewType } from '@/views/types/ViewType';
@@ -29,26 +25,19 @@ import { duplicateViewFiltersAndViewFilterGroups } from '@/views/utils/duplicate
import { mapRecordFilterGroupToViewFilterGroup } from '@/views/utils/mapRecordFilterGroupToViewFilterGroup';
import { mapRecordFilterToViewFilter } from '@/views/utils/mapRecordFilterToViewFilter';
import { mapRecordSortToViewSort } from '@/views/utils/mapRecordSortToViewSort';
import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap';
import { useRecoilCallback } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { v4 } from 'uuid';
import { FeatureFlagKey, useCreateCoreViewMutation } from '~/generated/graphql';
import { useCreateCoreViewMutation } from '~/generated/graphql';
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
const featureFlags = useFeatureFlagsMap();
const isCoreViewEnabled = featureFlags[FeatureFlagKey.IS_CORE_VIEW_ENABLED];
const [createCoreViewMutation] = useCreateCoreViewMutation();
const currentViewIdCallbackState = useRecoilComponentCallbackState(
contextStoreCurrentViewIdComponentState,
viewBarComponentId,
);
const { createOneRecord } = useCreateOneRecord<View>({
objectNameSingular: CoreObjectNameSingular.View,
});
const anyFieldFilterValue = useRecoilComponentValue(
anyFieldFilterValueComponentState,
);
@@ -67,11 +56,6 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
const { refreshCoreViews } = useRefreshCoreViews();
const { findManyRecordsLazy } = useLazyFindManyRecords({
objectNameSingular: CoreObjectNameSingular.View,
fetchPolicy: 'network-only',
});
const currentRecordFilterGroups = useRecoilComponentValue(
currentRecordFilterGroupsComponentState,
);
@@ -124,55 +108,30 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
set(isPersistingViewFieldsState, true);
let newViewId: string | undefined;
if (isCoreViewEnabled) {
const result = await createCoreViewMutation({
variables: {
input: {
id: id ?? v4(),
name: name ?? sourceView.name,
icon: icon ?? sourceView.icon,
key: null,
kanbanAggregateOperation: shouldCopyFiltersAndSortsAndAggregate
? sourceView.kanbanAggregateOperation
: undefined,
kanbanAggregateOperationFieldMetadataId:
shouldCopyFiltersAndSortsAndAggregate
? sourceView.kanbanAggregateOperationFieldMetadataId
: undefined,
type: convertViewTypeToCore(type ?? sourceView.type),
objectMetadataId: sourceView.objectMetadataId,
openRecordIn: convertViewOpenRecordInToCore(
sourceView.openRecordIn,
),
anyFieldFilterValue: anyFieldFilterValue,
},
},
});
newViewId = result.data?.createCoreView?.id ?? undefined;
} else {
const createdView = await createOneRecord({
id: id ?? v4(),
name: name ?? sourceView.name,
icon: icon ?? sourceView.icon,
key: null,
kanbanFieldMetadataId:
kanbanFieldMetadataId ?? sourceView.kanbanFieldMetadataId,
kanbanAggregateOperation: shouldCopyFiltersAndSortsAndAggregate
? sourceView.kanbanAggregateOperation
: undefined,
kanbanAggregateOperationFieldMetadataId:
shouldCopyFiltersAndSortsAndAggregate
? sourceView.kanbanAggregateOperationFieldMetadataId
const result = await createCoreViewMutation({
variables: {
input: {
id: id ?? v4(),
name: name ?? sourceView.name,
icon: icon ?? sourceView.icon,
key: null,
kanbanAggregateOperation: shouldCopyFiltersAndSortsAndAggregate
? sourceView.kanbanAggregateOperation
: undefined,
type: type ?? sourceView.type,
objectMetadataId: sourceView.objectMetadataId,
openRecordIn: sourceView.openRecordIn,
anyFieldFilterValue: anyFieldFilterValue,
});
newViewId = createdView.id;
}
kanbanAggregateOperationFieldMetadataId:
shouldCopyFiltersAndSortsAndAggregate
? sourceView.kanbanAggregateOperationFieldMetadataId
: undefined,
type: convertViewTypeToCore(type ?? sourceView.type),
objectMetadataId: sourceView.objectMetadataId,
openRecordIn: convertViewOpenRecordInToCore(
sourceView.openRecordIn,
),
anyFieldFilterValue: anyFieldFilterValue,
},
},
});
const newViewId = result.data?.createCoreView.id;
if (isUndefinedOrNull(newViewId)) {
throw new Error('Failed to create view');
@@ -253,22 +212,16 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
await createViewSortRecords(viewSortsToCreate, { id: newViewId });
}
if (isCoreViewEnabled) {
await refreshCoreViews(objectMetadataItem.id);
} else {
await findManyRecordsLazy();
}
await refreshCoreViews(objectMetadataItem.id);
set(isPersistingViewFieldsState, false);
return newViewId;
},
[
currentViewIdCallbackState,
isCoreViewEnabled,
createViewFieldRecords,
createCoreViewMutation,
anyFieldFilterValue,
createOneRecord,
objectMetadataItem.fields,
objectMetadataItem.id,
createViewGroupRecords,
@@ -279,7 +232,6 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
createViewFilterRecords,
createViewSortRecords,
refreshCoreViews,
findManyRecordsLazy,
],
);
@@ -1,21 +1,12 @@
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
import { useRefreshCoreViews } from '@/views/hooks/useRefreshCoreViews';
import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap';
import { useRecoilCallback } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { FeatureFlagKey, useDeleteCoreViewMutation } from '~/generated/graphql';
import { useDeleteCoreViewMutation } from '~/generated/graphql';
export const useDeleteView = () => {
const featureFlags = useFeatureFlagsMap();
const isCoreViewEnabled = featureFlags[FeatureFlagKey.IS_CORE_VIEW_ENABLED];
const [deleteCoreViewMutation] = useDeleteCoreViewMutation();
const { refreshCoreViews } = useRefreshCoreViews();
const { deleteOneRecord } = useDeleteOneRecord({
objectNameSingular: CoreObjectNameSingular.View,
});
const deleteView = useRecoilCallback(
({ snapshot }) =>
@@ -32,24 +23,15 @@ export const useDeleteView = () => {
return;
}
if (isCoreViewEnabled) {
await deleteCoreViewMutation({
variables: {
id: viewId,
},
});
await deleteCoreViewMutation({
variables: {
id: viewId,
},
});
await refreshCoreViews(currentView.objectMetadataId);
} else {
await deleteOneRecord(viewId);
}
await refreshCoreViews(currentView.objectMetadataId);
},
[
deleteCoreViewMutation,
deleteOneRecord,
isCoreViewEnabled,
refreshCoreViews,
],
[deleteCoreViewMutation, refreshCoreViews],
);
return { deleteView };
@@ -1,29 +1,19 @@
import { useRecoilCallback } from 'recoil';
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
import { useRefreshCoreViews } from '@/views/hooks/useRefreshCoreViews';
import { type GraphQLView } from '@/views/types/GraphQLView';
import { convertUpdateViewInputToCore } from '@/views/utils/convertUpdateViewInputToCore';
import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap';
import { isDefined } from 'twenty-shared/utils';
import { useUpdateCoreViewMutation } from '~/generated-metadata/graphql';
import { FeatureFlagKey } from '~/generated/graphql';
export const useUpdateCurrentView = () => {
const currentViewIdCallbackState = useRecoilComponentCallbackState(
contextStoreCurrentViewIdComponentState,
);
const featureFlagMap = useFeatureFlagsMap();
const isCoreViewEnabled = featureFlagMap[FeatureFlagKey.IS_CORE_VIEW_ENABLED];
const { updateOneRecord } = useUpdateOneRecord({
objectNameSingular: CoreObjectNameSingular.View,
});
const { refreshCoreViews } = useRefreshCoreViews();
const [updateOneCoreView] = useUpdateCoreViewMutation();
@@ -48,31 +38,18 @@ export const useUpdateCurrentView = () => {
}
if (isDefined(currentViewId)) {
if (isCoreViewEnabled) {
const input = convertUpdateViewInputToCore(view);
const input = convertUpdateViewInputToCore(view);
await updateOneCoreView({
variables: {
id: currentViewId,
input,
},
});
await refreshCoreViews(currentView.objectMetadataId);
} else {
await updateOneRecord({
idToUpdate: currentViewId,
updateOneRecordInput: view,
});
}
await updateOneCoreView({
variables: {
id: currentViewId,
input,
},
});
await refreshCoreViews(currentView.objectMetadataId);
}
},
[
currentViewIdCallbackState,
isCoreViewEnabled,
refreshCoreViews,
updateOneCoreView,
updateOneRecord,
],
[currentViewIdCallbackState, refreshCoreViews, updateOneCoreView],
);
return {
@@ -1,22 +1,12 @@
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
import { type GraphQLView } from '@/views/types/GraphQLView';
import { convertUpdateViewInputToCore } from '@/views/utils/convertUpdateViewInputToCore';
import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap';
import { useRecoilCallback } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { FeatureFlagKey, useUpdateCoreViewMutation } from '~/generated/graphql';
import { useUpdateCoreViewMutation } from '~/generated/graphql';
import { useRefreshCoreViews } from './useRefreshCoreViews';
export const useUpdateView = () => {
const featureFlagMap = useFeatureFlagsMap();
const isCoreViewEnabled = featureFlagMap[FeatureFlagKey.IS_CORE_VIEW_ENABLED];
const { updateOneRecord } = useUpdateOneRecord({
objectNameSingular: CoreObjectNameSingular.View,
});
const [updateOneCoreView] = useUpdateCoreViewMutation();
const { refreshCoreViews } = useRefreshCoreViews();
@@ -29,29 +19,16 @@ export const useUpdateView = () => {
return;
}
if (isCoreViewEnabled) {
await updateOneCoreView({
variables: {
id: view.id,
input: convertUpdateViewInputToCore(view),
},
});
await updateOneCoreView({
variables: {
id: view.id,
input: convertUpdateViewInputToCore(view),
},
});
await refreshCoreViews(objectMetadataItem.id);
} else {
await updateOneRecord({
idToUpdate: view.id,
updateOneRecordInput: view,
});
}
await refreshCoreViews(objectMetadataItem.id);
},
[
isCoreViewEnabled,
objectMetadataItem.id,
refreshCoreViews,
updateOneCoreView,
updateOneRecord,
],
[objectMetadataItem.id, refreshCoreViews, updateOneCoreView],
);
return {