feat: merge records (#13436)
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields';
|
||||
import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields';
|
||||
import { useMergeManyRecordsMutation } from '@/object-record/hooks/useMergeManyRecordsMutation';
|
||||
import { useRefetchAggregateQueries } from '@/object-record/hooks/useRefetchAggregateQueries';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { getMergeManyRecordsMutationResponseField } from '@/object-record/utils/getMergeManyRecordsMutationResponseField';
|
||||
|
||||
export type MergeManySettings = {
|
||||
conflictPriorityIndex: number;
|
||||
};
|
||||
|
||||
export type UseMergeManyRecordsProps = {
|
||||
objectNameSingular: string;
|
||||
recordGqlFields?: RecordGqlOperationGqlRecordFields;
|
||||
};
|
||||
|
||||
export const useMergeManyRecords = <
|
||||
MergedObjectRecord extends ObjectRecord = ObjectRecord,
|
||||
>({
|
||||
objectNameSingular,
|
||||
recordGqlFields,
|
||||
}: UseMergeManyRecordsProps) => {
|
||||
const apolloCoreClient = useApolloCoreClient();
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const computedRecordGqlFields =
|
||||
recordGqlFields ?? generateDepthOneRecordGqlFields({ objectMetadataItem });
|
||||
|
||||
const { mergeManyRecordsMutation } = useMergeManyRecordsMutation({
|
||||
objectNameSingular,
|
||||
recordGqlFields: computedRecordGqlFields,
|
||||
});
|
||||
|
||||
const { refetchAggregateQueries } = useRefetchAggregateQueries({
|
||||
objectMetadataNamePlural: objectMetadataItem.namePlural,
|
||||
});
|
||||
|
||||
type MergeManyRecordsProps = {
|
||||
recordIds: string[];
|
||||
mergeSettings: MergeManySettings;
|
||||
preview?: boolean;
|
||||
};
|
||||
|
||||
const mergeManyRecords = useCallback(
|
||||
async ({
|
||||
recordIds,
|
||||
mergeSettings,
|
||||
preview = false,
|
||||
}: MergeManyRecordsProps): Promise<MergedObjectRecord | null> => {
|
||||
setLoading(true);
|
||||
|
||||
const mutationResponseField = getMergeManyRecordsMutationResponseField(
|
||||
objectMetadataItem.namePlural,
|
||||
);
|
||||
|
||||
try {
|
||||
const mergedObject = await apolloCoreClient.mutate({
|
||||
mutation: mergeManyRecordsMutation,
|
||||
variables: {
|
||||
ids: recordIds,
|
||||
conflictPriorityIndex: mergeSettings.conflictPriorityIndex,
|
||||
dryRun: preview,
|
||||
},
|
||||
// Prevent cache updates during dry run to avoid overwriting original record data
|
||||
...(preview && {
|
||||
fetchPolicy: 'no-cache',
|
||||
errorPolicy: 'ignore',
|
||||
}),
|
||||
});
|
||||
|
||||
setLoading(false);
|
||||
|
||||
if (!preview) {
|
||||
await refetchAggregateQueries();
|
||||
}
|
||||
|
||||
return mergedObject.data?.[mutationResponseField] ?? null;
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
[
|
||||
apolloCoreClient,
|
||||
mergeManyRecordsMutation,
|
||||
objectMetadataItem.namePlural,
|
||||
refetchAggregateQueries,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
mergeManyRecords,
|
||||
loading,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,62 @@
|
||||
import gql from 'graphql-tag';
|
||||
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 { EMPTY_MUTATION } from '@/object-record/constants/EmptyMutation';
|
||||
import { RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields';
|
||||
import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { getMergeManyRecordsMutationResponseField } from '@/object-record/utils/getMergeManyRecordsMutationResponseField';
|
||||
import { capitalize } from 'twenty-shared/utils';
|
||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
|
||||
export const useMergeManyRecordsMutation = ({
|
||||
objectNameSingular,
|
||||
recordGqlFields,
|
||||
}: {
|
||||
objectNameSingular: string;
|
||||
recordGqlFields?: RecordGqlOperationGqlRecordFields;
|
||||
}) => {
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const appliedRecordGqlFields =
|
||||
recordGqlFields ??
|
||||
generateDepthOneRecordGqlFields({
|
||||
objectMetadataItem,
|
||||
});
|
||||
|
||||
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
||||
|
||||
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
|
||||
|
||||
if (isUndefinedOrNull(objectMetadataItem)) {
|
||||
return { mergeManyRecordsMutation: EMPTY_MUTATION };
|
||||
}
|
||||
|
||||
const capitalizedObjectName = capitalize(objectMetadataItem.nameSingular);
|
||||
|
||||
const mutationResponseField = getMergeManyRecordsMutationResponseField(
|
||||
objectMetadataItem.namePlural,
|
||||
);
|
||||
|
||||
const mergeManyRecordsMutation = gql`
|
||||
mutation merge${capitalizedObjectName}s($ids: [UUID!]!, $conflictPriorityIndex: Int!, $dryRun: Boolean) {
|
||||
${mutationResponseField}(ids: $ids, conflictPriorityIndex: $conflictPriorityIndex, dryRun: $dryRun) ${mapObjectMetadataToGraphQLQuery(
|
||||
{
|
||||
objectMetadataItems,
|
||||
objectMetadataItem,
|
||||
recordGqlFields: appliedRecordGqlFields,
|
||||
objectPermissionsByObjectMetadataId,
|
||||
},
|
||||
)}
|
||||
}
|
||||
`;
|
||||
|
||||
return {
|
||||
mergeManyRecordsMutation,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user