diff --git a/packages/twenty-front/src/modules/accounts/types/BlocklistItem.ts b/packages/twenty-front/src/modules/accounts/types/BlocklistItem.ts index 56ca9ef1e2..0b16357b70 100644 --- a/packages/twenty-front/src/modules/accounts/types/BlocklistItem.ts +++ b/packages/twenty-front/src/modules/accounts/types/BlocklistItem.ts @@ -3,4 +3,5 @@ export type BlocklistItem = { handle: string; workspaceMemberId: string; createdAt: string; + __typename: 'BlocklistItem'; }; diff --git a/packages/twenty-front/src/modules/accounts/types/CalendarChannel.ts b/packages/twenty-front/src/modules/accounts/types/CalendarChannel.ts index 173bf3c925..056d75dd55 100644 --- a/packages/twenty-front/src/modules/accounts/types/CalendarChannel.ts +++ b/packages/twenty-front/src/modules/accounts/types/CalendarChannel.ts @@ -9,4 +9,5 @@ export type CalendarChannel = { isContactAutoCreationEnabled?: boolean; isSyncEnabled?: boolean; visibility: CalendarChannelVisibility; + __typename: 'CalendarChannel'; }; diff --git a/packages/twenty-front/src/modules/accounts/types/ConnectedAccount.ts b/packages/twenty-front/src/modules/accounts/types/ConnectedAccount.ts index 2a78bb62e0..d8f42da6d5 100644 --- a/packages/twenty-front/src/modules/accounts/types/ConnectedAccount.ts +++ b/packages/twenty-front/src/modules/accounts/types/ConnectedAccount.ts @@ -13,4 +13,5 @@ export type ConnectedAccount = { authFailedAt: Date | null; messageChannels: MessageChannel[]; calendarChannels: CalendarChannel[]; + __typename: 'ConnectedAccount'; }; diff --git a/packages/twenty-front/src/modules/accounts/types/MessageChannel.ts b/packages/twenty-front/src/modules/accounts/types/MessageChannel.ts index 2517f506e5..9c9ef61401 100644 --- a/packages/twenty-front/src/modules/accounts/types/MessageChannel.ts +++ b/packages/twenty-front/src/modules/accounts/types/MessageChannel.ts @@ -7,4 +7,5 @@ export type MessageChannel = { isSyncEnabled: boolean; visibility: InboxSettingsVisibilityValue; syncStatus: string; + __typename: 'MessageChannel'; }; diff --git a/packages/twenty-front/src/modules/activities/calendar/hooks/useCalendarEvents.ts b/packages/twenty-front/src/modules/activities/calendar/hooks/useCalendarEvents.ts index 5f2e633816..15baaf0b2c 100644 --- a/packages/twenty-front/src/modules/activities/calendar/hooks/useCalendarEvents.ts +++ b/packages/twenty-front/src/modules/activities/calendar/hooks/useCalendarEvents.ts @@ -10,7 +10,7 @@ import { sortDesc } from '~/utils/sort'; type CalendarEventGeneric = Omit< CalendarEvent, - 'participants' | 'externalCreatedAt' + 'participants' | 'externalCreatedAt' | '__typename' >; export const useCalendarEvents = ( diff --git a/packages/twenty-front/src/modules/activities/calendar/right-drawer/components/RightDrawerCalendarEvent.tsx b/packages/twenty-front/src/modules/activities/calendar/right-drawer/components/RightDrawerCalendarEvent.tsx index f0e895dcda..845885e7cd 100644 --- a/packages/twenty-front/src/modules/activities/calendar/right-drawer/components/RightDrawerCalendarEvent.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/right-drawer/components/RightDrawerCalendarEvent.tsx @@ -14,7 +14,6 @@ export const RightDrawerCalendarEvent = () => { objectNameSingular: CoreObjectNameSingular.CalendarEvent, objectRecordId: viewableCalendarEventId ?? '', onCompleted: (record) => setRecords([record]), - depth: 2, }); if (!calendarEvent) return null; diff --git a/packages/twenty-front/src/modules/activities/calendar/types/CalendarEvent.ts b/packages/twenty-front/src/modules/activities/calendar/types/CalendarEvent.ts index a598c23d96..d15f958508 100644 --- a/packages/twenty-front/src/modules/activities/calendar/types/CalendarEvent.ts +++ b/packages/twenty-front/src/modules/activities/calendar/types/CalendarEvent.ts @@ -17,4 +17,5 @@ export type CalendarEvent = { title?: string; visibility: 'METADATA' | 'SHARE_EVERYTHING'; calendarEventParticipants?: CalendarEventParticipant[]; + __typename: 'CalendarEvent'; }; diff --git a/packages/twenty-front/src/modules/activities/components/ActivityBodyEditor.tsx b/packages/twenty-front/src/modules/activities/components/ActivityBodyEditor.tsx index 0b3994278a..1c55a9be62 100644 --- a/packages/twenty-front/src/modules/activities/components/ActivityBodyEditor.tsx +++ b/packages/twenty-front/src/modules/activities/components/ActivityBodyEditor.tsx @@ -161,6 +161,7 @@ export const ActivityBodyEditor = ({ ...oldActivity, id: activityId, body: newStringifiedBody, + __typename: 'Activity', }; }); @@ -192,6 +193,7 @@ export const ActivityBodyEditor = ({ ...oldActivity, id: activityId, title: newTitleFromBody, + __typename: 'Activity', }; }); diff --git a/packages/twenty-front/src/modules/activities/components/ActivityTitle.tsx b/packages/twenty-front/src/modules/activities/components/ActivityTitle.tsx index 288447dbec..da1c10d2f7 100644 --- a/packages/twenty-front/src/modules/activities/components/ActivityTitle.tsx +++ b/packages/twenty-front/src/modules/activities/components/ActivityTitle.tsx @@ -134,6 +134,7 @@ export const ActivityTitle = ({ activityId }: ActivityTitleProps) => { ...currentActivity, id: activity.id, title: newTitle, + __typename: activity.__typename, }; }); diff --git a/packages/twenty-front/src/modules/activities/emails/right-drawer/hooks/useRightDrawerEmailThread.ts b/packages/twenty-front/src/modules/activities/emails/right-drawer/hooks/useRightDrawerEmailThread.ts index a524679fdb..68b3f56579 100644 --- a/packages/twenty-front/src/modules/activities/emails/right-drawer/hooks/useRightDrawerEmailThread.ts +++ b/packages/twenty-front/src/modules/activities/emails/right-drawer/hooks/useRightDrawerEmailThread.ts @@ -28,7 +28,6 @@ export const useRightDrawerEmailThread = () => { loading, fetchMoreRecords, } = useFindManyRecords({ - depth: 3, limit: 10, filter: { messageThreadId: { diff --git a/packages/twenty-front/src/modules/activities/emails/types/EmailThreadMessage.ts b/packages/twenty-front/src/modules/activities/emails/types/EmailThreadMessage.ts index c86b40ece3..f585af847c 100644 --- a/packages/twenty-front/src/modules/activities/emails/types/EmailThreadMessage.ts +++ b/packages/twenty-front/src/modules/activities/emails/types/EmailThreadMessage.ts @@ -5,4 +5,5 @@ export type EmailThreadMessage = { text: string; receivedAt: string; messageParticipants: EmailThreadMessageParticipant[]; + __typename: 'EmailThreadMessage'; }; diff --git a/packages/twenty-front/src/modules/activities/files/hooks/useUploadAttachmentFile.tsx b/packages/twenty-front/src/modules/activities/files/hooks/useUploadAttachmentFile.tsx index d68645fe13..0fa258f56e 100644 --- a/packages/twenty-front/src/modules/activities/files/hooks/useUploadAttachmentFile.tsx +++ b/packages/twenty-front/src/modules/activities/files/hooks/useUploadAttachmentFile.tsx @@ -1,9 +1,9 @@ import { useRecoilValue } from 'recoil'; +import { Attachment } from '@/activities/files/types/Attachment'; import { getFileType } from '@/activities/files/utils/getFileType'; import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity'; import { getActivityTargetObjectFieldIdName } from '@/activities/utils/getActivityTargetObjectFieldIdName'; -import { Attachment } from '@/attachments/types/Attachment'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord'; diff --git a/packages/twenty-front/src/modules/activities/files/types/Attachment.ts b/packages/twenty-front/src/modules/activities/files/types/Attachment.ts index fbe2a9cc30..e37bcf8f92 100644 --- a/packages/twenty-front/src/modules/activities/files/types/Attachment.ts +++ b/packages/twenty-front/src/modules/activities/files/types/Attachment.ts @@ -8,7 +8,9 @@ export type Attachment = { activityId: string; authorId: string; createdAt: string; + __typename: string; }; + export type AttachmentType = | 'Archive' | 'Audio' diff --git a/packages/twenty-front/src/modules/activities/query-keys/FindManyActivitiesQueryKey.ts b/packages/twenty-front/src/modules/activities/graphql/operation-signatures/CreateOneActivityOperationSignature.ts similarity index 57% rename from packages/twenty-front/src/modules/activities/query-keys/FindManyActivitiesQueryKey.ts rename to packages/twenty-front/src/modules/activities/graphql/operation-signatures/CreateOneActivityOperationSignature.ts index 09e6b04d64..5a01a56a61 100644 --- a/packages/twenty-front/src/modules/activities/query-keys/FindManyActivitiesQueryKey.ts +++ b/packages/twenty-front/src/modules/activities/graphql/operation-signatures/CreateOneActivityOperationSignature.ts @@ -1,12 +1,11 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { QueryKey } from '@/object-record/query-keys/types/QueryKey'; +import { RecordGqlOperationSignature } from '@/object-record/graphql/types/RecordGqlOperationSignature'; -export const FIND_MANY_ACTIVITIES_QUERY_KEY: QueryKey = { - objectNameSingular: CoreObjectNameSingular.Activity, - variables: {}, - fieldsFactory: (_objectMetadataItems: ObjectMetadataItem[]) => { - return { +export const CREATE_ONE_ACTIVITY_OPERATION_SIGNATURE: RecordGqlOperationSignature = + { + objectNameSingular: CoreObjectNameSingular.Activity, + variables: {}, + fields: { id: true, __typename: true, createdAt: true, @@ -31,8 +30,5 @@ export const FIND_MANY_ACTIVITIES_QUERY_KEY: QueryKey = { dueAt: true, reminderAt: true, type: true, - activityTargets: true, - }; - }, - depth: 2, -}; + }, + }; diff --git a/packages/twenty-front/src/modules/activities/graphql/operation-signatures/factories/findActivitiesOperationSignatureFactory.ts b/packages/twenty-front/src/modules/activities/graphql/operation-signatures/factories/findActivitiesOperationSignatureFactory.ts new file mode 100644 index 0000000000..6dca7c5da1 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/graphql/operation-signatures/factories/findActivitiesOperationSignatureFactory.ts @@ -0,0 +1,45 @@ +import { generateActivityTargetMorphFieldKeys } from '@/activities/utils/generateActivityTargetMorphFieldKeys'; +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { RecordGqlOperationSignatureFactory } from '@/object-record/graphql/types/RecordGqlOperationSignatureFactory'; + +export const findActivitiesOperationSignatureFactory: RecordGqlOperationSignatureFactory = + ({ objectMetadataItems }: { objectMetadataItems: ObjectMetadataItem[] }) => ({ + objectNameSingular: CoreObjectNameSingular.Activity, + variables: {}, + fields: { + id: true, + __typename: true, + createdAt: true, + updatedAt: true, + author: { + id: true, + name: true, + __typename: true, + }, + authorId: true, + assigneeId: true, + assignee: { + id: true, + name: true, + __typename: true, + }, + comments: true, + attachments: true, + body: true, + title: true, + completedAt: true, + dueAt: true, + reminderAt: true, + type: true, + activityTargets: { + id: true, + __typename: true, + createdAt: true, + updatedAt: true, + activity: true, + activityId: true, + ...generateActivityTargetMorphFieldKeys(objectMetadataItems), + }, + }, + }); diff --git a/packages/twenty-front/src/modules/activities/query-keys/FindManyActivityTargetsQueryKey.ts b/packages/twenty-front/src/modules/activities/graphql/operation-signatures/factories/findActivityTargetsOperationSignatureFactory.ts similarity index 54% rename from packages/twenty-front/src/modules/activities/query-keys/FindManyActivityTargetsQueryKey.ts rename to packages/twenty-front/src/modules/activities/graphql/operation-signatures/factories/findActivityTargetsOperationSignatureFactory.ts index b0d34ff84a..259550ce53 100644 --- a/packages/twenty-front/src/modules/activities/query-keys/FindManyActivityTargetsQueryKey.ts +++ b/packages/twenty-front/src/modules/activities/graphql/operation-signatures/factories/findActivityTargetsOperationSignatureFactory.ts @@ -1,13 +1,13 @@ import { generateActivityTargetMorphFieldKeys } from '@/activities/utils/generateActivityTargetMorphFieldKeys'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { QueryKey } from '@/object-record/query-keys/types/QueryKey'; +import { RecordGqlOperationSignatureFactory } from '@/object-record/graphql/types/RecordGqlOperationSignatureFactory'; -export const FIND_MANY_ACTIVITY_TARGETS_QUERY_KEY: QueryKey = { - objectNameSingular: CoreObjectNameSingular.ActivityTarget, - variables: {}, - fieldsFactory: (objectMetadataItems: ObjectMetadataItem[]) => { - return { +export const findActivityTargetsOperationSignatureFactory: RecordGqlOperationSignatureFactory = + ({ objectMetadataItems }: { objectMetadataItems: ObjectMetadataItem[] }) => ({ + objectNameSingular: CoreObjectNameSingular.ActivityTarget, + variables: {}, + fields: { id: true, __typename: true, createdAt: true, @@ -15,7 +15,5 @@ export const FIND_MANY_ACTIVITY_TARGETS_QUERY_KEY: QueryKey = { activity: true, activityId: true, ...generateActivityTargetMorphFieldKeys(objectMetadataItems), - }; - }, - depth: 1, -}; + }, + }); diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivities.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivities.test.tsx index 0551b005c5..4e149d280f 100644 --- a/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivities.test.tsx +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivities.test.tsx @@ -79,7 +79,7 @@ const mocks: MockedResponse[] = [ } `, variables: { - filter: { activityTargetId: { eq: '123' } }, + filter: { companyId: { eq: '123' } }, limit: undefined, orderBy: undefined, }, @@ -180,7 +180,6 @@ describe('useActivities', () => { activitiesFilters: {}, activitiesOrderByVariables: {}, skip: false, - skipActivityTargets: false, }), { wrapper: Wrapper }, ); @@ -188,8 +187,6 @@ describe('useActivities', () => { expect(result.current).toEqual({ activities: [], loading: false, - initialized: true, - noActivities: true, }); }); @@ -202,12 +199,11 @@ describe('useActivities', () => { const activities = useActivities({ targetableObjects: [ - { targetObjectNameSingular: 'activityTarget', id: '123' }, + { targetObjectNameSingular: 'company', id: '123' }, ], activitiesFilters: {}, activitiesOrderByVariables: {}, skip: false, - skipActivityTargets: false, }); return { activities, setCurrentWorkspaceMember }; }, @@ -218,18 +214,9 @@ describe('useActivities', () => { result.current.setCurrentWorkspaceMember(mockWorkspaceMembers[0]); }); - expect(result.current.activities.loading).toBe(true); - - // Wait for activityTargets to complete fetching - await waitFor(() => !result.current.activities.loading); - - expect(result.current.activities.loading).toBe(false); - - // Wait for request to fetch activities to be made - await waitFor(() => result.current.activities.loading); - - // Wait for activities to complete fetching - await waitFor(() => !result.current.activities.loading); + await waitFor(() => { + expect(result.current.activities.loading).toBe(false); + }); const { activities } = result.current; diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetObjectRecords.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetObjectRecords.test.tsx index 76a0079eb8..2096f8c4a4 100644 --- a/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetObjectRecords.test.tsx +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetObjectRecords.test.tsx @@ -10,8 +10,8 @@ import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadat import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock'; import { getRecordFromRecordNode } from '@/object-record/cache/utils/getRecordFromRecordNode'; import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope'; +import { JestObjectMetadataItemSetter } from '~/testing/jest/JestObjectMetadataItemSetter'; import { mockWorkspaceMembers } from '~/testing/mock-data/workspace-members'; - const mockObjectMetadataItems = getObjectMetadataItemsMock(); const cache = new InMemoryCache(); @@ -85,7 +85,6 @@ cache.writeFragment({ id createdAt updatedAt - targetObjectNameSingular personId companyId company { @@ -114,9 +113,11 @@ cache.writeFragment({ const Wrapper = ({ children }: { children: ReactNode }) => ( - - {children} - + + + {children} + + ); diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useCreateActivityInDB.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useCreateActivityInDB.test.tsx index 5c982afaac..c4726cb8c7 100644 --- a/packages/twenty-front/src/modules/activities/hooks/__tests__/useCreateActivityInDB.test.tsx +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useCreateActivityInDB.test.tsx @@ -82,7 +82,10 @@ describe('useCreateActivityInDB', () => { }); await act(async () => { - await result.current.createActivityInDB(mockedActivity); + await result.current.createActivityInDB({ + ...mockedActivity, + __typename: 'Activity', + }); }); expect(mocks[0].result).toHaveBeenCalled(); diff --git a/packages/twenty-front/src/modules/activities/hooks/useActivities.ts b/packages/twenty-front/src/modules/activities/hooks/useActivities.ts index 1c2cb0943b..ee253bf87a 100644 --- a/packages/twenty-front/src/modules/activities/hooks/useActivities.ts +++ b/packages/twenty-front/src/modules/activities/hooks/useActivities.ts @@ -1,15 +1,14 @@ -import { useEffect, useState } from 'react'; -import { isNonEmptyArray, isNonEmptyString } from '@sniptt/guards'; +import { isNonEmptyString } from '@sniptt/guards'; import { useRecoilCallback } from 'recoil'; +import { findActivitiesOperationSignatureFactory } from '@/activities/graphql/operation-signatures/factories/findActivitiesOperationSignatureFactory'; import { useActivityTargetsForTargetableObjects } from '@/activities/hooks/useActivityTargetsForTargetableObjects'; -import { FIND_MANY_ACTIVITIES_QUERY_KEY } from '@/activities/query-keys/FindManyActivitiesQueryKey'; import { Activity } from '@/activities/types/Activity'; import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; -import { OrderByField } from '@/object-metadata/types/OrderByField'; +import { RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; +import { RecordGqlOperationOrderBy } from '@/object-record/graphql/types/RecordGqlOperationOrderBy'; import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; -import { ObjectRecordQueryFilter } from '@/object-record/record-filter/types/ObjectRecordQueryFilter'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { sortByAscString } from '~/utils/array/sortByAscString'; @@ -18,26 +17,19 @@ export const useActivities = ({ activitiesFilters, activitiesOrderByVariables, skip, - skipActivityTargets, }: { targetableObjects: ActivityTargetableObject[]; - activitiesFilters: ObjectRecordQueryFilter; - activitiesOrderByVariables: OrderByField; + activitiesFilters: RecordGqlOperationFilter; + activitiesOrderByVariables: RecordGqlOperationOrderBy; skip?: boolean; - skipActivityTargets?: boolean; }) => { - const [initialized, setInitialized] = useState(false); - const { objectMetadataItems } = useObjectMetadataItems(); - const { - activityTargets, - loadingActivityTargets, - initialized: initializedActivityTargets, - } = useActivityTargetsForTargetableObjects({ - targetableObjects, - skip: skipActivityTargets || skip, - }); + const { activityTargets, loadingActivityTargets } = + useActivityTargetsForTargetableObjects({ + targetableObjects, + skip: skip, + }); const activityIds = [ ...new Set( @@ -51,70 +43,40 @@ export const useActivities = ({ ), ]; - const activityTargetsFound = - initializedActivityTargets && isNonEmptyArray(activityTargets); - - const filter: ObjectRecordQueryFilter = { - id: activityTargetsFound - ? { - in: activityIds, - } - : undefined, + const filter: RecordGqlOperationFilter = { + id: + targetableObjects.length > 0 + ? { + in: activityIds, + } + : undefined, ...activitiesFilters, }; - const skipActivities = - skip || - (!skipActivityTargets && - (!initializedActivityTargets || !activityTargetsFound)); + const FIND_ACTIVITIES_OPERATION_SIGNATURE = + findActivitiesOperationSignatureFactory({ objectMetadataItems }); const { records: activities, loading: loadingActivities } = useFindManyRecords({ - skip: skipActivities, - objectNameSingular: FIND_MANY_ACTIVITIES_QUERY_KEY.objectNameSingular, - depth: FIND_MANY_ACTIVITIES_QUERY_KEY.depth, - queryFields: - FIND_MANY_ACTIVITIES_QUERY_KEY.fieldsFactory?.(objectMetadataItems), + skip: skip || loadingActivityTargets, + objectNameSingular: + FIND_ACTIVITIES_OPERATION_SIGNATURE.objectNameSingular, + recordGqlFields: FIND_ACTIVITIES_OPERATION_SIGNATURE.fields, filter, orderBy: activitiesOrderByVariables, onCompleted: useRecoilCallback( ({ set }) => (activities) => { - if (!initialized) { - setInitialized(true); - } - for (const activity of activities) { set(recordStoreFamilyState(activity.id), activity); } }, - [initialized], + [], ), }); - const loading = loadingActivities || loadingActivityTargets; - - const noActivities = - (!activityTargetsFound && !skipActivityTargets && initialized) || - (initialized && !loading && !isNonEmptyArray(activities)); - - useEffect(() => { - if (skipActivities || noActivities) { - setInitialized(true); - } - }, [ - activities, - initialized, - loading, - noActivities, - skipActivities, - skipActivityTargets, - ]); - return { activities, - loading, - initialized, - noActivities, + loading: loadingActivities || loadingActivityTargets, }; }; diff --git a/packages/twenty-front/src/modules/activities/hooks/useActivityTargetsForTargetableObject.ts b/packages/twenty-front/src/modules/activities/hooks/useActivityTargetsForTargetableObject.ts index 7d2a8e762c..159330bbdd 100644 --- a/packages/twenty-front/src/modules/activities/hooks/useActivityTargetsForTargetableObject.ts +++ b/packages/twenty-front/src/modules/activities/hooks/useActivityTargetsForTargetableObject.ts @@ -1,4 +1,3 @@ -import { useState } from 'react'; import { isNonEmptyString } from '@sniptt/guards'; import { ActivityTarget } from '@/activities/types/ActivityTarget'; @@ -16,8 +15,6 @@ export const useActivityTargetsForTargetableObject = ({ nameSingular: targetableObject.targetObjectNameSingular, }); - const [initialized, setInitialized] = useState(false); - const targetableObjectId = targetableObject.id; const skipRequest = !isNonEmptyString(targetableObjectId); @@ -34,16 +31,10 @@ export const useActivityTargetsForTargetableObject = ({ eq: targetableObject.id, }, }, - onCompleted: () => { - if (!initialized) { - setInitialized(true); - } - }, }); return { activityTargets, loadingActivityTargets, - initialized, }; }; diff --git a/packages/twenty-front/src/modules/activities/hooks/useActivityTargetsForTargetableObjects.ts b/packages/twenty-front/src/modules/activities/hooks/useActivityTargetsForTargetableObjects.ts index be82811029..4d19858082 100644 --- a/packages/twenty-front/src/modules/activities/hooks/useActivityTargetsForTargetableObjects.ts +++ b/packages/twenty-front/src/modules/activities/hooks/useActivityTargetsForTargetableObjects.ts @@ -1,7 +1,6 @@ -import { useState } from 'react'; import { useRecoilValue } from 'recoil'; -import { FIND_MANY_ACTIVITY_TARGETS_QUERY_KEY } from '@/activities/query-keys/FindManyActivityTargetsQueryKey'; +import { findActivityTargetsOperationSignatureFactory } from '@/activities/graphql/operation-signatures/factories/findActivityTargetsOperationSignatureFactory'; import { ActivityTarget } from '@/activities/types/ActivityTarget'; import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity'; import { getActivityTargetsFilter } from '@/activities/utils/getActivityTargetsFilter'; @@ -11,12 +10,14 @@ import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; export const useActivityTargetsForTargetableObjects = ({ targetableObjects, skip, + onCompleted, }: { targetableObjects: Pick< ActivityTargetableObject, 'id' | 'targetObjectNameSingular' >[]; skip?: boolean; + onCompleted?: (activityTargets: ActivityTarget[]) => void; }) => { const activityTargetsFilter = getActivityTargetsFilter({ targetableObjects: targetableObjects, @@ -24,7 +25,8 @@ export const useActivityTargetsForTargetableObjects = ({ const objectMetadataItems = useRecoilValue(objectMetadataItemsState); - const [initialized, setInitialized] = useState(false); + const FIND_ACTIVITY_TARGETS_OPERATION_SIGNATURE = + findActivityTargetsOperationSignatureFactory({ objectMetadataItems }); // TODO: We want to optimistically remove from this request // If we are on a show page and we remove the current show page object corresponding activity target @@ -33,22 +35,14 @@ export const useActivityTargetsForTargetableObjects = ({ useFindManyRecords({ skip, objectNameSingular: - FIND_MANY_ACTIVITY_TARGETS_QUERY_KEY.objectNameSingular, + FIND_ACTIVITY_TARGETS_OPERATION_SIGNATURE.objectNameSingular, filter: activityTargetsFilter, - queryFields: - FIND_MANY_ACTIVITY_TARGETS_QUERY_KEY.fieldsFactory?.( - objectMetadataItems, - ), - onCompleted: () => { - if (!initialized) { - setInitialized(true); - } - }, + recordGqlFields: FIND_ACTIVITY_TARGETS_OPERATION_SIGNATURE.fields, + onCompleted, }); return { activityTargets, loadingActivityTargets, - initialized, }; }; diff --git a/packages/twenty-front/src/modules/activities/hooks/useCreateActivityInCache.ts b/packages/twenty-front/src/modules/activities/hooks/useCreateActivityInCache.ts index 8f54fdf1f7..d909534736 100644 --- a/packages/twenty-front/src/modules/activities/hooks/useCreateActivityInCache.ts +++ b/packages/twenty-front/src/modules/activities/hooks/useCreateActivityInCache.ts @@ -34,7 +34,6 @@ export const useCreateActivityInCache = () => { const { record: currentWorkspaceMemberRecord } = useFindOneRecord({ objectNameSingular: CoreObjectNameSingular.WorkspaceMember, objectRecordId: currentWorkspaceMember?.id, - depth: 0, }); const { objectMetadataItem: objectMetadataItemActivity } = @@ -66,6 +65,7 @@ export const useCreateActivityInCache = () => { const createdActivityInCache = createOneActivityInCache({ id: activityId, + __typename: 'Activity', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), author: currentWorkspaceMemberRecord, diff --git a/packages/twenty-front/src/modules/activities/hooks/useCreateActivityInDB.ts b/packages/twenty-front/src/modules/activities/hooks/useCreateActivityInDB.ts index 58e0349e28..961514ede0 100644 --- a/packages/twenty-front/src/modules/activities/hooks/useCreateActivityInDB.ts +++ b/packages/twenty-front/src/modules/activities/hooks/useCreateActivityInDB.ts @@ -1,6 +1,6 @@ import { isNonEmptyArray } from '@sniptt/guards'; -import { CREATE_ONE_ACTIVITY_QUERY_KEY } from '@/activities/query-keys/CreateOneActivityQueryKey'; +import { CREATE_ONE_ACTIVITY_OPERATION_SIGNATURE } from '@/activities/graphql/operation-signatures/CreateOneActivityOperationSignature'; import { ActivityForEditor } from '@/activities/types/ActivityForEditor'; import { ActivityTarget } from '@/activities/types/ActivityTarget'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; @@ -9,9 +9,9 @@ import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord'; export const useCreateActivityInDB = () => { const { createOneRecord: createOneActivity } = useCreateOneRecord({ - objectNameSingular: CREATE_ONE_ACTIVITY_QUERY_KEY.objectNameSingular, - queryFields: CREATE_ONE_ACTIVITY_QUERY_KEY.fields, - depth: CREATE_ONE_ACTIVITY_QUERY_KEY.depth, + objectNameSingular: + CREATE_ONE_ACTIVITY_OPERATION_SIGNATURE.objectNameSingular, + recordGqlFields: CREATE_ONE_ACTIVITY_OPERATION_SIGNATURE.fields, }); const { createManyRecords: createManyActivityTargets } = diff --git a/packages/twenty-front/src/modules/activities/hooks/usePrepareFindManyActivitiesQuery.ts b/packages/twenty-front/src/modules/activities/hooks/usePrepareFindManyActivitiesQuery.ts index 9d2e50b837..a7cd55f7e7 100644 --- a/packages/twenty-front/src/modules/activities/hooks/usePrepareFindManyActivitiesQuery.ts +++ b/packages/twenty-front/src/modules/activities/hooks/usePrepareFindManyActivitiesQuery.ts @@ -1,6 +1,6 @@ import { useApolloClient } from '@apollo/client'; -import { FIND_MANY_ACTIVITIES_QUERY_KEY } from '@/activities/query-keys/FindManyActivitiesQueryKey'; +import { findActivitiesOperationSignatureFactory } from '@/activities/graphql/operation-signatures/factories/findActivitiesOperationSignatureFactory'; import { Activity } from '@/activities/types/Activity'; import { ActivityTarget } from '@/activities/types/ActivityTarget'; import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity'; @@ -104,15 +104,16 @@ export const usePrepareFindManyActivitiesQuery = () => { return a.createdAt > b.createdAt ? -1 : 1; }); + const FIND_ACTIVITIES_OPERATION_SIGNATURE = + findActivitiesOperationSignatureFactory({ objectMetadataItems }); + upsertFindManyActivitiesInCache({ objectRecordsToOverwrite: filteredActivities, queryVariables: { ...nextFindManyActivitiesQueryFilter, orderBy: { createdAt: 'DescNullsFirst' }, }, - depth: FIND_MANY_ACTIVITIES_QUERY_KEY.depth, - queryFields: - FIND_MANY_ACTIVITIES_QUERY_KEY.fieldsFactory?.(objectMetadataItems), + recordGqlFields: FIND_ACTIVITIES_OPERATION_SIGNATURE.fields, computeReferences: true, }); }; diff --git a/packages/twenty-front/src/modules/activities/notes/components/Notes.tsx b/packages/twenty-front/src/modules/activities/notes/components/Notes.tsx index 88956be733..173bda4ede 100644 --- a/packages/twenty-front/src/modules/activities/notes/components/Notes.tsx +++ b/packages/twenty-front/src/modules/activities/notes/components/Notes.tsx @@ -27,14 +27,10 @@ export const Notes = ({ }: { targetableObject: ActivityTargetableObject; }) => { - const { notes, initialized } = useNotes(targetableObject); + const { notes } = useNotes(targetableObject); const openCreateActivity = useOpenCreateActivityDrawer(); - if (!initialized) { - return <>; - } - if (notes?.length === 0) { return ( diff --git a/packages/twenty-front/src/modules/activities/notes/hooks/__tests__/useNotes.test.ts b/packages/twenty-front/src/modules/activities/notes/hooks/__tests__/useNotes.test.ts index f64b745f04..caf3430100 100644 --- a/packages/twenty-front/src/modules/activities/notes/hooks/__tests__/useNotes.test.ts +++ b/packages/twenty-front/src/modules/activities/notes/hooks/__tests__/useNotes.test.ts @@ -6,7 +6,6 @@ import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableE jest.mock('@/activities/hooks/useActivities', () => ({ useActivities: jest.fn(() => ({ activities: [{ id: '1', content: 'Example Note' }], - initialized: true, loading: false, })), })); @@ -29,7 +28,7 @@ jest.mock('recoil', () => { }); describe('useNotes', () => { - it('should return notes, initialized, and loading as expected', () => { + it('should return notes, and loading as expected', () => { const mockTargetableObject: ActivityTargetableObject = { id: '1', targetObjectNameSingular: 'Example Target', @@ -39,7 +38,6 @@ describe('useNotes', () => { expect(result.current.notes).toEqual([ { id: '1', content: 'Example Note' }, ]); - expect(result.current.initialized).toBe(true); expect(result.current.loading).toBe(false); }); }); diff --git a/packages/twenty-front/src/modules/activities/notes/hooks/useNotes.ts b/packages/twenty-front/src/modules/activities/notes/hooks/useNotes.ts index 039a8d11fb..b50231f9e4 100644 --- a/packages/twenty-front/src/modules/activities/notes/hooks/useNotes.ts +++ b/packages/twenty-front/src/modules/activities/notes/hooks/useNotes.ts @@ -5,7 +5,7 @@ import { useActivities } from '@/activities/hooks/useActivities'; import { currentNotesQueryVariablesState } from '@/activities/notes/states/currentNotesQueryVariablesState'; import { FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY } from '@/activities/timeline/constants/FindManyTimelineActivitiesOrderBy'; import { Note } from '@/activities/types/Note'; -import { ObjectRecordQueryVariables } from '@/object-record/types/ObjectRecordQueryVariables'; +import { RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; import { ActivityTargetableObject } from '../../types/ActivityTargetableEntity'; @@ -18,11 +18,11 @@ export const useNotes = (targetableObject: ActivityTargetableObject) => { type: { eq: 'Note' }, }, orderBy: FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY, - }) as ObjectRecordQueryVariables, + }) as RecordGqlOperationVariables, [], ); - const { activities, initialized, loading } = useActivities({ + const { activities, loading } = useActivities({ activitiesFilters: notesQueryVariables.filter ?? {}, activitiesOrderByVariables: notesQueryVariables.orderBy ?? {}, targetableObjects: [targetableObject], @@ -44,7 +44,6 @@ export const useNotes = (targetableObject: ActivityTargetableObject) => { return { notes: activities as Note[], - initialized, loading, }; }; diff --git a/packages/twenty-front/src/modules/activities/notes/states/currentNotesQueryVariablesState.ts b/packages/twenty-front/src/modules/activities/notes/states/currentNotesQueryVariablesState.ts index 9697d09518..27d2be9dfe 100644 --- a/packages/twenty-front/src/modules/activities/notes/states/currentNotesQueryVariablesState.ts +++ b/packages/twenty-front/src/modules/activities/notes/states/currentNotesQueryVariablesState.ts @@ -1,9 +1,9 @@ import { atom } from 'recoil'; -import { ObjectRecordQueryVariables } from '@/object-record/types/ObjectRecordQueryVariables'; +import { RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables'; export const currentNotesQueryVariablesState = - atom({ + atom({ default: null, key: 'currentNotesQueryVariablesState', }); diff --git a/packages/twenty-front/src/modules/activities/query-keys/CreateOneActivityQueryKey.ts b/packages/twenty-front/src/modules/activities/query-keys/CreateOneActivityQueryKey.ts deleted file mode 100644 index acec84ba75..0000000000 --- a/packages/twenty-front/src/modules/activities/query-keys/CreateOneActivityQueryKey.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { QueryKey } from '@/object-record/query-keys/types/QueryKey'; - -export const CREATE_ONE_ACTIVITY_QUERY_KEY: QueryKey = { - objectNameSingular: CoreObjectNameSingular.Activity, - variables: {}, - fields: { - id: true, - __typename: true, - createdAt: true, - updatedAt: true, - author: { - id: true, - name: true, - __typename: true, - }, - authorId: true, - assigneeId: true, - assignee: { - id: true, - name: true, - __typename: true, - }, - comments: true, - attachments: true, - body: true, - title: true, - completedAt: true, - dueAt: true, - reminderAt: true, - type: true, - }, - depth: 1, -}; diff --git a/packages/twenty-front/src/modules/activities/right-drawer/components/ActivityActionBar.tsx b/packages/twenty-front/src/modules/activities/right-drawer/components/ActivityActionBar.tsx index c374ab1e13..27cfbf2d3c 100644 --- a/packages/twenty-front/src/modules/activities/right-drawer/components/ActivityActionBar.tsx +++ b/packages/twenty-front/src/modules/activities/right-drawer/components/ActivityActionBar.tsx @@ -19,7 +19,6 @@ import { useDeleteRecordFromCache } from '@/object-record/cache/hooks/useDeleteR import { useDeleteManyRecords } from '@/object-record/hooks/useDeleteManyRecords'; import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { getChildRelationArray } from '@/object-record/utils/getChildRelationArray'; import { mapToRecordId } from '@/object-record/utils/mapToObjectId'; import { IconButton } from '@/ui/input/button/components/IconButton'; import { isRightDrawerOpenState } from '@/ui/layout/right-drawer/states/isRightDrawerOpenState'; @@ -85,10 +84,6 @@ export const ActivityActionBar = () => { .getLoadable(recordStoreFamilyState(activityIdInDrawer)) .getValue() as Activity; - const activityTargets = getChildRelationArray({ - childRelation: activity.activityTargets, - }); - setIsRightDrawerOpen(false); if (!isNonEmptyString(viewableActivityId)) { @@ -103,10 +98,10 @@ export const ActivityActionBar = () => { if (isNonEmptyString(activityIdInDrawer)) { const activityTargetIdsToDelete: string[] = - activityTargets.map(mapToRecordId) ?? []; + activity.activityTargets.map(mapToRecordId) ?? []; deleteActivityFromCache(activity); - activityTargets.forEach((activityTarget: ActivityTarget) => { + activity.activityTargets.forEach((activityTarget: ActivityTarget) => { deleteActivityTargetFromCache(activityTarget); }); diff --git a/packages/twenty-front/src/modules/activities/tasks/components/CurrentUserDueTaskCountEffect.tsx b/packages/twenty-front/src/modules/activities/tasks/components/CurrentUserDueTaskCountEffect.tsx index 802e03bb6b..b7c790e891 100644 --- a/packages/twenty-front/src/modules/activities/tasks/components/CurrentUserDueTaskCountEffect.tsx +++ b/packages/twenty-front/src/modules/activities/tasks/components/CurrentUserDueTaskCountEffect.tsx @@ -18,7 +18,6 @@ export const CurrentUserDueTaskCountEffect = () => { const { records: tasks } = useFindManyRecords({ objectNameSingular: CoreObjectNameSingular.Activity, - depth: 0, filter: { type: { eq: 'Task' }, completedAt: { is: 'NULL' }, diff --git a/packages/twenty-front/src/modules/activities/tasks/components/TaskGroups.tsx b/packages/twenty-front/src/modules/activities/tasks/components/TaskGroups.tsx index 4a52b39692..9103bb2d63 100644 --- a/packages/twenty-front/src/modules/activities/tasks/components/TaskGroups.tsx +++ b/packages/twenty-front/src/modules/activities/tasks/components/TaskGroups.tsx @@ -40,7 +40,6 @@ export const TaskGroups = ({ upcomingTasks, unscheduledTasks, completedTasks, - initialized, } = useTasks({ filterDropdownId: filterDropdownId, targetableObjects: targetableObjects ?? [], @@ -51,10 +50,6 @@ export const TaskGroups = ({ const { activeTabIdState } = useTabList(TASKS_TAB_LIST_COMPONENT_ID); const activeTabId = useRecoilValue(activeTabIdState); - if (!initialized) { - return <>; - } - if ( (activeTabId !== 'done' && todayOrPreviousTasks?.length === 0 && diff --git a/packages/twenty-front/src/modules/activities/tasks/hooks/__tests__/useTasks.test.tsx b/packages/twenty-front/src/modules/activities/tasks/hooks/__tests__/useTasks.test.tsx index c7171a76ae..0e7cdc3c47 100644 --- a/packages/twenty-front/src/modules/activities/tasks/hooks/__tests__/useTasks.test.tsx +++ b/packages/twenty-front/src/modules/activities/tasks/hooks/__tests__/useTasks.test.tsx @@ -49,7 +49,6 @@ const useActivitiesMock = jest.fn( activities: isCompletedFilter ? completedTasks : [...todayOrPreviousTasks, ...unscheduledTasks], - initialized: true, }; }, ); @@ -79,7 +78,6 @@ describe('useTasks', () => { upcomingTasks: [], unscheduledTasks, completedTasks, - initialized: true, }); }); }); diff --git a/packages/twenty-front/src/modules/activities/tasks/hooks/useTasks.ts b/packages/twenty-front/src/modules/activities/tasks/hooks/useTasks.ts index 0adbe01f18..bb8fb16566 100644 --- a/packages/twenty-front/src/modules/activities/tasks/hooks/useTasks.ts +++ b/packages/twenty-front/src/modules/activities/tasks/hooks/useTasks.ts @@ -1,5 +1,4 @@ import { useEffect, useMemo } from 'react'; -import { isNonEmptyArray } from '@sniptt/guards'; import { DateTime } from 'luxon'; import { useRecoilState, useRecoilValue } from 'recoil'; @@ -9,8 +8,8 @@ import { currentIncompleteTaskQueryVariablesState } from '@/activities/tasks/sta import { FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY } from '@/activities/timeline/constants/FindManyTimelineActivitiesOrderBy'; import { Activity } from '@/activities/types/Activity'; import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity'; +import { RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; -import { ObjectRecordQueryVariables } from '@/object-record/types/ObjectRecordQueryVariables'; import { parseDate } from '~/utils/date-utils'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; @@ -41,8 +40,6 @@ export const useTasks = ({ [selectedFilter], ); - const skipActivityTargets = !isNonEmptyArray(targetableObjects); - const completedQueryVariables = useMemo( () => ({ @@ -52,7 +49,7 @@ export const useTasks = ({ ...assigneeIdFilter, }, orderBy: FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY, - }) as ObjectRecordQueryVariables, + }) as RecordGqlOperationVariables, [assigneeIdFilter], ); @@ -65,7 +62,7 @@ export const useTasks = ({ ...assigneeIdFilter, }, orderBy: FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY, - }) as ObjectRecordQueryVariables, + }) as RecordGqlOperationVariables, [assigneeIdFilter], ); @@ -110,24 +107,16 @@ export const useTasks = ({ setCurrentIncompleteTaskQueryVariables, ]); - const { - activities: completeTasksData, - initialized: initializedCompleteTasks, - } = useActivities({ + const { activities: completeTasksData } = useActivities({ targetableObjects, activitiesFilters: completedQueryVariables.filter ?? {}, activitiesOrderByVariables: completedQueryVariables.orderBy ?? {}, - skipActivityTargets, }); - const { - activities: incompleteTaskData, - initialized: initializedIncompleteTasks, - } = useActivities({ + const { activities: incompleteTaskData } = useActivities({ targetableObjects, activitiesFilters: incompleteQueryVariables.filter ?? {}, activitiesOrderByVariables: incompleteQueryVariables.orderBy ?? {}, - skipActivityTargets, }); const todayOrPreviousTasks = incompleteTaskData?.filter((task) => { @@ -159,6 +148,5 @@ export const useTasks = ({ upcomingTasks: (upcomingTasks ?? []) as Activity[], unscheduledTasks: (unscheduledTasks ?? []) as Activity[], completedTasks: (completedTasks ?? []) as Activity[], - initialized: initializedCompleteTasks && initializedIncompleteTasks, }; }; diff --git a/packages/twenty-front/src/modules/activities/tasks/states/currentCompletedTaskQueryVariablesState.ts b/packages/twenty-front/src/modules/activities/tasks/states/currentCompletedTaskQueryVariablesState.ts index d408d89e31..f5c592dac5 100644 --- a/packages/twenty-front/src/modules/activities/tasks/states/currentCompletedTaskQueryVariablesState.ts +++ b/packages/twenty-front/src/modules/activities/tasks/states/currentCompletedTaskQueryVariablesState.ts @@ -1,9 +1,9 @@ import { atom } from 'recoil'; -import { ObjectRecordQueryVariables } from '@/object-record/types/ObjectRecordQueryVariables'; +import { RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables'; export const currentCompletedTaskQueryVariablesState = - atom({ + atom({ default: null, key: 'currentCompletedTaskQueryVariablesState', }); diff --git a/packages/twenty-front/src/modules/activities/tasks/states/currentIncompleteTaskQueryVariablesState.ts b/packages/twenty-front/src/modules/activities/tasks/states/currentIncompleteTaskQueryVariablesState.ts index 9a18ac27a8..d404068cd1 100644 --- a/packages/twenty-front/src/modules/activities/tasks/states/currentIncompleteTaskQueryVariablesState.ts +++ b/packages/twenty-front/src/modules/activities/tasks/states/currentIncompleteTaskQueryVariablesState.ts @@ -1,9 +1,9 @@ import { atom } from 'recoil'; -import { ObjectRecordQueryVariables } from '@/object-record/types/ObjectRecordQueryVariables'; +import { RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables'; export const currentIncompleteTaskQueryVariablesState = - atom({ + atom({ default: null, key: 'currentIncompleteTaskQueryVariablesState', }); diff --git a/packages/twenty-front/src/modules/activities/timeline/components/Timeline.tsx b/packages/twenty-front/src/modules/activities/timeline/components/Timeline.tsx index 37cc77560e..64f713e4d1 100644 --- a/packages/twenty-front/src/modules/activities/timeline/components/Timeline.tsx +++ b/packages/twenty-front/src/modules/activities/timeline/components/Timeline.tsx @@ -2,7 +2,7 @@ import styled from '@emotion/styled'; import { useRecoilValue } from 'recoil'; import { TimelineCreateButtonGroup } from '@/activities/timeline/components/TimelineCreateButtonGroup'; -import { timelineActivitiesNetworkingState } from '@/activities/timeline/states/timelineActivitiesNetworkingState'; +import { timelineActivitiesForGroupState } from '@/activities/timeline/states/timelineActivitiesForGroupState'; import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity'; import AnimatedPlaceholder from '@/ui/layout/animated-placeholder/components/AnimatedPlaceholder'; import { @@ -32,20 +32,11 @@ export const Timeline = ({ }: { targetableObject: ActivityTargetableObject; }) => { - const { initialized, noActivities } = useRecoilValue( - timelineActivitiesNetworkingState, + const timelineActivitiesForGroup = useRecoilValue( + timelineActivitiesForGroupState, ); - const showEmptyState = noActivities; - - const showLoadingState = !initialized; - - if (showLoadingState) { - // TODO: Display a beautiful loading page - return <>; - } - - if (showEmptyState) { + if (timelineActivitiesForGroup.length === 0) { return ( diff --git a/packages/twenty-front/src/modules/activities/timeline/components/TimelineQueryEffect.tsx b/packages/twenty-front/src/modules/activities/timeline/components/TimelineQueryEffect.tsx index 26a2b781b7..88c9669119 100644 --- a/packages/twenty-front/src/modules/activities/timeline/components/TimelineQueryEffect.tsx +++ b/packages/twenty-front/src/modules/activities/timeline/components/TimelineQueryEffect.tsx @@ -6,7 +6,6 @@ import { FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY } from '@/activities/timeline/co import { objectShowPageTargetableObjectState } from '@/activities/timeline/states/objectShowPageTargetableObjectIdState'; import { timelineActivitiesFammilyState } from '@/activities/timeline/states/timelineActivitiesFamilyState'; import { timelineActivitiesForGroupState } from '@/activities/timeline/states/timelineActivitiesForGroupState'; -import { timelineActivitiesNetworkingState } from '@/activities/timeline/states/timelineActivitiesNetworkingState'; import { timelineActivityWithoutTargetsFamilyState } from '@/activities/timeline/states/timelineActivityWithoutTargetsFamilyState'; import { Activity } from '@/activities/types/Activity'; import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity'; @@ -27,16 +26,13 @@ export const TimelineQueryEffect = ({ setTimelineTargetableObject(targetableObject); }, [targetableObject, setTimelineTargetableObject]); - const { activities, initialized, noActivities } = useActivities({ + const { activities } = useActivities({ targetableObjects: [targetableObject], activitiesFilters: {}, activitiesOrderByVariables: FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY, skip: !isDefined(targetableObject), }); - const [timelineActivitiesNetworking, setTimelineActivitiesNetworking] = - useRecoilState(timelineActivitiesNetworkingState); - const [timelineActivitiesForGroup, setTimelineActivitiesForGroup] = useRecoilState(timelineActivitiesForGroupState); @@ -49,6 +45,7 @@ export const TimelineQueryEffect = ({ ...activities.map((activity) => ({ id: activity.id, createdAt: activity.createdAt, + __typename: activity.__typename, })), ].sort(sortObjectRecordByDateField('createdAt', 'DescNullsLast')); @@ -59,23 +56,9 @@ export const TimelineQueryEffect = ({ if (!isDeeplyEqual(activitiesForGroup, timelineActivitiesForGroupSorted)) { setTimelineActivitiesForGroup(activitiesForGroup); } - - if ( - !isDeeplyEqual(timelineActivitiesNetworking.initialized, initialized) || - !isDeeplyEqual(timelineActivitiesNetworking.noActivities, noActivities) - ) { - setTimelineActivitiesNetworking({ - initialized, - noActivities, - }); - } }, [ activities, - initialized, - noActivities, - setTimelineActivitiesNetworking, targetableObject, - timelineActivitiesNetworking, timelineActivitiesForGroup, setTimelineActivitiesForGroup, ]); diff --git a/packages/twenty-front/src/modules/activities/timeline/constants/FindManyTimelineActivitiesOrderBy.ts b/packages/twenty-front/src/modules/activities/timeline/constants/FindManyTimelineActivitiesOrderBy.ts index 47de19c1e9..4e48c6dc5f 100644 --- a/packages/twenty-front/src/modules/activities/timeline/constants/FindManyTimelineActivitiesOrderBy.ts +++ b/packages/twenty-front/src/modules/activities/timeline/constants/FindManyTimelineActivitiesOrderBy.ts @@ -1,5 +1,6 @@ -import { OrderByField } from '@/object-metadata/types/OrderByField'; +import { RecordGqlOperationOrderBy } from '@/object-record/graphql/types/RecordGqlOperationOrderBy'; -export const FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY: OrderByField = { - createdAt: 'DescNullsFirst', -}; +export const FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY: RecordGqlOperationOrderBy = + { + createdAt: 'DescNullsFirst', + }; diff --git a/packages/twenty-front/src/modules/activities/timeline/hooks/useTimelineActivities.ts b/packages/twenty-front/src/modules/activities/timeline/hooks/useTimelineActivities.ts index f114b3f8d9..73eade9617 100644 --- a/packages/twenty-front/src/modules/activities/timeline/hooks/useTimelineActivities.ts +++ b/packages/twenty-front/src/modules/activities/timeline/hooks/useTimelineActivities.ts @@ -1,4 +1,4 @@ -import { useEffect, useState } from 'react'; +import { useEffect } from 'react'; import { isNonEmptyArray, isNonEmptyString } from '@sniptt/guards'; import { useRecoilCallback, useRecoilState } from 'recoil'; @@ -28,15 +28,10 @@ export const useTimelineActivities = ({ } }, [targetableObject, setObjectShowPageTargetableObject]); - const { - activityTargets, - loadingActivityTargets, - initialized: initializedActivityTargets, - } = useActivityTargetsForTargetableObject({ - targetableObject, - }); - - const [initialized, setInitialized] = useState(false); + const { activityTargets, loadingActivityTargets } = + useActivityTargetsForTargetableObject({ + targetableObject, + }); const activityIds = Array.from( new Set( @@ -65,33 +60,18 @@ export const useTimelineActivities = ({ onCompleted: useRecoilCallback( ({ set }) => (activities) => { - if (!initialized) { - setInitialized(true); - } - for (const activity of activities) { set(recordStoreFamilyState(activity.id), activity); } }, - [initialized], + [], ), - depth: 3, }); - const noActivityTargets = - initializedActivityTargets && !isNonEmptyArray(activityTargets); - - useEffect(() => { - if (noActivityTargets) { - setInitialized(true); - } - }, [noActivityTargets]); - const loading = loadingActivities || loadingActivityTargets; return { activities, loading, - initialized, }; }; diff --git a/packages/twenty-front/src/modules/activities/timeline/states/timelineActivitiesNetworkingState.ts b/packages/twenty-front/src/modules/activities/timeline/states/timelineActivitiesNetworkingState.ts deleted file mode 100644 index 24b4ecd6ec..0000000000 --- a/packages/twenty-front/src/modules/activities/timeline/states/timelineActivitiesNetworkingState.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { createState } from 'twenty-ui'; - -export const timelineActivitiesNetworkingState = createState<{ - initialized: boolean; - noActivities: boolean; -}>({ - key: 'timelineActivitiesNetworkingState', - defaultValue: { - initialized: false, - noActivities: false, - }, -}); diff --git a/packages/twenty-front/src/modules/activities/timeline/utils/groupActivitiesByMonth.ts b/packages/twenty-front/src/modules/activities/timeline/utils/groupActivitiesByMonth.ts index 44bf5b9e40..5764e6ee11 100644 --- a/packages/twenty-front/src/modules/activities/timeline/utils/groupActivitiesByMonth.ts +++ b/packages/twenty-front/src/modules/activities/timeline/utils/groupActivitiesByMonth.ts @@ -1,7 +1,10 @@ import { Activity } from '@/activities/types/Activity'; import { isDefined } from '~/utils/isDefined'; -export type ActivityForActivityGroup = Pick; +export type ActivityForActivityGroup = Pick< + Activity, + 'id' | 'createdAt' | '__typename' +>; export type ActivityGroup = { month: number; diff --git a/packages/twenty-front/src/modules/activities/timeline/utils/makeTimelineActivitiesQueryVariables.ts b/packages/twenty-front/src/modules/activities/timeline/utils/makeTimelineActivitiesQueryVariables.ts index eaf14bdab7..c8a7030d2d 100644 --- a/packages/twenty-front/src/modules/activities/timeline/utils/makeTimelineActivitiesQueryVariables.ts +++ b/packages/twenty-front/src/modules/activities/timeline/utils/makeTimelineActivitiesQueryVariables.ts @@ -1,11 +1,12 @@ -import { ObjectRecordQueryVariables } from '@/object-record/types/ObjectRecordQueryVariables'; +import { RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables'; import { sortByAscString } from '~/utils/array/sortByAscString'; +// Todo: this should be replace by the operationSignatureFactory pattern export const makeTimelineActivitiesQueryVariables = ({ activityIds, }: { activityIds: string[]; -}): ObjectRecordQueryVariables => { +}): RecordGqlOperationVariables => { return { filter: { id: { diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/types/TimelineActivity.ts b/packages/twenty-front/src/modules/activities/timelineActivities/types/TimelineActivity.ts index d7cf52b680..5c7a2df20f 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/types/TimelineActivity.ts +++ b/packages/twenty-front/src/modules/activities/timelineActivities/types/TimelineActivity.ts @@ -12,4 +12,5 @@ export type TimelineActivity = { linkedRecordCachedName: string; linkedRecordId: string; linkedObjectMetadataId: string; + __typename: 'TimelineActivity'; }; diff --git a/packages/twenty-front/src/modules/activities/types/ActivityForEditor.ts b/packages/twenty-front/src/modules/activities/types/ActivityForEditor.ts index 611f3794f2..b31c7e5d2d 100644 --- a/packages/twenty-front/src/modules/activities/types/ActivityForEditor.ts +++ b/packages/twenty-front/src/modules/activities/types/ActivityForEditor.ts @@ -5,7 +5,14 @@ import { WorkspaceMember } from '~/generated-metadata/graphql'; export type ActivityForEditor = Pick< Activity, - 'id' | 'title' | 'body' | 'type' | 'completedAt' | 'dueAt' | 'updatedAt' + | 'id' + | 'title' + | 'body' + | 'type' + | 'completedAt' + | 'dueAt' + | 'updatedAt' + | '__typename' > & { comments?: Comment[]; } & { diff --git a/packages/twenty-front/src/modules/activities/types/ActivityTarget.ts b/packages/twenty-front/src/modules/activities/types/ActivityTarget.ts index b06cb6b39a..34de00868c 100644 --- a/packages/twenty-front/src/modules/activities/types/ActivityTarget.ts +++ b/packages/twenty-front/src/modules/activities/types/ActivityTarget.ts @@ -12,4 +12,5 @@ export type ActivityTarget = { person?: Pick | null; company?: Pick | null; [key: string]: any; + __typename: 'ActivityTarget'; }; diff --git a/packages/twenty-front/src/modules/activities/types/Comment.ts b/packages/twenty-front/src/modules/activities/types/Comment.ts index 3b3375cd68..0e73848d0b 100644 --- a/packages/twenty-front/src/modules/activities/types/Comment.ts +++ b/packages/twenty-front/src/modules/activities/types/Comment.ts @@ -7,4 +7,5 @@ export type Comment = { updatedAt: string; activityId: string; author: Pick; + __typename: 'Comment'; }; diff --git a/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/sortCachedObjectEdges.ts b/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/sortCachedObjectEdges.ts index 10d4514af8..aa8434f0ba 100644 --- a/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/sortCachedObjectEdges.ts +++ b/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/sortCachedObjectEdges.ts @@ -1,9 +1,9 @@ import { Reference, StoreObject } from '@apollo/client'; import { ReadFieldFunction } from '@apollo/client/cache/core/types/common'; -import { CachedObjectRecordEdge } from '@/apollo/types/CachedObjectRecordEdge'; import { OrderBy } from '@/object-metadata/types/OrderBy'; -import { OrderByField } from '@/object-metadata/types/OrderByField'; +import { RecordGqlRefEdge } from '@/object-record/cache/types/RecordGqlRefEdge'; +import { RecordGqlOperationOrderBy } from '@/object-record/graphql/types/RecordGqlOperationOrderBy'; import { isDefined } from '~/utils/isDefined'; import { sortAsc, sortDesc, sortNullsFirst, sortNullsLast } from '~/utils/sort'; @@ -12,8 +12,8 @@ export const sortCachedObjectEdges = ({ orderBy, readCacheField, }: { - edges: CachedObjectRecordEdge[]; - orderBy: OrderByField; + edges: RecordGqlRefEdge[]; + orderBy: RecordGqlOperationOrderBy; readCacheField: ReadFieldFunction; }) => { const [orderByFieldName, orderByFieldValue] = Object.entries(orderBy)[0]; @@ -23,7 +23,7 @@ export const sortCachedObjectEdges = ({ : Object.entries(orderByFieldValue)[0]; const readFieldValueToSort = ( - edge: CachedObjectRecordEdge, + edge: RecordGqlRefEdge, ): string | number | null => { const recordFromCache = edge.node; const fieldValue = diff --git a/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerAttachRelationOptimisticEffect.ts b/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerAttachRelationOptimisticEffect.ts index 67ba4f8c69..bb650cad78 100644 --- a/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerAttachRelationOptimisticEffect.ts +++ b/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerAttachRelationOptimisticEffect.ts @@ -1,6 +1,6 @@ import { ApolloCache, StoreObject } from '@apollo/client'; -import { CachedObjectRecordEdge } from '@/apollo/types/CachedObjectRecordEdge'; +import { RecordGqlRefEdge } from '@/object-record/cache/types/RecordGqlRefEdge'; import { isObjectRecordConnectionWithRefs } from '@/object-record/cache/utils/isObjectRecordConnectionWithRefs'; import { isDefined } from '~/utils/isDefined'; import { capitalize } from '~/utils/string/capitalize'; @@ -48,7 +48,7 @@ export const triggerAttachRelationOptimisticEffect = ({ } if (fieldValueisObjectRecordConnectionWithRefs) { - const nextEdges: CachedObjectRecordEdge[] = [ + const nextEdges: RecordGqlRefEdge[] = [ ...targetRecordFieldValue.edges, { __typename: `${sourceRecordTypeName}Edge`, diff --git a/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect.ts b/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect.ts index 84d7aab6bf..4d9a7f69c0 100644 --- a/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect.ts +++ b/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect.ts @@ -2,11 +2,11 @@ import { ApolloCache, StoreObject } from '@apollo/client'; import { isNonEmptyString } from '@sniptt/guards'; import { triggerUpdateRelationsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerUpdateRelationsOptimisticEffect'; -import { CachedObjectRecord } from '@/apollo/types/CachedObjectRecord'; -import { CachedObjectRecordEdge } from '@/apollo/types/CachedObjectRecordEdge'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { RecordGqlRefEdge } from '@/object-record/cache/types/RecordGqlRefEdge'; import { getEdgeTypename } from '@/object-record/cache/utils/getEdgeTypename'; import { isObjectRecordConnectionWithRefs } from '@/object-record/cache/utils/isObjectRecordConnectionWithRefs'; +import { RecordGqlNode } from '@/object-record/graphql/types/RecordGqlNode'; /* TODO: for now new records are added to all cached record lists, no matter what the variables (filters, orderBy, etc.) are. @@ -21,7 +21,7 @@ export const triggerCreateRecordsOptimisticEffect = ({ }: { cache: ApolloCache; objectMetadataItem: ObjectMetadataItem; - recordsToCreate: CachedObjectRecord[]; + recordsToCreate: RecordGqlNode[]; objectMetadataItems: ObjectMetadataItem[]; }) => { recordsToCreate.forEach((record) => @@ -56,7 +56,7 @@ export const triggerCreateRecordsOptimisticEffect = ({ const rootQueryCachedObjectRecordConnection = rootQueryCachedResponse; - const rootQueryCachedRecordEdges = readField( + const rootQueryCachedRecordEdges = readField( 'edges', rootQueryCachedObjectRecordConnection, ); diff --git a/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerDeleteRecordsOptimisticEffect.ts b/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerDeleteRecordsOptimisticEffect.ts index 7c381ac866..e7b1219543 100644 --- a/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerDeleteRecordsOptimisticEffect.ts +++ b/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerDeleteRecordsOptimisticEffect.ts @@ -1,11 +1,11 @@ import { ApolloCache, StoreObject } from '@apollo/client'; import { triggerUpdateRelationsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerUpdateRelationsOptimisticEffect'; -import { CachedObjectRecord } from '@/apollo/types/CachedObjectRecord'; -import { CachedObjectRecordEdge } from '@/apollo/types/CachedObjectRecordEdge'; import { CachedObjectRecordQueryVariables } from '@/apollo/types/CachedObjectRecordQueryVariables'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { RecordGqlRefEdge } from '@/object-record/cache/types/RecordGqlRefEdge'; import { isObjectRecordConnectionWithRefs } from '@/object-record/cache/utils/isObjectRecordConnectionWithRefs'; +import { RecordGqlNode } from '@/object-record/graphql/types/RecordGqlNode'; import { isDefined } from '~/utils/isDefined'; import { parseApolloStoreFieldName } from '~/utils/parseApolloStoreFieldName'; @@ -17,7 +17,7 @@ export const triggerDeleteRecordsOptimisticEffect = ({ }: { cache: ApolloCache; objectMetadataItem: ObjectMetadataItem; - recordsToDelete: CachedObjectRecord[]; + recordsToDelete: RecordGqlNode[]; objectMetadataItems: ObjectMetadataItem[]; }) => { cache.modify({ @@ -45,7 +45,7 @@ export const triggerDeleteRecordsOptimisticEffect = ({ const recordIdsToDelete = recordsToDelete.map(({ id }) => id); - const cachedEdges = readField( + const cachedEdges = readField( 'edges', rootQueryCachedObjectRecordConnection, ); diff --git a/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerUpdateRecordOptimisticEffect.ts b/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerUpdateRecordOptimisticEffect.ts index 50c1faf790..97284ab2be 100644 --- a/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerUpdateRecordOptimisticEffect.ts +++ b/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerUpdateRecordOptimisticEffect.ts @@ -2,12 +2,12 @@ import { ApolloCache, StoreObject } from '@apollo/client'; import { sortCachedObjectEdges } from '@/apollo/optimistic-effect/utils/sortCachedObjectEdges'; import { triggerUpdateRelationsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerUpdateRelationsOptimisticEffect'; -import { CachedObjectRecord } from '@/apollo/types/CachedObjectRecord'; -import { CachedObjectRecordEdge } from '@/apollo/types/CachedObjectRecordEdge'; import { CachedObjectRecordQueryVariables } from '@/apollo/types/CachedObjectRecordQueryVariables'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { RecordGqlRefEdge } from '@/object-record/cache/types/RecordGqlRefEdge'; import { getEdgeTypename } from '@/object-record/cache/utils/getEdgeTypename'; import { isObjectRecordConnectionWithRefs } from '@/object-record/cache/utils/isObjectRecordConnectionWithRefs'; +import { RecordGqlNode } from '@/object-record/graphql/types/RecordGqlNode'; import { isRecordMatchingFilter } from '@/object-record/record-filter/utils/isRecordMatchingFilter'; import { isDefined } from '~/utils/isDefined'; import { parseApolloStoreFieldName } from '~/utils/parseApolloStoreFieldName'; @@ -23,8 +23,8 @@ export const triggerUpdateRecordOptimisticEffect = ({ }: { cache: ApolloCache; objectMetadataItem: ObjectMetadataItem; - currentRecord: CachedObjectRecord; - updatedRecord: CachedObjectRecord; + currentRecord: RecordGqlNode; + updatedRecord: RecordGqlNode; objectMetadataItems: ObjectMetadataItem[]; }) => { triggerUpdateRelationsOptimisticEffect({ @@ -58,8 +58,7 @@ export const triggerUpdateRecordOptimisticEffect = ({ ); const rootQueryCurrentEdges = - readField('edges', rootQueryConnection) ?? - []; + readField('edges', rootQueryConnection) ?? []; let rootQueryNextEdges = [...rootQueryCurrentEdges]; diff --git a/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerUpdateRelationsOptimisticEffect.ts b/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerUpdateRelationsOptimisticEffect.ts index d8deb5119d..0b12d7524b 100644 --- a/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerUpdateRelationsOptimisticEffect.ts +++ b/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerUpdateRelationsOptimisticEffect.ts @@ -4,12 +4,13 @@ import { getRelationDefinition } from '@/apollo/optimistic-effect/utils/getRelat import { triggerAttachRelationOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerAttachRelationOptimisticEffect'; import { triggerDeleteRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerDeleteRecordsOptimisticEffect'; import { triggerDetachRelationOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerDetachRelationOptimisticEffect'; -import { CachedObjectRecord } from '@/apollo/types/CachedObjectRecord'; import { CORE_OBJECT_NAMES_TO_DELETE_ON_TRIGGER_RELATION_DETACH } from '@/apollo/types/coreObjectNamesToDeleteOnRelationDetach'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { isObjectRecordConnection } from '@/object-record/cache/utils/isObjectRecordConnection'; -import { ObjectRecordConnection } from '@/object-record/types/ObjectRecordConnection'; +import { RecordGqlConnection } from '@/object-record/graphql/types/RecordGqlConnection'; +import { RecordGqlNode } from '@/object-record/graphql/types/RecordGqlNode'; +import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; import { isDefined } from '~/utils/isDefined'; @@ -23,8 +24,8 @@ export const triggerUpdateRelationsOptimisticEffect = ({ }: { cache: ApolloCache; sourceObjectMetadataItem: ObjectMetadataItem; - currentSourceRecord: CachedObjectRecord | null; - updatedSourceRecord: CachedObjectRecord | null; + currentSourceRecord: ObjectRecord | null; + updatedSourceRecord: ObjectRecord | null; objectMetadataItems: ObjectMetadataItem[]; }) => { return sourceObjectMetadataItem.fields.forEach( @@ -56,13 +57,13 @@ export const triggerUpdateRelationsOptimisticEffect = ({ relationDefinition; const currentFieldValueOnSourceRecord: - | ObjectRecordConnection - | CachedObjectRecord + | RecordGqlConnection + | RecordGqlNode | null = currentSourceRecord?.[fieldMetadataItemOnSourceRecord.name]; const updatedFieldValueOnSourceRecord: - | ObjectRecordConnection - | CachedObjectRecord + | RecordGqlConnection + | RecordGqlNode | null = updatedSourceRecord?.[fieldMetadataItemOnSourceRecord.name]; if ( @@ -85,7 +86,7 @@ export const triggerUpdateRelationsOptimisticEffect = ({ const targetRecordsToDetachFrom = currentFieldValueOnSourceRecordIsARecordConnection ? currentFieldValueOnSourceRecord.edges.map( - ({ node }) => node as CachedObjectRecord, + ({ node }) => node as RecordGqlNode, ) : [currentFieldValueOnSourceRecord].filter(isDefined); @@ -98,7 +99,7 @@ export const triggerUpdateRelationsOptimisticEffect = ({ const targetRecordsToAttachTo = updatedFieldValueOnSourceRecordIsARecordConnection ? updatedFieldValueOnSourceRecord.edges.map( - ({ node }) => node as CachedObjectRecord, + ({ node }) => node as RecordGqlNode, ) : [updatedFieldValueOnSourceRecord].filter(isDefined); diff --git a/packages/twenty-front/src/modules/apollo/types/CachedObjectRecord.ts b/packages/twenty-front/src/modules/apollo/types/CachedObjectRecord.ts deleted file mode 100644 index a457a06e0c..0000000000 --- a/packages/twenty-front/src/modules/apollo/types/CachedObjectRecord.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ObjectRecord } from '@/object-record/types/ObjectRecord'; - -export type CachedObjectRecord = T & { - __typename: string; -}; diff --git a/packages/twenty-front/src/modules/apollo/types/CachedObjectRecordConnection.ts b/packages/twenty-front/src/modules/apollo/types/CachedObjectRecordConnection.ts deleted file mode 100644 index 2be8f206b0..0000000000 --- a/packages/twenty-front/src/modules/apollo/types/CachedObjectRecordConnection.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { CachedObjectRecordEdge } from '@/apollo/types/CachedObjectRecordEdge'; -import { ObjectRecordConnection } from '@/object-record/types/ObjectRecordConnection'; - -export type CachedObjectRecordConnection = Omit< - ObjectRecordConnection, - 'edges' -> & { - edges: CachedObjectRecordEdge[]; -}; diff --git a/packages/twenty-front/src/modules/apollo/types/CachedObjectRecordEdge.ts b/packages/twenty-front/src/modules/apollo/types/CachedObjectRecordEdge.ts deleted file mode 100644 index 7ed37067b8..0000000000 --- a/packages/twenty-front/src/modules/apollo/types/CachedObjectRecordEdge.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Reference } from '@apollo/client'; - -import { ObjectRecordEdge } from '@/object-record/types/ObjectRecordEdge'; - -export type CachedObjectRecordEdge = Omit & { - node: Reference; -}; diff --git a/packages/twenty-front/src/modules/apollo/types/CachedObjectRecordQueryVariables.ts b/packages/twenty-front/src/modules/apollo/types/CachedObjectRecordQueryVariables.ts index c7430ce700..a627ca89a4 100644 --- a/packages/twenty-front/src/modules/apollo/types/CachedObjectRecordQueryVariables.ts +++ b/packages/twenty-front/src/modules/apollo/types/CachedObjectRecordQueryVariables.ts @@ -1,6 +1,6 @@ -import { ObjectRecordQueryVariables } from '@/object-record/types/ObjectRecordQueryVariables'; +import { RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables'; export type CachedObjectRecordQueryVariables = Omit< - ObjectRecordQueryVariables, + RecordGqlOperationVariables, 'limit' -> & { first?: ObjectRecordQueryVariables['limit'] }; +> & { first?: RecordGqlOperationVariables['limit'] }; diff --git a/packages/twenty-front/src/modules/files/graphql/queries/uploadFile.ts b/packages/twenty-front/src/modules/attachments/graphql/queries/uploadFile.ts similarity index 100% rename from packages/twenty-front/src/modules/files/graphql/queries/uploadFile.ts rename to packages/twenty-front/src/modules/attachments/graphql/queries/uploadFile.ts diff --git a/packages/twenty-front/src/modules/files/graphql/queries/uploadImage.ts b/packages/twenty-front/src/modules/attachments/graphql/queries/uploadImage.ts similarity index 100% rename from packages/twenty-front/src/modules/files/graphql/queries/uploadImage.ts rename to packages/twenty-front/src/modules/attachments/graphql/queries/uploadImage.ts diff --git a/packages/twenty-front/src/modules/attachments/types/Attachment.ts b/packages/twenty-front/src/modules/attachments/types/Attachment.ts deleted file mode 100644 index 21f316d8e0..0000000000 --- a/packages/twenty-front/src/modules/attachments/types/Attachment.ts +++ /dev/null @@ -1,6 +0,0 @@ -export type Attachment = { - id: string; - createdAt: string; - updatedAt: string; - deletedAt: string | null; -}; diff --git a/packages/twenty-front/src/modules/favorites/types/Favorite.ts b/packages/twenty-front/src/modules/favorites/types/Favorite.ts index 14332e1e57..a004141379 100644 --- a/packages/twenty-front/src/modules/favorites/types/Favorite.ts +++ b/packages/twenty-front/src/modules/favorites/types/Favorite.ts @@ -9,4 +9,5 @@ export type Favorite = { avatarType: AvatarType; link: string; recordId: string; + __typename: 'Favorite'; }; diff --git a/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsLoadEffect.tsx b/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsLoadEffect.tsx index 11a60715b4..103af4b230 100644 --- a/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsLoadEffect.tsx +++ b/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsLoadEffect.tsx @@ -4,6 +4,7 @@ import { useRecoilState, useRecoilValue } from 'recoil'; import { currentUserState } from '@/auth/states/currentUserState'; import { useFindManyObjectMetadataItems } from '@/object-metadata/hooks/useFindManyObjectMetadataItems'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; +import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; @@ -19,10 +20,18 @@ export const ObjectMetadataItemsLoadEffect = () => { ); useEffect(() => { - if (!isDeeplyEqual(objectMetadataItems, newObjectMetadataItems)) { - setObjectMetadataItems(newObjectMetadataItems); + const toSetObjectMetadataItems = isUndefinedOrNull(currentUser) + ? getObjectMetadataItemsMock() + : newObjectMetadataItems; + if (!isDeeplyEqual(objectMetadataItems, toSetObjectMetadataItems)) { + setObjectMetadataItems(toSetObjectMetadataItems); } - }, [newObjectMetadataItems, objectMetadataItems, setObjectMetadataItems]); + }, [ + currentUser, + newObjectMetadataItems, + objectMetadataItems, + setObjectMetadataItems, + ]); return <>; }; diff --git a/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsProvider.tsx b/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsProvider.tsx index eafc5c8849..85f240db9e 100644 --- a/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsProvider.tsx +++ b/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsProvider.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { useRecoilValue } from 'recoil'; -import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { ObjectMetadataItemsLoadEffect } from '@/object-metadata/components/ObjectMetadataItemsLoadEffect'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { RelationPickerScope } from '@/object-record/relation-picker/scopes/RelationPickerScope'; @@ -10,10 +9,8 @@ export const ObjectMetadataItemsProvider = ({ children, }: React.PropsWithChildren) => { const objectMetadataItems = useRecoilValue(objectMetadataItemsState); - const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); - const shouldDisplayChildren = - objectMetadataItems.length > 0 || !currentWorkspaceMember; + const shouldDisplayChildren = objectMetadataItems.length > 0; return ( <> diff --git a/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataNavItems.tsx b/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataNavItems.tsx index cbecac5758..69a68c2fb4 100644 --- a/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataNavItems.tsx +++ b/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataNavItems.tsx @@ -5,7 +5,7 @@ import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilte import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData'; import { PrefetchKey } from '@/prefetch/types/PrefetchKey'; import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem'; -import { GraphQLView } from '@/views/types/GraphQLView'; +import { View } from '@/views/types/View'; import { getObjectMetadataItemViews } from '@/views/utils/getObjectMetadataItemViews'; export const ObjectMetadataNavItems = () => { @@ -14,9 +14,7 @@ export const ObjectMetadataNavItems = () => { const { getIcon } = useIcons(); const currentPath = useLocation().pathname; - const { records: views } = usePrefetchedData( - PrefetchKey.AllViews, - ); + const { records: views } = usePrefetchedData(PrefetchKey.AllViews); return ( <> diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/useGetObjectOrderByField.ts b/packages/twenty-front/src/modules/object-metadata/hooks/useGetObjectOrderByField.ts index 111058a5ef..d656378ea2 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/useGetObjectOrderByField.ts +++ b/packages/twenty-front/src/modules/object-metadata/hooks/useGetObjectOrderByField.ts @@ -1,7 +1,7 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { OrderBy } from '@/object-metadata/types/OrderBy'; -import { OrderByField } from '@/object-metadata/types/OrderByField'; import { getOrderByFieldForObjectMetadataItem } from '@/object-metadata/utils/getObjectOrderByField'; +import { RecordGqlOperationOrderBy } from '@/object-record/graphql/types/RecordGqlOperationOrderBy'; export const useGetObjectOrderByField = ({ objectNameSingular, @@ -12,7 +12,9 @@ export const useGetObjectOrderByField = ({ objectNameSingular, }); - const getObjectOrderByField = (orderBy: OrderBy): OrderByField => { + const getObjectOrderByField = ( + orderBy: OrderBy, + ): RecordGqlOperationOrderBy => { return getOrderByFieldForObjectMetadataItem(objectMetadataItem, orderBy); }; diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItem.ts b/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItem.ts index 4f4f777c1f..91e4107fda 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItem.ts +++ b/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItem.ts @@ -14,6 +14,7 @@ export const useObjectMetadataItem = ({ }: ObjectMetadataItemIdentifier) => { const currentWorkspace = useRecoilValue(currentWorkspaceState); + // Todo: deprecate this logic as mocked objectMetadataItems are laod in ObjectMetadataItemsLoadEffect anyway const mockObjectMetadataItems = getObjectMetadataItemsMock(); let objectMetadataItem = useRecoilValue( diff --git a/packages/twenty-front/src/modules/object-metadata/utils/__tests__/mapFieldMetadataToGraphQLQuery.test.tsx b/packages/twenty-front/src/modules/object-metadata/utils/__tests__/mapFieldMetadataToGraphQLQuery.test.tsx index c13ec68d54..116874b232 100644 --- a/packages/twenty-front/src/modules/object-metadata/utils/__tests__/mapFieldMetadataToGraphQLQuery.test.tsx +++ b/packages/twenty-front/src/modules/object-metadata/utils/__tests__/mapFieldMetadataToGraphQLQuery.test.tsx @@ -37,21 +37,10 @@ describe('mapFieldMetadataToGraphQLQuery', () => { lastName }`); }); - it('should not return relation if depth is < 1', async () => { - const res = mapFieldMetadataToGraphQLQuery({ - objectMetadataItems: mockObjectMetadataItems, - depth: 0, - field: personObjectMetadataItem.fields.find( - (field) => field.name === 'company', - )!, - }); - expect(formatGQLString(res)).toEqual(''); - }); - it('should return relation if it matches depth', async () => { + it('should return non relation subFields if relation', async () => { const res = mapFieldMetadataToGraphQLQuery({ objectMetadataItems: mockObjectMetadataItems, - depth: 1, field: personObjectMetadataItem.fields.find( (field) => field.name === 'company', )!, @@ -83,168 +72,14 @@ accountOwnerId employees id idealCustomerProfile -}`); - }); - it('should return relation with all sub relations if it matches depth', async () => { - const res = mapFieldMetadataToGraphQLQuery({ - objectMetadataItems: mockObjectMetadataItems, - depth: 2, - field: personObjectMetadataItem.fields.find( - (field) => field.name === 'company', - )!, - }); - expect(formatGQLString(res)).toEqual(`company -{ -__typename -xLink -{ - label - url -} -accountOwner -{ -__typename -colorScheme -name -{ - firstName - lastName -} -locale -userId -avatarUrl -createdAt -updatedAt -id -} -linkedinLink -{ - label - url -} -attachments -{ - edges { - node { -__typename -updatedAt -createdAt -name -personId -activityId -companyId -id -authorId -type -fullPath -} - } -} -domainName -opportunities -{ - edges { - node { -__typename -personId -pointOfContactId -updatedAt -companyId -probability -closeDate -amount -{ - amountMicros - currencyCode -} -id -createdAt -} - } -} -annualRecurringRevenue -{ - amountMicros - currencyCode -} -createdAt -address -updatedAt -activityTargets -{ - edges { - node { -__typename -updatedAt -createdAt -personId -activityId -companyId -id -} - } -} -favorites -{ - edges { - node { -__typename -id -companyId -createdAt -personId -position -workspaceMemberId -updatedAt -} - } -} -people -{ - edges { - node { -__typename -xLink -{ - label - url -} -id -createdAt -city -email -jobTitle -name -{ - firstName - lastName -} -phone -linkedinLink -{ - label - url -} -updatedAt -avatarUrl -companyId -} - } -} -name -accountOwnerId -employees -id -idealCustomerProfile }`); }); - it('should return GraphQL fields based on queryFields', async () => { + it('should return only return relation subFields that are in recordGqlFields', async () => { const res = mapFieldMetadataToGraphQLQuery({ objectMetadataItems: mockObjectMetadataItems, - depth: 2, - queryFields: { - accountOwner: true, + relationrecordFields: { + accountOwner: { id: true, name: true }, people: true, xLink: true, linkedinLink: true, @@ -274,17 +109,11 @@ xLink accountOwner { __typename -colorScheme name { firstName lastName } -locale -userId -avatarUrl -createdAt -updatedAt id } linkedinLink diff --git a/packages/twenty-front/src/modules/object-metadata/utils/__tests__/mapObjectMetadataToGraphQLQuery.test.tsx b/packages/twenty-front/src/modules/object-metadata/utils/__tests__/mapObjectMetadataToGraphQLQuery.test.tsx index f8f32cead2..a5261cbfdc 100644 --- a/packages/twenty-front/src/modules/object-metadata/utils/__tests__/mapObjectMetadataToGraphQLQuery.test.tsx +++ b/packages/twenty-front/src/modules/object-metadata/utils/__tests__/mapObjectMetadataToGraphQLQuery.test.tsx @@ -15,209 +15,11 @@ if (!personObjectMetadataItem) { } describe('mapObjectMetadataToGraphQLQuery', () => { - it('should return typename if depth < 0', async () => { + it('should query only specified recordGqlFields', async () => { const res = mapObjectMetadataToGraphQLQuery({ objectMetadataItems: mockObjectMetadataItems, objectMetadataItem: personObjectMetadataItem, - depth: -1, - }); - expect(formatGQLString(res)).toEqual(`{ -__typename -}`); - }); - - it('should return depth 0 if depth = 0', async () => { - const res = mapObjectMetadataToGraphQLQuery({ - objectMetadataItems: mockObjectMetadataItems, - objectMetadataItem: personObjectMetadataItem, - depth: 0, - }); - expect(formatGQLString(res)).toEqual(`{ -__typename -xLink -{ - label - url -} -id -createdAt -city -email -jobTitle -name -{ - firstName - lastName -} -phone -linkedinLink -{ - label - url -} -updatedAt -avatarUrl -companyId -}`); - }); - - it('should return depth 1 if depth = 1', async () => { - const res = mapObjectMetadataToGraphQLQuery({ - objectMetadataItems: mockObjectMetadataItems, - objectMetadataItem: personObjectMetadataItem, - depth: 1, - }); - expect(formatGQLString(res)).toEqual(`{ -__typename -opportunities -{ - edges { - node { -__typename -personId -pointOfContactId -updatedAt -companyId -probability -closeDate -amount -{ - amountMicros - currencyCode -} -id -createdAt -} - } -} -xLink -{ - label - url -} -id -pointOfContactForOpportunities -{ - edges { - node { -__typename -personId -pointOfContactId -updatedAt -companyId -probability -closeDate -amount -{ - amountMicros - currencyCode -} -id -createdAt -} - } -} -createdAt -company -{ -__typename -xLink -{ - label - url -} -linkedinLink -{ - label - url -} -domainName -annualRecurringRevenue -{ - amountMicros - currencyCode -} -createdAt -address -updatedAt -name -accountOwnerId -employees -id -idealCustomerProfile -} -city -email -activityTargets -{ - edges { - node { -__typename -updatedAt -createdAt -personId -activityId -companyId -id -} - } -} -jobTitle -favorites -{ - edges { - node { -__typename -id -companyId -createdAt -personId -position -workspaceMemberId -updatedAt -} - } -} -attachments -{ - edges { - node { -__typename -updatedAt -createdAt -name -personId -activityId -companyId -id -authorId -type -fullPath -} - } -} -name -{ - firstName - lastName -} -phone -linkedinLink -{ - label - url -} -updatedAt -avatarUrl -companyId -}`); - }); - - it('should query only specified queryFields', async () => { - const res = mapObjectMetadataToGraphQLQuery({ - objectMetadataItems: mockObjectMetadataItems, - objectMetadataItem: personObjectMetadataItem, - queryFields: { + recordGqlFields: { company: true, xLink: true, id: true, @@ -232,7 +34,6 @@ companyId avatarUrl: true, companyId: true, }, - depth: 1, }); expect(formatGQLString(res)).toEqual(`{ __typename @@ -291,12 +92,11 @@ companyId }`); }); - it('should load only specified query fields', async () => { + it('should load only specified operation fields nested', async () => { const res = mapObjectMetadataToGraphQLQuery({ objectMetadataItems: mockObjectMetadataItems, objectMetadataItem: personObjectMetadataItem, - queryFields: { company: true, id: true, name: true }, - depth: 1, + recordGqlFields: { company: { id: true }, id: true, name: true }, }); expect(formatGQLString(res)).toEqual(`{ __typename @@ -304,30 +104,7 @@ id company { __typename -xLink -{ - label - url -} -linkedinLink -{ - label - url -} -domainName -annualRecurringRevenue -{ - amountMicros - currencyCode -} -createdAt -address -updatedAt -name -accountOwnerId -employees id -idealCustomerProfile } name { diff --git a/packages/twenty-front/src/modules/object-metadata/utils/__tests__/shouldFieldBeQueried.test.ts b/packages/twenty-front/src/modules/object-metadata/utils/__tests__/shouldFieldBeQueried.test.ts index 32992648d2..23135d32d2 100644 --- a/packages/twenty-front/src/modules/object-metadata/utils/__tests__/shouldFieldBeQueried.test.ts +++ b/packages/twenty-front/src/modules/object-metadata/utils/__tests__/shouldFieldBeQueried.test.ts @@ -2,113 +2,50 @@ import { shouldFieldBeQueried } from '@/object-metadata/utils/shouldFieldBeQueri import { FieldMetadataType } from '~/generated-metadata/graphql'; describe('shouldFieldBeQueried', () => { - describe('if field is not relation', () => { - it('should be queried if depth is undefined', () => { + describe('if recordGqlFields is absent, we query all except relations', () => { + it('should be queried if the field is not a relation', () => { const res = shouldFieldBeQueried({ field: { name: 'fieldName', type: FieldMetadataType.Boolean }, }); expect(res).toBe(true); }); - it('should be queried depth = 0', () => { + it('should not be queried if the field is a relation', () => { const res = shouldFieldBeQueried({ - depth: 0, - field: { name: 'fieldName', type: FieldMetadataType.Boolean }, - }); - expect(res).toBe(true); - }); - - it('should be queried depth > 0', () => { - const res = shouldFieldBeQueried({ - depth: 1, - field: { name: 'fieldName', type: FieldMetadataType.Boolean }, - }); - expect(res).toBe(true); - }); - - it('should NOT be queried depth < 0', () => { - const res = shouldFieldBeQueried({ - depth: -1, - field: { name: 'fieldName', type: FieldMetadataType.Boolean }, + field: { name: 'fieldName', type: FieldMetadataType.Relation }, }); expect(res).toBe(false); }); - - it('should not depends on queryFields', () => { - const res = shouldFieldBeQueried({ - depth: 0, - queryFields: { - fieldName: true, - }, - field: { name: 'fieldName', type: FieldMetadataType.Boolean }, - }); - expect(res).toBe(true); - }); }); - describe('if field is relation', () => { - it('should be queried if queryFields and depth are undefined', () => { + describe('if recordGqlFields is present, we respect it', () => { + it('should be queried if true', () => { const res = shouldFieldBeQueried({ + recordGqlFields: { fieldName: true }, field: { name: 'fieldName', type: FieldMetadataType.Relation }, }); expect(res).toBe(true); }); - it('should be queried if queryFields is undefined and depth = 1', () => { + it('should be queried if object', () => { const res = shouldFieldBeQueried({ - depth: 1, + recordGqlFields: { fieldName: { subFieldName: false } }, field: { name: 'fieldName', type: FieldMetadataType.Relation }, }); expect(res).toBe(true); }); - it('should be queried if queryFields is undefined and depth > 1', () => { + it('should not be queried if false', () => { const res = shouldFieldBeQueried({ - depth: 2, - field: { name: 'fieldName', type: FieldMetadataType.Relation }, - }); - expect(res).toBe(true); - }); - - it('should NOT be queried if queryFields is undefined and depth < 1', () => { - const res = shouldFieldBeQueried({ - depth: 0, + recordGqlFields: { fieldName: false }, field: { name: 'fieldName', type: FieldMetadataType.Relation }, }); expect(res).toBe(false); }); - it('should be queried if queryFields is matching and depth > 1', () => { + it('should not be queried if absent', () => { const res = shouldFieldBeQueried({ - depth: 1, - queryFields: { fieldName: true }, - field: { name: 'fieldName', type: FieldMetadataType.Relation }, - }); - expect(res).toBe(true); - }); - - it('should NOT be queried if queryFields is matching and depth < 1', () => { - const res = shouldFieldBeQueried({ - depth: 0, - queryFields: { fieldName: true }, - field: { name: 'fieldName', type: FieldMetadataType.Relation }, - }); - expect(res).toBe(false); - }); - - it('should NOT be queried if queryFields is not matching (falsy) and depth < 1', () => { - const res = shouldFieldBeQueried({ - depth: 1, - queryFields: { fieldName: false }, - field: { name: 'fieldName', type: FieldMetadataType.Relation }, - }); - expect(res).toBe(false); - }); - - it('should NOT be queried if queryFields is not matching and depth < 1', () => { - const res = shouldFieldBeQueried({ - depth: 0, - queryFields: { anotherFieldName: true }, + recordGqlFields: { otherFieldName: false }, field: { name: 'fieldName', type: FieldMetadataType.Relation }, }); expect(res).toBe(false); diff --git a/packages/twenty-front/src/modules/object-metadata/utils/getObjectOrderByField.ts b/packages/twenty-front/src/modules/object-metadata/utils/getObjectOrderByField.ts index 2219b1a024..97d31c9a6b 100644 --- a/packages/twenty-front/src/modules/object-metadata/utils/getObjectOrderByField.ts +++ b/packages/twenty-front/src/modules/object-metadata/utils/getObjectOrderByField.ts @@ -1,14 +1,14 @@ import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { OrderBy } from '@/object-metadata/types/OrderBy'; -import { OrderByField } from '@/object-metadata/types/OrderByField'; import { getLabelIdentifierFieldMetadataItem } from '@/object-metadata/utils/getLabelIdentifierFieldMetadataItem'; +import { RecordGqlOperationOrderBy } from '@/object-record/graphql/types/RecordGqlOperationOrderBy'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { isDefined } from '~/utils/isDefined'; export const getOrderByFieldForObjectMetadataItem = ( objectMetadataItem: ObjectMetadataItem, orderBy?: OrderBy | null, -): OrderByField => { +): RecordGqlOperationOrderBy => { const labelIdentifierFieldMetadata = getLabelIdentifierFieldMetadataItem(objectMetadataItem); diff --git a/packages/twenty-front/src/modules/object-metadata/utils/mapFieldMetadataToGraphQLQuery.ts b/packages/twenty-front/src/modules/object-metadata/utils/mapFieldMetadataToGraphQLQuery.ts index 172288fc9f..34e80fe1f8 100644 --- a/packages/twenty-front/src/modules/object-metadata/utils/mapFieldMetadataToGraphQLQuery.ts +++ b/packages/twenty-front/src/modules/object-metadata/utils/mapFieldMetadataToGraphQLQuery.ts @@ -10,8 +10,7 @@ import { FieldMetadataItem } from '../types/FieldMetadataItem'; export const mapFieldMetadataToGraphQLQuery = ({ objectMetadataItems, field, - depth = 0, - queryFields, + relationrecordFields, computeReferences = false, }: { objectMetadataItems: ObjectMetadataItem[]; @@ -19,8 +18,7 @@ export const mapFieldMetadataToGraphQLQuery = ({ FieldMetadataItem, 'name' | 'type' | 'toRelationMetadata' | 'fromRelationMetadata' >; - depth?: number; - queryFields?: Record; + relationrecordFields?: Record; computeReferences?: boolean; }): any => { const fieldType = field.type; @@ -47,8 +45,7 @@ export const mapFieldMetadataToGraphQLQuery = ({ return field.name; } else if ( fieldType === 'RELATION' && - field.toRelationMetadata?.relationType === 'ONE_TO_MANY' && - depth > 0 + field.toRelationMetadata?.relationType === 'ONE_TO_MANY' ) { const relationMetadataItem = objectMetadataItems.find( (objectMetadataItem) => @@ -64,15 +61,13 @@ export const mapFieldMetadataToGraphQLQuery = ({ ${mapObjectMetadataToGraphQLQuery({ objectMetadataItems, objectMetadataItem: relationMetadataItem, - depth: depth - 1, - queryFields, + recordGqlFields: relationrecordFields, computeReferences: computeReferences, isRootLevel: false, })}`; } else if ( fieldType === 'RELATION' && - field.fromRelationMetadata?.relationType === 'ONE_TO_MANY' && - depth > 0 + field.fromRelationMetadata?.relationType === 'ONE_TO_MANY' ) { const relationMetadataItem = objectMetadataItems.find( (objectMetadataItem) => @@ -90,8 +85,7 @@ ${mapObjectMetadataToGraphQLQuery({ node ${mapObjectMetadataToGraphQLQuery({ objectMetadataItems, objectMetadataItem: relationMetadataItem, - depth: depth - 1, - queryFields, + recordGqlFields: relationrecordFields, computeReferences, isRootLevel: false, })} diff --git a/packages/twenty-front/src/modules/object-metadata/utils/mapObjectMetadataToGraphQLQuery.ts b/packages/twenty-front/src/modules/object-metadata/utils/mapObjectMetadataToGraphQLQuery.ts index ebd05e7965..f9e248815d 100644 --- a/packages/twenty-front/src/modules/object-metadata/utils/mapObjectMetadataToGraphQLQuery.ts +++ b/packages/twenty-front/src/modules/object-metadata/utils/mapObjectMetadataToGraphQLQuery.ts @@ -5,15 +5,13 @@ import { shouldFieldBeQueried } from '@/object-metadata/utils/shouldFieldBeQueri export const mapObjectMetadataToGraphQLQuery = ({ objectMetadataItems, objectMetadataItem, - depth = 1, - queryFields, + recordGqlFields, computeReferences = false, isRootLevel = true, }: { objectMetadataItems: ObjectMetadataItem[]; objectMetadataItem: Pick; - depth?: number; - queryFields?: Record; + recordGqlFields?: Record; computeReferences?: boolean; isRootLevel?: boolean; }): any => { @@ -23,8 +21,7 @@ export const mapObjectMetadataToGraphQLQuery = ({ .filter((field) => shouldFieldBeQueried({ field, - depth, - queryFields, + recordGqlFields, }), ) ?? []; @@ -37,18 +34,17 @@ export const mapObjectMetadataToGraphQLQuery = ({ return `{ __typename ${fieldsThatShouldBeQueried - .map((field) => - mapFieldMetadataToGraphQLQuery({ + .map((field) => { + return mapFieldMetadataToGraphQLQuery({ objectMetadataItems, field, - depth, - queryFields: - typeof queryFields?.[field.name] === 'boolean' + relationrecordFields: + typeof recordGqlFields?.[field.name] === 'boolean' ? undefined - : queryFields?.[field.name], + : recordGqlFields?.[field.name], computeReferences, - }), - ) + }); + }) .join('\n')} }`; }; diff --git a/packages/twenty-front/src/modules/object-metadata/utils/shouldFieldBeQueried.ts b/packages/twenty-front/src/modules/object-metadata/utils/shouldFieldBeQueried.ts index f663359ad8..1d2d6b0cf1 100644 --- a/packages/twenty-front/src/modules/object-metadata/utils/shouldFieldBeQueried.ts +++ b/packages/twenty-front/src/modules/object-metadata/utils/shouldFieldBeQueried.ts @@ -1,36 +1,32 @@ -import { isUndefined } from '@sniptt/guards'; - +import { RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { isDefined } from '~/utils/isDefined'; +import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; import { FieldMetadataItem } from '../types/FieldMetadataItem'; export const shouldFieldBeQueried = ({ field, - depth, - queryFields, + recordGqlFields, }: { field: Pick; - depth?: number; objectRecord?: ObjectRecord; - queryFields?: Record; + recordGqlFields?: RecordGqlOperationGqlRecordFields; }): any => { - if (!isUndefined(depth) && depth < 0) { - return false; - } - if ( - !isUndefined(depth) && - depth < 1 && - field.type === FieldMetadataType.Relation + isUndefinedOrNull(recordGqlFields) && + field.type !== FieldMetadataType.Relation ) { - return false; + return true; + } + if ( + isDefined(recordGqlFields) && + isDefined(recordGqlFields[field.name]) && + recordGqlFields[field.name] !== false + ) { + return true; } - if (isDefined(queryFields) && !queryFields[field.name]) { - return false; - } - - return true; + return false; }; diff --git a/packages/twenty-front/src/modules/object-record/cache/constants/MaxQueryDepthForCacheInjection.ts b/packages/twenty-front/src/modules/object-record/cache/constants/MaxQueryDepthForCacheInjection.ts deleted file mode 100644 index e474d8a2ef..0000000000 --- a/packages/twenty-front/src/modules/object-record/cache/constants/MaxQueryDepthForCacheInjection.ts +++ /dev/null @@ -1 +0,0 @@ -export const MAX_QUERY_DEPTH_FOR_CACHE_INJECTION = 1; diff --git a/packages/twenty-front/src/modules/object-record/cache/hooks/useCreateOneRecordInCache.ts b/packages/twenty-front/src/modules/object-record/cache/hooks/useCreateOneRecordInCache.ts index 4ee8ad510f..fc8f572dad 100644 --- a/packages/twenty-front/src/modules/object-record/cache/hooks/useCreateOneRecordInCache.ts +++ b/packages/twenty-front/src/modules/object-record/cache/hooks/useCreateOneRecordInCache.ts @@ -7,6 +7,7 @@ import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery'; import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordFromCache'; import { getRecordNodeFromRecord } from '@/object-record/cache/utils/getRecordNodeFromRecord'; +import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { prefillRecord } from '@/object-record/utils/prefillRecord'; import { capitalize } from '~/utils/string/capitalize'; @@ -32,13 +33,15 @@ export const useCreateOneRecordInCache = ({ objectMetadataItems, objectMetadataItem, computeReferences: true, + recordGqlFields: generateDepthOneRecordGqlFields({ + objectMetadataItem, + }), })} `; const prefilledRecord = prefillRecord({ objectMetadataItem, input: record, - depth: 1, }); const recordToCreateWithNestedConnections = getRecordNodeFromRecord({ diff --git a/packages/twenty-front/src/modules/object-record/cache/hooks/useGetRecordFromCache.ts b/packages/twenty-front/src/modules/object-record/cache/hooks/useGetRecordFromCache.ts index edf234883a..bd864bc573 100644 --- a/packages/twenty-front/src/modules/object-record/cache/hooks/useGetRecordFromCache.ts +++ b/packages/twenty-front/src/modules/object-record/cache/hooks/useGetRecordFromCache.ts @@ -5,33 +5,46 @@ import { useRecoilValue } from 'recoil'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { getRecordFromCache } from '@/object-record/cache/utils/getRecordFromCache'; +import { RecordGqlFields } from '@/object-record/graphql/types/RecordGqlFields'; +import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; export const useGetRecordFromCache = ({ objectNameSingular, + recordGqlFields, }: { objectNameSingular: string; + recordGqlFields?: RecordGqlFields; }) => { const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular, }); + const appliedRecordGqlFields = + recordGqlFields ?? generateDepthOneRecordGqlFields({ objectMetadataItem }); + const objectMetadataItems = useRecoilValue(objectMetadataItemsState); const apolloClient = useApolloClient(); return useCallback( - ( + ( recordId: string, cache = apolloClient.cache, ) => { - return getRecordFromCache({ + return getRecordFromCache({ cache, recordId, objectMetadataItems, objectMetadataItem, + recordGqlFields: appliedRecordGqlFields, }); }, - [objectMetadataItem, objectMetadataItems, apolloClient], + [ + apolloClient.cache, + objectMetadataItems, + objectMetadataItem, + appliedRecordGqlFields, + ], ); }; diff --git a/packages/twenty-front/src/modules/object-record/cache/hooks/useReadFindManyRecordsQueryInCache.ts b/packages/twenty-front/src/modules/object-record/cache/hooks/useReadFindManyRecordsQueryInCache.ts index 405815034d..cab73ebbd5 100644 --- a/packages/twenty-front/src/modules/object-record/cache/hooks/useReadFindManyRecordsQueryInCache.ts +++ b/packages/twenty-front/src/modules/object-record/cache/hooks/useReadFindManyRecordsQueryInCache.ts @@ -3,9 +3,9 @@ import { useApolloClient } from '@apollo/client'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection'; +import { RecordGqlOperationFindManyResult } from '@/object-record/graphql/types/RecordGqlOperationFindManyResult'; +import { RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { ObjectRecordQueryResult } from '@/object-record/types/ObjectRecordQueryResult'; -import { ObjectRecordQueryVariables } from '@/object-record/types/ObjectRecordQueryVariables'; import { generateFindManyRecordsQuery } from '@/object-record/utils/generateFindManyRecordsQuery'; import { isDefined } from '~/utils/isDefined'; @@ -22,32 +22,28 @@ export const useReadFindManyRecordsQueryInCache = ({ T extends ObjectRecord = ObjectRecord, >({ queryVariables, - queryFields, - depth, + recordGqlFields, }: { - queryVariables: ObjectRecordQueryVariables; - queryFields?: Record; - depth?: number; + queryVariables: RecordGqlOperationVariables; + recordGqlFields?: Record; }) => { const findManyRecordsQueryForCacheRead = generateFindManyRecordsQuery({ objectMetadataItem, objectMetadataItems, - queryFields, - depth, + recordGqlFields, }); - const existingRecordsQueryResult = apolloClient.readQuery< - ObjectRecordQueryResult - >({ - query: findManyRecordsQueryForCacheRead, - variables: queryVariables, - }); + const existingRecordsQueryResult = + apolloClient.readQuery({ + query: findManyRecordsQueryForCacheRead, + variables: queryVariables, + }); const existingRecordConnection = existingRecordsQueryResult?.[objectMetadataItem.namePlural]; const existingObjectRecords = isDefined(existingRecordConnection) - ? getRecordsFromRecordConnection({ + ? getRecordsFromRecordConnection({ recordConnection: existingRecordConnection, }) : []; diff --git a/packages/twenty-front/src/modules/object-record/cache/hooks/useUpsertFindManyRecordsQueryInCache.ts b/packages/twenty-front/src/modules/object-record/cache/hooks/useUpsertFindManyRecordsQueryInCache.ts index 01be962261..5ba483a7b4 100644 --- a/packages/twenty-front/src/modules/object-record/cache/hooks/useUpsertFindManyRecordsQueryInCache.ts +++ b/packages/twenty-front/src/modules/object-record/cache/hooks/useUpsertFindManyRecordsQueryInCache.ts @@ -3,10 +3,9 @@ import { useRecoilValue } from 'recoil'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { MAX_QUERY_DEPTH_FOR_CACHE_INJECTION } from '@/object-record/cache/constants/MaxQueryDepthForCacheInjection'; import { getRecordConnectionFromRecords } from '@/object-record/cache/utils/getRecordConnectionFromRecords'; +import { RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { ObjectRecordQueryVariables } from '@/object-record/types/ObjectRecordQueryVariables'; import { generateFindManyRecordsQuery } from '@/object-record/utils/generateFindManyRecordsQuery'; export const useUpsertFindManyRecordsQueryInCache = ({ @@ -22,22 +21,19 @@ export const useUpsertFindManyRecordsQueryInCache = ({ T extends ObjectRecord = ObjectRecord, >({ queryVariables, - depth = MAX_QUERY_DEPTH_FOR_CACHE_INJECTION, objectRecordsToOverwrite, - queryFields, + recordGqlFields, computeReferences = false, }: { - queryVariables: ObjectRecordQueryVariables; - depth?: number; + queryVariables: RecordGqlOperationVariables; objectRecordsToOverwrite: T[]; - queryFields?: Record; + recordGqlFields?: Record; computeReferences?: boolean; }) => { const findManyRecordsQueryForCacheOverwrite = generateFindManyRecordsQuery({ objectMetadataItem, objectMetadataItems, - depth, - queryFields, + recordGqlFields, computeReferences, }); @@ -45,7 +41,7 @@ export const useUpsertFindManyRecordsQueryInCache = ({ objectMetadataItems: objectMetadataItems, objectMetadataItem: objectMetadataItem, records: objectRecordsToOverwrite, - queryFields, + recordGqlFields, computeReferences, }); diff --git a/packages/twenty-front/src/modules/object-record/cache/types/RecordGqlRefConnection.ts b/packages/twenty-front/src/modules/object-record/cache/types/RecordGqlRefConnection.ts new file mode 100644 index 0000000000..0bd61b2e49 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/cache/types/RecordGqlRefConnection.ts @@ -0,0 +1,6 @@ +import { RecordGqlRefEdge } from '@/object-record/cache/types/RecordGqlRefEdge'; +import { RecordGqlConnection } from '@/object-record/graphql/types/RecordGqlConnection'; + +export type RecordGqlRefConnection = Omit & { + edges: RecordGqlRefEdge[]; +}; diff --git a/packages/twenty-front/src/modules/object-record/cache/types/RecordGqlRefEdge.ts b/packages/twenty-front/src/modules/object-record/cache/types/RecordGqlRefEdge.ts new file mode 100644 index 0000000000..9b6a8a2125 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/cache/types/RecordGqlRefEdge.ts @@ -0,0 +1,6 @@ +import { RecordGqlRefNode } from '@/object-record/cache/types/RecordGqlRefNode'; +import { RecordGqlEdge } from '@/object-record/graphql/types/RecordGqlEdge'; + +export type RecordGqlRefEdge = Omit & { + node: RecordGqlRefNode; +}; diff --git a/packages/twenty-front/src/modules/object-record/cache/types/RecordGqlRefNode.ts b/packages/twenty-front/src/modules/object-record/cache/types/RecordGqlRefNode.ts new file mode 100644 index 0000000000..f9e8b8c2f3 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/cache/types/RecordGqlRefNode.ts @@ -0,0 +1,3 @@ +import { Reference } from '@apollo/client'; + +export type RecordGqlRefNode = Reference; diff --git a/packages/twenty-front/src/modules/object-record/cache/utils/getRecordConnectionFromRecords.ts b/packages/twenty-front/src/modules/object-record/cache/utils/getRecordConnectionFromRecords.ts index 70090d490c..345f66f00e 100644 --- a/packages/twenty-front/src/modules/object-record/cache/utils/getRecordConnectionFromRecords.ts +++ b/packages/twenty-front/src/modules/object-record/cache/utils/getRecordConnectionFromRecords.ts @@ -2,18 +2,18 @@ import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { getConnectionTypename } from '@/object-record/cache/utils/getConnectionTypename'; import { getEmptyPageInfo } from '@/object-record/cache/utils/getEmptyPageInfo'; import { getRecordEdgeFromRecord } from '@/object-record/cache/utils/getRecordEdgeFromRecord'; +import { RecordGqlConnection } from '@/object-record/graphql/types/RecordGqlConnection'; +import { RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { ObjectRecordConnection } from '@/object-record/types/ObjectRecordConnection'; export const getRecordConnectionFromRecords = ({ objectMetadataItems, objectMetadataItem, records, - queryFields, + recordGqlFields, withPageInfo = true, computeReferences = false, isRootLevel = true, - depth = 1, }: { objectMetadataItems: ObjectMetadataItem[]; objectMetadataItem: Pick< @@ -21,11 +21,10 @@ export const getRecordConnectionFromRecords = ({ 'fields' | 'namePlural' | 'nameSingular' >; records: T[]; - queryFields?: Record; + recordGqlFields?: RecordGqlOperationGqlRecordFields; withPageInfo?: boolean; isRootLevel?: boolean; computeReferences?: boolean; - depth?: number; }) => { return { __typename: getConnectionTypename(objectMetadataItem.nameSingular), @@ -33,14 +32,13 @@ export const getRecordConnectionFromRecords = ({ return getRecordEdgeFromRecord({ objectMetadataItems, objectMetadataItem, - queryFields, + recordGqlFields, record, isRootLevel, computeReferences, - depth, }); }), ...(withPageInfo && { pageInfo: getEmptyPageInfo() }), ...(withPageInfo && { totalCount: records.length }), - } as ObjectRecordConnection; + } as RecordGqlConnection; }; diff --git a/packages/twenty-front/src/modules/object-record/cache/utils/getRecordEdgeFromRecord.ts b/packages/twenty-front/src/modules/object-record/cache/utils/getRecordEdgeFromRecord.ts index 7327e2e169..bbb39d3216 100644 --- a/packages/twenty-front/src/modules/object-record/cache/utils/getRecordEdgeFromRecord.ts +++ b/packages/twenty-front/src/modules/object-record/cache/utils/getRecordEdgeFromRecord.ts @@ -1,13 +1,13 @@ import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { getEdgeTypename } from '@/object-record/cache/utils/getEdgeTypename'; import { getRecordNodeFromRecord } from '@/object-record/cache/utils/getRecordNodeFromRecord'; +import { RecordGqlEdge } from '@/object-record/graphql/types/RecordGqlEdge'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { ObjectRecordEdge } from '@/object-record/types/ObjectRecordEdge'; export const getRecordEdgeFromRecord = ({ objectMetadataItems, objectMetadataItem, - queryFields, + recordGqlFields, record, computeReferences = false, isRootLevel = false, @@ -17,10 +17,9 @@ export const getRecordEdgeFromRecord = ({ ObjectMetadataItem, 'fields' | 'namePlural' | 'nameSingular' >; - queryFields?: Record; + recordGqlFields?: Record; computeReferences?: boolean; isRootLevel?: boolean; - depth?: number; record: T; }) => { return { @@ -29,13 +28,12 @@ export const getRecordEdgeFromRecord = ({ ...getRecordNodeFromRecord({ objectMetadataItems, objectMetadataItem, - queryFields, + recordGqlFields, record, computeReferences, isRootLevel, - depth: 1, }), }, cursor: '', - } as ObjectRecordEdge; + } as RecordGqlEdge; }; diff --git a/packages/twenty-front/src/modules/object-record/cache/utils/getRecordFromCache.ts b/packages/twenty-front/src/modules/object-record/cache/utils/getRecordFromCache.ts index 5db9a5e65f..586497ed13 100644 --- a/packages/twenty-front/src/modules/object-record/cache/utils/getRecordFromCache.ts +++ b/packages/twenty-front/src/modules/object-record/cache/utils/getRecordFromCache.ts @@ -1,9 +1,10 @@ import { ApolloCache, gql } from '@apollo/client'; -import { CachedObjectRecord } from '@/apollo/types/CachedObjectRecord'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery'; import { getRecordFromRecordNode } from '@/object-record/cache/utils/getRecordFromRecordNode'; +import { RecordGqlFields } from '@/object-record/graphql/types/RecordGqlFields'; +import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; import { capitalize } from '~/utils/string/capitalize'; @@ -13,16 +14,21 @@ export const getRecordFromCache = ({ objectMetadataItems, cache, recordId, + recordGqlFields, }: { cache: ApolloCache; recordId: string; objectMetadataItems: ObjectMetadataItem[]; objectMetadataItem: ObjectMetadataItem; + recordGqlFields?: RecordGqlFields; }) => { if (isUndefinedOrNull(objectMetadataItem)) { return null; } + const appliedRecordGqlFields = + recordGqlFields ?? generateDepthOneRecordGqlFields({ objectMetadataItem }); + const capitalizedObjectName = capitalize(objectMetadataItem.nameSingular); const cacheReadFragment = gql` @@ -30,6 +36,7 @@ export const getRecordFromCache = ({ { objectMetadataItems, objectMetadataItem, + recordGqlFields: appliedRecordGqlFields, }, )} `; @@ -49,7 +56,7 @@ export const getRecordFromCache = ({ return null; } - return getRecordFromRecordNode({ + return getRecordFromRecordNode({ recordNode: record, - }) as CachedObjectRecord; + }); }; diff --git a/packages/twenty-front/src/modules/object-record/cache/utils/getRecordFromRecordNode.ts b/packages/twenty-front/src/modules/object-record/cache/utils/getRecordFromRecordNode.ts index 9a7d595388..49cfe10bca 100644 --- a/packages/twenty-front/src/modules/object-record/cache/utils/getRecordFromRecordNode.ts +++ b/packages/twenty-front/src/modules/object-record/cache/utils/getRecordFromRecordNode.ts @@ -1,4 +1,5 @@ import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection'; +import { RecordGqlNode } from '@/object-record/graphql/types/RecordGqlNode'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { isDefined } from '~/utils/isDefined'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; @@ -6,7 +7,7 @@ import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; export const getRecordFromRecordNode = ({ recordNode, }: { - recordNode: T; + recordNode: RecordGqlNode; }): T => { return { ...Object.fromEntries( @@ -32,5 +33,6 @@ export const getRecordFromRecordNode = ({ }), ), id: recordNode.id, + __typename: recordNode.__typename, } as T; }; diff --git a/packages/twenty-front/src/modules/object-record/cache/utils/getRecordNodeFromRecord.ts b/packages/twenty-front/src/modules/object-record/cache/utils/getRecordNodeFromRecord.ts index 886cbd6b93..f807b880dd 100644 --- a/packages/twenty-front/src/modules/object-record/cache/utils/getRecordNodeFromRecord.ts +++ b/packages/twenty-front/src/modules/object-record/cache/utils/getRecordNodeFromRecord.ts @@ -1,10 +1,10 @@ import { isNull, isUndefined } from '@sniptt/guards'; -import { CachedObjectRecord } from '@/apollo/types/CachedObjectRecord'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { getNodeTypename } from '@/object-record/cache/utils/getNodeTypename'; import { getObjectTypename } from '@/object-record/cache/utils/getObjectTypename'; import { getRecordConnectionFromRecords } from '@/object-record/cache/utils/getRecordConnectionFromRecords'; +import { RecordGqlNode } from '@/object-record/graphql/types/RecordGqlNode'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { FieldMetadataType, @@ -16,22 +16,20 @@ import { lowerAndCapitalize } from '~/utils/string/lowerAndCapitalize'; export const getRecordNodeFromRecord = ({ objectMetadataItems, objectMetadataItem, - queryFields, + recordGqlFields, record, computeReferences = true, isRootLevel = true, - depth = 1, }: { objectMetadataItems: ObjectMetadataItem[]; objectMetadataItem: Pick< ObjectMetadataItem, 'fields' | 'namePlural' | 'nameSingular' >; - queryFields?: Record; + recordGqlFields?: Record; computeReferences?: boolean; isRootLevel?: boolean; record: T | null; - depth?: number; }) => { if (isNull(record)) { return null; @@ -42,13 +40,13 @@ export const getRecordNodeFromRecord = ({ if (!isRootLevel && computeReferences) { return { __ref: `${nodeTypeName}:${record.id}`, - } as unknown as CachedObjectRecord; // Todo Fix typing + } as unknown as RecordGqlNode; // Fix typing: we want a Reference in computeReferences mode } const nestedRecord = Object.fromEntries( Object.entries(record) .map(([fieldName, value]) => { - if (isDefined(queryFields) && !queryFields[fieldName]) { + if (isDefined(recordGqlFields) && !recordGqlFields[fieldName]) { return undefined; } @@ -60,14 +58,6 @@ export const getRecordNodeFromRecord = ({ return undefined; } - if ( - !isUndefined(depth) && - depth < 1 && - field.type === FieldMetadataType.Relation - ) { - return undefined; - } - if ( field.type === FieldMetadataType.Relation && field.relationDefinition?.direction === @@ -87,15 +77,14 @@ export const getRecordNodeFromRecord = ({ objectMetadataItems, objectMetadataItem: oneToManyObjectMetadataItem, records: value as ObjectRecord[], - queryFields: - queryFields?.[fieldName] === true || - isUndefined(queryFields?.[fieldName]) + recordGqlFields: + recordGqlFields?.[fieldName] === true || + isUndefined(recordGqlFields?.[fieldName]) ? undefined - : queryFields?.[fieldName], + : recordGqlFields?.[fieldName], withPageInfo: false, isRootLevel: false, computeReferences, - depth: depth - 1, }), ]; } @@ -159,8 +148,5 @@ export const getRecordNodeFromRecord = ({ .filter(isDefined), ) as T; // Todo fix typing once we have investigated apollo edges / nodes removal - return { - __typename: getNodeTypename(objectMetadataItem.nameSingular), - ...nestedRecord, - }; + return { ...nestedRecord, __typename: nodeTypeName }; }; diff --git a/packages/twenty-front/src/modules/object-record/cache/utils/getRecordsFromRecordConnection.ts b/packages/twenty-front/src/modules/object-record/cache/utils/getRecordsFromRecordConnection.ts index c427bd0559..dcf641a2d4 100644 --- a/packages/twenty-front/src/modules/object-record/cache/utils/getRecordsFromRecordConnection.ts +++ b/packages/twenty-front/src/modules/object-record/cache/utils/getRecordsFromRecordConnection.ts @@ -1,11 +1,11 @@ import { getRecordFromRecordNode } from '@/object-record/cache/utils/getRecordFromRecordNode'; +import { RecordGqlConnection } from '@/object-record/graphql/types/RecordGqlConnection'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { ObjectRecordConnection } from '@/object-record/types/ObjectRecordConnection'; export const getRecordsFromRecordConnection = ({ recordConnection, }: { - recordConnection: ObjectRecordConnection; + recordConnection: RecordGqlConnection; }): T[] => { return recordConnection.edges.map((edge) => getRecordFromRecordNode({ recordNode: edge.node }), diff --git a/packages/twenty-front/src/modules/object-record/cache/utils/isObjectRecordConnection.ts b/packages/twenty-front/src/modules/object-record/cache/utils/isObjectRecordConnection.ts index c069a0a6c8..366a31a340 100644 --- a/packages/twenty-front/src/modules/object-record/cache/utils/isObjectRecordConnection.ts +++ b/packages/twenty-front/src/modules/object-record/cache/utils/isObjectRecordConnection.ts @@ -1,12 +1,12 @@ import { z } from 'zod'; -import { ObjectRecordConnection } from '@/object-record/types/ObjectRecordConnection'; +import { RecordGqlConnection } from '@/object-record/graphql/types/RecordGqlConnection'; import { capitalize } from '~/utils/string/capitalize'; export const isObjectRecordConnection = ( objectNameSingular: string, value: unknown, -): value is ObjectRecordConnection => { +): value is RecordGqlConnection => { const objectConnectionTypeName = `${capitalize( objectNameSingular, )}Connection`; diff --git a/packages/twenty-front/src/modules/object-record/cache/utils/isObjectRecordConnectionWithRefs.ts b/packages/twenty-front/src/modules/object-record/cache/utils/isObjectRecordConnectionWithRefs.ts index a893901960..fd8264aea0 100644 --- a/packages/twenty-front/src/modules/object-record/cache/utils/isObjectRecordConnectionWithRefs.ts +++ b/packages/twenty-front/src/modules/object-record/cache/utils/isObjectRecordConnectionWithRefs.ts @@ -1,13 +1,13 @@ import { StoreValue } from '@apollo/client'; import { z } from 'zod'; -import { CachedObjectRecordConnection } from '@/apollo/types/CachedObjectRecordConnection'; +import { RecordGqlRefConnection } from '@/object-record/cache/types/RecordGqlRefConnection'; import { capitalize } from '~/utils/string/capitalize'; export const isObjectRecordConnectionWithRefs = ( objectNameSingular: string, storeValue: StoreValue, -): storeValue is CachedObjectRecordConnection => { +): storeValue is RecordGqlRefConnection => { const objectConnectionTypeName = `${capitalize( objectNameSingular, )}Connection`; diff --git a/packages/twenty-front/src/modules/object-record/cache/utils/updateRecordFromCache.ts b/packages/twenty-front/src/modules/object-record/cache/utils/updateRecordFromCache.ts index 15636bc744..7ce423c092 100644 --- a/packages/twenty-front/src/modules/object-record/cache/utils/updateRecordFromCache.ts +++ b/packages/twenty-front/src/modules/object-record/cache/utils/updateRecordFromCache.ts @@ -4,6 +4,7 @@ import gql from 'graphql-tag'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery'; import { getRecordNodeFromRecord } from '@/object-record/cache/utils/getRecordNodeFromRecord'; +import { RecordGqlNode } from '@/object-record/graphql/types/RecordGqlNode'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; import { capitalize } from '~/utils/string/capitalize'; @@ -44,14 +45,13 @@ export const updateRecordFromCache = ({ objectMetadataItems, objectMetadataItem, record, - depth: 1, }); if (isUndefinedOrNull(recordWithConnection)) { return; } - cache.writeFragment({ + cache.writeFragment({ id: cachedRecordId, fragment: cacheWriteFragment, data: recordWithConnection, diff --git a/packages/twenty-front/src/modules/object-record/types/ObjectRecordConnection.ts b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlConnection.ts similarity index 50% rename from packages/twenty-front/src/modules/object-record/types/ObjectRecordConnection.ts rename to packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlConnection.ts index 1ab39b41a1..543a55b2fc 100644 --- a/packages/twenty-front/src/modules/object-record/types/ObjectRecordConnection.ts +++ b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlConnection.ts @@ -1,11 +1,10 @@ import { Nullable } from 'twenty-ui'; -import { ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { ObjectRecordEdge } from '@/object-record/types/ObjectRecordEdge'; +import { RecordGqlEdge } from '@/object-record/graphql/types/RecordGqlEdge'; -export type ObjectRecordConnection = { +export type RecordGqlConnection = { __typename?: string; - edges: ObjectRecordEdge[]; + edges: RecordGqlEdge[]; pageInfo: { hasNextPage?: boolean; hasPreviousPage?: boolean; diff --git a/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlEdge.ts b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlEdge.ts new file mode 100644 index 0000000000..16db0b994b --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlEdge.ts @@ -0,0 +1,7 @@ +import { RecordGqlNode } from '@/object-record/graphql/types/RecordGqlNode'; + +export type RecordGqlEdge = { + __typename: string; + node: RecordGqlNode; + cursor: string; +}; diff --git a/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlFields.ts b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlFields.ts new file mode 100644 index 0000000000..1148458a2a --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlFields.ts @@ -0,0 +1 @@ +export type RecordGqlFields = Record; diff --git a/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlNode.ts b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlNode.ts new file mode 100644 index 0000000000..a153c3b7ea --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlNode.ts @@ -0,0 +1,5 @@ +export type RecordGqlNode = { + id: string; + [key: string]: any; + __typename: string; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-filter/types/ObjectRecordQueryFilter.ts b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationFilter.ts similarity index 92% rename from packages/twenty-front/src/modules/object-record/record-filter/types/ObjectRecordQueryFilter.ts rename to packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationFilter.ts index 768221f5f8..66acadc80b 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/types/ObjectRecordQueryFilter.ts +++ b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationFilter.ts @@ -93,22 +93,22 @@ export type LeafFilter = | undefined; export type AndObjectRecordFilter = { - and?: ObjectRecordQueryFilter[]; + and?: RecordGqlOperationFilter[]; }; export type OrObjectRecordFilter = { - or?: ObjectRecordQueryFilter[] | ObjectRecordQueryFilter; + or?: RecordGqlOperationFilter[] | RecordGqlOperationFilter; }; export type NotObjectRecordFilter = { - not?: ObjectRecordQueryFilter; + not?: RecordGqlOperationFilter; }; export type LeafObjectRecordFilter = { [fieldName: string]: LeafFilter; }; -export type ObjectRecordQueryFilter = +export type RecordGqlOperationFilter = | LeafObjectRecordFilter | AndObjectRecordFilter | OrObjectRecordFilter diff --git a/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationFindManyResult.ts b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationFindManyResult.ts new file mode 100644 index 0000000000..d53cf167b5 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationFindManyResult.ts @@ -0,0 +1,5 @@ +import { RecordGqlConnection } from '@/object-record/graphql/types/RecordGqlConnection'; + +export type RecordGqlOperationFindManyResult = { + [objectNamePlural: string]: RecordGqlConnection; +}; diff --git a/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationFindOneResult.ts b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationFindOneResult.ts new file mode 100644 index 0000000000..39af186391 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationFindOneResult.ts @@ -0,0 +1,5 @@ +import { RecordGqlNode } from '@/object-record/graphql/types/RecordGqlNode'; + +export type RecordGqlOperationFindOneResult = { + [objectNameSingular: string]: RecordGqlNode; +}; diff --git a/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationGqlRecordFields.ts b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationGqlRecordFields.ts new file mode 100644 index 0000000000..b2ba0834bd --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationGqlRecordFields.ts @@ -0,0 +1,3 @@ +import { RecordGqlFields } from '@/object-record/graphql/types/RecordGqlFields'; + +export type RecordGqlOperationGqlRecordFields = RecordGqlFields; diff --git a/packages/twenty-front/src/modules/object-metadata/types/OrderByField.ts b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationOrderBy.ts similarity index 76% rename from packages/twenty-front/src/modules/object-metadata/types/OrderByField.ts rename to packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationOrderBy.ts index c97a74169d..67592770d1 100644 --- a/packages/twenty-front/src/modules/object-metadata/types/OrderByField.ts +++ b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationOrderBy.ts @@ -1,5 +1,5 @@ import { OrderBy } from '@/object-metadata/types/OrderBy'; -export type OrderByField = { +export type RecordGqlOperationOrderBy = { [fieldName: string]: OrderBy | { [subFieldName: string]: OrderBy }; }; diff --git a/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationSignature.ts b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationSignature.ts new file mode 100644 index 0000000000..48a7d6d513 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationSignature.ts @@ -0,0 +1,8 @@ +import { RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields'; +import { RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables'; + +export type RecordGqlOperationSignature = { + objectNameSingular: string; + variables: RecordGqlOperationVariables; + fields?: RecordGqlOperationGqlRecordFields; +}; diff --git a/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationSignatureFactory.ts b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationSignatureFactory.ts new file mode 100644 index 0000000000..3b4392ff11 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationSignatureFactory.ts @@ -0,0 +1,5 @@ +import { RecordGqlOperationSignature } from '@/object-record/graphql/types/RecordGqlOperationSignature'; + +export type RecordGqlOperationSignatureFactory = ( + factoryParams: any, +) => RecordGqlOperationSignature; diff --git a/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationVariables.ts b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationVariables.ts new file mode 100644 index 0000000000..9dc0fed4f0 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/graphql/types/RecordGqlOperationVariables.ts @@ -0,0 +1,8 @@ +import { RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; +import { RecordGqlOperationOrderBy } from '@/object-record/graphql/types/RecordGqlOperationOrderBy'; + +export type RecordGqlOperationVariables = { + filter?: RecordGqlOperationFilter; + orderBy?: RecordGqlOperationOrderBy; + limit?: number; +}; diff --git a/packages/twenty-front/src/modules/object-record/graphql/utils/generateDepthOneRecordGqlFields.ts b/packages/twenty-front/src/modules/object-record/graphql/utils/generateDepthOneRecordGqlFields.ts new file mode 100644 index 0000000000..ce52cd786d --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/graphql/utils/generateDepthOneRecordGqlFields.ts @@ -0,0 +1,14 @@ +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; + +export const generateDepthOneRecordGqlFields = ({ + objectMetadataItem, +}: { + objectMetadataItem: ObjectMetadataItem; +}) => { + return objectMetadataItem.fields.reduce((acc, field) => { + return { + ...acc, + [field.name]: true, + }; + }, {}); +}; diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useGenerateFindManyRecordsForMultipleMetadataItemsQuery.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useGenerateFindManyRecordsForMultipleMetadataItemsQuery.test.tsx index df7c904261..6d29107a32 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useGenerateFindManyRecordsForMultipleMetadataItemsQuery.test.tsx +++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useGenerateFindManyRecordsForMultipleMetadataItemsQuery.test.tsx @@ -1,22 +1,29 @@ import { ReactNode } from 'react'; +import { expect } from '@storybook/test'; import { renderHook } from '@testing-library/react'; import { RecoilRoot } from 'recoil'; import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock'; -import { useGenerateFindManyRecordsForMultipleMetadataItemsQuery } from '@/object-record/multiple-objects/hooks/useGenerateFindManyRecordsForMultipleMetadataItemsQuery'; +import { useGenerateCombinedFindManyRecordsQuery } from '@/object-record/multiple-objects/hooks/useGenerateCombinedFindManyRecordsQuery'; +import { JestObjectMetadataItemSetter } from '~/testing/jest/JestObjectMetadataItemSetter'; const Wrapper = ({ children }: { children: ReactNode }) => ( - {children} + + {children} + ); describe('useGenerateFindManyRecordsForMultipleMetadataItemsQuery', () => { it('should work as expected', async () => { const { result } = renderHook( () => { - const mockObjectMetadataItems = getObjectMetadataItemsMock(); - - return useGenerateFindManyRecordsForMultipleMetadataItemsQuery({ - targetObjectMetadataItems: mockObjectMetadataItems.slice(0, 2), + return useGenerateCombinedFindManyRecordsQuery({ + operationSignatures: getObjectMetadataItemsMock() + .slice(0, 2) + .map((item) => ({ + objectNameSingular: item.nameSingular, + variables: {}, + })), }); }, { diff --git a/packages/twenty-front/src/modules/object-record/hooks/useCreateManyRecords.ts b/packages/twenty-front/src/modules/object-record/hooks/useCreateManyRecords.ts index 1a62d1e46e..e95cbad37e 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useCreateManyRecords.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useCreateManyRecords.ts @@ -2,10 +2,12 @@ import { useApolloClient } from '@apollo/client'; import { v4 } from 'uuid'; import { triggerCreateRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect'; -import { CachedObjectRecord } from '@/apollo/types/CachedObjectRecord'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { useCreateOneRecordInCache } from '@/object-record/cache/hooks/useCreateOneRecordInCache'; +import { getObjectTypename } from '@/object-record/cache/utils/getObjectTypename'; +import { RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields'; +import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields'; import { useCreateManyRecordsMutation } from '@/object-record/hooks/useCreateManyRecordsMutation'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { getCreateManyRecordsMutationResponseField } from '@/object-record/utils/getCreateManyRecordsMutationResponseField'; @@ -14,8 +16,7 @@ import { isDefined } from '~/utils/isDefined'; type useCreateManyRecordsProps = { objectNameSingular: string; - queryFields?: Record; - depth?: number; + recordGqlFields?: RecordGqlOperationGqlRecordFields; skipPostOptmisticEffect?: boolean; }; @@ -23,8 +24,7 @@ export const useCreateManyRecords = < CreatedObjectRecord extends ObjectRecord = ObjectRecord, >({ objectNameSingular, - queryFields, - depth = 1, + recordGqlFields, skipPostOptmisticEffect = false, }: useCreateManyRecordsProps) => { const apolloClient = useApolloClient(); @@ -33,13 +33,15 @@ export const useCreateManyRecords = < objectNameSingular, }); + const computedRecordGqlFields = + recordGqlFields ?? generateDepthOneRecordGqlFields({ objectMetadataItem }); + const { createManyRecordsMutation } = useCreateManyRecordsMutation({ objectNameSingular, - queryFields, - depth, + recordGqlFields: computedRecordGqlFields, }); - const createOneRecordInCache = useCreateOneRecordInCache({ + const createOneRecordInCache = useCreateOneRecordInCache({ objectMetadataItem, }); @@ -65,7 +67,10 @@ export const useCreateManyRecords = < const recordsCreatedInCache = []; for (const recordToCreate of sanitizedCreateManyRecordsInput) { - const recordCreatedInCache = createOneRecordInCache(recordToCreate); + const recordCreatedInCache = createOneRecordInCache({ + ...recordToCreate, + __typename: getObjectTypename(objectMetadataItem.nameSingular), + }); if (isDefined(recordCreatedInCache)) { recordsCreatedInCache.push(recordCreatedInCache); diff --git a/packages/twenty-front/src/modules/object-record/hooks/useCreateManyRecordsMutation.ts b/packages/twenty-front/src/modules/object-record/hooks/useCreateManyRecordsMutation.ts index 5c43384ad8..f038531dc5 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useCreateManyRecordsMutation.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useCreateManyRecordsMutation.ts @@ -5,18 +5,17 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery'; import { EMPTY_MUTATION } from '@/object-record/constants/EmptyMutation'; +import { RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields'; import { getCreateManyRecordsMutationResponseField } from '@/object-record/utils/getCreateManyRecordsMutationResponseField'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; import { capitalize } from '~/utils/string/capitalize'; export const useCreateManyRecordsMutation = ({ objectNameSingular, - queryFields, - depth, + recordGqlFields, }: { objectNameSingular: string; - queryFields?: Record; - depth?: number; + recordGqlFields?: RecordGqlOperationGqlRecordFields; }) => { const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular, @@ -39,8 +38,7 @@ export const useCreateManyRecordsMutation = ({ ${mutationResponseField}(data: $data) ${mapObjectMetadataToGraphQLQuery({ objectMetadataItems, objectMetadataItem, - queryFields, - depth, + recordGqlFields, })} }`; diff --git a/packages/twenty-front/src/modules/object-record/hooks/useCreateOneRecord.ts b/packages/twenty-front/src/modules/object-record/hooks/useCreateOneRecord.ts index ba227173d7..47ab23f5b1 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useCreateOneRecord.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useCreateOneRecord.ts @@ -2,10 +2,12 @@ import { useApolloClient } from '@apollo/client'; import { v4 } from 'uuid'; import { triggerCreateRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect'; -import { CachedObjectRecord } from '@/apollo/types/CachedObjectRecord'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { useCreateOneRecordInCache } from '@/object-record/cache/hooks/useCreateOneRecordInCache'; +import { getObjectTypename } from '@/object-record/cache/utils/getObjectTypename'; +import { RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields'; +import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields'; import { useCreateOneRecordMutation } from '@/object-record/hooks/useCreateOneRecordMutation'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { getCreateOneRecordMutationResponseField } from '@/object-record/utils/getCreateOneRecordMutationResponseField'; @@ -14,8 +16,7 @@ import { isDefined } from '~/utils/isDefined'; type useCreateOneRecordProps = { objectNameSingular: string; - queryFields?: Record; - depth?: number; + recordGqlFields?: RecordGqlOperationGqlRecordFields; skipPostOptmisticEffect?: boolean; }; @@ -23,7 +24,7 @@ export const useCreateOneRecord = < CreatedObjectRecord extends ObjectRecord = ObjectRecord, >({ objectNameSingular, - queryFields, + recordGqlFields, skipPostOptmisticEffect = false, }: useCreateOneRecordProps) => { const apolloClient = useApolloClient(); @@ -32,14 +33,19 @@ export const useCreateOneRecord = < objectNameSingular, }); + const computedRecordGqlFields = + recordGqlFields ?? generateDepthOneRecordGqlFields({ objectMetadataItem }); + const { createOneRecordMutation } = useCreateOneRecordMutation({ objectNameSingular, - queryFields, + recordGqlFields: computedRecordGqlFields, }); - const createOneRecordInCache = useCreateOneRecordInCache({ - objectMetadataItem, - }); + const createOneRecordInCache = useCreateOneRecordInCache( + { + objectMetadataItem, + }, + ); const { objectMetadataItems } = useObjectMetadataItems(); @@ -57,6 +63,7 @@ export const useCreateOneRecord = < const recordCreatedInCache = createOneRecordInCache({ ...input, id: idForCreation, + __typename: getObjectTypename(objectMetadataItem.nameSingular), }); if (isDefined(recordCreatedInCache)) { diff --git a/packages/twenty-front/src/modules/object-record/hooks/useCreateOneRecordMutation.ts b/packages/twenty-front/src/modules/object-record/hooks/useCreateOneRecordMutation.ts index 6791336855..503d80fd39 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useCreateOneRecordMutation.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useCreateOneRecordMutation.ts @@ -5,23 +5,29 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery'; import { EMPTY_MUTATION } from '@/object-record/constants/EmptyMutation'; +import { RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields'; +import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields'; import { getCreateOneRecordMutationResponseField } from '@/object-record/utils/getCreateOneRecordMutationResponseField'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; import { capitalize } from '~/utils/string/capitalize'; export const useCreateOneRecordMutation = ({ objectNameSingular, - queryFields, - depth, + recordGqlFields, }: { objectNameSingular: string; - queryFields?: Record; - depth?: number; + recordGqlFields?: RecordGqlOperationGqlRecordFields; }) => { const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular, }); + const appliedRecordGqlFields = + recordGqlFields ?? + generateDepthOneRecordGqlFields({ + objectMetadataItem, + }); + const objectMetadataItems = useRecoilValue(objectMetadataItemsState); if (isUndefinedOrNull(objectMetadataItem)) { @@ -39,8 +45,7 @@ export const useCreateOneRecordMutation = ({ ${mutationResponseField}(data: $input) ${mapObjectMetadataToGraphQLQuery({ objectMetadataItems, objectMetadataItem, - queryFields, - depth, + recordGqlFields: appliedRecordGqlFields, })} } `; diff --git a/packages/twenty-front/src/modules/object-record/hooks/useFindDuplicateRecords.ts b/packages/twenty-front/src/modules/object-record/hooks/useFindDuplicateRecords.ts index f1c2efbec9..54e19160f5 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useFindDuplicateRecords.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useFindDuplicateRecords.ts @@ -4,25 +4,22 @@ import { useQuery } from '@apollo/client'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier'; import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection'; +import { RecordGqlConnection } from '@/object-record/graphql/types/RecordGqlConnection'; +import { RecordGqlOperationFindManyResult } from '@/object-record/graphql/types/RecordGqlOperationFindManyResult'; import { useFindDuplicateRecordsQuery } from '@/object-record/hooks/useFindDuplicatesRecordsQuery'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { ObjectRecordConnection } from '@/object-record/types/ObjectRecordConnection'; import { getFindDuplicateRecordsQueryResponseField } from '@/object-record/utils/getFindDuplicateRecordsQueryResponseField'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { logError } from '~/utils/logError'; -import { ObjectRecordQueryResult } from '../types/ObjectRecordQueryResult'; - export const useFindDuplicateRecords = ({ objectRecordId = '', objectNameSingular, onCompleted, - depth, }: ObjectMetadataItemIdentifier & { objectRecordId: string | undefined; - onCompleted?: (data: ObjectRecordConnection) => void; + onCompleted?: (data: RecordGqlConnection) => void; skip?: boolean; - depth?: number; }) => { const findDuplicateQueryStateIdentifier = objectNameSingular; @@ -32,7 +29,6 @@ export const useFindDuplicateRecords = ({ const { findDuplicateRecordsQuery } = useFindDuplicateRecordsQuery({ objectNameSingular, - depth, }); const { enqueueSnackBar } = useSnackBar(); @@ -41,7 +37,7 @@ export const useFindDuplicateRecords = ({ objectMetadataItem.nameSingular, ); - const { data, loading, error } = useQuery>( + const { data, loading, error } = useQuery( findDuplicateRecordsQuery, { variables: { diff --git a/packages/twenty-front/src/modules/object-record/hooks/useFindDuplicatesRecordsQuery.ts b/packages/twenty-front/src/modules/object-record/hooks/useFindDuplicatesRecordsQuery.ts index a24d08ab64..bab9f4fd1c 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useFindDuplicatesRecordsQuery.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useFindDuplicatesRecordsQuery.ts @@ -9,10 +9,8 @@ import { capitalize } from '~/utils/string/capitalize'; export const useFindDuplicateRecordsQuery = ({ objectNameSingular, - depth, }: { objectNameSingular: string; - depth?: number; }) => { const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular, @@ -31,7 +29,6 @@ export const useFindDuplicateRecordsQuery = ({ node ${mapObjectMetadataToGraphQLQuery({ objectMetadataItems, objectMetadataItem, - depth, })} cursor } diff --git a/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts b/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts index 535373a157..782761c6cd 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts @@ -8,11 +8,13 @@ import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMembe import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier'; import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection'; +import { RecordGqlConnection } from '@/object-record/graphql/types/RecordGqlConnection'; +import { RecordGqlEdge } from '@/object-record/graphql/types/RecordGqlEdge'; +import { RecordGqlOperationFindManyResult } from '@/object-record/graphql/types/RecordGqlOperationFindManyResult'; +import { RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields'; +import { RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables'; import { useFindManyRecordsQuery } from '@/object-record/hooks/useFindManyRecordsQuery'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { ObjectRecordConnection } from '@/object-record/types/ObjectRecordConnection'; -import { ObjectRecordEdge } from '@/object-record/types/ObjectRecordEdge'; -import { ObjectRecordQueryVariables } from '@/object-record/types/ObjectRecordQueryVariables'; import { filterUniqueRecordEdgesByCursor } from '@/object-record/utils/filterUniqueRecordEdgesByCursor'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { isDefined } from '~/utils/isDefined'; @@ -22,7 +24,6 @@ import { capitalize } from '~/utils/string/capitalize'; import { cursorFamilyState } from '../states/cursorFamilyState'; import { hasNextPageFamilyState } from '../states/hasNextPageFamilyState'; import { isFetchingMoreRecordsFamilyState } from '../states/isFetchingMoreRecordsFamilyState'; -import { ObjectRecordQueryResult } from '../types/ObjectRecordQueryResult'; export const useFindManyRecords = ({ objectNameSingular, @@ -31,20 +32,19 @@ export const useFindManyRecords = ({ limit, onCompleted, skip, - queryFields, + recordGqlFields, fetchPolicy, }: ObjectMetadataItemIdentifier & - ObjectRecordQueryVariables & { + RecordGqlOperationVariables & { onCompleted?: ( records: T[], options?: { - pageInfo?: ObjectRecordConnection['pageInfo']; + pageInfo?: RecordGqlConnection['pageInfo']; totalCount?: number; }, ) => void; skip?: boolean; - depth?: number; - queryFields?: Record; + recordGqlFields?: RecordGqlOperationGqlRecordFields; fetchPolicy?: WatchQueryFetchPolicy; }) => { const findManyQueryStateIdentifier = @@ -71,56 +71,55 @@ export const useFindManyRecords = ({ const { findManyRecordsQuery } = useFindManyRecordsQuery({ objectNameSingular, - queryFields, + recordGqlFields, }); const { enqueueSnackBar } = useSnackBar(); const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); - const { data, loading, error, fetchMore } = useQuery< - ObjectRecordQueryResult - >(findManyRecordsQuery, { - skip: skip || !objectMetadataItem || !currentWorkspaceMember, - variables: { - filter, - limit, - orderBy, - }, - fetchPolicy: fetchPolicy, - onCompleted: (data) => { - if (!isDefined(data)) { - onCompleted?.([]); - } + const { data, loading, error, fetchMore } = + useQuery(findManyRecordsQuery, { + skip: skip || !objectMetadataItem || !currentWorkspaceMember, + variables: { + filter, + limit, + orderBy, + }, + fetchPolicy: fetchPolicy, + onCompleted: (data) => { + if (!isDefined(data)) { + onCompleted?.([]); + } - const pageInfo = data?.[objectMetadataItem.namePlural]?.pageInfo; + const pageInfo = data?.[objectMetadataItem.namePlural]?.pageInfo; - const records = getRecordsFromRecordConnection({ - recordConnection: data?.[objectMetadataItem.namePlural], - }) as T[]; + const records = getRecordsFromRecordConnection({ + recordConnection: data?.[objectMetadataItem.namePlural], + }) as T[]; - onCompleted?.(records, { - pageInfo, - totalCount: data?.[objectMetadataItem.namePlural]?.totalCount, - }); + onCompleted?.(records, { + pageInfo, + totalCount: data?.[objectMetadataItem.namePlural]?.totalCount, + }); - if (isDefined(data?.[objectMetadataItem.namePlural])) { - setLastCursor(pageInfo.endCursor ?? ''); - setHasNextPage(pageInfo.hasNextPage ?? false); - } - }, - onError: (error) => { - logError( - `useFindManyRecords for "${objectMetadataItem.namePlural}" error : ` + - error, - ); - enqueueSnackBar( - `Error during useFindManyRecords for "${objectMetadataItem.namePlural}", ${error.message}`, - { - variant: 'error', - }, - ); - }, - }); + if (isDefined(data?.[objectMetadataItem.namePlural])) { + setLastCursor(pageInfo.endCursor ?? ''); + setHasNextPage(pageInfo.hasNextPage ?? false); + } + }, + onError: (error) => { + logError( + `useFindManyRecords for "${objectMetadataItem.namePlural}" error : ` + + error, + ); + enqueueSnackBar( + `Error during useFindManyRecords for "${objectMetadataItem.namePlural}", ${error.message}`, + { + variant: 'error', + }, + ); + }, + }); const fetchMoreRecords = useCallback(async () => { if (hasNextPage) { @@ -138,7 +137,7 @@ export const useFindManyRecords = ({ const nextEdges = fetchMoreResult?.[objectMetadataItem.namePlural]?.edges; - let newEdges: ObjectRecordEdge[] = []; + let newEdges: RecordGqlEdge[] = []; if (isNonEmptyArray(previousEdges) && isNonEmptyArray(nextEdges)) { newEdges = filterUniqueRecordEdgesByCursor([ @@ -180,7 +179,7 @@ export const useFindManyRecords = ({ totalCount: fetchMoreResult?.[objectMetadataItem.namePlural].totalCount, }, - } as ObjectRecordQueryResult); + } as RecordGqlOperationFindManyResult); }, }); } catch (error) { @@ -219,7 +218,7 @@ export const useFindManyRecords = ({ const records = useMemo( () => data?.[objectMetadataItem.namePlural] - ? getRecordsFromRecordConnection({ + ? getRecordsFromRecordConnection({ recordConnection: data?.[objectMetadataItem.namePlural], }) : ([] as T[]), diff --git a/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecordsQuery.ts b/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecordsQuery.ts index e41481c41c..55a6f270dc 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecordsQuery.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecordsQuery.ts @@ -2,18 +2,16 @@ import { useRecoilValue } from 'recoil'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; -import { QueryFields } from '@/object-record/query-keys/types/QueryFields'; +import { RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields'; import { generateFindManyRecordsQuery } from '@/object-record/utils/generateFindManyRecordsQuery'; export const useFindManyRecordsQuery = ({ objectNameSingular, - queryFields, - depth, + recordGqlFields, computeReferences, }: { objectNameSingular: string; - queryFields?: QueryFields; - depth?: number; + recordGqlFields?: RecordGqlOperationGqlRecordFields; computeReferences?: boolean; }) => { const { objectMetadataItem } = useObjectMetadataItem({ @@ -25,8 +23,7 @@ export const useFindManyRecordsQuery = ({ const findManyRecordsQuery = generateFindManyRecordsQuery({ objectMetadataItem, objectMetadataItems, - queryFields, - depth, + recordGqlFields, computeReferences, }); diff --git a/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecord.ts b/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecord.ts index acb2f92c45..af72ad296a 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecord.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecord.ts @@ -4,6 +4,9 @@ import { useQuery } from '@apollo/client'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier'; import { getRecordFromRecordNode } from '@/object-record/cache/utils/getRecordFromRecordNode'; +import { RecordGqlNode } from '@/object-record/graphql/types/RecordGqlNode'; +import { RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields'; +import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields'; import { useFindOneRecordQuery } from '@/object-record/hooks/useFindOneRecordQuery'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { isDefined } from '~/utils/isDefined'; @@ -11,32 +14,34 @@ import { isDefined } from '~/utils/isDefined'; export const useFindOneRecord = ({ objectNameSingular, objectRecordId = '', + recordGqlFields, onCompleted, skip, - depth, }: ObjectMetadataItemIdentifier & { objectRecordId: string | undefined; + recordGqlFields?: RecordGqlOperationGqlRecordFields; onCompleted?: (data: T) => void; skip?: boolean; - depth?: number; }) => { const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular, }); + const computedRecordGqlFields = + recordGqlFields ?? generateDepthOneRecordGqlFields({ objectMetadataItem }); + const { findOneRecordQuery } = useFindOneRecordQuery({ objectNameSingular, - depth, + recordGqlFields: computedRecordGqlFields, }); - const { data, loading, error } = useQuery< - { [nameSingular: string]: T }, - { objectRecordId: string } - >(findOneRecordQuery, { + const { data, loading, error } = useQuery<{ + [nameSingular: string]: RecordGqlNode; + }>(findOneRecordQuery, { skip: !objectMetadataItem || !objectRecordId || skip, variables: { objectRecordId }, onCompleted: (data) => { - const recordWithoutConnection = getRecordFromRecordNode({ + const recordWithoutConnection = getRecordFromRecordNode({ recordNode: { ...data[objectNameSingular] }, }); @@ -50,7 +55,7 @@ export const useFindOneRecord = ({ const recordWithoutConnection = useMemo( () => data?.[objectNameSingular] - ? getRecordFromRecordNode({ + ? getRecordFromRecordNode({ recordNode: data?.[objectNameSingular], }) : undefined, diff --git a/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecordQuery.ts b/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecordQuery.ts index 4dc2fc144a..725ec05d9c 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecordQuery.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecordQuery.ts @@ -4,14 +4,15 @@ import { useRecoilValue } from 'recoil'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery'; +import { RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields'; import { capitalize } from '~/utils/string/capitalize'; export const useFindOneRecordQuery = ({ objectNameSingular, - depth, + recordGqlFields, }: { objectNameSingular: string; - depth?: number; + recordGqlFields?: RecordGqlOperationGqlRecordFields; }) => { const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular, @@ -30,7 +31,7 @@ export const useFindOneRecordQuery = ({ })${mapObjectMetadataToGraphQLQuery({ objectMetadataItems, objectMetadataItem, - depth, + recordGqlFields, })} }, `; diff --git a/packages/twenty-front/src/modules/object-record/hooks/useLazyFindOneRecord.ts b/packages/twenty-front/src/modules/object-record/hooks/useLazyFindOneRecord.ts index a97a4cca87..a585d55fab 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useLazyFindOneRecord.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useLazyFindOneRecord.ts @@ -1,12 +1,15 @@ import { useLazyQuery } from '@apollo/client'; +import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier'; import { getRecordFromRecordNode } from '@/object-record/cache/utils/getRecordFromRecordNode'; +import { RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields'; +import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields'; import { useFindOneRecordQuery } from '@/object-record/hooks/useFindOneRecordQuery'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; type UseLazyFindOneRecordParams = ObjectMetadataItemIdentifier & { - depth?: number; + recordGqlFields?: RecordGqlOperationGqlRecordFields; }; type FindOneRecordParams = { @@ -16,11 +19,17 @@ type FindOneRecordParams = { export const useLazyFindOneRecord = ({ objectNameSingular, - depth, + recordGqlFields, }: UseLazyFindOneRecordParams) => { + const { objectMetadataItem } = useObjectMetadataItem({ + objectNameSingular, + }); + const { findOneRecordQuery } = useFindOneRecordQuery({ objectNameSingular, - depth, + recordGqlFields: + recordGqlFields ?? + generateDepthOneRecordGqlFields({ objectMetadataItem }), }); const [findOneRecord, { loading, error, data, called }] = diff --git a/packages/twenty-front/src/modules/object-record/hooks/useUpdateOneRecord.ts b/packages/twenty-front/src/modules/object-record/hooks/useUpdateOneRecord.ts index a9c50331ba..fc0b5a1eb9 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useUpdateOneRecord.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useUpdateOneRecord.ts @@ -6,23 +6,23 @@ import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadat import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordFromCache'; import { getRecordNodeFromRecord } from '@/object-record/cache/utils/getRecordNodeFromRecord'; import { updateRecordFromCache } from '@/object-record/cache/utils/updateRecordFromCache'; +import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields'; import { useUpdateOneRecordMutation } from '@/object-record/hooks/useUpdateOneRecordMutation'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { getUpdateOneRecordMutationResponseField } from '@/object-record/utils/getUpdateOneRecordMutationResponseField'; import { sanitizeRecordInput } from '@/object-record/utils/sanitizeRecordInput'; +import { capitalize } from '~/utils/string/capitalize'; type useUpdateOneRecordProps = { objectNameSingular: string; - queryFields?: Record; - depth?: number; + recordGqlFields?: Record; }; export const useUpdateOneRecord = < UpdatedObjectRecord extends ObjectRecord = ObjectRecord, >({ objectNameSingular, - queryFields, - depth = 1, + recordGqlFields, }: useUpdateOneRecordProps) => { const apolloClient = useApolloClient(); @@ -30,12 +30,16 @@ export const useUpdateOneRecord = < objectNameSingular, }); + const computedRecordGqlFields = + recordGqlFields ?? generateDepthOneRecordGqlFields({ objectMetadataItem }); + const getRecordFromCache = useGetRecordFromCache({ objectNameSingular, }); const { updateOneRecordMutation } = useUpdateOneRecordMutation({ objectNameSingular, + recordGqlFields: computedRecordGqlFields, }); const { objectMetadataItems } = useObjectMetadataItems(); @@ -54,14 +58,13 @@ export const useUpdateOneRecord = < }), }; - const cachedRecord = getRecordFromCache(idToUpdate); + const cachedRecord = getRecordFromCache(idToUpdate); const cachedRecordWithConnection = getRecordNodeFromRecord({ record: cachedRecord, objectMetadataItem, objectMetadataItems, - depth, - queryFields, + recordGqlFields: computedRecordGqlFields, computeReferences: true, }); @@ -69,6 +72,7 @@ export const useUpdateOneRecord = < ...cachedRecord, ...sanitizedInput, ...{ id: idToUpdate }, + ...{ __typename: capitalize(objectMetadataItem.nameSingular) }, }; const optimisticRecordWithConnection = @@ -76,8 +80,7 @@ export const useUpdateOneRecord = < record: optimisticRecord, objectMetadataItem, objectMetadataItems, - depth, - queryFields, + recordGqlFields: computedRecordGqlFields, computeReferences: true, }); diff --git a/packages/twenty-front/src/modules/object-record/hooks/useUpdateOneRecordMutation.ts b/packages/twenty-front/src/modules/object-record/hooks/useUpdateOneRecordMutation.ts index 9067845a76..9385b25188 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useUpdateOneRecordMutation.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useUpdateOneRecordMutation.ts @@ -5,18 +5,20 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery'; import { EMPTY_MUTATION } from '@/object-record/constants/EmptyMutation'; +import { RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields'; +import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields'; import { getUpdateOneRecordMutationResponseField } from '@/object-record/utils/getUpdateOneRecordMutationResponseField'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; import { capitalize } from '~/utils/string/capitalize'; export const useUpdateOneRecordMutation = ({ objectNameSingular, + recordGqlFields, computeReferences = false, - depth, }: { objectNameSingular: string; + recordGqlFields?: RecordGqlOperationGqlRecordFields; computeReferences?: boolean; - depth?: number; }) => { const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular, @@ -28,6 +30,12 @@ export const useUpdateOneRecordMutation = ({ return { updateOneRecordMutation: EMPTY_MUTATION }; } + const appliedRecordGqlFields = + recordGqlFields ?? + generateDepthOneRecordGqlFields({ + objectMetadataItem, + }); + const capitalizedObjectName = capitalize(objectMetadataItem.nameSingular); const mutationResponseField = getUpdateOneRecordMutationResponseField( @@ -40,8 +48,8 @@ export const useUpdateOneRecordMutation = ({ { objectMetadataItems, objectMetadataItem, - depth, computeReferences, + recordGqlFields: appliedRecordGqlFields, }, )} } diff --git a/packages/twenty-front/src/modules/object-record/hooks/useUpsertRecordFromState.ts b/packages/twenty-front/src/modules/object-record/hooks/useUpsertRecordFromState.ts index a65610a7d8..8251c8c780 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useUpsertRecordFromState.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useUpsertRecordFromState.ts @@ -1,13 +1,14 @@ import { useRecoilCallback } from 'recoil'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; // TODO: refactor with scoped state later export const useUpsertRecordFromState = () => useRecoilCallback( ({ set }) => - (record: T) => + (record: T) => set(recordStoreFamilyState(record.id), (previousRecord) => isDeeplyEqual(previousRecord, record) ? previousRecord : record, ), diff --git a/packages/twenty-front/src/modules/object-record/multiple-objects/hooks/useFindManyRecordsForMultipleMetadataItems.ts b/packages/twenty-front/src/modules/object-record/multiple-objects/hooks/useCombinedFindManyRecords.ts similarity index 60% rename from packages/twenty-front/src/modules/object-record/multiple-objects/hooks/useFindManyRecordsForMultipleMetadataItems.ts rename to packages/twenty-front/src/modules/object-record/multiple-objects/hooks/useCombinedFindManyRecords.ts index 3640dee6a6..95385c3777 100644 --- a/packages/twenty-front/src/modules/object-record/multiple-objects/hooks/useFindManyRecordsForMultipleMetadataItems.ts +++ b/packages/twenty-front/src/modules/object-record/multiple-objects/hooks/useCombinedFindManyRecords.ts @@ -1,26 +1,21 @@ import { useQuery } from '@apollo/client'; -import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection'; import { EMPTY_QUERY } from '@/object-record/constants/EmptyQuery'; -import { useGenerateFindManyRecordsForMultipleMetadataItemsQuery } from '@/object-record/multiple-objects/hooks/useGenerateFindManyRecordsForMultipleMetadataItemsQuery'; +import { RecordGqlOperationSignature } from '@/object-record/graphql/types/RecordGqlOperationSignature'; +import { useGenerateCombinedFindManyRecordsQuery } from '@/object-record/multiple-objects/hooks/useGenerateCombinedFindManyRecordsQuery'; import { MultiObjectRecordQueryResult } from '@/object-record/relation-picker/hooks/useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray'; -export const useFindManyRecordsForMultipleMetadataItems = ({ - objectMetadataItems, +export const useCombinedFindManyRecords = ({ + operationSignatures, skip = false, - depth = 2, }: { - objectMetadataItems: ObjectMetadataItem[]; + operationSignatures: RecordGqlOperationSignature[]; skip: boolean; - depth?: number; }) => { - const findManyQuery = useGenerateFindManyRecordsForMultipleMetadataItemsQuery( - { - targetObjectMetadataItems: objectMetadataItems, - depth, - }, - ); + const findManyQuery = useGenerateCombinedFindManyRecordsQuery({ + operationSignatures, + }); const { data } = useQuery( findManyQuery ?? EMPTY_QUERY, diff --git a/packages/twenty-front/src/modules/object-record/multiple-objects/hooks/useGenerateCombinedFindManyRecordsQuery.ts b/packages/twenty-front/src/modules/object-record/multiple-objects/hooks/useGenerateCombinedFindManyRecordsQuery.ts new file mode 100644 index 0000000000..e721722a95 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/multiple-objects/hooks/useGenerateCombinedFindManyRecordsQuery.ts @@ -0,0 +1,109 @@ +import { gql } from '@apollo/client'; +import { isUndefined } from '@sniptt/guards'; +import { useRecoilValue } from 'recoil'; + +import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; +import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery'; +import { RecordGqlOperationSignature } from '@/object-record/graphql/types/RecordGqlOperationSignature'; +import { isNonEmptyArray } from '~/utils/isNonEmptyArray'; +import { capitalize } from '~/utils/string/capitalize'; + +export const useGenerateCombinedFindManyRecordsQuery = ({ + operationSignatures, +}: { + operationSignatures: RecordGqlOperationSignature[]; +}) => { + const objectMetadataItems = useRecoilValue(objectMetadataItemsState); + + if (!isNonEmptyArray(operationSignatures)) { + return null; + } + + const filterPerMetadataItemArray = operationSignatures + .map( + ({ objectNameSingular }) => + `$filter${capitalize(objectNameSingular)}: ${capitalize( + objectNameSingular, + )}FilterInput`, + ) + .join(', '); + + const orderByPerMetadataItemArray = operationSignatures + .map( + ({ objectNameSingular }) => + `$orderBy${capitalize(objectNameSingular)}: ${capitalize( + objectNameSingular, + )}OrderByInput`, + ) + .join(', '); + + const lastCursorPerMetadataItemArray = operationSignatures + .map( + ({ objectNameSingular }) => + `$lastCursor${capitalize(objectNameSingular)}: String`, + ) + .join(', '); + + const limitPerMetadataItemArray = operationSignatures + .map( + ({ objectNameSingular }) => + `$limit${capitalize(objectNameSingular)}: Int`, + ) + .join(', '); + + const queryKeyWithObjectMetadataItemArray = operationSignatures.map( + (queryKey) => { + const objectMetadataItem = objectMetadataItems.find( + (objectMetadataItem) => + objectMetadataItem.nameSingular === queryKey.objectNameSingular, + ); + + if (isUndefined(objectMetadataItem)) { + throw new Error( + `Object metadata item not found for object name singular: ${queryKey.objectNameSingular}`, + ); + } + + return { ...queryKey, objectMetadataItem }; + }, + ); + + return gql` + query CombinedFindManyRecords( + ${filterPerMetadataItemArray}, + ${orderByPerMetadataItemArray}, + ${lastCursorPerMetadataItemArray}, + ${limitPerMetadataItemArray} + ) { + ${queryKeyWithObjectMetadataItemArray + .map( + ({ objectMetadataItem, fields }) => + `${objectMetadataItem.namePlural}(filter: $filter${capitalize( + objectMetadataItem.nameSingular, + )}, orderBy: $orderBy${capitalize( + objectMetadataItem.nameSingular, + )}, first: $limit${capitalize( + objectMetadataItem.nameSingular, + )}, after: $lastCursor${capitalize( + objectMetadataItem.nameSingular, + )}){ + edges { + node ${mapObjectMetadataToGraphQLQuery({ + objectMetadataItems: objectMetadataItems, + objectMetadataItem, + recordGqlFields: fields, + })} + cursor + } + pageInfo { + hasNextPage + startCursor + endCursor + } + totalCount + }`, + ) + .join('\n')} + } + `; +}; diff --git a/packages/twenty-front/src/modules/object-record/multiple-objects/hooks/useGenerateFindManyRecordsForMultipleMetadataItemsQuery.ts b/packages/twenty-front/src/modules/object-record/multiple-objects/hooks/useGenerateFindManyRecordsForMultipleMetadataItemsQuery.ts deleted file mode 100644 index 888a8c5bfa..0000000000 --- a/packages/twenty-front/src/modules/object-record/multiple-objects/hooks/useGenerateFindManyRecordsForMultipleMetadataItemsQuery.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { gql } from '@apollo/client'; -import { useRecoilValue } from 'recoil'; - -import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; -import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery'; -import { isNonEmptyArray } from '~/utils/isNonEmptyArray'; -import { capitalize } from '~/utils/string/capitalize'; - -export const useGenerateFindManyRecordsForMultipleMetadataItemsQuery = ({ - targetObjectMetadataItems, - depth, -}: { - targetObjectMetadataItems: ObjectMetadataItem[]; - depth?: number; -}) => { - const objectMetadataItems = useRecoilValue(objectMetadataItemsState); - const capitalizedObjectNameSingulars = targetObjectMetadataItems.map( - ({ nameSingular }) => capitalize(nameSingular), - ); - - if (!isNonEmptyArray(capitalizedObjectNameSingulars)) { - return null; - } - - const filterPerMetadataItemArray = capitalizedObjectNameSingulars - .map( - (capitalizedObjectNameSingular) => - `$filter${capitalizedObjectNameSingular}: ${capitalizedObjectNameSingular}FilterInput`, - ) - .join(', '); - - const orderByPerMetadataItemArray = capitalizedObjectNameSingulars - .map( - (capitalizedObjectNameSingular) => - `$orderBy${capitalizedObjectNameSingular}: ${capitalizedObjectNameSingular}OrderByInput`, - ) - .join(', '); - - const lastCursorPerMetadataItemArray = capitalizedObjectNameSingulars - .map( - (capitalizedObjectNameSingular) => - `$lastCursor${capitalizedObjectNameSingular}: String`, - ) - .join(', '); - - const limitPerMetadataItemArray = capitalizedObjectNameSingulars - .map( - (capitalizedObjectNameSingular) => - `$limit${capitalizedObjectNameSingular}: Int`, - ) - .join(', '); - - return gql` - query FindManyRecordsMultipleMetadataItems( - ${filterPerMetadataItemArray}, - ${orderByPerMetadataItemArray}, - ${lastCursorPerMetadataItemArray}, - ${limitPerMetadataItemArray} - ) { - ${targetObjectMetadataItems - .map( - (objectMetadataItem) => - `${objectMetadataItem.namePlural}(filter: $filter${capitalize( - objectMetadataItem.nameSingular, - )}, orderBy: $orderBy${capitalize( - objectMetadataItem.nameSingular, - )}, first: $limit${capitalize( - objectMetadataItem.nameSingular, - )}, after: $lastCursor${capitalize( - objectMetadataItem.nameSingular, - )}){ - edges { - node ${mapObjectMetadataToGraphQLQuery({ - objectMetadataItems: objectMetadataItems, - objectMetadataItem, - depth, - })} - cursor - } - pageInfo { - hasNextPage - startCursor - endCursor - } - totalCount - }`, - ) - .join('\n')} - } - `; -}; diff --git a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy.ts b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy.ts index 85452ddfcf..9441272179 100644 --- a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy.ts +++ b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy.ts @@ -1,5 +1,5 @@ import { OrderBy } from '@/object-metadata/types/OrderBy'; -import { OrderByField } from '@/object-metadata/types/OrderByField'; +import { RecordGqlOperationOrderBy } from '@/object-record/graphql/types/RecordGqlOperationOrderBy'; import { Field } from '~/generated/graphql'; import { mapArrayToObject } from '~/utils/array/mapArrayToObject'; import { isDefined } from '~/utils/isDefined'; @@ -10,7 +10,7 @@ import { Sort } from '../types/Sort'; export const turnSortsIntoOrderBy = ( sorts: Sort[], fields: Pick[], -): OrderByField => { +): RecordGqlOperationOrderBy => { const fieldsById = mapArrayToObject(fields, ({ id }) => id); const sortsOrderBy = Object.fromEntries( sorts diff --git a/packages/twenty-front/src/modules/object-record/query-keys/types/QueryFields.ts b/packages/twenty-front/src/modules/object-record/query-keys/types/QueryFields.ts deleted file mode 100644 index 78b2e21c3b..0000000000 --- a/packages/twenty-front/src/modules/object-record/query-keys/types/QueryFields.ts +++ /dev/null @@ -1 +0,0 @@ -export type QueryFields = Record; diff --git a/packages/twenty-front/src/modules/object-record/query-keys/types/QueryKey.ts b/packages/twenty-front/src/modules/object-record/query-keys/types/QueryKey.ts deleted file mode 100644 index c1a7a59849..0000000000 --- a/packages/twenty-front/src/modules/object-record/query-keys/types/QueryKey.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { QueryFields } from '@/object-record/query-keys/types/QueryFields'; -import { ObjectRecordQueryVariables } from '@/object-record/types/ObjectRecordQueryVariables'; - -export type QueryKey = { - objectNameSingular: string; - variables: ObjectRecordQueryVariables; - depth?: number; - fields?: QueryFields; // Todo: Fields should be required - fieldsFactory?: (fieldsFactoryParam: any) => QueryFields; -}; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFieldDisplay.tsx index 1cbffbcf2f..8d04ba863d 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFieldDisplay.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFieldDisplay.tsx @@ -1,4 +1,5 @@ import { RecordChip } from '@/object-record/components/RecordChip'; +import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { useRelationField } from '../../hooks/useRelationField'; @@ -12,7 +13,7 @@ export const RelationFieldDisplay = () => { objectNameSingular={ fieldDefinition.metadata.relationObjectMetadataNameSingular } - record={fieldValue} + record={fieldValue as unknown as ObjectRecord} // Todo: Fix this type maxWidth={maxWidth} /> ); diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingBooleanFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingBooleanFilter.ts index 87ce143024..5a3eaada6e 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingBooleanFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingBooleanFilter.ts @@ -1,4 +1,4 @@ -import { BooleanFilter } from '@/object-record/record-filter/types/ObjectRecordQueryFilter'; +import { BooleanFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; export const isMatchingBooleanFilter = ({ booleanFilter, diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingCurrencyFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingCurrencyFilter.ts index 19f6e9fea2..2d4719c395 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingCurrencyFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingCurrencyFilter.ts @@ -1,4 +1,4 @@ -import { CurrencyFilter } from '@/object-record/record-filter/types/ObjectRecordQueryFilter'; +import { CurrencyFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; export const isMatchingCurrencyFilter = ({ currencyFilter, diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingDateFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingDateFilter.ts index c769730de8..ecea7a55b0 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingDateFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingDateFilter.ts @@ -1,6 +1,6 @@ import { DateTime } from 'luxon'; -import { DateFilter } from '@/object-record/record-filter/types/ObjectRecordQueryFilter'; +import { DateFilter } from '@/object-record//graphql/types/RecordGqlOperationFilter'; export const isMatchingDateFilter = ({ dateFilter, diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingFloatFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingFloatFilter.ts index ddf6c2fb83..2998e8fb8c 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingFloatFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingFloatFilter.ts @@ -1,4 +1,4 @@ -import { FloatFilter } from '@/object-record/record-filter/types/ObjectRecordQueryFilter'; +import { FloatFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; export const isMatchingFloatFilter = ({ floatFilter, diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingStringFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingStringFilter.ts index 164266d8ec..053be8cdec 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingStringFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingStringFilter.ts @@ -1,4 +1,4 @@ -import { StringFilter } from '@/object-record/record-filter/types/ObjectRecordQueryFilter'; +import { StringFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; export const isMatchingStringFilter = ({ stringFilter, diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingUUIDFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingUUIDFilter.ts index 3c5cfb0bd9..034b688a97 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingUUIDFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/isMatchingUUIDFilter.ts @@ -1,7 +1,7 @@ import { UUIDFilter, UUIDFilterValue, -} from '@/object-record/record-filter/types/ObjectRecordQueryFilter'; +} from '@/object-record/graphql/types/RecordGqlOperationFilter'; export const isMatchingUUIDFilter = ({ uuidFilter, diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/isRecordMatchingFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/isRecordMatchingFilter.ts index 53a803ef26..0af419f375 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/isRecordMatchingFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/isRecordMatchingFilter.ts @@ -10,12 +10,12 @@ import { FloatFilter, FullNameFilter, NotObjectRecordFilter, - ObjectRecordQueryFilter, OrObjectRecordFilter, + RecordGqlOperationFilter, StringFilter, URLFilter, UUIDFilter, -} from '@/object-record/record-filter/types/ObjectRecordQueryFilter'; +} from '@/object-record/graphql/types/RecordGqlOperationFilter'; import { isMatchingBooleanFilter } from '@/object-record/record-filter/utils/isMatchingBooleanFilter'; import { isMatchingCurrencyFilter } from '@/object-record/record-filter/utils/isMatchingCurrencyFilter'; import { isMatchingDateFilter } from '@/object-record/record-filter/utils/isMatchingDateFilter'; @@ -27,15 +27,15 @@ import { isDefined } from '~/utils/isDefined'; import { isEmptyObject } from '~/utils/isEmptyObject'; const isAndFilter = ( - filter: ObjectRecordQueryFilter, + filter: RecordGqlOperationFilter, ): filter is AndObjectRecordFilter => 'and' in filter && !!filter.and; const isOrFilter = ( - filter: ObjectRecordQueryFilter, + filter: RecordGqlOperationFilter, ): filter is OrObjectRecordFilter => 'or' in filter && !!filter.or; const isNotFilter = ( - filter: ObjectRecordQueryFilter, + filter: RecordGqlOperationFilter, ): filter is NotObjectRecordFilter => 'not' in filter && !!filter.not; export const isRecordMatchingFilter = ({ @@ -44,7 +44,7 @@ export const isRecordMatchingFilter = ({ objectMetadataItem, }: { record: any; - filter: ObjectRecordQueryFilter; + filter: RecordGqlOperationFilter; objectMetadataItem: ObjectMetadataItem; }): boolean => { if (Object.keys(filter).length === 0) { diff --git a/packages/twenty-front/src/modules/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter.ts b/packages/twenty-front/src/modules/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter.ts index 8fce2cf7a8..3512185928 100644 --- a/packages/twenty-front/src/modules/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter.ts @@ -5,11 +5,11 @@ import { CurrencyFilter, DateFilter, FloatFilter, - ObjectRecordQueryFilter, + RecordGqlOperationFilter, StringFilter, URLFilter, UUIDFilter, -} from '@/object-record/record-filter/types/ObjectRecordQueryFilter'; +} from '@/object-record/graphql/types/RecordGqlOperationFilter'; import { makeAndFilterVariables } from '@/object-record/utils/makeAndFilterVariables'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; import { Field } from '~/generated/graphql'; @@ -27,8 +27,8 @@ export type ObjectDropdownFilter = Omit & { export const turnObjectDropdownFilterIntoQueryFilter = ( rawUIFilters: ObjectDropdownFilter[], fields: Pick[], -): ObjectRecordQueryFilter | undefined => { - const objectRecordFilters: ObjectRecordQueryFilter[] = []; +): RecordGqlOperationFilter | undefined => { + const objectRecordFilters: RecordGqlOperationFilter[] = []; for (const rawUIFilter of rawUIFilters) { const correspondingField = fields.find( diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoard.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoard.ts index 3e10a60337..e1171a2539 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoard.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoard.ts @@ -6,7 +6,7 @@ import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy'; import { useRecordBoard } from '@/object-record/record-board/hooks/useRecordBoard'; import { turnObjectDropdownFilterIntoQueryFilter } from '@/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter'; -import { useRecordBoardQueryFields } from '@/object-record/record-index/hooks/useRecordBoardQueryFields'; +import { useRecordBoardRecordGqlFields } from '@/object-record/record-index/hooks/useRecordBoardRecordGqlFields'; import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/states/recordIndexFieldDefinitionsState'; import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState'; import { recordIndexIsCompactModeActiveState } from '@/object-record/record-index/states/recordIndexIsCompactModeActiveState'; @@ -56,7 +56,7 @@ export const useLoadRecordIndexBoard = ({ recordIndexIsCompactModeActiveState, ); - const queryFields = useRecordBoardQueryFields({ + const recordGqlFields = useRecordBoardRecordGqlFields({ objectMetadataItem, recordBoardId, }); @@ -71,7 +71,7 @@ export const useLoadRecordIndexBoard = ({ objectNameSingular, filter: requestFilters, orderBy, - queryFields, + recordGqlFields, }); const { setRecordCountInCurrentView } = diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexTable.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexTable.ts index fe474fbfc5..e63f7e6d88 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexTable.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexTable.ts @@ -5,7 +5,7 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy'; import { turnObjectDropdownFilterIntoQueryFilter } from '@/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter'; -import { useRecordTableQueryFields } from '@/object-record/record-index/hooks/useRecordTableQueryFields'; +import { useRecordTableRecordGqlFields } from '@/object-record/record-index/hooks/useRecordTableRecordGqlFields'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; import { SIGN_IN_BACKGROUND_MOCK_COMPANIES } from '@/sign-in-background-mock/constants/SignInBackgroundMockCompanies'; @@ -49,7 +49,7 @@ export const useLoadRecordIndexTable = (objectNameSingular: string) => { const currentWorkspace = useRecoilValue(currentWorkspaceState); const params = useFindManyParams(objectNameSingular); - const queryFields = useRecordTableQueryFields(); + const recordGqlFields = useRecordTableRecordGqlFields(); const { records, @@ -59,7 +59,7 @@ export const useLoadRecordIndexTable = (objectNameSingular: string) => { queryStateIdentifier, } = useFindManyRecords({ ...params, - queryFields, + recordGqlFields, onCompleted: () => { setLastRowVisible(false); setIsRecordTableInitialLoading(false); diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordBoardQueryFields.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordBoardRecordGqlFields.ts similarity index 89% rename from packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordBoardQueryFields.ts rename to packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordBoardRecordGqlFields.ts index 7d1294ab60..d0b423dd3f 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordBoardQueryFields.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordBoardRecordGqlFields.ts @@ -5,7 +5,7 @@ import { getObjectMetadataIdentifierFields } from '@/object-metadata/utils/getOb import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates'; import { isDefined } from '~/utils/isDefined'; -export const useRecordBoardQueryFields = ({ +export const useRecordBoardRecordGqlFields = ({ objectMetadataItem, recordBoardId, }: { @@ -33,7 +33,7 @@ export const useRecordBoardQueryFields = ({ identifierQueryFields[imageIdentifierFieldMetadataItem.name] = true; } - const queryFields: Record = { + const recordGqlFields: Record = { id: true, ...Object.fromEntries( visibleFieldDefinitions.map((visibleFieldDefinition) => [ @@ -45,8 +45,8 @@ export const useRecordBoardQueryFields = ({ }; if (isDefined(kanbanFieldMetadataName)) { - queryFields[kanbanFieldMetadataName] = true; + recordGqlFields[kanbanFieldMetadataName] = true; } - return queryFields; + return recordGqlFields; }; diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordTableQueryFields.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordTableRecordGqlFields.ts similarity index 77% rename from packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordTableQueryFields.ts rename to packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordTableRecordGqlFields.ts index a97440e830..99d4a834a6 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordTableQueryFields.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordTableRecordGqlFields.ts @@ -2,12 +2,12 @@ import { useRecoilValue } from 'recoil'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; -export const useRecordTableQueryFields = () => { +export const useRecordTableRecordGqlFields = () => { const { visibleTableColumnsSelector } = useRecordTableStates(); const visibleTableColumns = useRecoilValue(visibleTableColumnsSelector()); - const queryFields: Record = { + const recordGqlFields: Record = { id: true, ...Object.fromEntries( visibleTableColumns.map((column) => [column.metadata.fieldName, true]), @@ -15,5 +15,5 @@ export const useRecordTableQueryFields = () => { position: true, }; - return queryFields; + return recordGqlFields; }; diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useExportTableData.ts b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useExportTableData.ts index 7dbe87226a..d9c9f26f07 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useExportTableData.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useExportTableData.ts @@ -139,7 +139,6 @@ export const useExportTableData = ({ // Todo: this needs to be done on click on the Export not button, not to be reactive. Use Lazy query for example const { totalCount, records, fetchMoreRecords } = useFindManyRecords({ ...usedFindManyParams, - depth: 0, limit: pageSize, onCompleted: (_data, options) => { setHasNextPage(options?.pageInfo?.hasNextPage ?? false); diff --git a/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainerEffect.tsx b/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainerEffect.tsx index 0f62468876..e3b835c9be 100644 --- a/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainerEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainerEffect.tsx @@ -17,7 +17,6 @@ export const RecordShowContainer = ({ const { record: activity, loading } = useFindOneRecord({ objectRecordId, objectNameSingular, - depth: 3, }); const setRecordStore = useSetRecoilState( diff --git a/packages/twenty-front/src/modules/object-record/record-show/graphql/operations/factories/findOneRecordForShowPageOperationSignatureFactory.ts b/packages/twenty-front/src/modules/object-record/record-show/graphql/operations/factories/findOneRecordForShowPageOperationSignatureFactory.ts new file mode 100644 index 0000000000..50082029ae --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-show/graphql/operations/factories/findOneRecordForShowPageOperationSignatureFactory.ts @@ -0,0 +1,11 @@ +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { RecordGqlOperationSignatureFactory } from '@/object-record/graphql/types/RecordGqlOperationSignatureFactory'; +import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields'; + +export const findOneRecordForShowPageOperationSignatureFactory: RecordGqlOperationSignatureFactory = + ({ objectMetadataItem }: { objectMetadataItem: ObjectMetadataItem }) => ({ + objectNameSingular: CoreObjectNameSingular.Activity, + variables: {}, + fields: generateDepthOneRecordGqlFields({ objectMetadataItem }), + }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetRecordTableData.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetRecordTableData.ts index 781d348b45..98f0d43983 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetRecordTableData.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetRecordTableData.ts @@ -2,6 +2,7 @@ import { useRecoilCallback } from 'recoil'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; +import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; @@ -23,7 +24,7 @@ export const useSetRecordTableData = ({ return useRecoilCallback( ({ set, snapshot }) => - (newEntityArray: T[], totalCount: number) => { + (newEntityArray: T[], totalCount: number) => { for (const entity of newEntityArray) { // TODO: refactor with scoped state later const currentEntity = snapshot diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/__tests__/useMultiObjectSearch.test.tsx b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/__tests__/useMultiObjectSearch.test.tsx index b41e626cec..a84dfcce94 100644 --- a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/__tests__/useMultiObjectSearch.test.tsx +++ b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/__tests__/useMultiObjectSearch.test.tsx @@ -9,7 +9,7 @@ import { useMultiObjectSearch } from '@/object-record/relation-picker/hooks/useM import { FieldMetadataType } from '~/generated/graphql'; const query = gql` - query FindManyRecordsMultipleMetadataItems( + query CombinedFindManyRecords( $filterNameSingular: NameSingularFilterInput $orderByNameSingular: NameSingularOrderByInput $lastCursorNameSingular: String diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray.ts b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray.ts index eedf253275..a1047478a7 100644 --- a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray.ts +++ b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray.ts @@ -3,12 +3,12 @@ import { useRecoilValue } from 'recoil'; import { objectMetadataItemsByNamePluralMapSelector } from '@/object-metadata/states/objectMetadataItemsByNamePluralMapSelector'; import { getObjectRecordIdentifier } from '@/object-metadata/utils/getObjectRecordIdentifier'; +import { RecordGqlConnection } from '@/object-record/graphql/types/RecordGqlConnection'; import { ObjectRecordForSelect } from '@/object-record/relation-picker/hooks/useMultiObjectSearch'; -import { ObjectRecordConnection } from '@/object-record/types/ObjectRecordConnection'; import { isDefined } from '~/utils/isDefined'; export type MultiObjectRecordQueryResult = { - [namePlural: string]: ObjectRecordConnection; + [namePlural: string]: RecordGqlConnection; }; export const useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray = diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterAndSelectedItemsQuery.ts b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterAndSelectedItemsQuery.ts index a8cd2b5094..d42b2338b3 100644 --- a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterAndSelectedItemsQuery.ts +++ b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterAndSelectedItemsQuery.ts @@ -4,7 +4,7 @@ import { useRecoilValue } from 'recoil'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { EMPTY_QUERY } from '@/object-record/constants/EmptyQuery'; -import { useGenerateFindManyRecordsForMultipleMetadataItemsQuery } from '@/object-record/multiple-objects/hooks/useGenerateFindManyRecordsForMultipleMetadataItemsQuery'; +import { useGenerateCombinedFindManyRecordsQuery } from '@/object-record/multiple-objects/hooks/useGenerateCombinedFindManyRecordsQuery'; import { useLimitPerMetadataItem } from '@/object-record/relation-picker/hooks/useLimitPerMetadataItem'; import { MultiObjectRecordQueryResult, @@ -84,9 +84,13 @@ export const useMultiObjectSearchMatchesSearchFilterAndSelectedItemsQuery = ({ }); const multiSelectQueryForSelectedIds = - useGenerateFindManyRecordsForMultipleMetadataItemsQuery({ - targetObjectMetadataItems: objectMetadataItemsUsedInSelectedIdsQuery, - depth: 0, + useGenerateCombinedFindManyRecordsQuery({ + operationSignatures: objectMetadataItemsUsedInSelectedIdsQuery.map( + (objectMetadataItem) => ({ + objectNameSingular: objectMetadataItem.nameSingular, + variables: {}, + }), + ), }); const { diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterAndToSelectQuery.ts b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterAndToSelectQuery.ts index aced1790ba..cf753a4df7 100644 --- a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterAndToSelectQuery.ts +++ b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterAndToSelectQuery.ts @@ -3,7 +3,7 @@ import { useRecoilValue } from 'recoil'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { EMPTY_QUERY } from '@/object-record/constants/EmptyQuery'; -import { useGenerateFindManyRecordsForMultipleMetadataItemsQuery } from '@/object-record/multiple-objects/hooks/useGenerateFindManyRecordsForMultipleMetadataItemsQuery'; +import { useGenerateCombinedFindManyRecordsQuery } from '@/object-record/multiple-objects/hooks/useGenerateCombinedFindManyRecordsQuery'; import { useLimitPerMetadataItem } from '@/object-record/relation-picker/hooks/useLimitPerMetadataItem'; import { MultiObjectRecordQueryResult, @@ -82,11 +82,14 @@ export const useMultiObjectSearchMatchesSearchFilterAndToSelectQuery = ({ limit, }); - const multiSelectQuery = - useGenerateFindManyRecordsForMultipleMetadataItemsQuery({ - targetObjectMetadataItems: nonSystemObjectMetadataItems, - depth: 0, - }); + const multiSelectQuery = useGenerateCombinedFindManyRecordsQuery({ + operationSignatures: nonSystemObjectMetadataItems.map( + (objectMetadataItem) => ({ + objectNameSingular: objectMetadataItem.nameSingular, + variables: {}, + }), + ), + }); const { loading: toSelectAndMatchesSearchFilterObjectRecordsLoading, diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearchSelectedItemsQuery.ts b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearchSelectedItemsQuery.ts index 155b584c3a..5656cb77f5 100644 --- a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearchSelectedItemsQuery.ts +++ b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearchSelectedItemsQuery.ts @@ -3,7 +3,7 @@ import { isNonEmptyArray } from '@sniptt/guards'; import { useRecoilValue } from 'recoil'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; -import { useGenerateFindManyRecordsForMultipleMetadataItemsQuery } from '@/object-record/multiple-objects/hooks/useGenerateFindManyRecordsForMultipleMetadataItemsQuery'; +import { useGenerateCombinedFindManyRecordsQuery } from '@/object-record/multiple-objects/hooks/useGenerateCombinedFindManyRecordsQuery'; import { useLimitPerMetadataItem } from '@/object-record/relation-picker/hooks/useLimitPerMetadataItem'; import { MultiObjectRecordQueryResult, @@ -67,8 +67,13 @@ export const useMultiObjectSearchSelectedItemsQuery = ({ }); const multiSelectQueryForSelectedIds = - useGenerateFindManyRecordsForMultipleMetadataItemsQuery({ - targetObjectMetadataItems: objectMetadataItemsUsedInSelectedIdsQuery, + useGenerateCombinedFindManyRecordsQuery({ + operationSignatures: objectMetadataItemsUsedInSelectedIdsQuery.map( + (objectMetadataItem) => ({ + objectNameSingular: objectMetadataItem.nameSingular, + variables: {}, + }), + ), }); const { diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useSearchFilterPerMetadataItem.ts b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useSearchFilterPerMetadataItem.ts index 40ec48828a..a4822dea14 100644 --- a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useSearchFilterPerMetadataItem.ts +++ b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useSearchFilterPerMetadataItem.ts @@ -2,7 +2,7 @@ import { isNonEmptyString } from '@sniptt/guards'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { getLabelIdentifierFieldMetadataItem } from '@/object-metadata/utils/getLabelIdentifierFieldMetadataItem'; -import { ObjectRecordQueryFilter } from '@/object-record/record-filter/types/ObjectRecordQueryFilter'; +import { RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; import { makeOrFilterVariables } from '@/object-record/utils/makeOrFilterVariables'; import { FieldMetadataType } from '~/generated/graphql'; import { generateILikeFiltersForCompositeFields } from '~/utils/array/generateILikeFiltersForCompositeFields'; @@ -16,7 +16,7 @@ export const useSearchFilterPerMetadataItem = ({ searchFilterValue: string; }) => { const searchFilterPerMetadataItemNameSingular = - Object.fromEntries( + Object.fromEntries( objectMetadataItems .map((objectMetadataItem) => { if (searchFilterValue === '') return null; @@ -24,7 +24,7 @@ export const useSearchFilterPerMetadataItem = ({ const labelIdentifierFieldMetadataItem = getLabelIdentifierFieldMetadataItem(objectMetadataItem); - let searchFilter: ObjectRecordQueryFilter = {}; + let searchFilter: RecordGqlOperationFilter = {}; if (isDefined(labelIdentifierFieldMetadataItem)) { switch (labelIdentifierFieldMetadataItem.type) { diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/types/EntityForSelect.ts b/packages/twenty-front/src/modules/object-record/relation-picker/types/EntityForSelect.ts index 7ac1147b98..d7958ba241 100644 --- a/packages/twenty-front/src/modules/object-record/relation-picker/types/EntityForSelect.ts +++ b/packages/twenty-front/src/modules/object-record/relation-picker/types/EntityForSelect.ts @@ -1,4 +1,6 @@ import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { ObjectRecordIdentifier } from '@/object-record/types/ObjectRecordIdentifier'; -export type EntityForSelect = ObjectRecordIdentifier & { record: ObjectRecord }; +export type EntityForSelect = ObjectRecordIdentifier & { + record: ObjectRecord; +}; diff --git a/packages/twenty-front/src/modules/object-record/types/ObjectRecord.ts b/packages/twenty-front/src/modules/object-record/types/ObjectRecord.ts index 7ffedb0257..1c511dd5ae 100644 --- a/packages/twenty-front/src/modules/object-record/types/ObjectRecord.ts +++ b/packages/twenty-front/src/modules/object-record/types/ObjectRecord.ts @@ -1 +1,4 @@ -export type ObjectRecord = Record & { id: string }; +export type ObjectRecord = Record & { + id: string; + __typename: string; +}; diff --git a/packages/twenty-front/src/modules/object-record/types/ObjectRecordEdge.ts b/packages/twenty-front/src/modules/object-record/types/ObjectRecordEdge.ts deleted file mode 100644 index e0e0154bfb..0000000000 --- a/packages/twenty-front/src/modules/object-record/types/ObjectRecordEdge.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { ObjectRecord } from '@/object-record/types/ObjectRecord'; - -export type ObjectRecordEdge = { - __typename?: string; - node: T; - cursor: string; -}; diff --git a/packages/twenty-front/src/modules/object-record/types/ObjectRecordQueryResult.ts b/packages/twenty-front/src/modules/object-record/types/ObjectRecordQueryResult.ts deleted file mode 100644 index ec828223b2..0000000000 --- a/packages/twenty-front/src/modules/object-record/types/ObjectRecordQueryResult.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { ObjectRecordConnection } from '@/object-record/types/ObjectRecordConnection'; - -export type ObjectRecordQueryResult = { - [objectNamePlural: string]: ObjectRecordConnection; -}; diff --git a/packages/twenty-front/src/modules/object-record/types/ObjectRecordQueryVariables.ts b/packages/twenty-front/src/modules/object-record/types/ObjectRecordQueryVariables.ts deleted file mode 100644 index 99e4956ae9..0000000000 --- a/packages/twenty-front/src/modules/object-record/types/ObjectRecordQueryVariables.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { OrderByField } from '@/object-metadata/types/OrderByField'; -import { ObjectRecordQueryFilter } from '@/object-record/record-filter/types/ObjectRecordQueryFilter'; - -export type ObjectRecordQueryVariables = { - filter?: ObjectRecordQueryFilter; - orderBy?: OrderByField; - limit?: number; -}; diff --git a/packages/twenty-front/src/modules/object-record/utils/filterUniqueRecordEdgesByCursor.ts b/packages/twenty-front/src/modules/object-record/utils/filterUniqueRecordEdgesByCursor.ts index 048ea38f36..07f6a982f2 100644 --- a/packages/twenty-front/src/modules/object-record/utils/filterUniqueRecordEdgesByCursor.ts +++ b/packages/twenty-front/src/modules/object-record/utils/filterUniqueRecordEdgesByCursor.ts @@ -1,9 +1,7 @@ -import { ObjectRecordEdge } from '@/object-record/types/ObjectRecordEdge'; +import { RecordGqlEdge } from '@/object-record/graphql/types/RecordGqlEdge'; -export const filterUniqueRecordEdgesByCursor = < - RecordType extends { id: string }, ->( - arrayToFilter: ObjectRecordEdge[], +export const filterUniqueRecordEdgesByCursor = ( + arrayToFilter: RecordGqlEdge[], ) => { const seenCursors = new Set(); diff --git a/packages/twenty-front/src/modules/object-record/utils/generateFindManyRecordsQuery.ts b/packages/twenty-front/src/modules/object-record/utils/generateFindManyRecordsQuery.ts index a231bef76a..8836d1d1fc 100644 --- a/packages/twenty-front/src/modules/object-record/utils/generateFindManyRecordsQuery.ts +++ b/packages/twenty-front/src/modules/object-record/utils/generateFindManyRecordsQuery.ts @@ -2,20 +2,18 @@ import gql from 'graphql-tag'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery'; -import { QueryFields } from '@/object-record/query-keys/types/QueryFields'; +import { RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields'; import { capitalize } from '~/utils/string/capitalize'; export const generateFindManyRecordsQuery = ({ objectMetadataItem, objectMetadataItems, - depth, - queryFields, + recordGqlFields, computeReferences, }: { objectMetadataItem: ObjectMetadataItem; objectMetadataItems: ObjectMetadataItem[]; - queryFields?: QueryFields; - depth?: number; + recordGqlFields?: RecordGqlOperationGqlRecordFields; computeReferences?: boolean; }) => gql` query FindMany${capitalize( @@ -32,8 +30,7 @@ query FindMany${capitalize( node ${mapObjectMetadataToGraphQLQuery({ objectMetadataItems, objectMetadataItem, - depth, - queryFields, + recordGqlFields, computeReferences, })} cursor diff --git a/packages/twenty-front/src/modules/object-record/utils/getChildRelationArray.ts b/packages/twenty-front/src/modules/object-record/utils/getChildRelationArray.ts deleted file mode 100644 index f7a93507c6..0000000000 --- a/packages/twenty-front/src/modules/object-record/utils/getChildRelationArray.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { ObjectRecordEdge } from '@/object-record/types/ObjectRecordEdge'; -import { isDefined } from '~/utils/isDefined'; - -export const getChildRelationArray = ({ - childRelation, -}: { - childRelation: any; -}) => { - if (isDefined(childRelation.edges) && Array.isArray(childRelation.edges)) { - return childRelation.edges.map((edge: ObjectRecordEdge) => edge.node); - } else { - return childRelation; - } -}; diff --git a/packages/twenty-front/src/modules/object-record/utils/makeAndFilterVariables.ts b/packages/twenty-front/src/modules/object-record/utils/makeAndFilterVariables.ts index 2f5e36d937..1f5ae29502 100644 --- a/packages/twenty-front/src/modules/object-record/utils/makeAndFilterVariables.ts +++ b/packages/twenty-front/src/modules/object-record/utils/makeAndFilterVariables.ts @@ -1,9 +1,9 @@ -import { ObjectRecordQueryFilter } from '@/object-record/record-filter/types/ObjectRecordQueryFilter'; +import { RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; import { isDefined } from '~/utils/isDefined'; export const makeAndFilterVariables = ( - filters: (ObjectRecordQueryFilter | undefined)[], -): ObjectRecordQueryFilter | undefined => { + filters: (RecordGqlOperationFilter | undefined)[], +): RecordGqlOperationFilter | undefined => { const definedFilters = filters.filter(isDefined); if (!definedFilters.length) return undefined; diff --git a/packages/twenty-front/src/modules/object-record/utils/makeOrFilterVariables.ts b/packages/twenty-front/src/modules/object-record/utils/makeOrFilterVariables.ts index 01cceb25c9..ed07e891c7 100644 --- a/packages/twenty-front/src/modules/object-record/utils/makeOrFilterVariables.ts +++ b/packages/twenty-front/src/modules/object-record/utils/makeOrFilterVariables.ts @@ -1,9 +1,9 @@ -import { ObjectRecordQueryFilter } from '@/object-record/record-filter/types/ObjectRecordQueryFilter'; +import { RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; import { isDefined } from '~/utils/isDefined'; export const makeOrFilterVariables = ( - filters: (ObjectRecordQueryFilter | undefined)[], -): ObjectRecordQueryFilter | undefined => { + filters: (RecordGqlOperationFilter | undefined)[], +): RecordGqlOperationFilter | undefined => { const definedFilters = filters.filter(isDefined); if (!definedFilters.length) return undefined; diff --git a/packages/twenty-front/src/modules/object-record/utils/mapEdgeToObjectRecord.ts b/packages/twenty-front/src/modules/object-record/utils/mapEdgeToObjectRecord.ts deleted file mode 100644 index 0bb1d52e74..0000000000 --- a/packages/twenty-front/src/modules/object-record/utils/mapEdgeToObjectRecord.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { ObjectRecordEdge } from '@/object-record/types/ObjectRecordEdge'; - -export const mapEdgeToObjectRecord = ( - objectRecordEdge: ObjectRecordEdge, -) => { - return objectRecordEdge.node as T; -}; diff --git a/packages/twenty-front/src/modules/object-record/utils/prefillRecord.ts b/packages/twenty-front/src/modules/object-record/utils/prefillRecord.ts index 4fd45e2fa8..53e686c5a2 100644 --- a/packages/twenty-front/src/modules/object-record/utils/prefillRecord.ts +++ b/packages/twenty-front/src/modules/object-record/utils/prefillRecord.ts @@ -8,18 +8,12 @@ import { isDefined } from '~/utils/isDefined'; export const prefillRecord = ({ objectMetadataItem, input, - depth = 1, }: { objectMetadataItem: ObjectMetadataItem; input: Record; - depth?: number; }) => { return Object.fromEntries( objectMetadataItem.fields - .filter( - (fieldMetadataItem) => - depth > 0 || fieldMetadataItem.type !== 'RELATION', - ) .map((fieldMetadataItem) => { const inputValue = input[fieldMetadataItem.name]; diff --git a/packages/twenty-front/src/modules/people/components/PersonChip.tsx b/packages/twenty-front/src/modules/people/components/PersonChip.tsx deleted file mode 100644 index 9c7b2177df..0000000000 --- a/packages/twenty-front/src/modules/people/components/PersonChip.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { EntityChip, EntityChipVariant } from 'twenty-ui'; - -import { getImageAbsoluteURIOrBase64 } from '~/utils/image/getImageAbsoluteURIOrBase64'; - -export type PersonChipProps = { - id: string; - name: string; - avatarUrl?: string; - variant?: EntityChipVariant; -}; - -export const PersonChip = ({ - id, - name, - avatarUrl, - variant, -}: PersonChipProps) => ( - -); diff --git a/packages/twenty-front/src/modules/people/components/__stories__/PeopleChip.stories.tsx b/packages/twenty-front/src/modules/people/components/__stories__/PeopleChip.stories.tsx deleted file mode 100644 index e885f8e564..0000000000 --- a/packages/twenty-front/src/modules/people/components/__stories__/PeopleChip.stories.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { Meta, StoryObj } from '@storybook/react'; - -import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator'; - -import { PersonChip } from '../PersonChip'; - -const meta: Meta = { - title: 'Modules/People/PersonChip', - component: PersonChip, - decorators: [ComponentWithRouterDecorator], -}; - -export default meta; -type Story = StoryObj; - -export const SmallName: Story = { - args: { id: 'tim_fake_id', name: 'Tim C.' }, -}; - -export const BigName: Story = { - args: { id: 'steve_fake_id', name: 'Steve LoremIpsumLoremIpsumLoremIpsum' }, -}; diff --git a/packages/twenty-front/src/modules/prefetch/components/PrefetchRunQueriesEffect.tsx b/packages/twenty-front/src/modules/prefetch/components/PrefetchRunQueriesEffect.tsx index e1ed69d597..981afe71f6 100644 --- a/packages/twenty-front/src/modules/prefetch/components/PrefetchRunQueriesEffect.tsx +++ b/packages/twenty-front/src/modules/prefetch/components/PrefetchRunQueriesEffect.tsx @@ -3,8 +3,10 @@ import { useRecoilValue } from 'recoil'; import { currentUserState } from '@/auth/states/currentUserState'; import { Favorite } from '@/favorites/types/Favorite'; -import { useFindManyRecordsForMultipleMetadataItems } from '@/object-record/multiple-objects/hooks/useFindManyRecordsForMultipleMetadataItems'; +import { useCombinedFindManyRecords } from '@/object-record/multiple-objects/hooks/useCombinedFindManyRecords'; import { usePrefetchRunQuery } from '@/prefetch/hooks/internal/usePrefetchRunQuery'; +import { FIND_ALL_FAVORITES_OPERATION_SIGNATURE } from '@/prefetch/query-keys/FindAllFavoritesOperationSignature'; +import { FIND_ALL_VIEWS_OPERATION_SIGNATURE } from '@/prefetch/query-keys/FindAllViewsOperationSignature'; import { PrefetchKey } from '@/prefetch/types/PrefetchKey'; import { View } from '@/views/types/View'; import { isDefined } from '~/utils/isDefined'; @@ -12,24 +14,22 @@ import { isDefined } from '~/utils/isDefined'; export const PrefetchRunQueriesEffect = () => { const currentUser = useRecoilValue(currentUserState); - const { - objectMetadataItem: objectMetadataItemView, - upsertRecordsInCache: upsertViewsInCache, - } = usePrefetchRunQuery({ - prefetchKey: PrefetchKey.AllViews, - }); + const { upsertRecordsInCache: upsertViewsInCache } = + usePrefetchRunQuery({ + prefetchKey: PrefetchKey.AllViews, + }); - const { - objectMetadataItem: objectMetadataItemFavorite, - upsertRecordsInCache: upsertFavoritesInCache, - } = usePrefetchRunQuery({ - prefetchKey: PrefetchKey.AllFavorites, - }); + const { upsertRecordsInCache: upsertFavoritesInCache } = + usePrefetchRunQuery({ + prefetchKey: PrefetchKey.AllFavorites, + }); - const { result } = useFindManyRecordsForMultipleMetadataItems({ - objectMetadataItems: [objectMetadataItemView, objectMetadataItemFavorite], + const { result } = useCombinedFindManyRecords({ + operationSignatures: [ + FIND_ALL_VIEWS_OPERATION_SIGNATURE, + FIND_ALL_FAVORITES_OPERATION_SIGNATURE, + ], skip: !currentUser, - depth: 1, }); useEffect(() => { diff --git a/packages/twenty-front/src/modules/prefetch/constants/PrefetchConfig.ts b/packages/twenty-front/src/modules/prefetch/constants/PrefetchConfig.ts index a796311583..e23d51f683 100644 --- a/packages/twenty-front/src/modules/prefetch/constants/PrefetchConfig.ts +++ b/packages/twenty-front/src/modules/prefetch/constants/PrefetchConfig.ts @@ -1,9 +1,10 @@ -import { QueryKey } from '@/object-record/query-keys/types/QueryKey'; -import { ALL_FAVORITES_QUERY_KEY } from '@/prefetch/query-keys/AllFavoritesQueryKey'; -import { ALL_VIEWS_QUERY_KEY } from '@/prefetch/query-keys/AllViewsQueryKey'; +import { RecordGqlOperationSignature } from '@/object-record/graphql/types/RecordGqlOperationSignature'; +import { FIND_ALL_FAVORITES_OPERATION_SIGNATURE } from '@/prefetch/query-keys/FindAllFavoritesOperationSignature'; +import { FIND_ALL_VIEWS_OPERATION_SIGNATURE } from '@/prefetch/query-keys/FindAllViewsOperationSignature'; import { PrefetchKey } from '@/prefetch/types/PrefetchKey'; -export const PREFETCH_CONFIG: Record = { - ALL_VIEWS: ALL_VIEWS_QUERY_KEY, - ALL_FAVORITES: ALL_FAVORITES_QUERY_KEY, -}; +export const PREFETCH_CONFIG: Record = + { + ALL_VIEWS: FIND_ALL_VIEWS_OPERATION_SIGNATURE, + ALL_FAVORITES: FIND_ALL_FAVORITES_OPERATION_SIGNATURE, + }; diff --git a/packages/twenty-front/src/modules/prefetch/hooks/internal/usePrefetchRunQuery.ts b/packages/twenty-front/src/modules/prefetch/hooks/internal/usePrefetchRunQuery.ts index b010e65db7..33ff7bc679 100644 --- a/packages/twenty-front/src/modules/prefetch/hooks/internal/usePrefetchRunQuery.ts +++ b/packages/twenty-front/src/modules/prefetch/hooks/internal/usePrefetchRunQuery.ts @@ -29,7 +29,7 @@ export const usePrefetchRunQuery = ({ const upsertRecordsInCache = (records: T[]) => { upsertFindManyRecordsQueryInCache({ queryVariables: PREFETCH_CONFIG[prefetchKey].variables, - depth: PREFETCH_CONFIG[prefetchKey].depth, + recordGqlFields: PREFETCH_CONFIG[prefetchKey].fields, objectRecordsToOverwrite: records, computeReferences: false, }); diff --git a/packages/twenty-front/src/modules/prefetch/hooks/usePrefetchedData.ts b/packages/twenty-front/src/modules/prefetch/hooks/usePrefetchedData.ts index 3072733c85..a82d02de73 100644 --- a/packages/twenty-front/src/modules/prefetch/hooks/usePrefetchedData.ts +++ b/packages/twenty-front/src/modules/prefetch/hooks/usePrefetchedData.ts @@ -16,7 +16,8 @@ export const usePrefetchedData = ( const { records } = useFindManyRecords({ skip: !isDataPrefetched, - ...prefetchQueryKey, + objectNameSingular: prefetchQueryKey.objectNameSingular, + recordGqlFields: prefetchQueryKey.fields, }); return { diff --git a/packages/twenty-front/src/modules/prefetch/query-keys/AllFavoritesQueryKey.ts b/packages/twenty-front/src/modules/prefetch/query-keys/AllFavoritesQueryKey.ts deleted file mode 100644 index a5e4427158..0000000000 --- a/packages/twenty-front/src/modules/prefetch/query-keys/AllFavoritesQueryKey.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { QueryKey } from '@/object-record/query-keys/types/QueryKey'; - -export const ALL_FAVORITES_QUERY_KEY: QueryKey = { - objectNameSingular: CoreObjectNameSingular.Favorite, - variables: {}, - depth: 1, -}; diff --git a/packages/twenty-front/src/modules/prefetch/query-keys/AllViewsQueryKey.ts b/packages/twenty-front/src/modules/prefetch/query-keys/AllViewsQueryKey.ts deleted file mode 100644 index df1c781630..0000000000 --- a/packages/twenty-front/src/modules/prefetch/query-keys/AllViewsQueryKey.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { QueryKey } from '@/object-record/query-keys/types/QueryKey'; - -export const ALL_VIEWS_QUERY_KEY: QueryKey = { - objectNameSingular: CoreObjectNameSingular.View, - variables: {}, - depth: 1, -}; diff --git a/packages/twenty-front/src/modules/prefetch/query-keys/FindAllFavoritesOperationSignature.ts b/packages/twenty-front/src/modules/prefetch/query-keys/FindAllFavoritesOperationSignature.ts new file mode 100644 index 0000000000..32364260b3 --- /dev/null +++ b/packages/twenty-front/src/modules/prefetch/query-keys/FindAllFavoritesOperationSignature.ts @@ -0,0 +1,8 @@ +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { RecordGqlOperationSignature } from '@/object-record/graphql/types/RecordGqlOperationSignature'; + +export const FIND_ALL_FAVORITES_OPERATION_SIGNATURE: RecordGqlOperationSignature = + { + objectNameSingular: CoreObjectNameSingular.Favorite, + variables: {}, + }; diff --git a/packages/twenty-front/src/modules/prefetch/query-keys/FindAllViewsOperationSignature.ts b/packages/twenty-front/src/modules/prefetch/query-keys/FindAllViewsOperationSignature.ts new file mode 100644 index 0000000000..a0a14f3d5b --- /dev/null +++ b/packages/twenty-front/src/modules/prefetch/query-keys/FindAllViewsOperationSignature.ts @@ -0,0 +1,23 @@ +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { RecordGqlOperationSignature } from '@/object-record/graphql/types/RecordGqlOperationSignature'; + +export const FIND_ALL_VIEWS_OPERATION_SIGNATURE: RecordGqlOperationSignature = { + objectNameSingular: CoreObjectNameSingular.View, + variables: {}, + fields: { + id: true, + createdAt: true, + updatedAt: true, + isCompact: true, + objectMetadataId: true, + position: true, + type: true, + kanbanFieldMetadataId: true, + name: true, + icon: true, + key: true, + viewFilters: true, + viewSorts: true, + viewFields: true, + }, +}; diff --git a/packages/twenty-front/src/modules/search/hooks/useFilteredSearchEntityQuery.ts b/packages/twenty-front/src/modules/search/hooks/useFilteredSearchEntityQuery.ts index 5d12f9625d..b4d337c007 100644 --- a/packages/twenty-front/src/modules/search/hooks/useFilteredSearchEntityQuery.ts +++ b/packages/twenty-front/src/modules/search/hooks/useFilteredSearchEntityQuery.ts @@ -3,8 +3,8 @@ import { isNonEmptyString } from '@sniptt/guards'; import { useMapToObjectRecordIdentifier } from '@/object-metadata/hooks/useMapToObjectRecordIdentifier'; import { OrderBy } from '@/object-metadata/types/OrderBy'; import { DEFAULT_SEARCH_REQUEST_LIMIT } from '@/object-record/constants/DefaultSearchRequestLimit'; +import { RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; -import { ObjectRecordQueryFilter } from '@/object-record/record-filter/types/ObjectRecordQueryFilter'; import { EntitiesForMultipleEntitySelect } from '@/object-record/relation-picker/types/EntitiesForMultipleEntitySelect'; import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; @@ -59,7 +59,7 @@ export const useFilteredSearchEntityQuery = ({ } const formattedFilters = fieldNames.reduce( - (previousValue: ObjectRecordQueryFilter[], fieldName) => { + (previousValue: RecordGqlOperationFilter[], fieldName) => { const [parentFieldName, subFieldName] = fieldName.split('.'); if (isNonEmptyString(subFieldName)) { diff --git a/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectItemTableRow.tsx b/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectItemTableRow.tsx index f19004c5a9..02bd504bb2 100644 --- a/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectItemTableRow.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectItemTableRow.tsx @@ -39,7 +39,6 @@ export const SettingsObjectItemTableRow = ({ const { totalCount } = useFindManyRecords({ objectNameSingular: objectItem.nameSingular, - depth: 0, }); const { getIcon } = useIcons(); const Icon = getIcon(objectItem.icon); diff --git a/packages/twenty-front/src/modules/settings/developers/components/SettingsDevelopersWebhookTableRow.tsx b/packages/twenty-front/src/modules/settings/developers/components/SettingsDevelopersWebhookTableRow.tsx index 74a7352674..e6541f6115 100644 --- a/packages/twenty-front/src/modules/settings/developers/components/SettingsDevelopersWebhookTableRow.tsx +++ b/packages/twenty-front/src/modules/settings/developers/components/SettingsDevelopersWebhookTableRow.tsx @@ -3,7 +3,7 @@ import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { IconChevronRight } from 'twenty-ui'; -import { WebhookFieldItem } from '@/settings/developers/types/webhook/WebhookFieldItem'; +import { Webhook } from '@/settings/developers/types/webhook/Webhook'; import { TableCell } from '@/ui/layout/table/components/TableCell'; import { TableRow } from '@/ui/layout/table/components/TableRow'; @@ -30,7 +30,7 @@ export const SettingsDevelopersWebhookTableRow = ({ fieldItem, onClick, }: { - fieldItem: WebhookFieldItem; + fieldItem: Webhook; onClick: () => void; }) => { const theme = useTheme(); diff --git a/packages/twenty-front/src/modules/settings/developers/components/SettingsWebhooksTable.tsx b/packages/twenty-front/src/modules/settings/developers/components/SettingsWebhooksTable.tsx index f20c81cb80..e1e04d5d5e 100644 --- a/packages/twenty-front/src/modules/settings/developers/components/SettingsWebhooksTable.tsx +++ b/packages/twenty-front/src/modules/settings/developers/components/SettingsWebhooksTable.tsx @@ -4,7 +4,7 @@ import styled from '@emotion/styled'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { SettingsDevelopersWebhookTableRow } from '@/settings/developers/components/SettingsDevelopersWebhookTableRow'; -import { WebhookFieldItem } from '@/settings/developers/types/webhook/WebhookFieldItem'; +import { Webhook } from '@/settings/developers/types/webhook/Webhook'; import { Table } from '@/ui/layout/table/components/Table'; import { TableBody } from '@/ui/layout/table/components/TableBody'; import { TableHeader } from '@/ui/layout/table/components/TableHeader'; @@ -21,7 +21,7 @@ const StyledTableRow = styled(TableRow)` export const SettingsWebhooksTable = () => { const navigate = useNavigate(); - const { records: webhooks } = useFindManyRecords({ + const { records: webhooks } = useFindManyRecords({ objectNameSingular: CoreObjectNameSingular.Webhook, }); diff --git a/packages/twenty-front/src/modules/settings/developers/types/api-key/ApiKey.ts b/packages/twenty-front/src/modules/settings/developers/types/api-key/ApiKey.ts index 7f21f804cc..463f0defa6 100644 --- a/packages/twenty-front/src/modules/settings/developers/types/api-key/ApiKey.ts +++ b/packages/twenty-front/src/modules/settings/developers/types/api-key/ApiKey.ts @@ -6,4 +6,5 @@ export type ApiKey = { name: string; expiresAt: string; revokedAt: string | null; + __typename: 'ApiKey'; }; diff --git a/packages/twenty-front/src/modules/settings/developers/types/webhook/Webhook.ts b/packages/twenty-front/src/modules/settings/developers/types/webhook/Webhook.ts index 77f44b3596..5eefd25fb0 100644 --- a/packages/twenty-front/src/modules/settings/developers/types/webhook/Webhook.ts +++ b/packages/twenty-front/src/modules/settings/developers/types/webhook/Webhook.ts @@ -2,4 +2,5 @@ export type Webhook = { id: string; targetUrl: string; operation: string; + __typename: 'Webhook'; }; diff --git a/packages/twenty-front/src/modules/settings/developers/types/webhook/WebhookFieldItem.ts b/packages/twenty-front/src/modules/settings/developers/types/webhook/WebhookFieldItem.ts deleted file mode 100644 index 593c356ffc..0000000000 --- a/packages/twenty-front/src/modules/settings/developers/types/webhook/WebhookFieldItem.ts +++ /dev/null @@ -1,5 +0,0 @@ -export type WebhookFieldItem = { - id: string; - targetUrl: string; - operation: string; -}; diff --git a/packages/twenty-front/src/modules/ui/utilities/hotkey/hooks/useScopedHotkeyCallback.ts b/packages/twenty-front/src/modules/ui/utilities/hotkey/hooks/useScopedHotkeyCallback.ts index 3fb4ba29e3..13aefa697d 100644 --- a/packages/twenty-front/src/modules/ui/utilities/hotkey/hooks/useScopedHotkeyCallback.ts +++ b/packages/twenty-front/src/modules/ui/utilities/hotkey/hooks/useScopedHotkeyCallback.ts @@ -5,7 +5,7 @@ import { logDebug } from '~/utils/logDebug'; import { internalHotkeysEnabledScopesState } from '../states/internal/internalHotkeysEnabledScopesState'; -export const DEBUG_HOTKEY_SCOPE = true; +export const DEBUG_HOTKEY_SCOPE = false; export const useScopedHotkeyCallback = () => useRecoilCallback( diff --git a/packages/twenty-front/src/modules/views/hooks/useHandleViews.ts b/packages/twenty-front/src/modules/views/hooks/useHandleViews.ts index e0acd68598..63dc6732bb 100644 --- a/packages/twenty-front/src/modules/views/hooks/useHandleViews.ts +++ b/packages/twenty-front/src/modules/views/hooks/useHandleViews.ts @@ -14,6 +14,7 @@ import { useGetViewFromCache } from '@/views/hooks/useGetViewFromCache'; import { useResetCurrentView } from '@/views/hooks/useResetCurrentView'; import { useSaveCurrentViewFiltersAndSorts } from '@/views/hooks/useSaveCurrentViewFiltersAndSorts'; import { GraphQLView } from '@/views/types/GraphQLView'; +import { View } from '@/views/types/View'; import { isDefined } from '~/utils/isDefined'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; @@ -29,7 +30,7 @@ export const useHandleViews = (viewBarComponentId?: string) => { objectNameSingular: CoreObjectNameSingular.View, }); - const { createOneRecord } = useCreateOneRecord({ + const { createOneRecord } = useCreateOneRecord({ objectNameSingular: CoreObjectNameSingular.View, }); diff --git a/packages/twenty-front/src/modules/views/types/View.ts b/packages/twenty-front/src/modules/views/types/View.ts index 59c506a63c..a3c9cac58b 100644 --- a/packages/twenty-front/src/modules/views/types/View.ts +++ b/packages/twenty-front/src/modules/views/types/View.ts @@ -17,4 +17,5 @@ export type View = { kanbanFieldMetadataId: string; position: number; icon: string; + __typename: 'View'; }; diff --git a/packages/twenty-front/src/modules/views/utils/combinedViewFilters.ts b/packages/twenty-front/src/modules/views/utils/combinedViewFilters.ts index ac33a83f39..84eefa8f5b 100644 --- a/packages/twenty-front/src/modules/views/utils/combinedViewFilters.ts +++ b/packages/twenty-front/src/modules/views/utils/combinedViewFilters.ts @@ -1,20 +1,22 @@ import { ViewFilter } from '@/views/types/ViewFilter'; export const combinedViewFilters = ( - viewFilter: ViewFilter[], + viewFilters: ViewFilter[], toUpsertViewFilters: ViewFilter[], toDeleteViewFilterIds: string[], ): ViewFilter[] => { const toCreateViewFilters = toUpsertViewFilters.filter( (toUpsertViewFilter) => - !viewFilter.some((viewFilter) => viewFilter.id === toUpsertViewFilter.id), + !viewFilters.some( + (viewFilter) => viewFilter.id === toUpsertViewFilter.id, + ), ); const toUpdateViewFilters = toUpsertViewFilters.filter((toUpsertViewFilter) => - viewFilter.some((viewFilter) => viewFilter.id === toUpsertViewFilter.id), + viewFilters.some((viewFilter) => viewFilter.id === toUpsertViewFilter.id), ); - const combinedViewFilters = viewFilter + const combinedViewFilters = viewFilters .filter((viewFilter) => !toDeleteViewFilterIds.includes(viewFilter.id)) .map((viewFilter) => { const toUpdateViewFilter = toUpdateViewFilters.find( diff --git a/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx b/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx index 9d6c1d5236..336f705234 100644 --- a/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx +++ b/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx @@ -8,6 +8,7 @@ import { useLabelIdentifierFieldMetadataItem } from '@/object-metadata/hooks/use import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord'; import { RecordShowContainer } from '@/object-record/record-show/components/RecordShowContainer'; +import { findOneRecordForShowPageOperationSignatureFactory } from '@/object-record/record-show/graphql/operations/factories/findOneRecordForShowPageOperationSignatureFactory'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { PageBody } from '@/ui/layout/page/PageBody'; import { PageContainer } from '@/ui/layout/page/PageContainer'; @@ -53,9 +54,13 @@ export const RecordShowPage = () => { const headerIcon = getIcon(objectMetadataItem?.icon); + const FIND_ONE_RECORD_FOR_SHOW_PAGE_OPERATION_SIGNATURE = + findOneRecordForShowPageOperationSignatureFactory({ objectMetadataItem }); + const { record, loading } = useFindOneRecord({ objectRecordId, objectNameSingular, + recordGqlFields: FIND_ONE_RECORD_FOR_SHOW_PAGE_OPERATION_SIGNATURE.fields, }); useEffect(() => { diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep2.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep2.tsx index 89c07742b0..65ddf9534d 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep2.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep2.tsx @@ -4,12 +4,12 @@ import { Reference, useApolloClient } from '@apollo/client'; import styled from '@emotion/styled'; import { IconSettings } from 'twenty-ui'; -import { CachedObjectRecordEdge } from '@/apollo/types/CachedObjectRecordEdge'; import { useCreateOneRelationMetadataItem } from '@/object-metadata/hooks/useCreateOneRelationMetadataItem'; import { useFieldMetadataItem } from '@/object-metadata/hooks/useFieldMetadataItem'; import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { RecordGqlRefEdge } from '@/object-record/cache/types/RecordGqlRefEdge'; import { modifyRecordFromCache } from '@/object-record/cache/utils/modifyRecordFromCache'; import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons'; @@ -252,7 +252,7 @@ export const SettingsObjectNewFieldStep2 = () => { cache: cache, fieldModifiers: { viewFields: (cachedViewFieldsConnection, { readField }) => { - const edges = readField( + const edges = readField( 'edges', cachedViewFieldsConnection, ); diff --git a/packages/twenty-front/src/testing/jest/JestObjectMetadataItemSetter.tsx b/packages/twenty-front/src/testing/jest/JestObjectMetadataItemSetter.tsx new file mode 100644 index 0000000000..35d4a861f5 --- /dev/null +++ b/packages/twenty-front/src/testing/jest/JestObjectMetadataItemSetter.tsx @@ -0,0 +1,20 @@ +import { ReactNode, useEffect, useState } from 'react'; +import { useSetRecoilState } from 'recoil'; + +import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; +import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock'; + +export const JestObjectMetadataItemSetter = ({ + children, +}: { + children: ReactNode; +}) => { + const setObjectMetadataItems = useSetRecoilState(objectMetadataItemsState); + const [isLoaded, setIsLoaded] = useState(false); + useEffect(() => { + setObjectMetadataItems(getObjectMetadataItemsMock()); + setIsLoaded(true); + }, [setObjectMetadataItems]); + + return isLoaded ? <>{children} : null; +}; diff --git a/packages/twenty-front/src/testing/mock-data/calendar.ts b/packages/twenty-front/src/testing/mock-data/calendar.ts index a58f0074ec..28eeeaef08 100644 --- a/packages/twenty-front/src/testing/mock-data/calendar.ts +++ b/packages/twenty-front/src/testing/mock-data/calendar.ts @@ -33,6 +33,7 @@ export const mockedCalendarEvents: CalendarEvent[] = [ displayName: 'Tim Apple', }, ], + __typename: 'CalendarEvent', }, { externalCreatedAt: subHours(new Date(), 2).toISOString(), @@ -43,6 +44,7 @@ export const mockedCalendarEvents: CalendarEvent[] = [ startsAt: new Date(new Date().setHours(18, 0)).toISOString(), title: 'Bug solving', visibility: 'SHARE_EVERYTHING', + __typename: 'CalendarEvent', }, { externalCreatedAt: subHours(new Date(), 2).toISOString(), @@ -52,6 +54,7 @@ export const mockedCalendarEvents: CalendarEvent[] = [ startsAt: new Date(new Date().setHours(15, 15)).toISOString(), title: 'Onboarding Follow-Up Call', visibility: 'SHARE_EVERYTHING', + __typename: 'CalendarEvent', }, { externalCreatedAt: subHours(new Date(), 2).toISOString(), @@ -61,6 +64,7 @@ export const mockedCalendarEvents: CalendarEvent[] = [ startsAt: new Date(new Date().setHours(10, 0)).toISOString(), title: 'Onboarding Call', visibility: 'SHARE_EVERYTHING', + __typename: 'CalendarEvent', }, { externalCreatedAt: subHours(new Date(), 2).toISOString(), @@ -68,6 +72,7 @@ export const mockedCalendarEvents: CalendarEvent[] = [ isFullDay: true, startsAt: subMonths(new Date().setHours(8, 0), 1).toISOString(), visibility: 'METADATA', + __typename: 'CalendarEvent', }, { externalCreatedAt: subHours(new Date(), 2).toISOString(), @@ -77,5 +82,6 @@ export const mockedCalendarEvents: CalendarEvent[] = [ startsAt: subMonths(new Date().setHours(14, 0), 3).toISOString(), title: 'Alan x Garry', visibility: 'SHARE_EVERYTHING', + __typename: 'CalendarEvent', }, ]; diff --git a/packages/twenty-front/src/testing/mock-data/timeline-activities.ts b/packages/twenty-front/src/testing/mock-data/timeline-activities.ts index 35df59b20b..14cb0e5b7f 100644 --- a/packages/twenty-front/src/testing/mock-data/timeline-activities.ts +++ b/packages/twenty-front/src/testing/mock-data/timeline-activities.ts @@ -24,6 +24,7 @@ export const mockedTimelineActivities: Array = [ }, workspaceMemberId: '20202020-0687-4c41-b707-ed1bfca972a7', deletedAt: null, + __typename: 'TimelineActivity', }, { properties: @@ -49,5 +50,6 @@ export const mockedTimelineActivities: Array = [ }, workspaceMemberId: '20202020-0687-4c41-b707-ed1bfca972a7', deletedAt: null, + __typename: 'TimelineActivity', }, ]; diff --git a/packages/twenty-front/src/utils/array/generateILikeFiltersForCompositeFields.ts b/packages/twenty-front/src/utils/array/generateILikeFiltersForCompositeFields.ts index 176931e169..4d92976934 100644 --- a/packages/twenty-front/src/utils/array/generateILikeFiltersForCompositeFields.ts +++ b/packages/twenty-front/src/utils/array/generateILikeFiltersForCompositeFields.ts @@ -1,4 +1,4 @@ -import { ObjectRecordQueryFilter } from '@/object-record/record-filter/types/ObjectRecordQueryFilter'; +import { RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; export const generateILikeFiltersForCompositeFields = ( filterString: string, @@ -7,7 +7,7 @@ export const generateILikeFiltersForCompositeFields = ( ) => { return filterString .split(' ') - .reduce((previousValue: ObjectRecordQueryFilter[], currentValue) => { + .reduce((previousValue: RecordGqlOperationFilter[], currentValue) => { return [ ...previousValue, ...subFields.map((subField) => {