diff --git a/core/i18n/resources/en/common.js b/core/i18n/resources/en/common.js index 6e1ca5c97f..2e9b094ff4 100644 --- a/core/i18n/resources/en/common.js +++ b/core/i18n/resources/en/common.js @@ -724,6 +724,12 @@ Please refine your query (e.g. adding a filter) to reduce the number of items. merge: { label: 'Merge', confirmLabel: 'Confirm merge', + confirmTooManyDifferencesMessage: `**Too many differences**. +It seems like the records are very different each other. +Many attributes (~{{nodesUpdated}}) will be updated during merge. +Continue with merge preview?`, + noChangesWillBeApplied: `No changes would be applied to target record. +Merge cannot be performed.`, performedSuccessfullyMessage: 'Records merge performed successfully!', previewTitle: 'Merging preview (record {{keyValues}})', }, diff --git a/server/modules/record/api/recordApi.js b/server/modules/record/api/recordApi.js index 60f7869cbc..6175135e44 100644 --- a/server/modules/record/api/recordApi.js +++ b/server/modules/record/api/recordApi.js @@ -368,14 +368,14 @@ export const init = (app) => { const { dryRun, surveyId, sourceRecordUuid, targetRecordUuid } = Request.getParams(req) const user = Request.getUser(req) - const { record } = await RecordService.mergeRecords({ + const { record, nodesCreated, nodesUpdated } = await RecordService.mergeRecords({ user, surveyId, sourceRecordUuid, targetRecordUuid, dryRun, }) - res.json({ record }) + res.json({ record, nodesCreated, nodesUpdated }) } catch (error) { next(error) } diff --git a/server/modules/record/service/recordService.js b/server/modules/record/service/recordService.js index 1e710b9afa..aa3cf99858 100644 --- a/server/modules/record/service/recordService.js +++ b/server/modules/record/service/recordService.js @@ -478,6 +478,8 @@ export const mergeRecords = async ( sideEffect: true, })(recordTarget) + const nodesArray = Object.values(nodesUpdated) + if (!dryRun) { const logContent = { sourceRecordUuid, @@ -487,8 +489,6 @@ export const mergeRecords = async ( } await ActivityLogService.insert(user, surveyId, ActivityLog.type.recordMerge, logContent, false, tx) - const nodesArray = Object.values(nodesUpdated) - await persistRecordNodes({ user, survey, record: recordTargetUpdated, nodesArray }, tx) await RecordManager.updateRecordMergedInto( @@ -503,5 +503,9 @@ export const mergeRecords = async ( await RecordManager.updateRecordDateModified({ surveyId, recordUuid: targetRecordUuid }, tx) } - return { record: recordTargetUpdated } + return { + record: recordTargetUpdated, + nodesCreated: nodesArray.filter(Node.isCreated).length, + nodesUpdated: nodesArray.filter(Node.isUpdated).length, + } }) diff --git a/webapp/service/api/data/index.js b/webapp/service/api/data/index.js index 5380a638cc..96d90ab988 100644 --- a/webapp/service/api/data/index.js +++ b/webapp/service/api/data/index.js @@ -155,7 +155,7 @@ export const startRecordsCloneJob = async ({ surveyId, cycleFrom, cycleTo, recor export const mergeRecords = async ({ surveyId, sourceRecordUuid, targetRecordUuid, preview = false }) => { const uri = `/api/survey/${surveyId}/records/merge` const { - data: { record }, + data: { record, nodesCreated, nodesUpdated }, } = await axios.post(uri, { dryRun: preview, surveyId, sourceRecordUuid, targetRecordUuid }) - return record + return { record, nodesCreated, nodesUpdated } } diff --git a/webapp/store/ui/record/actions/merge.js b/webapp/store/ui/record/actions/merge.js index d7d9e0b9bc..5babcbb789 100644 --- a/webapp/store/ui/record/actions/merge.js +++ b/webapp/store/ui/record/actions/merge.js @@ -1,9 +1,11 @@ import * as API from '@webapp/service/api' import { SurveyState } from '@webapp/store/survey' -import { LoaderActions, NotificationActions } from '@webapp/store/ui' +import { DialogConfirmActions, LoaderActions, NotificationActions } from '@webapp/store/ui' import * as ActionTypes from './actionTypes' +const updatedNodesWarnLimit = 10 + export const previewRecordsMerge = ({ sourceRecordUuid, targetRecordUuid }) => async (dispatch, getState) => { @@ -12,11 +14,30 @@ export const previewRecordsMerge = const state = getState() const surveyId = SurveyState.getSurveyId(state) - const record = await API.mergeRecords({ surveyId, sourceRecordUuid, targetRecordUuid, preview: true }) - - dispatch({ type: ActionTypes.recordLoad, record, noHeader: true }) + const { record, nodesCreated, nodesUpdated } = await API.mergeRecords({ + surveyId, + sourceRecordUuid, + targetRecordUuid, + preview: true, + }) dispatch(LoaderActions.hideLoader()) + + const onMergeConfirmed = () => dispatch({ type: ActionTypes.recordLoad, record, noHeader: true }) + + if (nodesUpdated + nodesCreated === 0) { + dispatch(NotificationActions.notifyWarning({ key: 'dataView.records.merge.noChangesWillBeApplied' })) + } else if (nodesUpdated > updatedNodesWarnLimit) { + dispatch( + DialogConfirmActions.showDialogConfirm({ + key: 'dataView.records.merge.confirmTooManyDifferencesMessage', + params: { nodesUpdated }, + onOk: onMergeConfirmed, + }) + ) + } else { + onMergeConfirmed() + } } export const mergeRecords = diff --git a/yarn.lock b/yarn.lock index 80e5c3f3f2..8d56f9e952 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5098,9 +5098,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001517, caniuse-lite@^1.0.30001587: - version "1.0.30001589" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001589.tgz" - integrity sha512-vNQWS6kI+q6sBlHbh71IIeC+sRwK2N3EDySc/updIGhIee2x5z00J4c1242/5/d6EpEMdOnk/m+6tuk4/tcsqg== + version "1.0.30001653" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001653.tgz" + integrity sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw== caniuse-lite@^1.0.30001646: version "1.0.30001653"