From 61f0393690ba4a63abcce74e59aa3a6529a0c5ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Malfait?= Date: Wed, 9 Oct 2024 14:23:38 +0200 Subject: [PATCH 1/2] Revert optimistic rendering on negative response --- .../hooks/useCreateManyRecords.ts | 54 +++++++--- .../object-record/hooks/useCreateOneRecord.ts | 56 +++++++--- .../hooks/useDeleteManyRecords.ts | 100 ++++++++++++------ .../object-record/hooks/useDeleteOneRecord.ts | 79 ++++++++++---- .../hooks/useDestroyManyRecords.ts | 80 ++++++++------ .../hooks/useDestroyOneRecord.ts | 59 +++++++---- .../object-record/hooks/useUpdateOneRecord.ts | 52 ++++++--- 7 files changed, 328 insertions(+), 152 deletions(-) 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 b9313fae3ecc..3c12e532a5af 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useCreateManyRecords.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useCreateManyRecords.ts @@ -2,9 +2,11 @@ import { useApolloClient } from '@apollo/client'; import { v4 } from 'uuid'; import { triggerCreateRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect'; +import { triggerDeleteRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerDeleteRecordsOptimisticEffect'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { useCreateOneRecordInCache } from '@/object-record/cache/hooks/useCreateOneRecordInCache'; +import { deleteRecordFromCache } from '@/object-record/cache/utils/deleteRecordFromCache'; import { getObjectTypename } from '@/object-record/cache/utils/getObjectTypename'; import { RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields'; import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields'; @@ -67,7 +69,7 @@ export const useCreateManyRecords = < }, ); - const recordsCreatedInCache = []; + const recordsCreatedInCache: ObjectRecord[] = []; for (const recordToCreate of sanitizedCreateManyRecordsInput) { if (recordToCreate.id === null) { @@ -98,26 +100,46 @@ export const useCreateManyRecords = < objectMetadataItem.namePlural, ); - const createdObjects = await apolloClient.mutate({ - mutation: createManyRecordsMutation, - variables: { - data: sanitizedCreateManyRecordsInput, - upsert: upsert, - }, - update: (cache, { data }) => { - const records = data?.[mutationResponseField]; + const createdObjects = await apolloClient + .mutate({ + mutation: createManyRecordsMutation, + variables: { + data: sanitizedCreateManyRecordsInput, + upsert: upsert, + }, + update: (cache, { data }) => { + const records = data?.[mutationResponseField]; + + if (!records?.length || skipPostOptmisticEffect) return; - if (!records?.length || skipPostOptmisticEffect) return; + triggerCreateRecordsOptimisticEffect({ + cache, + objectMetadataItem, + recordsToCreate: records, + objectMetadataItems, + shouldMatchRootQueryFilter, + }); + }, + }) + .catch((error: Error) => { + recordsCreatedInCache.forEach((recordToDelete) => { + deleteRecordFromCache({ + objectMetadataItems, + objectMetadataItem, + cache: apolloClient.cache, + recordToDelete: recordToDelete, + }); + }); - triggerCreateRecordsOptimisticEffect({ - cache, + triggerDeleteRecordsOptimisticEffect({ + cache: apolloClient.cache, objectMetadataItem, - recordsToCreate: records, + recordsToDelete: recordsCreatedInCache, objectMetadataItems, - shouldMatchRootQueryFilter, }); - }, - }); + + throw error; + }); return createdObjects.data?.[mutationResponseField] ?? []; }; 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 f34ce0692f7a..2e9d79239094 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useCreateOneRecord.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useCreateOneRecord.ts @@ -3,9 +3,11 @@ import { useState } from 'react'; import { v4 } from 'uuid'; import { triggerCreateRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect'; +import { triggerDeleteRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerDeleteRecordsOptimisticEffect'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { useCreateOneRecordInCache } from '@/object-record/cache/hooks/useCreateOneRecordInCache'; +import { deleteRecordFromCache } from '@/object-record/cache/utils/deleteRecordFromCache'; import { getObjectTypename } from '@/object-record/cache/utils/getObjectTypename'; import { RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields'; import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields'; @@ -85,27 +87,49 @@ export const useCreateOneRecord = < const mutationResponseField = getCreateOneRecordMutationResponseField(objectNameSingular); - const createdObject = await apolloClient.mutate({ - mutation: createOneRecordMutation, - variables: { - input: sanitizedInput, - }, - update: (cache, { data }) => { - const record = data?.[mutationResponseField]; - - if (!record || skipPostOptmisticEffect) return; + const createdObject = await apolloClient + .mutate({ + mutation: createOneRecordMutation, + variables: { + input: sanitizedInput, + }, + update: (cache, { data }) => { + const record = data?.[mutationResponseField]; + + if (!record || skipPostOptmisticEffect) return; + + triggerCreateRecordsOptimisticEffect({ + cache, + objectMetadataItem, + recordsToCreate: [record], + objectMetadataItems, + shouldMatchRootQueryFilter, + }); + + setLoading(false); + }, + }) + .catch((error: Error) => { + if (!recordCreatedInCache) { + throw error; + } + + deleteRecordFromCache({ + objectMetadataItems, + objectMetadataItem, + cache: apolloClient.cache, + recordToDelete: recordCreatedInCache, + }); - triggerCreateRecordsOptimisticEffect({ - cache, + triggerDeleteRecordsOptimisticEffect({ + cache: apolloClient.cache, objectMetadataItem, - recordsToCreate: [record], + recordsToDelete: [recordCreatedInCache], objectMetadataItems, - shouldMatchRootQueryFilter, }); - setLoading(false); - }, - }); + throw error; + }); return createdObject.data?.[mutationResponseField] ?? null; }; diff --git a/packages/twenty-front/src/modules/object-record/hooks/useDeleteManyRecords.ts b/packages/twenty-front/src/modules/object-record/hooks/useDeleteManyRecords.ts index 35a65a507765..38bd825d55de 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useDeleteManyRecords.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useDeleteManyRecords.ts @@ -1,10 +1,12 @@ import { useApolloClient } from '@apollo/client'; +import { triggerCreateRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect'; import { triggerDeleteRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerDeleteRecordsOptimisticEffect'; import { apiConfigState } from '@/client-config/states/apiConfigState'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordFromCache'; +import { updateRecordFromCache } from '@/object-record/cache/utils/updateRecordFromCache'; import { DEFAULT_MUTATION_BATCH_SIZE } from '@/object-record/constants/DefaultMutationBatchSize'; import { useDeleteManyRecordsMutation } from '@/object-record/hooks/useDeleteManyRecordsMutation'; import { getDeleteManyRecordsMutationResponseField } from '@/object-record/utils/getDeleteManyRecordsMutationResponseField'; @@ -65,38 +67,74 @@ export const useDeleteManyRecords = ({ (batchIndex + 1) * mutationPageSize, ); - const deletedRecordsResponse = await apolloClient.mutate({ - mutation: deleteManyRecordsMutation, - variables: { - filter: { id: { in: batchIds } }, - }, - optimisticResponse: options?.skipOptimisticEffect - ? undefined - : { - [mutationResponseField]: batchIds.map((idToDelete) => ({ - __typename: capitalize(objectNameSingular), - id: idToDelete, + const deletedRecordsResponse = await apolloClient + .mutate({ + mutation: deleteManyRecordsMutation, + variables: { + filter: { id: { in: batchIds } }, + }, + optimisticResponse: options?.skipOptimisticEffect + ? undefined + : { + [mutationResponseField]: batchIds.map((idToDelete) => ({ + __typename: capitalize(objectNameSingular), + id: idToDelete, + })), + }, + update: options?.skipOptimisticEffect + ? undefined + : (cache, { data }) => { + const records = data?.[mutationResponseField]; + + if (!records?.length) return; + + const cachedRecords = records + .map((record) => getRecordFromCache(record.id, cache)) + .filter(isDefined); + + triggerDeleteRecordsOptimisticEffect({ + cache, + objectMetadataItem, + recordsToDelete: cachedRecords, + objectMetadataItems, + }); + }, + }) + .catch((error: Error) => { + const cachedRecords = batchIds.map((idToDelete) => + getRecordFromCache(idToDelete, apolloClient.cache), + ); + + cachedRecords.forEach((cachedRecord) => { + if (!cachedRecord) { + return; + } + + updateRecordFromCache({ + objectMetadataItems, + objectMetadataItem, + cache: apolloClient.cache, + record: { + ...cachedRecord, + deletedAt: null, + }, + }); + }); + + triggerCreateRecordsOptimisticEffect({ + cache: apolloClient.cache, + objectMetadataItem, + objectMetadataItems, + recordsToCreate: cachedRecords + .filter(isDefined) + .map((cachedRecord) => ({ + ...cachedRecord, + deletedAt: null, })), - }, - update: options?.skipOptimisticEffect - ? undefined - : (cache, { data }) => { - const records = data?.[mutationResponseField]; - - if (!records?.length) return; - - const cachedRecords = records - .map((record) => getRecordFromCache(record.id, cache)) - .filter(isDefined); - - triggerDeleteRecordsOptimisticEffect({ - cache, - objectMetadataItem, - recordsToDelete: cachedRecords, - objectMetadataItems, - }); - }, - }); + }); + + throw error; + }); const deletedRecordsForThisBatch = deletedRecordsResponse.data?.[mutationResponseField] ?? []; diff --git a/packages/twenty-front/src/modules/object-record/hooks/useDeleteOneRecord.ts b/packages/twenty-front/src/modules/object-record/hooks/useDeleteOneRecord.ts index 3b33fe3e7ed1..b39871ba2753 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useDeleteOneRecord.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useDeleteOneRecord.ts @@ -1,10 +1,12 @@ import { useApolloClient } from '@apollo/client'; import { useCallback } from 'react'; +import { triggerCreateRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect'; import { triggerDeleteRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerDeleteRecordsOptimisticEffect'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordFromCache'; +import { updateRecordFromCache } from '@/object-record/cache/utils/updateRecordFromCache'; import { useDeleteOneRecordMutation } from '@/object-record/hooks/useDeleteOneRecordMutation'; import { getDeleteOneRecordMutationResponseField } from '@/object-record/utils/getDeleteOneRecordMutationResponseField'; import { capitalize } from '~/utils/string/capitalize'; @@ -39,35 +41,70 @@ export const useDeleteOneRecord = ({ async (idToDelete: string) => { const currentTimestamp = new Date().toISOString(); - const deletedRecord = await apolloClient.mutate({ - mutation: deleteOneRecordMutation, - variables: { - idToDelete: idToDelete, - }, - optimisticResponse: { - [mutationResponseField]: { - __typename: capitalize(objectNameSingular), - id: idToDelete, - deletedAt: currentTimestamp, + const deletedRecord = await apolloClient + .mutate({ + mutation: deleteOneRecordMutation, + variables: { + idToDelete: idToDelete, }, - }, - update: (cache, { data }) => { - const record = data?.[mutationResponseField]; + optimisticResponse: { + [mutationResponseField]: { + __typename: capitalize(objectNameSingular), + id: idToDelete, + deletedAt: currentTimestamp, + }, + }, + update: (cache, { data }) => { + const record = data?.[mutationResponseField]; - if (!record) return; + if (!record) return; - const cachedRecord = getRecordFromCache(record.id, cache); + const cachedRecord = getRecordFromCache(record.id, cache); - if (!cachedRecord) return; + if (!cachedRecord) return; - triggerDeleteRecordsOptimisticEffect({ - cache, + triggerDeleteRecordsOptimisticEffect({ + cache, + objectMetadataItem, + recordsToDelete: [cachedRecord], + objectMetadataItems, + }); + }, + }) + .catch((error: Error) => { + const cachedRecord = getRecordFromCache( + idToDelete, + apolloClient.cache, + ); + + if (!cachedRecord) { + throw error; + } + + updateRecordFromCache({ + objectMetadataItems, + objectMetadataItem, + cache: apolloClient.cache, + record: { + ...cachedRecord, + deletedAt: null, + }, + }); + + triggerCreateRecordsOptimisticEffect({ + cache: apolloClient.cache, objectMetadataItem, - recordsToDelete: [cachedRecord], objectMetadataItems, + recordsToCreate: [ + { + ...cachedRecord, + deletedAt: null, + }, + ], }); - }, - }); + + throw error; + }); return deletedRecord.data?.[mutationResponseField] ?? null; }, diff --git a/packages/twenty-front/src/modules/object-record/hooks/useDestroyManyRecords.ts b/packages/twenty-front/src/modules/object-record/hooks/useDestroyManyRecords.ts index 08f4d092a135..243a6fb4f8f6 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useDestroyManyRecords.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useDestroyManyRecords.ts @@ -1,5 +1,6 @@ import { useApolloClient } from '@apollo/client'; +import { triggerCreateRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect'; import { triggerDeleteRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerDeleteRecordsOptimisticEffect'; import { apiConfigState } from '@/client-config/states/apiConfigState'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; @@ -7,6 +8,7 @@ import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadat import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordFromCache'; import { DEFAULT_MUTATION_BATCH_SIZE } from '@/object-record/constants/DefaultMutationBatchSize'; import { useDestroyManyRecordsMutation } from '@/object-record/hooks/useDestroyManyRecordsMutation'; +import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { getDestroyManyRecordsMutationResponseField } from '@/object-record/utils/getDestroyManyRecordsMutationResponseField'; import { useRecoilValue } from 'recoil'; import { isDefined } from '~/utils/isDefined'; @@ -65,38 +67,52 @@ export const useDestroyManyRecords = ({ (batchIndex + 1) * mutationPageSize, ); - const destroyedRecordsResponse = await apolloClient.mutate({ - mutation: destroyManyRecordsMutation, - variables: { - filter: { id: { in: batchIds } }, - }, - optimisticResponse: options?.skipOptimisticEffect - ? undefined - : { - [mutationResponseField]: batchIds.map((idToDestroy) => ({ - __typename: capitalize(objectNameSingular), - id: idToDestroy, - })), - }, - update: options?.skipOptimisticEffect - ? undefined - : (cache, { data }) => { - const records = data?.[mutationResponseField]; - - if (!records?.length) return; - - const cachedRecords = records - .map((record) => getRecordFromCache(record.id, cache)) - .filter(isDefined); - - triggerDeleteRecordsOptimisticEffect({ - cache, - objectMetadataItem, - recordsToDelete: cachedRecords, - objectMetadataItems, - }); - }, - }); + let cachedRecords: ObjectRecord[] = []; + + const destroyedRecordsResponse = await apolloClient + .mutate({ + mutation: destroyManyRecordsMutation, + variables: { + filter: { id: { in: batchIds } }, + }, + optimisticResponse: options?.skipOptimisticEffect + ? undefined + : { + [mutationResponseField]: batchIds.map((idToDestroy) => ({ + __typename: capitalize(objectNameSingular), + id: idToDestroy, + })), + }, + update: options?.skipOptimisticEffect + ? undefined + : (cache, { data }) => { + const records = data?.[mutationResponseField]; + + if (!records?.length) return; + + cachedRecords = records + .map((record) => getRecordFromCache(record.id, cache)) + .filter(isDefined); + + triggerDeleteRecordsOptimisticEffect({ + cache, + objectMetadataItem, + recordsToDelete: cachedRecords, + objectMetadataItems, + }); + }, + }) + .catch((error: Error) => { + if (cachedRecords.length > 0) { + triggerCreateRecordsOptimisticEffect({ + cache: apolloClient.cache, + objectMetadataItem, + recordsToCreate: cachedRecords, + objectMetadataItems, + }); + } + throw error; + }); const destroyedRecordsForThisBatch = destroyedRecordsResponse.data?.[mutationResponseField] ?? []; diff --git a/packages/twenty-front/src/modules/object-record/hooks/useDestroyOneRecord.ts b/packages/twenty-front/src/modules/object-record/hooks/useDestroyOneRecord.ts index fc5d75d0a42f..f345b8fa55e8 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useDestroyOneRecord.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useDestroyOneRecord.ts @@ -1,12 +1,15 @@ import { useApolloClient } from '@apollo/client'; import { useCallback } from 'react'; +import { triggerCreateRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect'; import { triggerDeleteRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerDeleteRecordsOptimisticEffect'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordFromCache'; import { useDestroyOneRecordMutation } from '@/object-record/hooks/useDestroyOneRecordMutation'; +import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { getDestroyOneRecordMutationResponseField } from '@/object-record/utils/getDestroyOneRecordMutationResponseField'; +import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; import { capitalize } from '~/utils/string/capitalize'; type useDestroyOneRecordProps = { @@ -36,34 +39,48 @@ export const useDestroyOneRecord = ({ const mutationResponseField = getDestroyOneRecordMutationResponseField(objectNameSingular); + let cachedRecord: ObjectRecord; + const destroyOneRecord = useCallback( async (idToDestroy: string) => { - const deletedRecord = await apolloClient.mutate({ - mutation: destroyOneRecordMutation, - variables: { idToDestroy }, - optimisticResponse: { - [mutationResponseField]: { - __typename: capitalize(objectNameSingular), - id: idToDestroy, + const deletedRecord = await apolloClient + .mutate({ + mutation: destroyOneRecordMutation, + variables: { idToDestroy }, + optimisticResponse: { + [mutationResponseField]: { + __typename: capitalize(objectNameSingular), + id: idToDestroy, + }, }, - }, - update: (cache, { data }) => { - const record = data?.[mutationResponseField]; + update: (cache, { data }) => { + const record = data?.[mutationResponseField]; - if (!record) return; + if (!record) return; - const cachedRecord = getRecordFromCache(record.id, cache); + const cachedRecord = getRecordFromCache(record.id, cache); - if (!cachedRecord) return; + if (!cachedRecord) return; - triggerDeleteRecordsOptimisticEffect({ - cache, - objectMetadataItem, - recordsToDelete: [cachedRecord], - objectMetadataItems, - }); - }, - }); + triggerDeleteRecordsOptimisticEffect({ + cache, + objectMetadataItem, + recordsToDelete: [cachedRecord], + objectMetadataItems, + }); + }, + }) + .catch((error: Error) => { + if (!isUndefinedOrNull(cachedRecord)) { + triggerCreateRecordsOptimisticEffect({ + cache: apolloClient.cache, + objectMetadataItem, + recordsToCreate: [cachedRecord], + objectMetadataItems, + }); + } + throw error; + }); return deletedRecord.data?.[mutationResponseField] ?? null; }, 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 427c48547172..c87cbf9246a9 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useUpdateOneRecord.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useUpdateOneRecord.ts @@ -108,26 +108,48 @@ export const useUpdateOneRecord = < const mutationResponseField = getUpdateOneRecordMutationResponseField(objectNameSingular); - const updatedRecord = await apolloClient.mutate({ - mutation: updateOneRecordMutation, - variables: { - idToUpdate, - input: sanitizedInput, - }, - update: (cache, { data }) => { - const record = data?.[mutationResponseField]; - - if (!record || !cachedRecord) return; + const updatedRecord = await apolloClient + .mutate({ + mutation: updateOneRecordMutation, + variables: { + idToUpdate, + input: sanitizedInput, + }, + update: (cache, { data }) => { + const record = data?.[mutationResponseField]; + + if (!record || !cachedRecord) return; + + triggerUpdateRecordOptimisticEffect({ + cache, + objectMetadataItem, + currentRecord: cachedRecord, + updatedRecord: record, + objectMetadataItems, + }); + }, + }) + .catch((error: Error) => { + if (!cachedRecord) { + throw error; + } + updateRecordFromCache({ + objectMetadataItems, + objectMetadataItem, + cache: apolloClient.cache, + record: cachedRecord, + }); triggerUpdateRecordOptimisticEffect({ - cache, + cache: apolloClient.cache, objectMetadataItem, - currentRecord: cachedRecord, - updatedRecord: record, + currentRecord: optimisticRecordWithConnection, + updatedRecord: cachedRecordWithConnection, objectMetadataItems, }); - }, - }); + + throw error; + }); return updatedRecord?.data?.[mutationResponseField] ?? null; }; From 31f5f3571779cf8d29843ed4a96915cec1c4aa5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Malfait?= Date: Wed, 9 Oct 2024 15:27:40 +0200 Subject: [PATCH 2/2] Fixes --- .../hooks/useCreateManyRecords.ts | 2 +- .../hooks/useDestroyManyRecords.ts | 11 +++--- .../hooks/useDestroyOneRecord.ts | 11 ++++-- .../hooks/useRestoreManyRecords.ts | 37 +++++++++++-------- 4 files changed, 35 insertions(+), 26 deletions(-) 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 3c12e532a5af..017dad72de49 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useCreateManyRecords.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useCreateManyRecords.ts @@ -127,7 +127,7 @@ export const useCreateManyRecords = < objectMetadataItems, objectMetadataItem, cache: apolloClient.cache, - recordToDelete: recordToDelete, + recordToDelete, }); }); diff --git a/packages/twenty-front/src/modules/object-record/hooks/useDestroyManyRecords.ts b/packages/twenty-front/src/modules/object-record/hooks/useDestroyManyRecords.ts index 243a6fb4f8f6..3ba7283b9666 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useDestroyManyRecords.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useDestroyManyRecords.ts @@ -8,7 +8,6 @@ import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadat import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordFromCache'; import { DEFAULT_MUTATION_BATCH_SIZE } from '@/object-record/constants/DefaultMutationBatchSize'; import { useDestroyManyRecordsMutation } from '@/object-record/hooks/useDestroyManyRecordsMutation'; -import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { getDestroyManyRecordsMutationResponseField } from '@/object-record/utils/getDestroyManyRecordsMutationResponseField'; import { useRecoilValue } from 'recoil'; import { isDefined } from '~/utils/isDefined'; @@ -67,7 +66,9 @@ export const useDestroyManyRecords = ({ (batchIndex + 1) * mutationPageSize, ); - let cachedRecords: ObjectRecord[] = []; + const originalRecords = idsToDestroy + .map((recordId) => getRecordFromCache(recordId, apolloClient.cache)) + .filter(isDefined); const destroyedRecordsResponse = await apolloClient .mutate({ @@ -90,7 +91,7 @@ export const useDestroyManyRecords = ({ if (!records?.length) return; - cachedRecords = records + const cachedRecords = records .map((record) => getRecordFromCache(record.id, cache)) .filter(isDefined); @@ -103,11 +104,11 @@ export const useDestroyManyRecords = ({ }, }) .catch((error: Error) => { - if (cachedRecords.length > 0) { + if (originalRecords.length > 0) { triggerCreateRecordsOptimisticEffect({ cache: apolloClient.cache, objectMetadataItem, - recordsToCreate: cachedRecords, + recordsToCreate: originalRecords, objectMetadataItems, }); } diff --git a/packages/twenty-front/src/modules/object-record/hooks/useDestroyOneRecord.ts b/packages/twenty-front/src/modules/object-record/hooks/useDestroyOneRecord.ts index f345b8fa55e8..91446a87262a 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useDestroyOneRecord.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useDestroyOneRecord.ts @@ -39,10 +39,13 @@ export const useDestroyOneRecord = ({ const mutationResponseField = getDestroyOneRecordMutationResponseField(objectNameSingular); - let cachedRecord: ObjectRecord; - const destroyOneRecord = useCallback( async (idToDestroy: string) => { + const originalRecord: ObjectRecord | null = getRecordFromCache( + idToDestroy, + apolloClient.cache, + ); + const deletedRecord = await apolloClient .mutate({ mutation: destroyOneRecordMutation, @@ -71,11 +74,11 @@ export const useDestroyOneRecord = ({ }, }) .catch((error: Error) => { - if (!isUndefinedOrNull(cachedRecord)) { + if (!isUndefinedOrNull(originalRecord)) { triggerCreateRecordsOptimisticEffect({ cache: apolloClient.cache, objectMetadataItem, - recordsToCreate: [cachedRecord], + recordsToCreate: [originalRecord], objectMetadataItems, }); } diff --git a/packages/twenty-front/src/modules/object-record/hooks/useRestoreManyRecords.ts b/packages/twenty-front/src/modules/object-record/hooks/useRestoreManyRecords.ts index 55bd5cc5e865..66af0949fef0 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useRestoreManyRecords.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useRestoreManyRecords.ts @@ -62,22 +62,27 @@ export const useRestoreManyRecords = ({ objectMetadataItem.namePlural, )}`; - const restoredRecordsResponse = await apolloClient.mutate({ - mutation: restoreManyRecordsMutation, - refetchQueries: [findOneQueryName, findManyQueryName], - variables: { - filter: { id: { in: batchIds } }, - }, - optimisticResponse: options?.skipOptimisticEffect - ? undefined - : { - [mutationResponseField]: batchIds.map((idToRestore) => ({ - __typename: capitalize(objectNameSingular), - id: idToRestore, - deletedAt: null, - })), - }, - }); + const restoredRecordsResponse = await apolloClient + .mutate({ + mutation: restoreManyRecordsMutation, + refetchQueries: [findOneQueryName, findManyQueryName], + variables: { + filter: { id: { in: batchIds } }, + }, + optimisticResponse: options?.skipOptimisticEffect + ? undefined + : { + [mutationResponseField]: batchIds.map((idToRestore) => ({ + __typename: capitalize(objectNameSingular), + id: idToRestore, + deletedAt: null, + })), + }, + }) + .catch((error: Error) => { + // TODO: revert optimistic effect (once optimistic effect is fixed) + throw error; + }); const restoredRecordsForThisBatch = restoredRecordsResponse.data?.[mutationResponseField] ?? [];