feat: find duplicate objects init (#4038)

* feat: find duplicate objects backend init

* refactor: move duplicate criteria to constants

* fix: correct constant usage after type change

* feat: skip query generation in case its not necessary

* feat: filter out existing duplicate

* feat: FE queries and hooks

* feat: show duplicates on FE

* refactor: should-skip-query moved to workspace utils

* refactor: naming improvements

* refactor: current record typings/parsing improvements

* refactor: throw error if existing record not found

* fix: domain -> domainName duplicate criteria

* refactor: fieldNames -> columnNames

* docs: add explanation to duplicate criteria collection

* feat: add person linkedinLinkUrl as duplicate criteria

* feat: throw early when bot id and data are empty

* refactor: trying to improve readability of filter criteria query

* refactor: naming improvements

* refactor: remove shouldSkipQuery

* feat: resolve empty array in case of empty filter

* feat: hide whole section in case of no duplicates

* feat: FE display list the same way as relations

* test: basic unit test coverage

* Refactor Record detail section front

* Use Create as input argument of findDuplicates

* Improve coverage

* Fix

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
rostaklein
2024-02-24 19:12:21 +01:00
committed by GitHub
parent 05c206073d
commit 1b04dfe3c6
30 changed files with 875 additions and 100 deletions

View File

@ -0,0 +1,79 @@
import { useMemo } from 'react';
import { useQuery } from '@apollo/client';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier';
import { useMapConnectionToRecords } from '@/object-record/hooks/useMapConnectionToRecords';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { ObjectRecordConnection } from '@/object-record/types/ObjectRecordConnection';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { logError } from '~/utils/logError';
import { ObjectRecordQueryResult } from '../types/ObjectRecordQueryResult';
export const useFindDuplicateRecords = <T extends ObjectRecord = ObjectRecord>({
objectRecordId = '',
objectNameSingular,
onCompleted,
depth,
}: ObjectMetadataItemIdentifier & {
objectRecordId: string | undefined;
onCompleted?: (data: ObjectRecordConnection<T>) => void;
skip?: boolean;
depth?: number;
}) => {
const findDuplicateQueryStateIdentifier = objectNameSingular;
const { objectMetadataItem, findDuplicateRecordsQuery } =
useObjectMetadataItem({ objectNameSingular }, depth);
const { enqueueSnackBar } = useSnackBar();
const { data, loading, error } = useQuery<ObjectRecordQueryResult<T>>(
findDuplicateRecordsQuery,
{
variables: {
id: objectRecordId,
},
onCompleted: (data) => {
onCompleted?.(data[objectMetadataItem.nameSingular]);
},
onError: (error) => {
logError(
`useFindDuplicateRecords for "${objectMetadataItem.nameSingular}" error : ` +
error,
);
enqueueSnackBar(
`Error during useFindDuplicateRecords for "${objectMetadataItem.nameSingular}", ${error.message}`,
{
variant: 'error',
},
);
},
},
);
const objectRecordConnection =
data?.[`${objectMetadataItem.nameSingular}Duplicates`];
const mapConnectionToRecords = useMapConnectionToRecords();
const records = useMemo(
() =>
mapConnectionToRecords({
objectRecordConnection,
objectNameSingular,
depth: 5,
}) as T[],
[mapConnectionToRecords, objectRecordConnection, objectNameSingular],
);
return {
objectMetadataItem,
records,
totalCount: objectRecordConnection?.totalCount || 0,
loading,
error,
queryStateIdentifier: findDuplicateQueryStateIdentifier,
};
};

View File

@ -0,0 +1,42 @@
import { gql } from '@apollo/client';
import { useMapFieldMetadataToGraphQLQuery } from '@/object-metadata/hooks/useMapFieldMetadataToGraphQLQuery';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { capitalize } from '~/utils/string/capitalize';
export const useGenerateFindDuplicateRecordsQuery = () => {
const mapFieldMetadataToGraphQLQuery = useMapFieldMetadataToGraphQLQuery();
return ({
objectMetadataItem,
depth,
}: {
objectMetadataItem: ObjectMetadataItem;
depth?: number;
}) => gql`
query FindDuplicate${capitalize(objectMetadataItem.nameSingular)}($id: ID) {
${objectMetadataItem.nameSingular}Duplicates(id: $id){
edges {
node {
id
${objectMetadataItem.fields
.map((field) =>
mapFieldMetadataToGraphQLQuery({
field,
maxDepthForRelations: depth,
}),
)
.join('\n')}
}
cursor
}
pageInfo {
hasNextPage
startCursor
endCursor
}
totalCount
}
}
`;
};