Skip to content

Commit

Permalink
Enable deletion of relation fields (twentyhq#5338)
Browse files Browse the repository at this point in the history
In this PR
1. Enable deletion of relation fields in the product and via the api
(migration part was missing in the api)
3. Change wording, only use "deactivate" and "delete" everywhere (and
not a mix of the two + "disable", "erase")
  • Loading branch information
ijreilly committed May 13, 2024
1 parent 0018ec7 commit b9154f3
Show file tree
Hide file tree
Showing 30 changed files with 519 additions and 117 deletions.
9 changes: 7 additions & 2 deletions packages/twenty-front/src/generated-metadata/gql.ts

Large diffs are not rendered by default.

29 changes: 13 additions & 16 deletions packages/twenty-front/src/generated-metadata/graphql.ts

Large diffs are not rendered by default.

35 changes: 23 additions & 12 deletions packages/twenty-front/src/generated/graphql.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,11 @@ export type MutationTrackArgs = {
};


export type MutationUpdateOneObjectArgs = {
input: UpdateOneObjectInput;
};


export type MutationUpdatePasswordViaResetTokenArgs = {
newPassword: Scalars['String'];
passwordResetToken: Scalars['String'];
Expand Down Expand Up @@ -548,18 +553,6 @@ export enum RelationDefinitionType {
OneToOne = 'ONE_TO_ONE'
}

export type RelationDeleteResponse = {
__typename?: 'RelationDeleteResponse';
createdAt?: Maybe<Scalars['DateTime']>;
fromFieldMetadataId?: Maybe<Scalars['String']>;
fromObjectMetadataId?: Maybe<Scalars['String']>;
id?: Maybe<Scalars['UUID']>;
relationType?: Maybe<RelationMetadataType>;
toFieldMetadataId?: Maybe<Scalars['String']>;
toObjectMetadataId?: Maybe<Scalars['String']>;
updatedAt?: Maybe<Scalars['DateTime']>;
};

/** Type of the relation */
export enum RelationMetadataType {
ManyToMany = 'MANY_TO_MANY',
Expand Down Expand Up @@ -728,6 +721,24 @@ export type UpdateBillingEntity = {
success: Scalars['Boolean'];
};

export type UpdateObjectPayload = {
description?: InputMaybe<Scalars['String']>;
icon?: InputMaybe<Scalars['String']>;
imageIdentifierFieldMetadataId?: InputMaybe<Scalars['String']>;
isActive?: InputMaybe<Scalars['Boolean']>;
labelIdentifierFieldMetadataId?: InputMaybe<Scalars['String']>;
labelPlural?: InputMaybe<Scalars['String']>;
labelSingular?: InputMaybe<Scalars['String']>;
namePlural?: InputMaybe<Scalars['String']>;
nameSingular?: InputMaybe<Scalars['String']>;
};

export type UpdateOneObjectInput = {
/** The id of the object to update */
id: Scalars['UUID'];
update: UpdateObjectPayload;
};

export type UpdateWorkspaceInput = {
allowImpersonation?: InputMaybe<Scalars['Boolean']>;
displayName?: InputMaybe<Scalars['String']>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,11 @@ export const DELETE_ONE_FIELD_METADATA_ITEM = gql`
}
}
`;

export const DELETE_ONE_RELATION_METADATA_ITEM = gql`
mutation DeleteOneRelationMetadataItem($idToDelete: UUID!) {
deleteOneRelation(input: { id: $idToDelete }) {
id
}
}
`;
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export const FIND_MANY_OBJECT_METADATA_ITEMS = gql`
defaultValue
options
relationDefinition {
relationId
direction
sourceObjectMetadata {
id
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { gql } from '@apollo/client';

export const query = gql`
mutation DeleteOneRelationMetadataItem($idToDelete: UUID!) {
deleteOneRelation(input: { id: $idToDelete }) {
id
}
}
`;

export const variables = { idToDelete: 'idToDelete' };

export const responseData = {
id: 'idToDelete'
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { gql } from '@apollo/client';
import { FieldMetadataType } from '~/generated/graphql';

export const FIELD_METADATA_ID = '2c43466a-fe9e-4005-8d08-c5836067aa6c';
export const FIELD_RELATION_METADATA_ID = '4da0302d-358a-45cd-9973-9f92723ed3c1';
export const RELATION_METADATA_ID = 'f81d4fae-7dec-11d0-a765-00a0c91e6bf6';

const baseFields = `
id
Expand All @@ -15,13 +20,20 @@ const baseFields = `
`;

export const queries = {
eraseMetadataField: gql`
deleteMetadataField: gql`
mutation DeleteOneFieldMetadataItem($idToDelete: UUID!) {
deleteOneField(input: { id: $idToDelete }) {
${baseFields}
}
}
`,
deleteMetadataFieldRelation: gql`
mutation DeleteOneRelationMetadataItem($idToDelete: UUID!) {
deleteOneRelation(input: { id: $idToDelete }) {
id
}
}
`,
activateMetadataField: gql`
mutation UpdateOneFieldMetadataItem(
$idToUpdate: UUID!
Expand All @@ -43,13 +55,13 @@ export const queries = {
`,
};

const fieldId = '2c43466a-fe9e-4005-8d08-c5836067aa6c';
export const objectMetadataId = '25611fce-6637-4089-b0ca-91afeec95784';

export const variables = {
eraseMetadataField: { idToDelete: fieldId },
deleteMetadataField: { idToDelete: FIELD_METADATA_ID },
deleteMetadataFieldRelation: { idToDelete: RELATION_METADATA_ID },
activateMetadataField: {
idToUpdate: fieldId,
idToUpdate: FIELD_METADATA_ID,
updatePayload: { isActive: true, label: undefined },
},
createMetadataField: {
Expand All @@ -66,14 +78,14 @@ export const variables = {
},
},
},
disableMetadataField: {
idToUpdate: fieldId,
deactivateMetadataField: {
idToUpdate: FIELD_METADATA_ID,
updatePayload: { isActive: false, label: undefined },
}
};

const defaultResponseData = {
id: '2c43466a-fe9e-4005-8d08-c5836067aa6c',
id: FIELD_METADATA_ID,
type: 'type',
name: 'name',
label: 'label',
Expand All @@ -86,11 +98,19 @@ const defaultResponseData = {
updatedAt: '1996-10-10T08:27:57.117Z',
};

const fieldRelationResponseData = {
...defaultResponseData,
id: FIELD_RELATION_METADATA_ID,
type: FieldMetadataType.Relation,
};

export const responseData = {
default: defaultResponseData,
fieldRelation: fieldRelationResponseData,
createMetadataField: {
...defaultResponseData,
defaultValue: '',
options: [],
},
};

Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { ReactNode } from 'react';
import { MockedProvider } from '@apollo/client/testing';
import { act, renderHook } from '@testing-library/react';
import { RecoilRoot } from 'recoil';

import { useDeleteOneRelationMetadataItem } from '@/object-metadata/hooks/useDeleteOneRelationMetadataItem';

import {
query,
responseData,
variables,
} from '../__mocks__/useDeleteOneRelationMetadataItem';

const mocks = [
{
request: {
query,
variables,
},
result: jest.fn(() => ({
data: {
deleteOneRelation: responseData,
},
})),
},
];

const Wrapper = ({ children }: { children: ReactNode }) => (
<RecoilRoot>
<MockedProvider mocks={mocks} addTypename={false}>
{children}
</MockedProvider>
</RecoilRoot>
);

describe('useDeleteOneRelationMetadataItem', () => {
it('should work as expected', async () => {
const { result } = renderHook(() => useDeleteOneRelationMetadataItem(), {
wrapper: Wrapper,
});

await act(async () => {
const res =
await result.current.deleteOneRelationMetadataItem('idToDelete');

expect(res.data).toEqual({ deleteOneRelation: responseData });
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,81 @@ import { RecoilRoot } from 'recoil';

import { useFieldMetadataItem } from '@/object-metadata/hooks/useFieldMetadataItem';
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { FieldMetadataType } from '~/generated/graphql';
import { FieldMetadataType, RelationDefinitionType } from '~/generated/graphql';

import {
FIELD_METADATA_ID,
FIELD_RELATION_METADATA_ID,
objectMetadataId,
queries,
RELATION_METADATA_ID,
responseData,
variables,
} from '../__mocks__/useFieldMetadataItem';

const fieldMetadataItem: FieldMetadataItem = {
id: '2c43466a-fe9e-4005-8d08-c5836067aa6c',
id: FIELD_METADATA_ID,
createdAt: '',
label: 'label',
name: 'name',
type: FieldMetadataType.Text,
updatedAt: '',
};

const fieldRelationMetadataItem: FieldMetadataItem = {
id: FIELD_RELATION_METADATA_ID,
createdAt: '',
label: 'label',
name: 'name',
type: FieldMetadataType.Relation,
updatedAt: '',
relationDefinition: {
relationId: RELATION_METADATA_ID,
direction: RelationDefinitionType.OneToMany,
sourceFieldMetadata: {
id: 'e5903d91-9b10-4f3e-b761-35c36e93b7c1',
name: 'sourceField',
},
targetFieldMetadata: {
id: 'd23d82d4-690b-489f-a8e3-fc5ed01a91f6',
name: 'targetField',
},
sourceObjectMetadata: {
id: 'bf46be8a-7c47-45a7-b2f1-30f49e14fbd9',
nameSingular: 'sourceObject',
namePlural: 'sourceObjects',
},
targetObjectMetadata: {
id: '987c0489-2855-4a63-bb81-93692e51b2a9',
nameSingular: 'targetObject',
namePlural: 'targetObjects',
},
},
};

const mocks = [
{
request: {
query: queries.eraseMetadataField,
variables: variables.eraseMetadataField,
query: queries.deleteMetadataField,
variables: variables.deleteMetadataField,
},
result: jest.fn(() => ({
data: {
deleteOneField: responseData.default,
},
})),
},
{
request: {
query: queries.deleteMetadataFieldRelation,
variables: variables.deleteMetadataFieldRelation,
},
result: jest.fn(() => ({
data: {
deleteOneRelation: responseData.fieldRelation,
},
})),
},
{
request: {
query: queries.activateMetadataField,
Expand All @@ -60,7 +105,7 @@ const mocks = [
{
request: {
query: queries.activateMetadataField,
variables: variables.disableMetadataField,
variables: variables.deactivateMetadataField,
},
result: jest.fn(() => ({
data: {
Expand Down Expand Up @@ -111,31 +156,48 @@ describe('useFieldMetadataItem', () => {
});
});

it('should disableMetadataField', async () => {
it('should deactivateMetadataField', async () => {
const { result } = renderHook(() => useFieldMetadataItem(), {
wrapper: Wrapper,
});

await act(async () => {
const res = await result.current.disableMetadataField(fieldMetadataItem);
const res =
await result.current.deactivateMetadataField(fieldMetadataItem);

expect(res.data).toEqual({
updateOneField: responseData.default,
});
});
});

it('should eraseMetadataField', async () => {
it('should deleteOneFieldMetadataItem when calling deleteMetadataField for a non-relation field', async () => {
const { result } = renderHook(() => useFieldMetadataItem(), {
wrapper: Wrapper,
});

await act(async () => {
const res = await result.current.eraseMetadataField(fieldMetadataItem);
const res = await result.current.deleteMetadataField(fieldMetadataItem);

expect(res.data).toEqual({
deleteOneField: responseData.default,
});
});
});

it('should deleteOneFieldMetadataItem when calling deleteMetadataField for a relation field', async () => {
const { result } = renderHook(() => useFieldMetadataItem(), {
wrapper: Wrapper,
});

await act(async () => {
const res = await result.current.deleteMetadataField(
fieldRelationMetadataItem,
);

expect(res.data).toEqual({
deleteOneRelation: responseData.fieldRelation,
});
});
});
});

0 comments on commit b9154f3

Please sign in to comment.