From 0c28d853e4fa403024e82d3f81a3d766a2ff749a Mon Sep 17 00:00:00 2001 From: neo773 <62795688+neo773@users.noreply.github.com> Date: Sat, 13 Sep 2025 18:54:22 +0530 Subject: [PATCH] fix merge records network race condition (#14466) /closes #13643 image --- .../object-record/record-merge/hooks/useMergePreview.ts | 6 ++++-- .../record-merge/hooks/useMergeRecordsActions.ts | 8 +++++++- .../record-merge/states/mergeInProgressState.ts | 6 ++++++ 3 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 packages/twenty-front/src/modules/object-record/record-merge/states/mergeInProgressState.ts diff --git a/packages/twenty-front/src/modules/object-record/record-merge/hooks/useMergePreview.ts b/packages/twenty-front/src/modules/object-record/record-merge/hooks/useMergePreview.ts index 5bf3c29ecb5..4aa7d69cadf 100644 --- a/packages/twenty-front/src/modules/object-record/record-merge/hooks/useMergePreview.ts +++ b/packages/twenty-front/src/modules/object-record/record-merge/hooks/useMergePreview.ts @@ -6,6 +6,7 @@ import { useMergeManyRecords } from '@/object-record/hooks/useMergeManyRecords'; import { useMergeRecordRelationships } from '@/object-record/record-merge/hooks/useMergeRecordRelationships'; import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { isMergeInProgressState } from '../states/mergeInProgressState'; import { mergeSettingsState } from '../states/mergeSettingsState'; type UseMergePreviewProps = { @@ -20,6 +21,7 @@ export const useMergePreview = ({ const [isGeneratingPreview, setIsGeneratingPreview] = useState(false); const mergeSettings = useRecoilValue(mergeSettingsState); + const isMergeInProgress = useRecoilValue(isMergeInProgressState); const { records: selectedRecords } = useFindManyRecordsSelectedInContextStore( { limit: 10, @@ -39,7 +41,7 @@ export const useMergePreview = ({ useEffect(() => { const fetchPreview = async () => { - if (selectedRecords.length < 2) return; + if (selectedRecords.length < 2 || isMergeInProgress) return; setIsGeneratingPreview(true); try { const previewRecord = await mergeManyRecords({ @@ -62,7 +64,7 @@ export const useMergePreview = ({ } }; - if (selectedRecords.length > 0) { + if (selectedRecords.length > 0 && !isMergeInProgress) { fetchPreview(); } // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/packages/twenty-front/src/modules/object-record/record-merge/hooks/useMergeRecordsActions.ts b/packages/twenty-front/src/modules/object-record/record-merge/hooks/useMergeRecordsActions.ts index b4aa2fab02b..e686c761f3e 100644 --- a/packages/twenty-front/src/modules/object-record/record-merge/hooks/useMergeRecordsActions.ts +++ b/packages/twenty-front/src/modules/object-record/record-merge/hooks/useMergeRecordsActions.ts @@ -1,5 +1,5 @@ import { useLingui } from '@lingui/react/macro'; -import { useRecoilValue } from 'recoil'; +import { useRecoilValue, useSetRecoilState } from 'recoil'; import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu'; import { useFindManyRecordsSelectedInContextStore } from '@/context-store/hooks/useFindManyRecordsSelectedInContextStore'; @@ -7,6 +7,7 @@ import { useMergeManyRecords } from '@/object-record/hooks/useMergeManyRecords'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { AppPath } from 'twenty-shared/types'; import { useNavigateApp } from '~/hooks/useNavigateApp'; +import { isMergeInProgressState } from '../states/mergeInProgressState'; import { mergeSettingsState } from '../states/mergeSettingsState'; type UseMergeRecordsActionsProps = { @@ -27,12 +28,15 @@ export const useMergeRecordsActions = ({ objectNameSingular, }); + const setMergeInProgress = useSetRecoilState(isMergeInProgressState); + const { t } = useLingui(); const { enqueueSuccessSnackBar, enqueueErrorSnackBar } = useSnackBar(); const { closeCommandMenu } = useCommandMenu(); const navigate = useNavigateApp(); const handleMergeRecords = async () => { + setMergeInProgress(true); try { const mergedRecord = await mergeManyRecords({ recordIds: selectedRecords.map((record) => record.id), @@ -62,6 +66,8 @@ export const useMergeRecordsActions = ({ ? error.message : 'Failed to merge records. Please try again.', }); + } finally { + setMergeInProgress(false); } }; diff --git a/packages/twenty-front/src/modules/object-record/record-merge/states/mergeInProgressState.ts b/packages/twenty-front/src/modules/object-record/record-merge/states/mergeInProgressState.ts new file mode 100644 index 00000000000..f7c952a11e0 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-merge/states/mergeInProgressState.ts @@ -0,0 +1,6 @@ +import { createState } from 'twenty-ui/utilities'; + +export const isMergeInProgressState = createState({ + key: 'isMergeInProgress', + defaultValue: false, +});