From 4eb123275072a9a8a234443f93f19734e4bf3029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Magrin?= Date: Wed, 7 Aug 2024 17:52:49 +0200 Subject: [PATCH 01/22] feat: wip soft delete --- packages/twenty-front/project.json | 2 +- .../src/generated-metadata/gql.ts | 4 +- .../src/generated-metadata/graphql.ts | 28 +++++++---- .../object-metadata/graphql/queries.ts | 1 + .../object-record/hooks/useFindManyRecords.ts | 5 +- packages/twenty-server/package.json | 3 +- .../migrations/1723038077987-addSoftDelete.ts | 17 +++++++ .../workspace-query-runner.service.ts | 50 +++++++++++++++---- .../interfaces/object-metadata.interface.ts | 1 + .../dtos/object-metadata.dto.ts | 3 ++ .../object-metadata/object-metadata.entity.ts | 3 ++ .../twenty-orm/base.workspace-entity.ts | 11 ++++ .../twenty-orm/custom.workspace-entity.ts | 14 +++++- .../workspace-custom-object.decorator.ts | 9 +++- .../decorators/workspace-entity.decorator.ts | 2 + .../factories/entity-schema-column.factory.ts | 6 +++ .../factories/entity-schema.factory.ts | 1 + ...orkspace-entity-metadata-args.interface.ts | 7 ++- ...extended-entity-metadata-args.interface.ts | 5 ++ .../constants/standard-field-ids.ts | 2 + .../factories/standard-field.factory.ts | 8 +++ .../company.workspace-entity.ts | 1 + .../note-target.workspace-entity.ts | 1 + .../standard-objects/note.workspace-entity.ts | 1 + .../opportunity.workspace-entity.ts | 1 + .../person.workspace-entity.ts | 1 + .../task-target.workspace-entity.ts | 1 + .../standard-objects/task.workspace-entity.ts | 1 + 28 files changed, 160 insertions(+), 29 deletions(-) create mode 100644 packages/twenty-server/src/database/typeorm/metadata/migrations/1723038077987-addSoftDelete.ts diff --git a/packages/twenty-front/project.json b/packages/twenty-front/project.json index 636fd29af6a6..91eee0796542 100644 --- a/packages/twenty-front/project.json +++ b/packages/twenty-front/project.json @@ -119,7 +119,7 @@ }, "graphql:generate": { "executor": "nx:run-commands", - "defaultConfiguration": "data", + "defaultConfiguration": "metadata", "options": { "cwd": "{projectRoot}", "command": "dotenv cross-var graphql-codegen -- --config={args.config}" diff --git a/packages/twenty-front/src/generated-metadata/gql.ts b/packages/twenty-front/src/generated-metadata/gql.ts index 1aca61a965d2..e0c7dc125a3a 100644 --- a/packages/twenty-front/src/generated-metadata/gql.ts +++ b/packages/twenty-front/src/generated-metadata/gql.ts @@ -32,7 +32,7 @@ const documents = { "\n mutation DeleteOneObjectMetadataItem($idToDelete: UUID!) {\n deleteOneObject(input: { id: $idToDelete }) {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isActive\n createdAt\n updatedAt\n labelIdentifierFieldMetadataId\n imageIdentifierFieldMetadataId\n }\n }\n": types.DeleteOneObjectMetadataItemDocument, "\n mutation DeleteOneFieldMetadataItem($idToDelete: UUID!) {\n deleteOneField(input: { id: $idToDelete }) {\n id\n type\n name\n label\n description\n icon\n isCustom\n isActive\n isNullable\n createdAt\n updatedAt\n }\n }\n": types.DeleteOneFieldMetadataItemDocument, "\n mutation DeleteOneRelationMetadataItem($idToDelete: UUID!) {\n deleteOneRelation(input: { id: $idToDelete }) {\n id\n }\n }\n": types.DeleteOneRelationMetadataItemDocument, - "\n query ObjectMetadataItems(\n $objectFilter: objectFilter\n $fieldFilter: fieldFilter\n ) {\n objects(paging: { first: 1000 }, filter: $objectFilter) {\n edges {\n node {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isRemote\n isActive\n isSystem\n createdAt\n updatedAt\n labelIdentifierFieldMetadataId\n imageIdentifierFieldMetadataId\n fields(paging: { first: 1000 }, filter: $fieldFilter) {\n edges {\n node {\n id\n type\n name\n label\n description\n icon\n isCustom\n isActive\n isSystem\n isNullable\n createdAt\n updatedAt\n fromRelationMetadata {\n id\n relationType\n toObjectMetadata {\n id\n dataSourceId\n nameSingular\n namePlural\n isSystem\n isRemote\n }\n toFieldMetadataId\n }\n toRelationMetadata {\n id\n relationType\n fromObjectMetadata {\n id\n dataSourceId\n nameSingular\n namePlural\n isSystem\n isRemote\n }\n fromFieldMetadataId\n }\n defaultValue\n options\n relationDefinition {\n relationId\n direction\n sourceObjectMetadata {\n id\n nameSingular\n namePlural\n }\n sourceFieldMetadata {\n id\n name\n }\n targetObjectMetadata {\n id\n nameSingular\n namePlural\n }\n targetFieldMetadata {\n id\n name\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n": types.ObjectMetadataItemsDocument, + "\n query ObjectMetadataItems(\n $objectFilter: objectFilter\n $fieldFilter: fieldFilter\n ) {\n objects(paging: { first: 1000 }, filter: $objectFilter) {\n edges {\n node {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isRemote\n isActive\n isSystem\n createdAt\n updatedAt\n softDelete\n labelIdentifierFieldMetadataId\n imageIdentifierFieldMetadataId\n fields(paging: { first: 1000 }, filter: $fieldFilter) {\n edges {\n node {\n id\n type\n name\n label\n description\n icon\n isCustom\n isActive\n isSystem\n isNullable\n createdAt\n updatedAt\n fromRelationMetadata {\n id\n relationType\n toObjectMetadata {\n id\n dataSourceId\n nameSingular\n namePlural\n isSystem\n isRemote\n }\n toFieldMetadataId\n }\n toRelationMetadata {\n id\n relationType\n fromObjectMetadata {\n id\n dataSourceId\n nameSingular\n namePlural\n isSystem\n isRemote\n }\n fromFieldMetadataId\n }\n defaultValue\n options\n relationDefinition {\n relationId\n direction\n sourceObjectMetadata {\n id\n nameSingular\n namePlural\n }\n sourceFieldMetadata {\n id\n name\n }\n targetObjectMetadata {\n id\n nameSingular\n namePlural\n }\n targetFieldMetadata {\n id\n name\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n": types.ObjectMetadataItemsDocument, "\n fragment ServerlessFunctionFields on ServerlessFunction {\n id\n name\n description\n sourceCodeHash\n sourceCodeFullPath\n runtime\n syncStatus\n createdAt\n updatedAt\n }\n": types.ServerlessFunctionFieldsFragmentDoc, "\n \n mutation CreateOneServerlessFunctionItem(\n $input: CreateServerlessFunctionInput!\n ) {\n createOneServerlessFunction(input: $input) {\n ...ServerlessFunctionFields\n }\n }\n": types.CreateOneServerlessFunctionItemDocument, "\n \n mutation DeleteOneServerlessFunction($input: DeleteServerlessFunctionInput!) {\n deleteOneServerlessFunction(input: $input) {\n ...ServerlessFunctionFields\n }\n }\n": types.DeleteOneServerlessFunctionDocument, @@ -135,7 +135,7 @@ export function graphql(source: "\n mutation DeleteOneRelationMetadataItem($idT /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query ObjectMetadataItems(\n $objectFilter: objectFilter\n $fieldFilter: fieldFilter\n ) {\n objects(paging: { first: 1000 }, filter: $objectFilter) {\n edges {\n node {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isRemote\n isActive\n isSystem\n createdAt\n updatedAt\n labelIdentifierFieldMetadataId\n imageIdentifierFieldMetadataId\n fields(paging: { first: 1000 }, filter: $fieldFilter) {\n edges {\n node {\n id\n type\n name\n label\n description\n icon\n isCustom\n isActive\n isSystem\n isNullable\n createdAt\n updatedAt\n fromRelationMetadata {\n id\n relationType\n toObjectMetadata {\n id\n dataSourceId\n nameSingular\n namePlural\n isSystem\n isRemote\n }\n toFieldMetadataId\n }\n toRelationMetadata {\n id\n relationType\n fromObjectMetadata {\n id\n dataSourceId\n nameSingular\n namePlural\n isSystem\n isRemote\n }\n fromFieldMetadataId\n }\n defaultValue\n options\n relationDefinition {\n relationId\n direction\n sourceObjectMetadata {\n id\n nameSingular\n namePlural\n }\n sourceFieldMetadata {\n id\n name\n }\n targetObjectMetadata {\n id\n nameSingular\n namePlural\n }\n targetFieldMetadata {\n id\n name\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n"): (typeof documents)["\n query ObjectMetadataItems(\n $objectFilter: objectFilter\n $fieldFilter: fieldFilter\n ) {\n objects(paging: { first: 1000 }, filter: $objectFilter) {\n edges {\n node {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isRemote\n isActive\n isSystem\n createdAt\n updatedAt\n labelIdentifierFieldMetadataId\n imageIdentifierFieldMetadataId\n fields(paging: { first: 1000 }, filter: $fieldFilter) {\n edges {\n node {\n id\n type\n name\n label\n description\n icon\n isCustom\n isActive\n isSystem\n isNullable\n createdAt\n updatedAt\n fromRelationMetadata {\n id\n relationType\n toObjectMetadata {\n id\n dataSourceId\n nameSingular\n namePlural\n isSystem\n isRemote\n }\n toFieldMetadataId\n }\n toRelationMetadata {\n id\n relationType\n fromObjectMetadata {\n id\n dataSourceId\n nameSingular\n namePlural\n isSystem\n isRemote\n }\n fromFieldMetadataId\n }\n defaultValue\n options\n relationDefinition {\n relationId\n direction\n sourceObjectMetadata {\n id\n nameSingular\n namePlural\n }\n sourceFieldMetadata {\n id\n name\n }\n targetObjectMetadata {\n id\n nameSingular\n namePlural\n }\n targetFieldMetadata {\n id\n name\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n"]; +export function graphql(source: "\n query ObjectMetadataItems(\n $objectFilter: objectFilter\n $fieldFilter: fieldFilter\n ) {\n objects(paging: { first: 1000 }, filter: $objectFilter) {\n edges {\n node {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isRemote\n isActive\n isSystem\n createdAt\n updatedAt\n softDelete\n labelIdentifierFieldMetadataId\n imageIdentifierFieldMetadataId\n fields(paging: { first: 1000 }, filter: $fieldFilter) {\n edges {\n node {\n id\n type\n name\n label\n description\n icon\n isCustom\n isActive\n isSystem\n isNullable\n createdAt\n updatedAt\n fromRelationMetadata {\n id\n relationType\n toObjectMetadata {\n id\n dataSourceId\n nameSingular\n namePlural\n isSystem\n isRemote\n }\n toFieldMetadataId\n }\n toRelationMetadata {\n id\n relationType\n fromObjectMetadata {\n id\n dataSourceId\n nameSingular\n namePlural\n isSystem\n isRemote\n }\n fromFieldMetadataId\n }\n defaultValue\n options\n relationDefinition {\n relationId\n direction\n sourceObjectMetadata {\n id\n nameSingular\n namePlural\n }\n sourceFieldMetadata {\n id\n name\n }\n targetObjectMetadata {\n id\n nameSingular\n namePlural\n }\n targetFieldMetadata {\n id\n name\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n"): (typeof documents)["\n query ObjectMetadataItems(\n $objectFilter: objectFilter\n $fieldFilter: fieldFilter\n ) {\n objects(paging: { first: 1000 }, filter: $objectFilter) {\n edges {\n node {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isRemote\n isActive\n isSystem\n createdAt\n updatedAt\n softDelete\n labelIdentifierFieldMetadataId\n imageIdentifierFieldMetadataId\n fields(paging: { first: 1000 }, filter: $fieldFilter) {\n edges {\n node {\n id\n type\n name\n label\n description\n icon\n isCustom\n isActive\n isSystem\n isNullable\n createdAt\n updatedAt\n fromRelationMetadata {\n id\n relationType\n toObjectMetadata {\n id\n dataSourceId\n nameSingular\n namePlural\n isSystem\n isRemote\n }\n toFieldMetadataId\n }\n toRelationMetadata {\n id\n relationType\n fromObjectMetadata {\n id\n dataSourceId\n nameSingular\n namePlural\n isSystem\n isRemote\n }\n fromFieldMetadataId\n }\n defaultValue\n options\n relationDefinition {\n relationId\n direction\n sourceObjectMetadata {\n id\n nameSingular\n namePlural\n }\n sourceFieldMetadata {\n id\n name\n }\n targetObjectMetadata {\n id\n nameSingular\n namePlural\n }\n targetFieldMetadata {\n id\n name\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index f3c3f0e781f2..86727a7cccf0 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -344,9 +344,9 @@ export type FieldConnection = { /** Type of the field */ export enum FieldMetadataType { + Actor = 'ACTOR', Address = 'ADDRESS', Boolean = 'BOOLEAN', - Actor = 'ACTOR', Currency = 'CURRENCY', Date = 'DATE', DateTime = 'DATE_TIME', @@ -452,13 +452,13 @@ export type Mutation = { generateTransientToken: TransientToken; impersonate: Verify; renewToken: AuthTokens; + runWorkflowVersion: WorkflowTriggerResult; sendInviteLink: SendInviteLink; signUp: LoginToken; skipSyncEmailOnboardingStep: OnboardingStepSuccess; syncRemoteTable: RemoteTable; syncRemoteTableSchemaChanges: RemoteTable; track: Analytics; - triggerWorkflow: WorkflowTriggerResult; unsyncRemoteTable: RemoteTable; updateBillingSubscription: UpdateBillingEntity; updateOneField: Field; @@ -610,6 +610,11 @@ export type MutationRenewTokenArgs = { }; +export type MutationRunWorkflowVersionArgs = { + input: RunWorkflowVersionInput; +}; + + export type MutationSendInviteLinkArgs = { emails: Array; }; @@ -639,11 +644,6 @@ export type MutationTrackArgs = { }; -export type MutationTriggerWorkflowArgs = { - workflowVersionId: Scalars['String']['input']; -}; - - export type MutationUnsyncRemoteTableArgs = { input: RemoteTableInput; }; @@ -1001,6 +1001,13 @@ export enum RemoteTableStatus { Synced = 'SYNCED' } +export type RunWorkflowVersionInput = { + /** Execution result in JSON format */ + payload?: InputMaybe; + /** Workflow version ID */ + workflowVersionId: Scalars['String']['input']; +}; + export type SendInviteLink = { __typename?: 'SendInviteLink'; /** Boolean that confirms query was dispatched */ @@ -1400,6 +1407,7 @@ export type WorkspaceFeatureFlagsArgs = { export enum WorkspaceActivationStatus { Active = 'ACTIVE', Inactive = 'INACTIVE', + OngoingCreation = 'ONGOING_CREATION', PendingCreation = 'PENDING_CREATION' } @@ -1500,6 +1508,7 @@ export type Object = { labelSingular: Scalars['String']['output']; namePlural: Scalars['String']['output']; nameSingular: Scalars['String']['output']; + softDelete?: Maybe; updatedAt: Scalars['DateTime']['output']; }; @@ -1525,6 +1534,7 @@ export type ObjectFilter = { isRemote?: InputMaybe; isSystem?: InputMaybe; or?: InputMaybe>; + softDelete?: InputMaybe; }; export type Relation = { @@ -1680,7 +1690,7 @@ export type ObjectMetadataItemsQueryVariables = Exact<{ }>; -export type ObjectMetadataItemsQuery = { __typename?: 'Query', objects: { __typename?: 'ObjectConnection', edges: Array<{ __typename?: 'objectEdge', node: { __typename?: 'object', id: any, dataSourceId: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, isCustom: boolean, isRemote: boolean, isActive: boolean, isSystem: boolean, createdAt: any, updatedAt: any, labelIdentifierFieldMetadataId?: string | null, imageIdentifierFieldMetadataId?: string | null, fields: { __typename?: 'ObjectFieldsConnection', edges: Array<{ __typename?: 'fieldEdge', node: { __typename?: 'field', id: any, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isSystem?: boolean | null, isNullable?: boolean | null, createdAt: any, updatedAt: any, defaultValue?: any | null, options?: any | null, fromRelationMetadata?: { __typename?: 'relation', id: any, relationType: RelationMetadataType, toFieldMetadataId: string, toObjectMetadata: { __typename?: 'object', id: any, dataSourceId: string, nameSingular: string, namePlural: string, isSystem: boolean, isRemote: boolean } } | null, toRelationMetadata?: { __typename?: 'relation', id: any, relationType: RelationMetadataType, fromFieldMetadataId: string, fromObjectMetadata: { __typename?: 'object', id: any, dataSourceId: string, nameSingular: string, namePlural: string, isSystem: boolean, isRemote: boolean } } | null, relationDefinition?: { __typename?: 'RelationDefinition', relationId: any, direction: RelationDefinitionType, sourceObjectMetadata: { __typename?: 'object', id: any, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'field', id: any, name: string }, targetObjectMetadata: { __typename?: 'object', id: any, nameSingular: string, namePlural: string }, targetFieldMetadata: { __typename?: 'field', id: any, name: string } } | null } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } }; +export type ObjectMetadataItemsQuery = { __typename?: 'Query', objects: { __typename?: 'ObjectConnection', edges: Array<{ __typename?: 'objectEdge', node: { __typename?: 'object', id: any, dataSourceId: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, isCustom: boolean, isRemote: boolean, isActive: boolean, isSystem: boolean, createdAt: any, updatedAt: any, softDelete?: boolean | null, labelIdentifierFieldMetadataId?: string | null, imageIdentifierFieldMetadataId?: string | null, fields: { __typename?: 'ObjectFieldsConnection', edges: Array<{ __typename?: 'fieldEdge', node: { __typename?: 'field', id: any, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isSystem?: boolean | null, isNullable?: boolean | null, createdAt: any, updatedAt: any, defaultValue?: any | null, options?: any | null, fromRelationMetadata?: { __typename?: 'relation', id: any, relationType: RelationMetadataType, toFieldMetadataId: string, toObjectMetadata: { __typename?: 'object', id: any, dataSourceId: string, nameSingular: string, namePlural: string, isSystem: boolean, isRemote: boolean } } | null, toRelationMetadata?: { __typename?: 'relation', id: any, relationType: RelationMetadataType, fromFieldMetadataId: string, fromObjectMetadata: { __typename?: 'object', id: any, dataSourceId: string, nameSingular: string, namePlural: string, isSystem: boolean, isRemote: boolean } } | null, relationDefinition?: { __typename?: 'RelationDefinition', relationId: any, direction: RelationDefinitionType, sourceObjectMetadata: { __typename?: 'object', id: any, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'field', id: any, name: string }, targetObjectMetadata: { __typename?: 'object', id: any, nameSingular: string, namePlural: string }, targetFieldMetadata: { __typename?: 'field', id: any, name: string } } | null } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } }; export type ServerlessFunctionFieldsFragment = { __typename?: 'ServerlessFunction', id: any, name: string, description?: string | null, sourceCodeHash: string, sourceCodeFullPath: string, runtime: string, syncStatus: ServerlessFunctionSyncStatus, createdAt: any, updatedAt: any }; @@ -1745,7 +1755,7 @@ export const UpdateOneObjectMetadataItemDocument = {"kind":"Document","definitio export const DeleteOneObjectMetadataItemDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteOneObjectMetadataItem"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"idToDelete"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteOneObject"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"idToDelete"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"dataSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}},{"kind":"Field","name":{"kind":"Name","value":"labelSingular"}},{"kind":"Field","name":{"kind":"Name","value":"labelPlural"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"labelIdentifierFieldMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"imageIdentifierFieldMetadataId"}}]}}]}}]} as unknown as DocumentNode; export const DeleteOneFieldMetadataItemDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteOneFieldMetadataItem"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"idToDelete"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteOneField"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"idToDelete"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"isNullable"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode; export const DeleteOneRelationMetadataItemDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteOneRelationMetadataItem"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"idToDelete"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteOneRelation"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"idToDelete"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; -export const ObjectMetadataItemsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ObjectMetadataItems"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"objectFilter"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"objectFilter"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"fieldFilter"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"fieldFilter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"objects"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"paging"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"first"},"value":{"kind":"IntValue","value":"1000"}}]}},{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"objectFilter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"dataSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}},{"kind":"Field","name":{"kind":"Name","value":"labelSingular"}},{"kind":"Field","name":{"kind":"Name","value":"labelPlural"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isRemote"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"isSystem"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"labelIdentifierFieldMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"imageIdentifierFieldMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"fields"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"paging"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"first"},"value":{"kind":"IntValue","value":"1000"}}]}},{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"fieldFilter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"isSystem"}},{"kind":"Field","name":{"kind":"Name","value":"isNullable"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"fromRelationMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"relationType"}},{"kind":"Field","name":{"kind":"Name","value":"toObjectMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"dataSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}},{"kind":"Field","name":{"kind":"Name","value":"isSystem"}},{"kind":"Field","name":{"kind":"Name","value":"isRemote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"toFieldMetadataId"}}]}},{"kind":"Field","name":{"kind":"Name","value":"toRelationMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"relationType"}},{"kind":"Field","name":{"kind":"Name","value":"fromObjectMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"dataSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}},{"kind":"Field","name":{"kind":"Name","value":"isSystem"}},{"kind":"Field","name":{"kind":"Name","value":"isRemote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fromFieldMetadataId"}}]}},{"kind":"Field","name":{"kind":"Name","value":"defaultValue"}},{"kind":"Field","name":{"kind":"Name","value":"options"}},{"kind":"Field","name":{"kind":"Name","value":"relationDefinition"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"relationId"}},{"kind":"Field","name":{"kind":"Name","value":"direction"}},{"kind":"Field","name":{"kind":"Name","value":"sourceObjectMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}}]}},{"kind":"Field","name":{"kind":"Name","value":"sourceFieldMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"targetObjectMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}}]}},{"kind":"Field","name":{"kind":"Name","value":"targetFieldMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"pageInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hasNextPage"}},{"kind":"Field","name":{"kind":"Name","value":"hasPreviousPage"}},{"kind":"Field","name":{"kind":"Name","value":"startCursor"}},{"kind":"Field","name":{"kind":"Name","value":"endCursor"}}]}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"pageInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hasNextPage"}},{"kind":"Field","name":{"kind":"Name","value":"hasPreviousPage"}},{"kind":"Field","name":{"kind":"Name","value":"startCursor"}},{"kind":"Field","name":{"kind":"Name","value":"endCursor"}}]}}]}}]}}]} as unknown as DocumentNode; +export const ObjectMetadataItemsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ObjectMetadataItems"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"objectFilter"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"objectFilter"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"fieldFilter"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"fieldFilter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"objects"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"paging"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"first"},"value":{"kind":"IntValue","value":"1000"}}]}},{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"objectFilter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"dataSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}},{"kind":"Field","name":{"kind":"Name","value":"labelSingular"}},{"kind":"Field","name":{"kind":"Name","value":"labelPlural"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isRemote"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"isSystem"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"softDelete"}},{"kind":"Field","name":{"kind":"Name","value":"labelIdentifierFieldMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"imageIdentifierFieldMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"fields"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"paging"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"first"},"value":{"kind":"IntValue","value":"1000"}}]}},{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"fieldFilter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"isSystem"}},{"kind":"Field","name":{"kind":"Name","value":"isNullable"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"fromRelationMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"relationType"}},{"kind":"Field","name":{"kind":"Name","value":"toObjectMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"dataSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}},{"kind":"Field","name":{"kind":"Name","value":"isSystem"}},{"kind":"Field","name":{"kind":"Name","value":"isRemote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"toFieldMetadataId"}}]}},{"kind":"Field","name":{"kind":"Name","value":"toRelationMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"relationType"}},{"kind":"Field","name":{"kind":"Name","value":"fromObjectMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"dataSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}},{"kind":"Field","name":{"kind":"Name","value":"isSystem"}},{"kind":"Field","name":{"kind":"Name","value":"isRemote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fromFieldMetadataId"}}]}},{"kind":"Field","name":{"kind":"Name","value":"defaultValue"}},{"kind":"Field","name":{"kind":"Name","value":"options"}},{"kind":"Field","name":{"kind":"Name","value":"relationDefinition"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"relationId"}},{"kind":"Field","name":{"kind":"Name","value":"direction"}},{"kind":"Field","name":{"kind":"Name","value":"sourceObjectMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}}]}},{"kind":"Field","name":{"kind":"Name","value":"sourceFieldMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"targetObjectMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}}]}},{"kind":"Field","name":{"kind":"Name","value":"targetFieldMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"pageInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hasNextPage"}},{"kind":"Field","name":{"kind":"Name","value":"hasPreviousPage"}},{"kind":"Field","name":{"kind":"Name","value":"startCursor"}},{"kind":"Field","name":{"kind":"Name","value":"endCursor"}}]}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"pageInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hasNextPage"}},{"kind":"Field","name":{"kind":"Name","value":"hasPreviousPage"}},{"kind":"Field","name":{"kind":"Name","value":"startCursor"}},{"kind":"Field","name":{"kind":"Name","value":"endCursor"}}]}}]}}]}}]} as unknown as DocumentNode; export const CreateOneServerlessFunctionItemDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateOneServerlessFunctionItem"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateServerlessFunctionInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createOneServerlessFunction"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ServerlessFunctionFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ServerlessFunctionFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ServerlessFunction"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"sourceCodeHash"}},{"kind":"Field","name":{"kind":"Name","value":"sourceCodeFullPath"}},{"kind":"Field","name":{"kind":"Name","value":"runtime"}},{"kind":"Field","name":{"kind":"Name","value":"syncStatus"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode; export const DeleteOneServerlessFunctionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteOneServerlessFunction"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DeleteServerlessFunctionInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteOneServerlessFunction"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ServerlessFunctionFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ServerlessFunctionFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ServerlessFunction"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"sourceCodeHash"}},{"kind":"Field","name":{"kind":"Name","value":"sourceCodeFullPath"}},{"kind":"Field","name":{"kind":"Name","value":"runtime"}},{"kind":"Field","name":{"kind":"Name","value":"syncStatus"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode; export const ExecuteOneServerlessFunctionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ExecuteOneServerlessFunction"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"payload"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"executeOneServerlessFunction"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"payload"},"value":{"kind":"Variable","name":{"kind":"Name","value":"payload"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"error"}}]}}]}}]} as unknown as DocumentNode; diff --git a/packages/twenty-front/src/modules/object-metadata/graphql/queries.ts b/packages/twenty-front/src/modules/object-metadata/graphql/queries.ts index 729e1f96bf53..c040189d1198 100644 --- a/packages/twenty-front/src/modules/object-metadata/graphql/queries.ts +++ b/packages/twenty-front/src/modules/object-metadata/graphql/queries.ts @@ -22,6 +22,7 @@ export const FIND_MANY_OBJECT_METADATA_ITEMS = gql` isSystem createdAt updatedAt + softDelete labelIdentifierFieldMetadataId imageIdentifierFieldMetadataId fields(paging: { first: 1000 }, filter: $fieldFilter) { diff --git a/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts b/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts index c5f22c9f640e..32e259271e00 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts @@ -68,7 +68,10 @@ export const useFindManyRecords = ({ useQuery(findManyRecordsQuery, { skip: skip || !objectMetadataItem || !currentWorkspaceMember, variables: { - filter, + filter: { + ...filter, + ...(objectMetadataItem.softDelete ? { deletedAt: null } : {}), + }, orderBy, lastCursor: cursorFilter?.cursor ?? undefined, limit: cursorFilter?.limit ?? limit, diff --git a/packages/twenty-server/package.json b/packages/twenty-server/package.json index abcab3e11298..4b80f49e6871 100644 --- a/packages/twenty-server/package.json +++ b/packages/twenty-server/package.json @@ -11,7 +11,8 @@ "command:prod": "node dist/src/command/command", "worker:prod": "node dist/src/queue-worker/queue-worker", "database:init:prod": "npx ts-node ./scripts/setup-db.ts && yarn database:migrate:prod", - "database:migrate:prod": "npx -y typeorm migration:run -d dist/src/database/typeorm/metadata/metadata.datasource && npx -y typeorm migration:run -d dist/src/database/typeorm/core/core.datasource" + "database:migrate:prod": "npx -y typeorm migration:run -d dist/src/database/typeorm/metadata/metadata.datasource && npx -y typeorm migration:run -d dist/src/database/typeorm/core/core.datasource", + "typeorm": "../../node_modules/typeorm/.bin/typeorm" }, "dependencies": { "@graphql-yoga/nestjs": "patch:@graphql-yoga/nestjs@2.1.0#./patches/@graphql-yoga-nestjs-npm-2.1.0-cb509e6047.patch", diff --git a/packages/twenty-server/src/database/typeorm/metadata/migrations/1723038077987-addSoftDelete.ts b/packages/twenty-server/src/database/typeorm/metadata/migrations/1723038077987-addSoftDelete.ts new file mode 100644 index 000000000000..0aca8e67d56b --- /dev/null +++ b/packages/twenty-server/src/database/typeorm/metadata/migrations/1723038077987-addSoftDelete.ts @@ -0,0 +1,17 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class AddSoftDelete1723038077987 implements MigrationInterface { + name = 'AddSoftDelete1723038077987'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "metadata"."objectMetadata" ADD "softDelete" boolean`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "metadata"."objectMetadata" DROP COLUMN "softDelete"`, + ); + } +} diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts index 18a55038861f..4665ec3fc998 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts @@ -540,6 +540,7 @@ export class WorkspaceQueryRunnerService { options: WorkspaceQueryRunnerOptions, ): Promise { const { authContext, objectMetadataItem } = options; + let query: string; assertMutationNotOnRemoteObject(objectMetadataItem); @@ -555,21 +556,35 @@ export class WorkspaceQueryRunnerService { args, ); - const query = await this.workspaceQueryBuilderFactory.deleteMany( - hookedArgs, - { + if (objectMetadataItem.softDelete) { + query = await this.workspaceQueryBuilderFactory.updateMany( + { + filter: hookedArgs.filter, + data: { + deletedAt: new Date().toISOString(), + }, + }, + { + ...options, + atMost: maximumRecordAffected, + }, + ); + } else { + query = await this.workspaceQueryBuilderFactory.deleteMany(hookedArgs, { ...options, atMost: maximumRecordAffected, - }, - ); + }); + } const result = await this.execute(query, authContext.workspace.id); + console.log('result', JSON.stringify(result, null, 2)); + const parsedResults = ( await this.parseResult>( result, objectMetadataItem, - 'deleteFrom', + objectMetadataItem.softDelete ? 'update' : 'deleteFrom', authContext.workspace.id, ) )?.records; @@ -606,6 +621,7 @@ export class WorkspaceQueryRunnerService { authContext.workspace.id, objectMetadataItem.nameSingular, ); + let query: string; assertMutationNotOnRemoteObject(objectMetadataItem); assertIsValidUuid(args.id); @@ -618,10 +634,22 @@ export class WorkspaceQueryRunnerService { args, ); - const query = await this.workspaceQueryBuilderFactory.deleteOne( - hookedArgs, - options, - ); + if (objectMetadataItem.softDelete) { + query = await this.workspaceQueryBuilderFactory.updateOne( + { + id: hookedArgs.id, + data: { + deletedAt: new Date().toISOString(), + }, + }, + options, + ); + } else { + query = await this.workspaceQueryBuilderFactory.deleteOne( + hookedArgs, + options, + ); + } const existingRecord = await repository.findOne({ where: { id: args.id }, @@ -633,7 +661,7 @@ export class WorkspaceQueryRunnerService { await this.parseResult>( result, objectMetadataItem, - 'deleteFrom', + objectMetadataItem.softDelete ? 'update' : 'deleteFrom', authContext.workspace.id, ) )?.records; diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface.ts index 8d805dfe4a03..23e14d23dfff 100644 --- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface.ts +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface.ts @@ -20,4 +20,5 @@ export interface ObjectMetadataInterface { isAuditLogged: boolean; labelIdentifierFieldMetadataId?: string | null; imageIdentifierFieldMetadataId?: string | null; + softDelete?: boolean | null; } diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/dtos/object-metadata.dto.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/dtos/object-metadata.dto.ts index 217bc5e89217..6db880d8258e 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/dtos/object-metadata.dto.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/dtos/object-metadata.dto.ts @@ -63,6 +63,9 @@ export class ObjectMetadataDTO { @FilterableField() isSystem: boolean; + @FilterableField({ nullable: true }) + softDelete: boolean; + @HideField() workspaceId: string; diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts index 3d550b02fe5d..5b31550aa04a 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts @@ -69,6 +69,9 @@ export class ObjectMetadataEntity implements ObjectMetadataInterface { @Column({ default: true }) isAuditLogged: boolean; + @Column({ nullable: true, type: 'boolean' }) + softDelete?: boolean | null; + @Column({ nullable: true, type: 'uuid' }) labelIdentifierFieldMetadataId?: string | null; diff --git a/packages/twenty-server/src/engine/twenty-orm/base.workspace-entity.ts b/packages/twenty-server/src/engine/twenty-orm/base.workspace-entity.ts index f7e430a8d6b9..8184620b98a9 100644 --- a/packages/twenty-server/src/engine/twenty-orm/base.workspace-entity.ts +++ b/packages/twenty-server/src/engine/twenty-orm/base.workspace-entity.ts @@ -1,5 +1,6 @@ import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator'; +import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; import { WorkspaceIsPimaryField } from 'src/engine/twenty-orm/decorators/workspace-is-primary-field.decorator'; import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; import { BASE_OBJECT_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; @@ -36,4 +37,14 @@ export abstract class BaseWorkspaceEntity { defaultValue: 'now', }) updatedAt: Date; + + @WorkspaceField({ + standardId: BASE_OBJECT_STANDARD_FIELD_IDS.deletedAt, + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + }) + @WorkspaceIsNullable() + deletedAt?: Date | null; } diff --git a/packages/twenty-server/src/engine/twenty-orm/custom.workspace-entity.ts b/packages/twenty-server/src/engine/twenty-orm/custom.workspace-entity.ts index 5fd099f02531..52b56fe8a503 100644 --- a/packages/twenty-server/src/engine/twenty-orm/custom.workspace-entity.ts +++ b/packages/twenty-server/src/engine/twenty-orm/custom.workspace-entity.ts @@ -21,7 +21,9 @@ import { NoteTargetWorkspaceEntity } from 'src/modules/note/standard-objects/not import { TaskTargetWorkspaceEntity } from 'src/modules/task/standard-objects/task-target.workspace-entity'; import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity'; -@WorkspaceCustomObject() +@WorkspaceCustomObject({ + softDelete: true, +}) export class CustomWorkspaceEntity extends BaseWorkspaceEntity { @WorkspaceField({ standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.name, @@ -57,6 +59,16 @@ export class CustomWorkspaceEntity extends BaseWorkspaceEntity { }) createdBy: ActorMetadata; + @WorkspaceField({ + standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.deletedAt, + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + }) + @WorkspaceIsNullable() + deletedAt?: Date | null; + @WorkspaceRelation({ standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.activityTargets, label: 'Activities', diff --git a/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-custom-object.decorator.ts b/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-custom-object.decorator.ts index 17f6ef526b31..8f1af61835cd 100644 --- a/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-custom-object.decorator.ts +++ b/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-custom-object.decorator.ts @@ -1,7 +1,13 @@ import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage'; import { TypedReflect } from 'src/utils/typed-reflect'; -export function WorkspaceCustomObject(): ClassDecorator { +interface WorkspaceCustomEntityOptions { + softDelete?: boolean; +} + +export function WorkspaceCustomObject( + options: WorkspaceCustomEntityOptions = {}, +): ClassDecorator { return (target) => { const gate = TypedReflect.getMetadata( 'workspace:gate-metadata-args', @@ -11,6 +17,7 @@ export function WorkspaceCustomObject(): ClassDecorator { metadataArgsStorage.addExtendedEntities({ target, gate, + softDelete: options.softDelete, }); }; } diff --git a/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-entity.decorator.ts b/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-entity.decorator.ts index 5e56de14008c..3b9e5b6f1d66 100644 --- a/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-entity.decorator.ts +++ b/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-entity.decorator.ts @@ -12,6 +12,7 @@ interface WorkspaceEntityOptions { icon?: string; labelIdentifierStandardId?: string; imageIdentifierStandardId?: string; + softDelete?: boolean; } export function WorkspaceEntity( @@ -47,6 +48,7 @@ export function WorkspaceEntity( isAuditLogged, isSystem, gate, + softDelete: options.softDelete, }); }; } diff --git a/packages/twenty-server/src/engine/twenty-orm/factories/entity-schema-column.factory.ts b/packages/twenty-server/src/engine/twenty-orm/factories/entity-schema-column.factory.ts index d85282c6293d..251e3058d778 100644 --- a/packages/twenty-server/src/engine/twenty-orm/factories/entity-schema-column.factory.ts +++ b/packages/twenty-server/src/engine/twenty-orm/factories/entity-schema-column.factory.ts @@ -22,12 +22,18 @@ type EntitySchemaColumnMap = { export class EntitySchemaColumnFactory { create( fieldMetadataCollection: FieldMetadataEntity[], + softDelete: boolean, ): EntitySchemaColumnMap { let entitySchemaColumnMap: EntitySchemaColumnMap = {}; for (const fieldMetadata of fieldMetadataCollection) { const key = fieldMetadata.name; + // Skip deletedAt column if soft delete is not enabled + if (!softDelete && key === 'deletedAt') { + continue; + } + if (isRelationFieldMetadataType(fieldMetadata.type)) { const relationMetadata = fieldMetadata.fromRelationMetadata ?? diff --git a/packages/twenty-server/src/engine/twenty-orm/factories/entity-schema.factory.ts b/packages/twenty-server/src/engine/twenty-orm/factories/entity-schema.factory.ts index 14564a02920a..f6c9c04d4be1 100644 --- a/packages/twenty-server/src/engine/twenty-orm/factories/entity-schema.factory.ts +++ b/packages/twenty-server/src/engine/twenty-orm/factories/entity-schema.factory.ts @@ -21,6 +21,7 @@ export class EntitySchemaFactory { ): Promise { const columns = this.entitySchemaColumnFactory.create( objectMetadata.fields, + objectMetadata.softDelete ?? false, ); const relations = await this.entitySchemaRelationFactory.create( diff --git a/packages/twenty-server/src/engine/twenty-orm/interfaces/workspace-entity-metadata-args.interface.ts b/packages/twenty-server/src/engine/twenty-orm/interfaces/workspace-entity-metadata-args.interface.ts index ac10ea898dd2..0f506c5e25a1 100644 --- a/packages/twenty-server/src/engine/twenty-orm/interfaces/workspace-entity-metadata-args.interface.ts +++ b/packages/twenty-server/src/engine/twenty-orm/interfaces/workspace-entity-metadata-args.interface.ts @@ -54,12 +54,15 @@ export interface WorkspaceEntityMetadataArgs { /** * Label identifier. */ - readonly labelIdentifierStandardId: string | null; /** * Image identifier. */ - readonly imageIdentifierStandardId: string | null; + + /** + * Enable soft delete. + */ + readonly softDelete?: boolean; } diff --git a/packages/twenty-server/src/engine/twenty-orm/interfaces/workspace-extended-entity-metadata-args.interface.ts b/packages/twenty-server/src/engine/twenty-orm/interfaces/workspace-extended-entity-metadata-args.interface.ts index 12706f004849..fe29d8c15e86 100644 --- a/packages/twenty-server/src/engine/twenty-orm/interfaces/workspace-extended-entity-metadata-args.interface.ts +++ b/packages/twenty-server/src/engine/twenty-orm/interfaces/workspace-extended-entity-metadata-args.interface.ts @@ -13,4 +13,9 @@ export interface WorkspaceExtendedEntityMetadataArgs { * Entity gate. */ readonly gate?: Gate; + + /** + * Enable soft delete. + */ + readonly softDelete?: boolean; } diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts index 38e43ffdc65f..f459a98836ff 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts @@ -53,6 +53,7 @@ export const BASE_OBJECT_STANDARD_FIELD_IDS = { id: '20202020-eda0-4cee-9577-3eb357e3c22b', createdAt: '20202020-66ac-4502-9975-e4d959c50311', updatedAt: '20202020-d767-4622-bdcf-d8a084834d86', + deletedAt: '20202020-b9a7-48d8-8387-b9a3090a50ec', }; export const BLOCKLIST_STANDARD_FIELD_IDS = { @@ -443,6 +444,7 @@ export const CUSTOM_OBJECT_STANDARD_FIELD_IDS = { name: '20202020-ba07-4ffd-ba63-009491f5749c', position: '20202020-c2bd-4e16-bb9a-c8b0411bf49d', createdBy: '20202020-be0e-4971-865b-32ca87cbb315', + deletedAt: '20202020-7857-4ff5-8cdb-1b21482bc305', activityTargets: '20202020-7f42-40ae-b96c-c8a61acc83bf', noteTargets: '20202020-01fd-4f37-99dc-9427a444018a', taskTargets: '20202020-0860-4566-b865-bff3c626c303', diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/factories/standard-field.factory.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/factories/standard-field.factory.ts index 44ba0da72150..a54b77c38b96 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/factories/standard-field.factory.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/factories/standard-field.factory.ts @@ -150,6 +150,14 @@ export class StandardFieldFactory { return []; } + if ( + workspaceFieldMetadataArgs.name === 'deletedAt' && + workspaceEntityMetadataArgs && + !workspaceEntityMetadataArgs.softDelete + ) { + return []; + } + return [ { type: workspaceFieldMetadataArgs.type, diff --git a/packages/twenty-server/src/modules/company/standard-objects/company.workspace-entity.ts b/packages/twenty-server/src/modules/company/standard-objects/company.workspace-entity.ts index 3947cd94b92b..75c76db3cfa8 100644 --- a/packages/twenty-server/src/modules/company/standard-objects/company.workspace-entity.ts +++ b/packages/twenty-server/src/modules/company/standard-objects/company.workspace-entity.ts @@ -40,6 +40,7 @@ import { AddressMetadata } from 'src/engine/metadata-modules/field-metadata/comp description: 'A company', icon: 'IconBuildingSkyscraper', labelIdentifierStandardId: COMPANY_STANDARD_FIELD_IDS.name, + softDelete: true, }) export class CompanyWorkspaceEntity extends BaseWorkspaceEntity { @WorkspaceField({ diff --git a/packages/twenty-server/src/modules/note/standard-objects/note-target.workspace-entity.ts b/packages/twenty-server/src/modules/note/standard-objects/note-target.workspace-entity.ts index f4f260cea167..674fab9718a9 100644 --- a/packages/twenty-server/src/modules/note/standard-objects/note-target.workspace-entity.ts +++ b/packages/twenty-server/src/modules/note/standard-objects/note-target.workspace-entity.ts @@ -23,6 +23,7 @@ import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/perso labelPlural: 'Note Targets', description: 'A note target', icon: 'IconCheckbox', + softDelete: true, }) @WorkspaceIsSystem() export class NoteTargetWorkspaceEntity extends BaseWorkspaceEntity { diff --git a/packages/twenty-server/src/modules/note/standard-objects/note.workspace-entity.ts b/packages/twenty-server/src/modules/note/standard-objects/note.workspace-entity.ts index 7b5c9611885e..a8aa5b9342c4 100644 --- a/packages/twenty-server/src/modules/note/standard-objects/note.workspace-entity.ts +++ b/packages/twenty-server/src/modules/note/standard-objects/note.workspace-entity.ts @@ -30,6 +30,7 @@ import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-o description: 'A note', icon: 'IconNotes', labelIdentifierStandardId: NOTE_STANDARD_FIELD_IDS.title, + softDelete: true, }) export class NoteWorkspaceEntity extends BaseWorkspaceEntity { @WorkspaceField({ diff --git a/packages/twenty-server/src/modules/opportunity/standard-objects/opportunity.workspace-entity.ts b/packages/twenty-server/src/modules/opportunity/standard-objects/opportunity.workspace-entity.ts index 142b000b9a0d..3acd4dc88ebd 100644 --- a/packages/twenty-server/src/modules/opportunity/standard-objects/opportunity.workspace-entity.ts +++ b/packages/twenty-server/src/modules/opportunity/standard-objects/opportunity.workspace-entity.ts @@ -39,6 +39,7 @@ import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-o description: 'An opportunity', icon: 'IconTargetArrow', labelIdentifierStandardId: OPPORTUNITY_STANDARD_FIELD_IDS.name, + softDelete: true, }) @WorkspaceIsNotAuditLogged() export class OpportunityWorkspaceEntity extends BaseWorkspaceEntity { diff --git a/packages/twenty-server/src/modules/person/standard-objects/person.workspace-entity.ts b/packages/twenty-server/src/modules/person/standard-objects/person.workspace-entity.ts index 46300a1451cc..4da65896f7fd 100644 --- a/packages/twenty-server/src/modules/person/standard-objects/person.workspace-entity.ts +++ b/packages/twenty-server/src/modules/person/standard-objects/person.workspace-entity.ts @@ -40,6 +40,7 @@ import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-o icon: 'IconUser', labelIdentifierStandardId: PERSON_STANDARD_FIELD_IDS.name, imageIdentifierStandardId: PERSON_STANDARD_FIELD_IDS.avatarUrl, + softDelete: true, }) export class PersonWorkspaceEntity extends BaseWorkspaceEntity { @WorkspaceField({ diff --git a/packages/twenty-server/src/modules/task/standard-objects/task-target.workspace-entity.ts b/packages/twenty-server/src/modules/task/standard-objects/task-target.workspace-entity.ts index 8f9cac2acaec..394fcbb0c753 100644 --- a/packages/twenty-server/src/modules/task/standard-objects/task-target.workspace-entity.ts +++ b/packages/twenty-server/src/modules/task/standard-objects/task-target.workspace-entity.ts @@ -23,6 +23,7 @@ import { TaskWorkspaceEntity } from 'src/modules/task/standard-objects/task.work labelPlural: 'Task Targets', description: 'An task target', icon: 'IconCheckbox', + softDelete: true, }) @WorkspaceIsSystem() export class TaskTargetWorkspaceEntity extends BaseWorkspaceEntity { diff --git a/packages/twenty-server/src/modules/task/standard-objects/task.workspace-entity.ts b/packages/twenty-server/src/modules/task/standard-objects/task.workspace-entity.ts index 03f0c88002e3..d087d69c6fbd 100644 --- a/packages/twenty-server/src/modules/task/standard-objects/task.workspace-entity.ts +++ b/packages/twenty-server/src/modules/task/standard-objects/task.workspace-entity.ts @@ -32,6 +32,7 @@ import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/sta description: 'A task', icon: 'IconCheckbox', labelIdentifierStandardId: TASK_STANDARD_FIELD_IDS.title, + softDelete: true, }) export class TaskWorkspaceEntity extends BaseWorkspaceEntity { @WorkspaceField({ From 1b3b1d4f17eb85decade96778a0d29f0d4da00f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Magrin?= Date: Thu, 8 Aug 2024 10:31:05 +0200 Subject: [PATCH 02/22] feat: soft delete --- packages/twenty-front/project.json | 2 +- .../src/generated-metadata/gql.ts | 4 ++-- .../src/generated-metadata/graphql.ts | 6 ++---- .../object-metadata/graphql/queries.ts | 1 - .../object-record/hooks/useFindManyRecords.ts | 5 +---- .../interfaces/record.interface.ts | 1 + .../workspace-query-runner.service.ts | 20 +++++++++++++++++-- .../dtos/object-metadata.dto.ts | 3 --- 8 files changed, 25 insertions(+), 17 deletions(-) diff --git a/packages/twenty-front/project.json b/packages/twenty-front/project.json index 91eee0796542..636fd29af6a6 100644 --- a/packages/twenty-front/project.json +++ b/packages/twenty-front/project.json @@ -119,7 +119,7 @@ }, "graphql:generate": { "executor": "nx:run-commands", - "defaultConfiguration": "metadata", + "defaultConfiguration": "data", "options": { "cwd": "{projectRoot}", "command": "dotenv cross-var graphql-codegen -- --config={args.config}" diff --git a/packages/twenty-front/src/generated-metadata/gql.ts b/packages/twenty-front/src/generated-metadata/gql.ts index e0c7dc125a3a..1aca61a965d2 100644 --- a/packages/twenty-front/src/generated-metadata/gql.ts +++ b/packages/twenty-front/src/generated-metadata/gql.ts @@ -32,7 +32,7 @@ const documents = { "\n mutation DeleteOneObjectMetadataItem($idToDelete: UUID!) {\n deleteOneObject(input: { id: $idToDelete }) {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isActive\n createdAt\n updatedAt\n labelIdentifierFieldMetadataId\n imageIdentifierFieldMetadataId\n }\n }\n": types.DeleteOneObjectMetadataItemDocument, "\n mutation DeleteOneFieldMetadataItem($idToDelete: UUID!) {\n deleteOneField(input: { id: $idToDelete }) {\n id\n type\n name\n label\n description\n icon\n isCustom\n isActive\n isNullable\n createdAt\n updatedAt\n }\n }\n": types.DeleteOneFieldMetadataItemDocument, "\n mutation DeleteOneRelationMetadataItem($idToDelete: UUID!) {\n deleteOneRelation(input: { id: $idToDelete }) {\n id\n }\n }\n": types.DeleteOneRelationMetadataItemDocument, - "\n query ObjectMetadataItems(\n $objectFilter: objectFilter\n $fieldFilter: fieldFilter\n ) {\n objects(paging: { first: 1000 }, filter: $objectFilter) {\n edges {\n node {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isRemote\n isActive\n isSystem\n createdAt\n updatedAt\n softDelete\n labelIdentifierFieldMetadataId\n imageIdentifierFieldMetadataId\n fields(paging: { first: 1000 }, filter: $fieldFilter) {\n edges {\n node {\n id\n type\n name\n label\n description\n icon\n isCustom\n isActive\n isSystem\n isNullable\n createdAt\n updatedAt\n fromRelationMetadata {\n id\n relationType\n toObjectMetadata {\n id\n dataSourceId\n nameSingular\n namePlural\n isSystem\n isRemote\n }\n toFieldMetadataId\n }\n toRelationMetadata {\n id\n relationType\n fromObjectMetadata {\n id\n dataSourceId\n nameSingular\n namePlural\n isSystem\n isRemote\n }\n fromFieldMetadataId\n }\n defaultValue\n options\n relationDefinition {\n relationId\n direction\n sourceObjectMetadata {\n id\n nameSingular\n namePlural\n }\n sourceFieldMetadata {\n id\n name\n }\n targetObjectMetadata {\n id\n nameSingular\n namePlural\n }\n targetFieldMetadata {\n id\n name\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n": types.ObjectMetadataItemsDocument, + "\n query ObjectMetadataItems(\n $objectFilter: objectFilter\n $fieldFilter: fieldFilter\n ) {\n objects(paging: { first: 1000 }, filter: $objectFilter) {\n edges {\n node {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isRemote\n isActive\n isSystem\n createdAt\n updatedAt\n labelIdentifierFieldMetadataId\n imageIdentifierFieldMetadataId\n fields(paging: { first: 1000 }, filter: $fieldFilter) {\n edges {\n node {\n id\n type\n name\n label\n description\n icon\n isCustom\n isActive\n isSystem\n isNullable\n createdAt\n updatedAt\n fromRelationMetadata {\n id\n relationType\n toObjectMetadata {\n id\n dataSourceId\n nameSingular\n namePlural\n isSystem\n isRemote\n }\n toFieldMetadataId\n }\n toRelationMetadata {\n id\n relationType\n fromObjectMetadata {\n id\n dataSourceId\n nameSingular\n namePlural\n isSystem\n isRemote\n }\n fromFieldMetadataId\n }\n defaultValue\n options\n relationDefinition {\n relationId\n direction\n sourceObjectMetadata {\n id\n nameSingular\n namePlural\n }\n sourceFieldMetadata {\n id\n name\n }\n targetObjectMetadata {\n id\n nameSingular\n namePlural\n }\n targetFieldMetadata {\n id\n name\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n": types.ObjectMetadataItemsDocument, "\n fragment ServerlessFunctionFields on ServerlessFunction {\n id\n name\n description\n sourceCodeHash\n sourceCodeFullPath\n runtime\n syncStatus\n createdAt\n updatedAt\n }\n": types.ServerlessFunctionFieldsFragmentDoc, "\n \n mutation CreateOneServerlessFunctionItem(\n $input: CreateServerlessFunctionInput!\n ) {\n createOneServerlessFunction(input: $input) {\n ...ServerlessFunctionFields\n }\n }\n": types.CreateOneServerlessFunctionItemDocument, "\n \n mutation DeleteOneServerlessFunction($input: DeleteServerlessFunctionInput!) {\n deleteOneServerlessFunction(input: $input) {\n ...ServerlessFunctionFields\n }\n }\n": types.DeleteOneServerlessFunctionDocument, @@ -135,7 +135,7 @@ export function graphql(source: "\n mutation DeleteOneRelationMetadataItem($idT /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query ObjectMetadataItems(\n $objectFilter: objectFilter\n $fieldFilter: fieldFilter\n ) {\n objects(paging: { first: 1000 }, filter: $objectFilter) {\n edges {\n node {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isRemote\n isActive\n isSystem\n createdAt\n updatedAt\n softDelete\n labelIdentifierFieldMetadataId\n imageIdentifierFieldMetadataId\n fields(paging: { first: 1000 }, filter: $fieldFilter) {\n edges {\n node {\n id\n type\n name\n label\n description\n icon\n isCustom\n isActive\n isSystem\n isNullable\n createdAt\n updatedAt\n fromRelationMetadata {\n id\n relationType\n toObjectMetadata {\n id\n dataSourceId\n nameSingular\n namePlural\n isSystem\n isRemote\n }\n toFieldMetadataId\n }\n toRelationMetadata {\n id\n relationType\n fromObjectMetadata {\n id\n dataSourceId\n nameSingular\n namePlural\n isSystem\n isRemote\n }\n fromFieldMetadataId\n }\n defaultValue\n options\n relationDefinition {\n relationId\n direction\n sourceObjectMetadata {\n id\n nameSingular\n namePlural\n }\n sourceFieldMetadata {\n id\n name\n }\n targetObjectMetadata {\n id\n nameSingular\n namePlural\n }\n targetFieldMetadata {\n id\n name\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n"): (typeof documents)["\n query ObjectMetadataItems(\n $objectFilter: objectFilter\n $fieldFilter: fieldFilter\n ) {\n objects(paging: { first: 1000 }, filter: $objectFilter) {\n edges {\n node {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isRemote\n isActive\n isSystem\n createdAt\n updatedAt\n softDelete\n labelIdentifierFieldMetadataId\n imageIdentifierFieldMetadataId\n fields(paging: { first: 1000 }, filter: $fieldFilter) {\n edges {\n node {\n id\n type\n name\n label\n description\n icon\n isCustom\n isActive\n isSystem\n isNullable\n createdAt\n updatedAt\n fromRelationMetadata {\n id\n relationType\n toObjectMetadata {\n id\n dataSourceId\n nameSingular\n namePlural\n isSystem\n isRemote\n }\n toFieldMetadataId\n }\n toRelationMetadata {\n id\n relationType\n fromObjectMetadata {\n id\n dataSourceId\n nameSingular\n namePlural\n isSystem\n isRemote\n }\n fromFieldMetadataId\n }\n defaultValue\n options\n relationDefinition {\n relationId\n direction\n sourceObjectMetadata {\n id\n nameSingular\n namePlural\n }\n sourceFieldMetadata {\n id\n name\n }\n targetObjectMetadata {\n id\n nameSingular\n namePlural\n }\n targetFieldMetadata {\n id\n name\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n"]; +export function graphql(source: "\n query ObjectMetadataItems(\n $objectFilter: objectFilter\n $fieldFilter: fieldFilter\n ) {\n objects(paging: { first: 1000 }, filter: $objectFilter) {\n edges {\n node {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isRemote\n isActive\n isSystem\n createdAt\n updatedAt\n labelIdentifierFieldMetadataId\n imageIdentifierFieldMetadataId\n fields(paging: { first: 1000 }, filter: $fieldFilter) {\n edges {\n node {\n id\n type\n name\n label\n description\n icon\n isCustom\n isActive\n isSystem\n isNullable\n createdAt\n updatedAt\n fromRelationMetadata {\n id\n relationType\n toObjectMetadata {\n id\n dataSourceId\n nameSingular\n namePlural\n isSystem\n isRemote\n }\n toFieldMetadataId\n }\n toRelationMetadata {\n id\n relationType\n fromObjectMetadata {\n id\n dataSourceId\n nameSingular\n namePlural\n isSystem\n isRemote\n }\n fromFieldMetadataId\n }\n defaultValue\n options\n relationDefinition {\n relationId\n direction\n sourceObjectMetadata {\n id\n nameSingular\n namePlural\n }\n sourceFieldMetadata {\n id\n name\n }\n targetObjectMetadata {\n id\n nameSingular\n namePlural\n }\n targetFieldMetadata {\n id\n name\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n"): (typeof documents)["\n query ObjectMetadataItems(\n $objectFilter: objectFilter\n $fieldFilter: fieldFilter\n ) {\n objects(paging: { first: 1000 }, filter: $objectFilter) {\n edges {\n node {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isRemote\n isActive\n isSystem\n createdAt\n updatedAt\n labelIdentifierFieldMetadataId\n imageIdentifierFieldMetadataId\n fields(paging: { first: 1000 }, filter: $fieldFilter) {\n edges {\n node {\n id\n type\n name\n label\n description\n icon\n isCustom\n isActive\n isSystem\n isNullable\n createdAt\n updatedAt\n fromRelationMetadata {\n id\n relationType\n toObjectMetadata {\n id\n dataSourceId\n nameSingular\n namePlural\n isSystem\n isRemote\n }\n toFieldMetadataId\n }\n toRelationMetadata {\n id\n relationType\n fromObjectMetadata {\n id\n dataSourceId\n nameSingular\n namePlural\n isSystem\n isRemote\n }\n fromFieldMetadataId\n }\n defaultValue\n options\n relationDefinition {\n relationId\n direction\n sourceObjectMetadata {\n id\n nameSingular\n namePlural\n }\n sourceFieldMetadata {\n id\n name\n }\n targetObjectMetadata {\n id\n nameSingular\n namePlural\n }\n targetFieldMetadata {\n id\n name\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index 86727a7cccf0..f5e61e07afd5 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -1508,7 +1508,6 @@ export type Object = { labelSingular: Scalars['String']['output']; namePlural: Scalars['String']['output']; nameSingular: Scalars['String']['output']; - softDelete?: Maybe; updatedAt: Scalars['DateTime']['output']; }; @@ -1534,7 +1533,6 @@ export type ObjectFilter = { isRemote?: InputMaybe; isSystem?: InputMaybe; or?: InputMaybe>; - softDelete?: InputMaybe; }; export type Relation = { @@ -1690,7 +1688,7 @@ export type ObjectMetadataItemsQueryVariables = Exact<{ }>; -export type ObjectMetadataItemsQuery = { __typename?: 'Query', objects: { __typename?: 'ObjectConnection', edges: Array<{ __typename?: 'objectEdge', node: { __typename?: 'object', id: any, dataSourceId: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, isCustom: boolean, isRemote: boolean, isActive: boolean, isSystem: boolean, createdAt: any, updatedAt: any, softDelete?: boolean | null, labelIdentifierFieldMetadataId?: string | null, imageIdentifierFieldMetadataId?: string | null, fields: { __typename?: 'ObjectFieldsConnection', edges: Array<{ __typename?: 'fieldEdge', node: { __typename?: 'field', id: any, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isSystem?: boolean | null, isNullable?: boolean | null, createdAt: any, updatedAt: any, defaultValue?: any | null, options?: any | null, fromRelationMetadata?: { __typename?: 'relation', id: any, relationType: RelationMetadataType, toFieldMetadataId: string, toObjectMetadata: { __typename?: 'object', id: any, dataSourceId: string, nameSingular: string, namePlural: string, isSystem: boolean, isRemote: boolean } } | null, toRelationMetadata?: { __typename?: 'relation', id: any, relationType: RelationMetadataType, fromFieldMetadataId: string, fromObjectMetadata: { __typename?: 'object', id: any, dataSourceId: string, nameSingular: string, namePlural: string, isSystem: boolean, isRemote: boolean } } | null, relationDefinition?: { __typename?: 'RelationDefinition', relationId: any, direction: RelationDefinitionType, sourceObjectMetadata: { __typename?: 'object', id: any, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'field', id: any, name: string }, targetObjectMetadata: { __typename?: 'object', id: any, nameSingular: string, namePlural: string }, targetFieldMetadata: { __typename?: 'field', id: any, name: string } } | null } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } }; +export type ObjectMetadataItemsQuery = { __typename?: 'Query', objects: { __typename?: 'ObjectConnection', edges: Array<{ __typename?: 'objectEdge', node: { __typename?: 'object', id: any, dataSourceId: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, isCustom: boolean, isRemote: boolean, isActive: boolean, isSystem: boolean, createdAt: any, updatedAt: any, labelIdentifierFieldMetadataId?: string | null, imageIdentifierFieldMetadataId?: string | null, fields: { __typename?: 'ObjectFieldsConnection', edges: Array<{ __typename?: 'fieldEdge', node: { __typename?: 'field', id: any, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isSystem?: boolean | null, isNullable?: boolean | null, createdAt: any, updatedAt: any, defaultValue?: any | null, options?: any | null, fromRelationMetadata?: { __typename?: 'relation', id: any, relationType: RelationMetadataType, toFieldMetadataId: string, toObjectMetadata: { __typename?: 'object', id: any, dataSourceId: string, nameSingular: string, namePlural: string, isSystem: boolean, isRemote: boolean } } | null, toRelationMetadata?: { __typename?: 'relation', id: any, relationType: RelationMetadataType, fromFieldMetadataId: string, fromObjectMetadata: { __typename?: 'object', id: any, dataSourceId: string, nameSingular: string, namePlural: string, isSystem: boolean, isRemote: boolean } } | null, relationDefinition?: { __typename?: 'RelationDefinition', relationId: any, direction: RelationDefinitionType, sourceObjectMetadata: { __typename?: 'object', id: any, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'field', id: any, name: string }, targetObjectMetadata: { __typename?: 'object', id: any, nameSingular: string, namePlural: string }, targetFieldMetadata: { __typename?: 'field', id: any, name: string } } | null } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } }; export type ServerlessFunctionFieldsFragment = { __typename?: 'ServerlessFunction', id: any, name: string, description?: string | null, sourceCodeHash: string, sourceCodeFullPath: string, runtime: string, syncStatus: ServerlessFunctionSyncStatus, createdAt: any, updatedAt: any }; @@ -1755,7 +1753,7 @@ export const UpdateOneObjectMetadataItemDocument = {"kind":"Document","definitio export const DeleteOneObjectMetadataItemDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteOneObjectMetadataItem"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"idToDelete"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteOneObject"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"idToDelete"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"dataSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}},{"kind":"Field","name":{"kind":"Name","value":"labelSingular"}},{"kind":"Field","name":{"kind":"Name","value":"labelPlural"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"labelIdentifierFieldMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"imageIdentifierFieldMetadataId"}}]}}]}}]} as unknown as DocumentNode; export const DeleteOneFieldMetadataItemDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteOneFieldMetadataItem"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"idToDelete"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteOneField"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"idToDelete"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"isNullable"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode; export const DeleteOneRelationMetadataItemDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteOneRelationMetadataItem"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"idToDelete"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteOneRelation"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"idToDelete"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; -export const ObjectMetadataItemsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ObjectMetadataItems"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"objectFilter"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"objectFilter"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"fieldFilter"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"fieldFilter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"objects"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"paging"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"first"},"value":{"kind":"IntValue","value":"1000"}}]}},{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"objectFilter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"dataSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}},{"kind":"Field","name":{"kind":"Name","value":"labelSingular"}},{"kind":"Field","name":{"kind":"Name","value":"labelPlural"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isRemote"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"isSystem"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"softDelete"}},{"kind":"Field","name":{"kind":"Name","value":"labelIdentifierFieldMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"imageIdentifierFieldMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"fields"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"paging"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"first"},"value":{"kind":"IntValue","value":"1000"}}]}},{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"fieldFilter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"isSystem"}},{"kind":"Field","name":{"kind":"Name","value":"isNullable"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"fromRelationMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"relationType"}},{"kind":"Field","name":{"kind":"Name","value":"toObjectMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"dataSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}},{"kind":"Field","name":{"kind":"Name","value":"isSystem"}},{"kind":"Field","name":{"kind":"Name","value":"isRemote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"toFieldMetadataId"}}]}},{"kind":"Field","name":{"kind":"Name","value":"toRelationMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"relationType"}},{"kind":"Field","name":{"kind":"Name","value":"fromObjectMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"dataSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}},{"kind":"Field","name":{"kind":"Name","value":"isSystem"}},{"kind":"Field","name":{"kind":"Name","value":"isRemote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fromFieldMetadataId"}}]}},{"kind":"Field","name":{"kind":"Name","value":"defaultValue"}},{"kind":"Field","name":{"kind":"Name","value":"options"}},{"kind":"Field","name":{"kind":"Name","value":"relationDefinition"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"relationId"}},{"kind":"Field","name":{"kind":"Name","value":"direction"}},{"kind":"Field","name":{"kind":"Name","value":"sourceObjectMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}}]}},{"kind":"Field","name":{"kind":"Name","value":"sourceFieldMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"targetObjectMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}}]}},{"kind":"Field","name":{"kind":"Name","value":"targetFieldMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"pageInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hasNextPage"}},{"kind":"Field","name":{"kind":"Name","value":"hasPreviousPage"}},{"kind":"Field","name":{"kind":"Name","value":"startCursor"}},{"kind":"Field","name":{"kind":"Name","value":"endCursor"}}]}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"pageInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hasNextPage"}},{"kind":"Field","name":{"kind":"Name","value":"hasPreviousPage"}},{"kind":"Field","name":{"kind":"Name","value":"startCursor"}},{"kind":"Field","name":{"kind":"Name","value":"endCursor"}}]}}]}}]}}]} as unknown as DocumentNode; +export const ObjectMetadataItemsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ObjectMetadataItems"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"objectFilter"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"objectFilter"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"fieldFilter"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"fieldFilter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"objects"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"paging"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"first"},"value":{"kind":"IntValue","value":"1000"}}]}},{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"objectFilter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"dataSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}},{"kind":"Field","name":{"kind":"Name","value":"labelSingular"}},{"kind":"Field","name":{"kind":"Name","value":"labelPlural"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isRemote"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"isSystem"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"labelIdentifierFieldMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"imageIdentifierFieldMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"fields"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"paging"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"first"},"value":{"kind":"IntValue","value":"1000"}}]}},{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"fieldFilter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"isSystem"}},{"kind":"Field","name":{"kind":"Name","value":"isNullable"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"fromRelationMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"relationType"}},{"kind":"Field","name":{"kind":"Name","value":"toObjectMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"dataSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}},{"kind":"Field","name":{"kind":"Name","value":"isSystem"}},{"kind":"Field","name":{"kind":"Name","value":"isRemote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"toFieldMetadataId"}}]}},{"kind":"Field","name":{"kind":"Name","value":"toRelationMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"relationType"}},{"kind":"Field","name":{"kind":"Name","value":"fromObjectMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"dataSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}},{"kind":"Field","name":{"kind":"Name","value":"isSystem"}},{"kind":"Field","name":{"kind":"Name","value":"isRemote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fromFieldMetadataId"}}]}},{"kind":"Field","name":{"kind":"Name","value":"defaultValue"}},{"kind":"Field","name":{"kind":"Name","value":"options"}},{"kind":"Field","name":{"kind":"Name","value":"relationDefinition"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"relationId"}},{"kind":"Field","name":{"kind":"Name","value":"direction"}},{"kind":"Field","name":{"kind":"Name","value":"sourceObjectMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}}]}},{"kind":"Field","name":{"kind":"Name","value":"sourceFieldMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"targetObjectMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}}]}},{"kind":"Field","name":{"kind":"Name","value":"targetFieldMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"pageInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hasNextPage"}},{"kind":"Field","name":{"kind":"Name","value":"hasPreviousPage"}},{"kind":"Field","name":{"kind":"Name","value":"startCursor"}},{"kind":"Field","name":{"kind":"Name","value":"endCursor"}}]}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"pageInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hasNextPage"}},{"kind":"Field","name":{"kind":"Name","value":"hasPreviousPage"}},{"kind":"Field","name":{"kind":"Name","value":"startCursor"}},{"kind":"Field","name":{"kind":"Name","value":"endCursor"}}]}}]}}]}}]} as unknown as DocumentNode; export const CreateOneServerlessFunctionItemDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateOneServerlessFunctionItem"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateServerlessFunctionInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createOneServerlessFunction"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ServerlessFunctionFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ServerlessFunctionFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ServerlessFunction"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"sourceCodeHash"}},{"kind":"Field","name":{"kind":"Name","value":"sourceCodeFullPath"}},{"kind":"Field","name":{"kind":"Name","value":"runtime"}},{"kind":"Field","name":{"kind":"Name","value":"syncStatus"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode; export const DeleteOneServerlessFunctionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteOneServerlessFunction"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DeleteServerlessFunctionInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteOneServerlessFunction"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ServerlessFunctionFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ServerlessFunctionFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ServerlessFunction"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"sourceCodeHash"}},{"kind":"Field","name":{"kind":"Name","value":"sourceCodeFullPath"}},{"kind":"Field","name":{"kind":"Name","value":"runtime"}},{"kind":"Field","name":{"kind":"Name","value":"syncStatus"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode; export const ExecuteOneServerlessFunctionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ExecuteOneServerlessFunction"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"payload"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"executeOneServerlessFunction"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"payload"},"value":{"kind":"Variable","name":{"kind":"Name","value":"payload"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"error"}}]}}]}}]} as unknown as DocumentNode; diff --git a/packages/twenty-front/src/modules/object-metadata/graphql/queries.ts b/packages/twenty-front/src/modules/object-metadata/graphql/queries.ts index c040189d1198..729e1f96bf53 100644 --- a/packages/twenty-front/src/modules/object-metadata/graphql/queries.ts +++ b/packages/twenty-front/src/modules/object-metadata/graphql/queries.ts @@ -22,7 +22,6 @@ export const FIND_MANY_OBJECT_METADATA_ITEMS = gql` isSystem createdAt updatedAt - softDelete labelIdentifierFieldMetadataId imageIdentifierFieldMetadataId fields(paging: { first: 1000 }, filter: $fieldFilter) { diff --git a/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts b/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts index 32e259271e00..c5f22c9f640e 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts @@ -68,10 +68,7 @@ export const useFindManyRecords = ({ useQuery(findManyRecordsQuery, { skip: skip || !objectMetadataItem || !currentWorkspaceMember, variables: { - filter: { - ...filter, - ...(objectMetadataItem.softDelete ? { deletedAt: null } : {}), - }, + filter, orderBy, lastCursor: cursorFilter?.cursor ?? undefined, limit: cursorFilter?.limit ?? limit, diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/interfaces/record.interface.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/interfaces/record.interface.ts index 32ee60f567c6..54d2c373b642 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/interfaces/record.interface.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/interfaces/record.interface.ts @@ -3,6 +3,7 @@ export interface Record { [key: string]: any; createdAt: string; updatedAt: string; + deletedAt: string | null; } export type RecordFilter = { diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts index 4665ec3fc998..d54449b11847 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts @@ -101,7 +101,15 @@ export class WorkspaceQueryRunnerService { ); const computedArgs = (await this.queryRunnerArgsFactory.create( - hookedArgs, + { + ...hookedArgs, + filter: { + ...hookedArgs.filter, + ...(objectMetadataItem.softDelete + ? { deletedAt: { is: 'NULL' } } + : {}), + }, + }, options, ResolverArgsType.FindMany, )) as FindManyResolverArgs; @@ -152,7 +160,15 @@ export class WorkspaceQueryRunnerService { ); const computedArgs = (await this.queryRunnerArgsFactory.create( - hookedArgs, + { + ...hookedArgs, + filter: { + ...hookedArgs.filter, + ...(objectMetadataItem.softDelete + ? { deletedAt: { is: 'NULL' } } + : {}), + }, + }, options, ResolverArgsType.FindOne, )) as FindOneResolverArgs; diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/dtos/object-metadata.dto.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/dtos/object-metadata.dto.ts index 6db880d8258e..217bc5e89217 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/dtos/object-metadata.dto.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/dtos/object-metadata.dto.ts @@ -63,9 +63,6 @@ export class ObjectMetadataDTO { @FilterableField() isSystem: boolean; - @FilterableField({ nullable: true }) - softDelete: boolean; - @HideField() workspaceId: string; From 9097cae0e0359537f87d8049eee56e7702c13880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Magrin?= Date: Thu, 8 Aug 2024 11:01:29 +0200 Subject: [PATCH 03/22] fix: typing issue --- .../src/engine/twenty-orm/base.workspace-entity.ts | 6 +++--- .../src/engine/twenty-orm/custom.workspace-entity.ts | 10 ---------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/packages/twenty-server/src/engine/twenty-orm/base.workspace-entity.ts b/packages/twenty-server/src/engine/twenty-orm/base.workspace-entity.ts index 8184620b98a9..08b4e6a0555d 100644 --- a/packages/twenty-server/src/engine/twenty-orm/base.workspace-entity.ts +++ b/packages/twenty-server/src/engine/twenty-orm/base.workspace-entity.ts @@ -26,7 +26,7 @@ export abstract class BaseWorkspaceEntity { icon: 'IconCalendar', defaultValue: 'now', }) - createdAt: Date; + createdAt: string; @WorkspaceField({ standardId: BASE_OBJECT_STANDARD_FIELD_IDS.updatedAt, @@ -36,7 +36,7 @@ export abstract class BaseWorkspaceEntity { icon: 'IconCalendarClock', defaultValue: 'now', }) - updatedAt: Date; + updatedAt: string; @WorkspaceField({ standardId: BASE_OBJECT_STANDARD_FIELD_IDS.deletedAt, @@ -46,5 +46,5 @@ export abstract class BaseWorkspaceEntity { icon: 'IconCalendarMinus', }) @WorkspaceIsNullable() - deletedAt?: Date | null; + deletedAt?: string | null; } diff --git a/packages/twenty-server/src/engine/twenty-orm/custom.workspace-entity.ts b/packages/twenty-server/src/engine/twenty-orm/custom.workspace-entity.ts index 52b56fe8a503..66f769e5d675 100644 --- a/packages/twenty-server/src/engine/twenty-orm/custom.workspace-entity.ts +++ b/packages/twenty-server/src/engine/twenty-orm/custom.workspace-entity.ts @@ -59,16 +59,6 @@ export class CustomWorkspaceEntity extends BaseWorkspaceEntity { }) createdBy: ActorMetadata; - @WorkspaceField({ - standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.deletedAt, - type: FieldMetadataType.DATE_TIME, - label: 'Deleted at', - description: 'Date when the record was deleted', - icon: 'IconCalendarMinus', - }) - @WorkspaceIsNullable() - deletedAt?: Date | null; - @WorkspaceRelation({ standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.activityTargets, label: 'Activities', From 6396ad4abe421ef8fd9f41a105f107111348c978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Magrin?= Date: Thu, 8 Aug 2024 11:02:24 +0200 Subject: [PATCH 04/22] fix: remove unused standard id --- .../workspace-sync-metadata/constants/standard-field-ids.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts index f459a98836ff..2e8f737ce6fd 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts @@ -444,7 +444,6 @@ export const CUSTOM_OBJECT_STANDARD_FIELD_IDS = { name: '20202020-ba07-4ffd-ba63-009491f5749c', position: '20202020-c2bd-4e16-bb9a-c8b0411bf49d', createdBy: '20202020-be0e-4971-865b-32ca87cbb315', - deletedAt: '20202020-7857-4ff5-8cdb-1b21482bc305', activityTargets: '20202020-7f42-40ae-b96c-c8a61acc83bf', noteTargets: '20202020-01fd-4f37-99dc-9427a444018a', taskTargets: '20202020-0860-4566-b865-bff3c626c303', From abe16d1591e0bcf4b9185e0a2d6e6f93132005b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Magrin?= Date: Thu, 8 Aug 2024 11:06:54 +0200 Subject: [PATCH 05/22] fix: rename soft delete in object metadata entity --- .../migrations/1723038077987-addSoftDelete.ts | 4 ++-- .../workspace-query-runner.service.ts | 14 ++++++-------- .../interfaces/object-metadata.interface.ts | 2 +- .../object-metadata/object-metadata.entity.ts | 2 +- .../twenty-orm/factories/entity-schema.factory.ts | 2 +- .../factories/standard-object.factory.ts | 1 + 6 files changed, 12 insertions(+), 13 deletions(-) diff --git a/packages/twenty-server/src/database/typeorm/metadata/migrations/1723038077987-addSoftDelete.ts b/packages/twenty-server/src/database/typeorm/metadata/migrations/1723038077987-addSoftDelete.ts index 0aca8e67d56b..c9550c95408e 100644 --- a/packages/twenty-server/src/database/typeorm/metadata/migrations/1723038077987-addSoftDelete.ts +++ b/packages/twenty-server/src/database/typeorm/metadata/migrations/1723038077987-addSoftDelete.ts @@ -5,13 +5,13 @@ export class AddSoftDelete1723038077987 implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise { await queryRunner.query( - `ALTER TABLE "metadata"."objectMetadata" ADD "softDelete" boolean`, + `ALTER TABLE "metadata"."objectMetadata" ADD "isSoftDeletable" boolean`, ); } public async down(queryRunner: QueryRunner): Promise { await queryRunner.query( - `ALTER TABLE "metadata"."objectMetadata" DROP COLUMN "softDelete"`, + `ALTER TABLE "metadata"."objectMetadata" DROP COLUMN "isSoftDeletable"`, ); } } diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts index d54449b11847..62eb7f3aa1e5 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts @@ -105,7 +105,7 @@ export class WorkspaceQueryRunnerService { ...hookedArgs, filter: { ...hookedArgs.filter, - ...(objectMetadataItem.softDelete + ...(objectMetadataItem.isSoftDeletable ? { deletedAt: { is: 'NULL' } } : {}), }, @@ -164,7 +164,7 @@ export class WorkspaceQueryRunnerService { ...hookedArgs, filter: { ...hookedArgs.filter, - ...(objectMetadataItem.softDelete + ...(objectMetadataItem.isSoftDeletable ? { deletedAt: { is: 'NULL' } } : {}), }, @@ -572,7 +572,7 @@ export class WorkspaceQueryRunnerService { args, ); - if (objectMetadataItem.softDelete) { + if (objectMetadataItem.isSoftDeletable) { query = await this.workspaceQueryBuilderFactory.updateMany( { filter: hookedArgs.filter, @@ -594,13 +594,11 @@ export class WorkspaceQueryRunnerService { const result = await this.execute(query, authContext.workspace.id); - console.log('result', JSON.stringify(result, null, 2)); - const parsedResults = ( await this.parseResult>( result, objectMetadataItem, - objectMetadataItem.softDelete ? 'update' : 'deleteFrom', + objectMetadataItem.isSoftDeletable ? 'update' : 'deleteFrom', authContext.workspace.id, ) )?.records; @@ -650,7 +648,7 @@ export class WorkspaceQueryRunnerService { args, ); - if (objectMetadataItem.softDelete) { + if (objectMetadataItem.isSoftDeletable) { query = await this.workspaceQueryBuilderFactory.updateOne( { id: hookedArgs.id, @@ -677,7 +675,7 @@ export class WorkspaceQueryRunnerService { await this.parseResult>( result, objectMetadataItem, - objectMetadataItem.softDelete ? 'update' : 'deleteFrom', + objectMetadataItem.isSoftDeletable ? 'update' : 'deleteFrom', authContext.workspace.id, ) )?.records; diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface.ts index 23e14d23dfff..2eac59ec319a 100644 --- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface.ts +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface.ts @@ -20,5 +20,5 @@ export interface ObjectMetadataInterface { isAuditLogged: boolean; labelIdentifierFieldMetadataId?: string | null; imageIdentifierFieldMetadataId?: string | null; - softDelete?: boolean | null; + isSoftDeletable?: boolean | null; } diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts index 5b31550aa04a..ebbb188669b9 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts @@ -70,7 +70,7 @@ export class ObjectMetadataEntity implements ObjectMetadataInterface { isAuditLogged: boolean; @Column({ nullable: true, type: 'boolean' }) - softDelete?: boolean | null; + isSoftDeletable?: boolean | null; @Column({ nullable: true, type: 'uuid' }) labelIdentifierFieldMetadataId?: string | null; diff --git a/packages/twenty-server/src/engine/twenty-orm/factories/entity-schema.factory.ts b/packages/twenty-server/src/engine/twenty-orm/factories/entity-schema.factory.ts index f6c9c04d4be1..249f14091139 100644 --- a/packages/twenty-server/src/engine/twenty-orm/factories/entity-schema.factory.ts +++ b/packages/twenty-server/src/engine/twenty-orm/factories/entity-schema.factory.ts @@ -21,7 +21,7 @@ export class EntitySchemaFactory { ): Promise { const columns = this.entitySchemaColumnFactory.create( objectMetadata.fields, - objectMetadata.softDelete ?? false, + objectMetadata.isSoftDeletable ?? false, ); const relations = await this.entitySchemaRelationFactory.create( diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/factories/standard-object.factory.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/factories/standard-object.factory.ts index 72e29753e992..da2c8318b8fa 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/factories/standard-object.factory.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/factories/standard-object.factory.ts @@ -54,6 +54,7 @@ export class StandardObjectFactory { isCustom: false, isRemote: false, isSystem: workspaceEntityMetadataArgs.isSystem ?? false, + isSoftDeletable: workspaceEntityMetadataArgs.softDelete ?? false, }; } } From c1b21292cce324c7a3ae4a5862c128478b13aa53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Magrin?= Date: Thu, 8 Aug 2024 11:08:48 +0200 Subject: [PATCH 06/22] fix: typo --- .../src/engine/twenty-orm/base.workspace-entity.ts | 4 ++-- .../decorators/workspace-is-primary-field.decorator.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/twenty-server/src/engine/twenty-orm/base.workspace-entity.ts b/packages/twenty-server/src/engine/twenty-orm/base.workspace-entity.ts index 08b4e6a0555d..f122f29c47a5 100644 --- a/packages/twenty-server/src/engine/twenty-orm/base.workspace-entity.ts +++ b/packages/twenty-server/src/engine/twenty-orm/base.workspace-entity.ts @@ -1,7 +1,7 @@ import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; -import { WorkspaceIsPimaryField } from 'src/engine/twenty-orm/decorators/workspace-is-primary-field.decorator'; +import { WorkspaceIsPrimaryField } from 'src/engine/twenty-orm/decorators/workspace-is-primary-field.decorator'; import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; import { BASE_OBJECT_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; @@ -14,7 +14,7 @@ export abstract class BaseWorkspaceEntity { defaultValue: 'uuid', icon: 'Icon123', }) - @WorkspaceIsPimaryField() + @WorkspaceIsPrimaryField() @WorkspaceIsSystem() id: string; diff --git a/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-is-primary-field.decorator.ts b/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-is-primary-field.decorator.ts index 5dc8a389b675..efebefa469d3 100644 --- a/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-is-primary-field.decorator.ts +++ b/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-is-primary-field.decorator.ts @@ -1,6 +1,6 @@ import { TypedReflect } from 'src/utils/typed-reflect'; -export function WorkspaceIsPimaryField(): PropertyDecorator { +export function WorkspaceIsPrimaryField(): PropertyDecorator { return (object, propertyKey) => { TypedReflect.defineMetadata( 'workspace:is-primary-field-metadata-args', From 50c57599eaa2b33d14257d7363a369c4a666bd1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Magrin?= Date: Thu, 8 Aug 2024 11:09:25 +0200 Subject: [PATCH 07/22] fix: rename workspace custom decorator --- .../src/engine/twenty-orm/custom.workspace-entity.ts | 4 ++-- ...ject.decorator.ts => workspace-custom-entity.decorator.ts} | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename packages/twenty-server/src/engine/twenty-orm/decorators/{workspace-custom-object.decorator.ts => workspace-custom-entity.decorator.ts} (93%) diff --git a/packages/twenty-server/src/engine/twenty-orm/custom.workspace-entity.ts b/packages/twenty-server/src/engine/twenty-orm/custom.workspace-entity.ts index 66f769e5d675..92085ec61151 100644 --- a/packages/twenty-server/src/engine/twenty-orm/custom.workspace-entity.ts +++ b/packages/twenty-server/src/engine/twenty-orm/custom.workspace-entity.ts @@ -8,7 +8,7 @@ import { RelationOnDeleteAction, } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; -import { WorkspaceCustomObject } from 'src/engine/twenty-orm/decorators/workspace-custom-object.decorator'; +import { WorkspaceCustomEntity } from 'src/engine/twenty-orm/decorators/workspace-custom-entity.decorator'; import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator'; import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; @@ -21,7 +21,7 @@ import { NoteTargetWorkspaceEntity } from 'src/modules/note/standard-objects/not import { TaskTargetWorkspaceEntity } from 'src/modules/task/standard-objects/task-target.workspace-entity'; import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity'; -@WorkspaceCustomObject({ +@WorkspaceCustomEntity({ softDelete: true, }) export class CustomWorkspaceEntity extends BaseWorkspaceEntity { diff --git a/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-custom-object.decorator.ts b/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-custom-entity.decorator.ts similarity index 93% rename from packages/twenty-server/src/engine/twenty-orm/decorators/workspace-custom-object.decorator.ts rename to packages/twenty-server/src/engine/twenty-orm/decorators/workspace-custom-entity.decorator.ts index 8f1af61835cd..74f1ff0295be 100644 --- a/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-custom-object.decorator.ts +++ b/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-custom-entity.decorator.ts @@ -5,7 +5,7 @@ interface WorkspaceCustomEntityOptions { softDelete?: boolean; } -export function WorkspaceCustomObject( +export function WorkspaceCustomEntity( options: WorkspaceCustomEntityOptions = {}, ): ClassDecorator { return (target) => { From 286b6c52ab113901b86544ed86bc1a80ed8584f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Magrin?= Date: Thu, 8 Aug 2024 18:17:49 +0200 Subject: [PATCH 08/22] feat: wip nested filtering --- .../factories/args-string.factory.ts | 7 +++++ .../factories/fields-string.factory.ts | 15 ++++++++-- .../factories/find-many-query.factory.ts | 9 ++++++ .../factories/find-one-query.factory.ts | 2 ++ .../factories/relation-field-alias.factory.ts | 17 +++++++++-- ...rkspace-query-builder-options.interface.ts | 1 + .../workspace-query-runner.service.ts | 30 +++++++------------ 7 files changed, 57 insertions(+), 24 deletions(-) diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/args-string.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/args-string.factory.ts index d4b8efd77ed6..562886d9d5b8 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/args-string.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/args-string.factory.ts @@ -13,10 +13,17 @@ export class ArgsStringFactory { create( initialArgs: Record | undefined, fieldMetadataCollection: FieldMetadataInterface[], + softDeletable?: boolean, ): string | null { if (!initialArgs) { return null; } + if (softDeletable) { + initialArgs.filter = { + deletedAt: { is: 'NULL' }, + ...initialArgs.filter, + }; + } let argsString = ''; const computedArgs = this.argsAliasFactory.create( initialArgs, diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/fields-string.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/fields-string.factory.ts index 1acc3778d15f..cddca887b024 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/fields-string.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/fields-string.factory.ts @@ -22,19 +22,27 @@ export class FieldsStringFactory { private readonly relationFieldAliasFactory: RelationFieldAliasFactory, ) {} - create( + async create( info: GraphQLResolveInfo, fieldMetadataCollection: FieldMetadataInterface[], objectMetadataCollection: ObjectMetadataInterface[], + withSoftDeleted?: boolean, ): Promise { const selectedFields: Partial = graphqlFields(info); - return this.createFieldsStringRecursive( + console.log('selectedFields', JSON.stringify(selectedFields, null, 2)); + + const res = await this.createFieldsStringRecursive( info, selectedFields, fieldMetadataCollection, objectMetadataCollection, + withSoftDeleted ?? false, ); + + console.log('res', res); + + return res; } async createFieldsStringRecursive( @@ -42,6 +50,7 @@ export class FieldsStringFactory { selectedFields: Partial, fieldMetadataCollection: FieldMetadataInterface[], objectMetadataCollection: ObjectMetadataInterface[], + withSoftDeleted: boolean, accumulator = '', ): Promise { const fieldMetadataMap = new Map( @@ -65,6 +74,7 @@ export class FieldsStringFactory { fieldMetadata, objectMetadataCollection, info, + withSoftDeleted, ); fieldAlias = alias; @@ -91,6 +101,7 @@ export class FieldsStringFactory { fieldValue, fieldMetadataCollection, objectMetadataCollection, + withSoftDeleted, accumulator, ); accumulator += `}\n`; diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/find-many-query.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/find-many-query.factory.ts index 476695f3c6dd..19bb616a8763 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/find-many-query.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/find-many-query.factory.ts @@ -36,6 +36,15 @@ export class FindManyQueryFactory { const argsString = this.argsStringFactory.create( args, options.fieldMetadataCollection, + !options.withSoftDeleted && !!options.objectMetadataItem.isSoftDeletable, + ); + + console.log( + 'argsString', + args, + argsString, + options.withSoftDeleted, + options.objectMetadataItem.isSoftDeletable, ); return ` diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/find-one-query.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/find-one-query.factory.ts index 80bbf3c9eea0..efef8ff69ff5 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/find-one-query.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/find-one-query.factory.ts @@ -26,10 +26,12 @@ export class FindOneQueryFactory { options.info, options.fieldMetadataCollection, options.objectMetadataCollection, + options.withSoftDeleted, ); const argsString = this.argsStringFactory.create( args, options.fieldMetadataCollection, + !options.withSoftDeleted && !!options.objectMetadataItem.isSoftDeletable, ); return ` diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/relation-field-alias.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/relation-field-alias.factory.ts index 51371924dd15..4229cc5d9fa9 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/relation-field-alias.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/relation-field-alias.factory.ts @@ -12,7 +12,6 @@ import { RelationDirection, } from 'src/engine/utils/deduce-relation-direction.util'; import { getFieldArgumentsByKey } from 'src/engine/api/graphql/workspace-query-builder/utils/get-field-arguments-by-key.util'; -import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service'; import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util'; import { computeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util'; @@ -27,7 +26,6 @@ export class RelationFieldAliasFactory { @Inject(forwardRef(() => FieldsStringFactory)) private readonly fieldsStringFactory: CircularDep, private readonly argsStringFactory: ArgsStringFactory, - private readonly objectMetadataService: ObjectMetadataService, ) {} create( @@ -36,6 +34,7 @@ export class RelationFieldAliasFactory { fieldMetadata: FieldMetadataInterface, objectMetadataCollection: ObjectMetadataInterface[], info: GraphQLResolveInfo, + withSoftDeleted?: boolean, ): Promise { if (!isRelationFieldMetadataType(fieldMetadata.type)) { throw new Error(`Field ${fieldMetadata.name} is not a relation field`); @@ -47,6 +46,7 @@ export class RelationFieldAliasFactory { fieldMetadata, objectMetadataCollection, info, + withSoftDeleted, ); } @@ -56,6 +56,7 @@ export class RelationFieldAliasFactory { fieldMetadata: FieldMetadataInterface, objectMetadataCollection: ObjectMetadataInterface[], info: GraphQLResolveInfo, + withSoftDeleted?: boolean, ): Promise { const relationMetadata = fieldMetadata.fromRelationMetadata ?? fieldMetadata.toRelationMetadata; @@ -98,9 +99,19 @@ export class RelationFieldAliasFactory { relationDirection === RelationDirection.FROM ) { const args = getFieldArgumentsByKey(info, fieldKey); + + // If the referenced object is soft deletable, we need to filter out the deleted objects + if (!withSoftDeleted && referencedObjectMetadata.isSoftDeletable) { + args.filter = { + deletedAt: { is: 'NULL' }, + ...args.filter, + }; + } + const argsString = this.argsStringFactory.create( args, referencedObjectMetadata.fields ?? [], + !withSoftDeleted && !!referencedObjectMetadata.isSoftDeletable, ); const fieldsString = await this.fieldsStringFactory.createFieldsStringRecursive( @@ -108,6 +119,7 @@ export class RelationFieldAliasFactory { fieldValue, referencedObjectMetadata.fields ?? [], objectMetadataCollection, + withSoftDeleted ?? false, ); return ` @@ -137,6 +149,7 @@ export class RelationFieldAliasFactory { fieldValue, referencedObjectMetadata.fields ?? [], objectMetadataCollection, + withSoftDeleted ?? false, ); // Otherwise it means it's a relation destination is of kind ONE diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/interfaces/workspace-query-builder-options.interface.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/interfaces/workspace-query-builder-options.interface.ts index 4f1ace4a8013..4a543cea0eda 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/interfaces/workspace-query-builder-options.interface.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/interfaces/workspace-query-builder-options.interface.ts @@ -8,4 +8,5 @@ export interface WorkspaceQueryBuilderOptions { info: GraphQLResolveInfo; fieldMetadataCollection: FieldMetadataInterface[]; objectMetadataCollection: ObjectMetadataInterface[]; + withSoftDeleted?: boolean; } diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts index 62eb7f3aa1e5..a3c927b0f92b 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts @@ -101,22 +101,17 @@ export class WorkspaceQueryRunnerService { ); const computedArgs = (await this.queryRunnerArgsFactory.create( - { - ...hookedArgs, - filter: { - ...hookedArgs.filter, - ...(objectMetadataItem.isSoftDeletable - ? { deletedAt: { is: 'NULL' } } - : {}), - }, - }, + hookedArgs, options, ResolverArgsType.FindMany, )) as FindManyResolverArgs; const query = await this.workspaceQueryBuilderFactory.findMany( computedArgs, - options, + { + ...options, + withSoftDeleted: !!args.filter?.deletedAt, + }, ); const result = await this.execute(query, authContext.workspace.id); @@ -160,22 +155,17 @@ export class WorkspaceQueryRunnerService { ); const computedArgs = (await this.queryRunnerArgsFactory.create( - { - ...hookedArgs, - filter: { - ...hookedArgs.filter, - ...(objectMetadataItem.isSoftDeletable - ? { deletedAt: { is: 'NULL' } } - : {}), - }, - }, + hookedArgs, options, ResolverArgsType.FindOne, )) as FindOneResolverArgs; const query = await this.workspaceQueryBuilderFactory.findOne( computedArgs, - options, + { + ...options, + withSoftDeleted: !!args.filter?.deletedAt, + }, ); const result = await this.execute(query, authContext.workspace.id); From 58f94b031438939633232849c7f7d840daa872d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Magrin?= Date: Fri, 9 Aug 2024 12:38:05 +0200 Subject: [PATCH 09/22] feat: soft delete front-end wip --- .../object-filter-dropdown/types/Filter.ts | 1 + .../hooks/useHandleToggleTrashColumnFilter.ts | 67 +++++++++++++++++++ .../RecordIndexOptionsDropdownContent.tsx | 15 +++++ .../views/components/SortOrFilterChip.tsx | 52 ++++++++++++-- .../views/components/VariantFilterChip.tsx | 42 ++++++++++++ .../views/components/ViewBarDetails.tsx | 51 +++++++++++++- .../src/modules/views/types/ViewFilter.ts | 1 + 7 files changed, 219 insertions(+), 10 deletions(-) create mode 100644 packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleTrashColumnFilter.ts create mode 100644 packages/twenty-front/src/modules/views/components/VariantFilterChip.tsx diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/types/Filter.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/types/Filter.ts index 862e99bed5f4..99f65ecdf72a 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/types/Filter.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/types/Filter.ts @@ -4,6 +4,7 @@ import { FilterDefinition } from './FilterDefinition'; export type Filter = { id: string; + variant?: 'default' | 'trash'; fieldMetadataId: string; value: string; displayValue: string; diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleTrashColumnFilter.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleTrashColumnFilter.ts new file mode 100644 index 000000000000..aa72ef2a99a2 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleTrashColumnFilter.ts @@ -0,0 +1,67 @@ +import { useCallback } from 'react'; +import { v4 } from 'uuid'; + +import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata'; +import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; +import { Filter } from '@/object-record/object-filter-dropdown/types/Filter'; +import { useCombinedViewFilters } from '@/views/hooks/useCombinedViewFilters'; +import { isDefined } from '~/utils/isDefined'; +import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; + +type UseHandleToggleTrashColumnFilterProps = { + objectNameSingular: string; + viewBarId: string; +}; + +export const useHandleToggleTrashColumnFilter = ({ + viewBarId, + objectNameSingular, +}: UseHandleToggleTrashColumnFilterProps) => { + const { objectMetadataItem } = useObjectMetadataItem({ + objectNameSingular, + }); + + const { columnDefinitions } = + useColumnDefinitionsFromFieldMetadata(objectMetadataItem); + + const { upsertCombinedViewFilter } = useCombinedViewFilters(viewBarId); + + const handleToggleTrashColumnFilter = useCallback(() => { + const trashFieldMetadata = objectMetadataItem.fields.find( + (field) => field.name === 'deletedAt', + ); + + if (!isDefined(trashFieldMetadata)) return; + + const correspondingColumnDefinition = columnDefinitions.find( + (columnDefinition) => + columnDefinition.fieldMetadataId === trashFieldMetadata.id, + ); + + if (!isDefined(correspondingColumnDefinition)) return; + + const filterType = getFilterTypeFromFieldType( + correspondingColumnDefinition?.type, + ); + + const newFilter: Filter = { + id: v4(), + variant: 'trash', + fieldMetadataId: trashFieldMetadata.id, + operand: ViewFilterOperand.IsNotEmpty, + displayValue: '', + definition: { + label: 'Trash', + iconName: 'IconTrash', + fieldMetadataId: trashFieldMetadata.id, + type: filterType, + }, + value: '', + }; + + upsertCombinedViewFilter(newFilter); + }, [columnDefinitions, objectMetadataItem.fields, upsertCombinedViewFilter]); + + return handleToggleTrashColumnFilter; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/components/RecordIndexOptionsDropdownContent.tsx b/packages/twenty-front/src/modules/object-record/record-index/options/components/RecordIndexOptionsDropdownContent.tsx index 29e15b03a7ac..fdd6fe6a191d 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/options/components/RecordIndexOptionsDropdownContent.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/options/components/RecordIndexOptionsDropdownContent.tsx @@ -8,6 +8,7 @@ import { IconFileImport, IconSettings, IconTag, + IconTrash, } from 'twenty-ui'; import { useObjectNamePluralFromSingular } from '@/object-metadata/hooks/useObjectNamePluralFromSingular'; @@ -37,6 +38,8 @@ import { useGetCurrentView } from '@/views/hooks/useGetCurrentView'; import { ViewType } from '@/views/types/ViewType'; import { useLocation } from 'react-router-dom'; import { useSetRecoilState } from 'recoil'; +import { useCombinedViewFilters } from '@/views/hooks/useCombinedViewFilters'; +import { useHandleToggleTrashColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleTrashColumnFilter'; type RecordIndexOptionsMenu = 'fields' | 'hiddenFields'; @@ -59,6 +62,8 @@ export const RecordIndexOptionsDropdownContent = ({ RecordIndexOptionsMenu | undefined >(undefined); + const { upsertCombinedViewFilter } = useCombinedViewFilters(); + const resetMenu = () => setCurrentMenu(undefined); const handleSelectMenu = (option: RecordIndexOptionsMenu) => { @@ -88,6 +93,11 @@ export const RecordIndexOptionsDropdownContent = ({ hiddenTableColumns, } = useRecordIndexOptionsForTable(recordIndexId); + const handleToggleTrashColumnFilter = useHandleToggleTrashColumnFilter({ + objectNameSingular, + viewBarId: recordIndexId, + }); + const { visibleBoardFields, hiddenBoardFields, @@ -153,6 +163,11 @@ export const RecordIndexOptionsDropdownContent = ({ LeftIcon={IconFileExport} text={displayedExportProgress(progress)} /> + )} {currentMenu === 'fields' && ( diff --git a/packages/twenty-front/src/modules/views/components/SortOrFilterChip.tsx b/packages/twenty-front/src/modules/views/components/SortOrFilterChip.tsx index 47106b58c1f8..87c1a404097e 100644 --- a/packages/twenty-front/src/modules/views/components/SortOrFilterChip.tsx +++ b/packages/twenty-front/src/modules/views/components/SortOrFilterChip.tsx @@ -2,12 +2,37 @@ import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { IconComponent, IconX } from 'twenty-ui'; -const StyledChip = styled.div` +const StyledChip = styled.div<{ variant: SortOrFitlerChipVariant }>` align-items: center; - background-color: ${({ theme }) => theme.accent.quaternary}; - border: 1px solid ${({ theme }) => theme.accent.tertiary}; + background-color: ${({ theme, variant }) => { + switch (variant) { + case 'delete': + return theme.background.danger; + case 'default': + default: + return theme.accent.quaternary; + } + }}; + border: 1px solid + ${({ theme, variant }) => { + switch (variant) { + case 'delete': + return theme.border.color.danger; + case 'default': + default: + return theme.accent.tertiary; + } + }}; border-radius: 4px; - color: ${({ theme }) => theme.color.blue}; + color: ${({ theme, variant }) => { + switch (variant) { + case 'delete': + return theme.color.red; + case 'default': + default: + return theme.color.blue; + } + }}; cursor: pointer; display: flex; flex-direction: row; @@ -24,7 +49,7 @@ const StyledIcon = styled.div` margin-right: ${({ theme }) => theme.spacing(1)}; `; -const StyledDelete = styled.div` +const StyledDelete = styled.div<{ variant: SortOrFitlerChipVariant }>` align-items: center; cursor: pointer; display: flex; @@ -33,7 +58,15 @@ const StyledDelete = styled.div` margin-top: 1px; user-select: none; &:hover { - background-color: ${({ theme }) => theme.accent.secondary}; + background-color: ${({ theme, variant }) => { + switch (variant) { + case 'delete': + return theme.color.red20; + case 'default': + default: + return theme.accent.secondary; + } + }}; border-radius: ${({ theme }) => theme.border.radius.sm}; } `; @@ -42,9 +75,12 @@ const StyledLabelKey = styled.div` font-weight: ${({ theme }) => theme.font.weight.medium}; `; +type SortOrFitlerChipVariant = 'default' | 'delete'; + type SortOrFilterChipProps = { labelKey?: string; labelValue: string; + variant?: SortOrFitlerChipVariant; Icon?: IconComponent; onRemove: () => void; onClick?: () => void; @@ -54,6 +90,7 @@ type SortOrFilterChipProps = { export const SortOrFilterChip = ({ labelKey, labelValue, + variant = 'default', Icon, onRemove, testId, @@ -67,7 +104,7 @@ export const SortOrFilterChip = ({ }; return ( - + {Icon && ( @@ -76,6 +113,7 @@ export const SortOrFilterChip = ({ {labelKey && {labelKey}} {labelValue} diff --git a/packages/twenty-front/src/modules/views/components/VariantFilterChip.tsx b/packages/twenty-front/src/modules/views/components/VariantFilterChip.tsx new file mode 100644 index 000000000000..43d25d1f8602 --- /dev/null +++ b/packages/twenty-front/src/modules/views/components/VariantFilterChip.tsx @@ -0,0 +1,42 @@ +import { useIcons } from 'twenty-ui'; + +import { SortOrFilterChip } from '@/views/components/SortOrFilterChip'; +import { Filter } from '@/object-record/object-filter-dropdown/types/Filter'; +import { useCombinedViewFilters } from '@/views/hooks/useCombinedViewFilters'; +import { useMemo } from 'react'; + +type VariantFilterChipProps = { + viewFilter: Filter; +}; + +export const VariantFilterChip = ({ viewFilter }: VariantFilterChipProps) => { + const { removeCombinedViewFilter } = useCombinedViewFilters(); + + const { getIcon } = useIcons(); + + const handleRemoveClick = () => { + // FixMe: Why it's not working ? + removeCombinedViewFilter(viewFilter.fieldMetadataId); + }; + + const variant = useMemo(() => { + switch (viewFilter.variant) { + case 'trash': + return 'delete'; + case 'default': + default: + return 'default'; + } + }, [viewFilter.variant]); + + return ( + + ); +}; diff --git a/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx b/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx index e51137f74461..163475dc1563 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx @@ -1,4 +1,4 @@ -import { ReactNode } from 'react'; +import { ReactNode, useMemo } from 'react'; import styled from '@emotion/styled'; import { useRecoilValue } from 'recoil'; @@ -14,6 +14,8 @@ import { useGetCurrentView } from '@/views/hooks/useGetCurrentView'; import { useResetCurrentView } from '@/views/hooks/useResetCurrentView'; import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters'; import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts'; +import { VariantFilterChip } from './VariantFilterChip'; +import { Filter } from '@/object-record/object-filter-dropdown/types/Filter'; export type ViewBarDetailsProps = { hasFilterButton?: boolean; @@ -118,6 +120,29 @@ export const ViewBarDetails = ({ const { resetCurrentView } = useResetCurrentView(); const canResetView = canPersistView && !hasFiltersQueryParams; + const { otherViewFilters, defaultViewFilters } = useMemo(() => { + if (!currentViewWithCombinedFiltersAndSorts) { + return { + otherViewFilters: [], + defaultViewFilters: [], + }; + } + + const otherViewFilters = + currentViewWithCombinedFiltersAndSorts.viewFilters.filter( + (viewFilter) => viewFilter.variant && viewFilter.variant !== 'default', + ); + const defaultViewFilters = + currentViewWithCombinedFiltersAndSorts.viewFilters.filter( + (viewFilter) => !viewFilter.variant || viewFilter.variant === 'default', + ); + + return { + otherViewFilters, + defaultViewFilters, + }; + }, [currentViewWithCombinedFiltersAndSorts]); + const handleCancelClick = () => { resetCurrentView(); }; @@ -132,10 +157,30 @@ export const ViewBarDetails = ({ return null; } + console.log( + 'currentViewWithCombinedFiltersAndSorts?.viewFilters: ', + currentViewWithCombinedFiltersAndSorts?.viewFilters, + ); + return ( + {otherViewFilters.map((viewFilter) => ( + + ))} + {!!otherViewFilters.length && + !!currentViewWithCombinedFiltersAndSorts?.viewSorts?.length && ( + + + + )} {mapViewSortsToSorts( currentViewWithCombinedFiltersAndSorts?.viewSorts ?? [], availableSortDefinitions, @@ -143,13 +188,13 @@ export const ViewBarDetails = ({ ))} {!!currentViewWithCombinedFiltersAndSorts?.viewSorts?.length && - !!currentViewWithCombinedFiltersAndSorts?.viewFilters?.length && ( + !!defaultViewFilters.length && ( )} {mapViewFiltersToFilters( - currentViewWithCombinedFiltersAndSorts?.viewFilters ?? [], + defaultViewFilters, availableFilterDefinitions, ).map((viewFilter) => ( Date: Mon, 12 Aug 2024 17:52:47 +0200 Subject: [PATCH 10/22] feat: working trash filter button --- .../RecordIndexOptionsDropdownContent.tsx | 8 +++--- .../views/components/VariantFilterChip.tsx | 3 +-- .../views/components/ViewBarDetails.tsx | 6 +---- .../factories/args-string.factory.ts | 6 +++-- .../factories/fields-string.factory.ts | 4 --- .../factories/find-many-query.factory.ts | 8 ------ .../factories/relation-field-alias.factory.ts | 8 ------ .../utils/with-soft-deleted.util.ts | 27 +++++++++++++++++++ .../workspace-query-runner.service.ts | 5 ++-- 9 files changed, 40 insertions(+), 35 deletions(-) create mode 100644 packages/twenty-server/src/engine/api/graphql/workspace-query-runner/utils/with-soft-deleted.util.ts diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/components/RecordIndexOptionsDropdownContent.tsx b/packages/twenty-front/src/modules/object-record/record-index/options/components/RecordIndexOptionsDropdownContent.tsx index fdd6fe6a191d..8a2201d8192a 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/options/components/RecordIndexOptionsDropdownContent.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/options/components/RecordIndexOptionsDropdownContent.tsx @@ -38,7 +38,6 @@ import { useGetCurrentView } from '@/views/hooks/useGetCurrentView'; import { ViewType } from '@/views/types/ViewType'; import { useLocation } from 'react-router-dom'; import { useSetRecoilState } from 'recoil'; -import { useCombinedViewFilters } from '@/views/hooks/useCombinedViewFilters'; import { useHandleToggleTrashColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleTrashColumnFilter'; type RecordIndexOptionsMenu = 'fields' | 'hiddenFields'; @@ -62,8 +61,6 @@ export const RecordIndexOptionsDropdownContent = ({ RecordIndexOptionsMenu | undefined >(undefined); - const { upsertCombinedViewFilter } = useCombinedViewFilters(); - const resetMenu = () => setCurrentMenu(undefined); const handleSelectMenu = (option: RecordIndexOptionsMenu) => { @@ -164,7 +161,10 @@ export const RecordIndexOptionsDropdownContent = ({ text={displayedExportProgress(progress)} /> { + handleToggleTrashColumnFilter(); + closeDropdown(); + }} LeftIcon={IconTrash} text="Trash" /> diff --git a/packages/twenty-front/src/modules/views/components/VariantFilterChip.tsx b/packages/twenty-front/src/modules/views/components/VariantFilterChip.tsx index 43d25d1f8602..910e8e77a053 100644 --- a/packages/twenty-front/src/modules/views/components/VariantFilterChip.tsx +++ b/packages/twenty-front/src/modules/views/components/VariantFilterChip.tsx @@ -15,8 +15,7 @@ export const VariantFilterChip = ({ viewFilter }: VariantFilterChipProps) => { const { getIcon } = useIcons(); const handleRemoveClick = () => { - // FixMe: Why it's not working ? - removeCombinedViewFilter(viewFilter.fieldMetadataId); + removeCombinedViewFilter(viewFilter.id); }; const variant = useMemo(() => { diff --git a/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx b/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx index 163475dc1563..d656eb52c197 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx @@ -157,11 +157,6 @@ export const ViewBarDetails = ({ return null; } - console.log( - 'currentViewWithCombinedFiltersAndSorts?.viewFilters: ', - currentViewWithCombinedFiltersAndSorts?.viewFilters, - ); - return ( @@ -171,6 +166,7 @@ export const ViewBarDetails = ({ key={viewFilter.fieldMetadataId} // Why do we have two types, Filter and ViewFilter? // Why key defition is already present in the Filter type and added on the fly here with mapViewFiltersToFilters ? + // Also as filter is spread into viewFilter, definition is present // FixMe: Ugly hack to make it work viewFilter={viewFilter as unknown as Filter} /> diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/args-string.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/args-string.factory.ts index 562886d9d5b8..5755fe413489 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/args-string.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/args-string.factory.ts @@ -3,6 +3,7 @@ import { Injectable } from '@nestjs/common'; import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface'; import { stringifyWithoutKeyQuote } from 'src/engine/api/graphql/workspace-query-builder/utils/stringify-without-key-quote.util'; +import { isDefined } from 'src/utils/is-defined'; import { ArgsAliasFactory } from './args-alias.factory'; @@ -20,8 +21,9 @@ export class ArgsStringFactory { } if (softDeletable) { initialArgs.filter = { - deletedAt: { is: 'NULL' }, - ...initialArgs.filter, + and: [initialArgs.filter, { deletedAt: { is: 'NULL' } }].filter( + isDefined, + ), }; } let argsString = ''; diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/fields-string.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/fields-string.factory.ts index cddca887b024..7dbf38b897c8 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/fields-string.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/fields-string.factory.ts @@ -30,8 +30,6 @@ export class FieldsStringFactory { ): Promise { const selectedFields: Partial = graphqlFields(info); - console.log('selectedFields', JSON.stringify(selectedFields, null, 2)); - const res = await this.createFieldsStringRecursive( info, selectedFields, @@ -40,8 +38,6 @@ export class FieldsStringFactory { withSoftDeleted ?? false, ); - console.log('res', res); - return res; } diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/find-many-query.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/find-many-query.factory.ts index 19bb616a8763..03391ce4cb53 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/find-many-query.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/find-many-query.factory.ts @@ -39,14 +39,6 @@ export class FindManyQueryFactory { !options.withSoftDeleted && !!options.objectMetadataItem.isSoftDeletable, ); - console.log( - 'argsString', - args, - argsString, - options.withSoftDeleted, - options.objectMetadataItem.isSoftDeletable, - ); - return ` query { ${computeObjectTargetTable(options.objectMetadataItem)}Collection${ diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/relation-field-alias.factory.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/relation-field-alias.factory.ts index 4229cc5d9fa9..00918785cc97 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/relation-field-alias.factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-builder/factories/relation-field-alias.factory.ts @@ -100,14 +100,6 @@ export class RelationFieldAliasFactory { ) { const args = getFieldArgumentsByKey(info, fieldKey); - // If the referenced object is soft deletable, we need to filter out the deleted objects - if (!withSoftDeleted && referencedObjectMetadata.isSoftDeletable) { - args.filter = { - deletedAt: { is: 'NULL' }, - ...args.filter, - }; - } - const argsString = this.argsStringFactory.create( args, referencedObjectMetadata.fields ?? [], diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/utils/with-soft-deleted.util.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/utils/with-soft-deleted.util.ts new file mode 100644 index 000000000000..b6e77d33d07b --- /dev/null +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/utils/with-soft-deleted.util.ts @@ -0,0 +1,27 @@ +import { RecordFilter } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface'; + +import { isDefined } from 'src/utils/is-defined'; + +export const withSoftDeleted = ( + filter: T | undefined | null, +): boolean => { + if (!isDefined(filter)) { + return false; + } + + if (Array.isArray(filter)) { + return filter.some((item) => withSoftDeleted(item)); + } + + for (const [key, value] of Object.entries(filter)) { + if (key === 'deletedAt') { + return true; + } + + if (typeof value === 'object') { + return withSoftDeleted(value); + } + } + + return false; +}; diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts index a3c927b0f92b..c64183f5cbc4 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts @@ -52,6 +52,7 @@ import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global. import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util'; import { isQueryTimeoutError } from 'src/engine/utils/query-timeout.util'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; +import { withSoftDeleted } from 'src/engine/api/graphql/workspace-query-runner/utils/with-soft-deleted.util'; import { PGGraphQLMutation, @@ -110,7 +111,7 @@ export class WorkspaceQueryRunnerService { computedArgs, { ...options, - withSoftDeleted: !!args.filter?.deletedAt, + withSoftDeleted: withSoftDeleted(args.filter), }, ); @@ -164,7 +165,7 @@ export class WorkspaceQueryRunnerService { computedArgs, { ...options, - withSoftDeleted: !!args.filter?.deletedAt, + withSoftDeleted: withSoftDeleted(args.filter), }, ); From 305ae89b5b0003718ed3785762d3b855604ced55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Malfait?= Date: Tue, 13 Aug 2024 17:24:40 +0200 Subject: [PATCH 11/22] Fix show page not displaying deleted records --- .../object-record/hooks/useFindOneRecord.ts | 3 +++ .../object-record/hooks/useFindOneRecordQuery.ts | 14 ++++++++++++++ ...neRecordForShowPageOperationSignatureFactory.ts | 2 +- .../record-show/hooks/useRecordShowPage.ts | 1 + .../modules/views/components/ViewBarDetails.tsx | 4 ++-- .../utils/with-soft-deleted.util.ts | 6 ++++-- 6 files changed, 25 insertions(+), 5 deletions(-) diff --git a/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecord.ts b/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecord.ts index 76c9645bd850..0ddbde032ac3 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecord.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecord.ts @@ -17,11 +17,13 @@ export const useFindOneRecord = ({ recordGqlFields, onCompleted, skip, + withSoftDeleted = false, }: ObjectMetadataItemIdentifier & { objectRecordId: string | undefined; recordGqlFields?: RecordGqlOperationGqlRecordFields; onCompleted?: (data: T) => void; skip?: boolean; + withSoftDeleted?: boolean; }) => { const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular, @@ -33,6 +35,7 @@ export const useFindOneRecord = ({ const { findOneRecordQuery } = useFindOneRecordQuery({ objectNameSingular, recordGqlFields: computedRecordGqlFields, + withSoftDeleted, }); const { data, loading, error } = useQuery<{ diff --git a/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecordQuery.ts b/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecordQuery.ts index 725ec05d9c3c..10832f03436b 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecordQuery.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecordQuery.ts @@ -10,9 +10,11 @@ import { capitalize } from '~/utils/string/capitalize'; export const useFindOneRecordQuery = ({ objectNameSingular, recordGqlFields, + withSoftDeleted = false, }: { objectNameSingular: string; recordGqlFields?: RecordGqlOperationGqlRecordFields; + withSoftDeleted?: boolean; }) => { const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular, @@ -25,6 +27,16 @@ export const useFindOneRecordQuery = ({ objectMetadataItem.nameSingular, )}($objectRecordId: ID!) { ${objectMetadataItem.nameSingular}(filter: { + ${ + withSoftDeleted + ? ` + or: [ + { deletedAt: { is: NULL } }, + { deletedAt: { is: NOT_NULL } } + ], + ` + : '' + } id: { eq: $objectRecordId } @@ -36,6 +48,8 @@ export const useFindOneRecordQuery = ({ }, `; + console.log(findOneRecordQuery); + return { findOneRecordQuery, }; diff --git a/packages/twenty-front/src/modules/object-record/record-show/graphql/operations/factories/findOneRecordForShowPageOperationSignatureFactory.ts b/packages/twenty-front/src/modules/object-record/record-show/graphql/operations/factories/findOneRecordForShowPageOperationSignatureFactory.ts index 510c1f7a5d47..f9ed0579c3ba 100644 --- a/packages/twenty-front/src/modules/object-record/record-show/graphql/operations/factories/findOneRecordForShowPageOperationSignatureFactory.ts +++ b/packages/twenty-front/src/modules/object-record/record-show/graphql/operations/factories/findOneRecordForShowPageOperationSignatureFactory.ts @@ -29,7 +29,7 @@ export const buildFindOneRecordForShowPageOperationSignature: RecordGqlOperation }, } : {}), - ...(objectMetadataItem.nameSingular === 'Note' + ...(objectMetadataItem.nameSingular === CoreObjectNameSingular.Note ? { noteTargets: { id: true, diff --git a/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowPage.ts b/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowPage.ts index 667f4eac13b5..7bdaf0b4284b 100644 --- a/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowPage.ts +++ b/packages/twenty-front/src/modules/object-record/record-show/hooks/useRecordShowPage.ts @@ -50,6 +50,7 @@ export const useRecordShowPage = ( objectRecordId, objectNameSingular, recordGqlFields: FIND_ONE_RECORD_FOR_SHOW_PAGE_OPERATION_SIGNATURE.fields, + withSoftDeleted: true, }); useEffect(() => { diff --git a/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx b/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx index d656eb52c197..6f2c9f6e7076 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx @@ -1,9 +1,10 @@ -import { ReactNode, useMemo } from 'react'; import styled from '@emotion/styled'; +import { ReactNode, useMemo } from 'react'; import { useRecoilValue } from 'recoil'; import { AddObjectFilterFromDetailsButton } from '@/object-record/object-filter-dropdown/components/AddObjectFilterFromDetailsButton'; import { ObjectFilterDropdownScope } from '@/object-record/object-filter-dropdown/scopes/ObjectFilterDropdownScope'; +import { Filter } from '@/object-record/object-filter-dropdown/types/Filter'; import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope'; import { EditableFilterDropdownButton } from '@/views/components/EditableFilterDropdownButton'; import { EditableSortChip } from '@/views/components/EditableSortChip'; @@ -15,7 +16,6 @@ import { useResetCurrentView } from '@/views/hooks/useResetCurrentView'; import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters'; import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts'; import { VariantFilterChip } from './VariantFilterChip'; -import { Filter } from '@/object-record/object-filter-dropdown/types/Filter'; export type ViewBarDetailsProps = { hasFilterButton?: boolean; diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/utils/with-soft-deleted.util.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/utils/with-soft-deleted.util.ts index b6e77d33d07b..a972782a6ad1 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/utils/with-soft-deleted.util.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/utils/with-soft-deleted.util.ts @@ -18,8 +18,10 @@ export const withSoftDeleted = ( return true; } - if (typeof value === 'object') { - return withSoftDeleted(value); + if (typeof value === 'object' && value !== null) { + if (withSoftDeleted(value)) { + return true; + } } } From 3b62a3dc96298d92db30415890a134dfb4c0c4cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Malfait?= Date: Tue, 13 Aug 2024 17:28:59 +0200 Subject: [PATCH 12/22] Rename variants --- .../object-record/hooks/useFindOneRecordQuery.ts | 2 -- .../object-filter-dropdown/types/Filter.ts | 2 +- .../hooks/useHandleToggleTrashColumnFilter.ts | 4 ++-- .../modules/views/components/SortOrFilterChip.tsx | 10 +++++----- .../views/components/VariantFilterChip.tsx | 15 ++------------- .../src/modules/views/types/ViewFilter.ts | 2 +- 6 files changed, 11 insertions(+), 24 deletions(-) diff --git a/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecordQuery.ts b/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecordQuery.ts index 10832f03436b..b67b28e52d11 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecordQuery.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useFindOneRecordQuery.ts @@ -48,8 +48,6 @@ export const useFindOneRecordQuery = ({ }, `; - console.log(findOneRecordQuery); - return { findOneRecordQuery, }; diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/types/Filter.ts b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/types/Filter.ts index 99f65ecdf72a..52ed99ac5531 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/types/Filter.ts +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/types/Filter.ts @@ -4,7 +4,7 @@ import { FilterDefinition } from './FilterDefinition'; export type Filter = { id: string; - variant?: 'default' | 'trash'; + variant?: 'default' | 'danger'; fieldMetadataId: string; value: string; displayValue: string; diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleTrashColumnFilter.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleTrashColumnFilter.ts index aa72ef2a99a2..170e912d726c 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleTrashColumnFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleTrashColumnFilter.ts @@ -6,8 +6,8 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import { Filter } from '@/object-record/object-filter-dropdown/types/Filter'; import { useCombinedViewFilters } from '@/views/hooks/useCombinedViewFilters'; -import { isDefined } from '~/utils/isDefined'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; +import { isDefined } from '~/utils/isDefined'; type UseHandleToggleTrashColumnFilterProps = { objectNameSingular: string; @@ -47,7 +47,7 @@ export const useHandleToggleTrashColumnFilter = ({ const newFilter: Filter = { id: v4(), - variant: 'trash', + variant: 'danger', fieldMetadataId: trashFieldMetadata.id, operand: ViewFilterOperand.IsNotEmpty, displayValue: '', diff --git a/packages/twenty-front/src/modules/views/components/SortOrFilterChip.tsx b/packages/twenty-front/src/modules/views/components/SortOrFilterChip.tsx index 87c1a404097e..0fab6fffdece 100644 --- a/packages/twenty-front/src/modules/views/components/SortOrFilterChip.tsx +++ b/packages/twenty-front/src/modules/views/components/SortOrFilterChip.tsx @@ -6,7 +6,7 @@ const StyledChip = styled.div<{ variant: SortOrFitlerChipVariant }>` align-items: center; background-color: ${({ theme, variant }) => { switch (variant) { - case 'delete': + case 'danger': return theme.background.danger; case 'default': default: @@ -16,7 +16,7 @@ const StyledChip = styled.div<{ variant: SortOrFitlerChipVariant }>` border: 1px solid ${({ theme, variant }) => { switch (variant) { - case 'delete': + case 'danger': return theme.border.color.danger; case 'default': default: @@ -26,7 +26,7 @@ const StyledChip = styled.div<{ variant: SortOrFitlerChipVariant }>` border-radius: 4px; color: ${({ theme, variant }) => { switch (variant) { - case 'delete': + case 'danger': return theme.color.red; case 'default': default: @@ -60,7 +60,7 @@ const StyledDelete = styled.div<{ variant: SortOrFitlerChipVariant }>` &:hover { background-color: ${({ theme, variant }) => { switch (variant) { - case 'delete': + case 'danger': return theme.color.red20; case 'default': default: @@ -75,7 +75,7 @@ const StyledLabelKey = styled.div` font-weight: ${({ theme }) => theme.font.weight.medium}; `; -type SortOrFitlerChipVariant = 'default' | 'delete'; +type SortOrFitlerChipVariant = 'default' | 'danger'; type SortOrFilterChipProps = { labelKey?: string; diff --git a/packages/twenty-front/src/modules/views/components/VariantFilterChip.tsx b/packages/twenty-front/src/modules/views/components/VariantFilterChip.tsx index 910e8e77a053..70033af530d8 100644 --- a/packages/twenty-front/src/modules/views/components/VariantFilterChip.tsx +++ b/packages/twenty-front/src/modules/views/components/VariantFilterChip.tsx @@ -1,9 +1,8 @@ import { useIcons } from 'twenty-ui'; -import { SortOrFilterChip } from '@/views/components/SortOrFilterChip'; import { Filter } from '@/object-record/object-filter-dropdown/types/Filter'; +import { SortOrFilterChip } from '@/views/components/SortOrFilterChip'; import { useCombinedViewFilters } from '@/views/hooks/useCombinedViewFilters'; -import { useMemo } from 'react'; type VariantFilterChipProps = { viewFilter: Filter; @@ -18,21 +17,11 @@ export const VariantFilterChip = ({ viewFilter }: VariantFilterChipProps) => { removeCombinedViewFilter(viewFilter.id); }; - const variant = useMemo(() => { - switch (viewFilter.variant) { - case 'trash': - return 'delete'; - case 'default': - default: - return 'default'; - } - }, [viewFilter.variant]); - return ( Date: Tue, 13 Aug 2024 21:40:22 +0200 Subject: [PATCH 13/22] Add logs and timeline activity for deletion --- .../rows/components/EventIconDynamicComponent.tsx | 5 ++++- .../main-object/components/EventRowMainObject.tsx | 11 +++++++++++ .../listeners/entity-events-to-db.listener.ts | 6 ++++-- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/rows/components/EventIconDynamicComponent.tsx b/packages/twenty-front/src/modules/activities/timelineActivities/rows/components/EventIconDynamicComponent.tsx index d1b35d7f2293..ecb7bc90d51f 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/rows/components/EventIconDynamicComponent.tsx +++ b/packages/twenty-front/src/modules/activities/timelineActivities/rows/components/EventIconDynamicComponent.tsx @@ -1,4 +1,4 @@ -import { IconCirclePlus, IconEditCircle, useIcons } from 'twenty-ui'; +import { IconCirclePlus, IconEditCircle, IconTrash, useIcons } from 'twenty-ui'; import { TimelineActivity } from '@/activities/timelineActivities/types/TimelineActivity'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; @@ -19,6 +19,9 @@ export const EventIconDynamicComponent = ({ if (eventAction === 'updated') { return ; } + if (eventAction === 'deleted') { + return ; + } const IconComponent = getIcon(linkedObjectMetadataItem?.icon); diff --git a/packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/EventRowMainObject.tsx b/packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/EventRowMainObject.tsx index f2dcc69055fa..053e9217bb66 100644 --- a/packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/EventRowMainObject.tsx +++ b/packages/twenty-front/src/modules/activities/timelineActivities/rows/main-object/components/EventRowMainObject.tsx @@ -45,6 +45,17 @@ export const EventRowMainObject = ({ /> ); } + case 'deleted': { + return ( + + + {labelIdentifierValue} + + was deleted by + {authorFullName} + + ); + } default: return null; } diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/entity-events-to-db.listener.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/entity-events-to-db.listener.ts index 0d5909471ddb..ebab1efd4ff5 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/entity-events-to-db.listener.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/entity-events-to-db.listener.ts @@ -35,8 +35,10 @@ export class EntityEventsToDbListener { return this.handle(payload); } - // @OnEvent('*.deleted') - TODO: implement when we soft delete has been implemented - // .... + @OnEvent('*.deleted') + async handleDelete(payload: ObjectRecordUpdateEvent) { + return this.handle(payload); + } // @OnEvent('*.restored') - TODO: implement when we soft delete has been implemented // .... From 56f11b2207d6cba56575ae2ff3b560b39f6e3c6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Malfait?= Date: Tue, 13 Aug 2024 21:51:05 +0200 Subject: [PATCH 14/22] Remove createdAt and deletedAt field from showpage --- .../record-show/components/RecordShowContainer.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainer.tsx b/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainer.tsx index ae6a92be30c0..d34b5850a2d6 100644 --- a/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainer.tsx @@ -126,7 +126,11 @@ export const RecordShowContainer = ({ ); const { inlineFieldMetadataItems, relationFieldMetadataItems } = groupBy( - availableFieldMetadataItems, + availableFieldMetadataItems.filter( + (fieldMetadataItem) => + fieldMetadataItem.name !== 'createdAt' && + fieldMetadataItem.name !== 'deletedAt', + ), (fieldMetadataItem) => fieldMetadataItem.type === FieldMetadataType.Relation ? 'relationFieldMetadataItems' From d8490ef1fd66a6bcf3ba072942ac925a72a6e270 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Malfait?= Date: Wed, 14 Aug 2024 15:16:26 +0200 Subject: [PATCH 15/22] Begin displaying header bar and migrate settings to new display --- .../components/InformationBanner.tsx | 28 ++-- .../InformationBannerDeletedRecord.tsx | 29 ++++ .../constants/InformationBannerHeight.ts | 1 + .../components/RecordShowContainer.tsx | 46 +++--- .../SettingsNavigationDrawerItems.tsx | 3 +- .../components/SettingsPageContainer.tsx | 18 ++- .../objects/SettingsObjectCoverImage.tsx | 3 +- ...grationDatabaseConnectionShowContainer.tsx | 3 +- ...tegrationEditDatabaseConnectionContent.tsx | 5 +- .../twenty-front/src/modules/types/AppPath.ts | 2 +- .../ui/input/button/components/Button.tsx | 1 + .../button/components/FloatingButton.tsx | 12 +- .../src/modules/ui/layout/page/PageHeader.tsx | 19 ++- .../src/modules/ui/layout/page/PagePanel.tsx | 12 +- .../ui/layout/page/SubMenuTopBarContainer.tsx | 15 +- .../bread-crumb/components/Breadcrumb.tsx | 10 +- .../src/pages/settings/Releases.tsx | 4 +- .../src/pages/settings/SettingsProfile.tsx | 10 +- .../src/pages/settings/SettingsWorkspace.tsx | 10 +- .../settings/SettingsWorkspaceMembers.tsx | 9 +- .../settings/accounts/SettingsAccounts.tsx | 7 +- .../accounts/SettingsAccountsCalendars.tsx | 11 +- .../accounts/SettingsAccountsEmails.tsx | 11 +- .../settings/accounts/SettingsNewAccount.tsx | 11 +- .../crm-migration/SettingsCRMMigration.tsx | 11 +- .../settings/data-model/SettingsNewObject.tsx | 43 ++--- .../data-model/SettingsObjectDetail.tsx | 10 +- .../data-model/SettingsObjectEdit.tsx | 36 +++-- .../data-model/SettingsObjectFieldEdit.tsx | 28 ++-- .../SettingsObjectNewFieldStep1.tsx | 47 +++--- .../data-model/SettingsObjectOverview.tsx | 17 +- .../settings/data-model/SettingsObjects.tsx | 153 ++++++++---------- .../developers/SettingsDevelopers.tsx | 14 +- .../SettingsDevelopersApiKeyDetail.tsx | 25 +-- .../api-keys/SettingsDevelopersApiKeysNew.tsx | 45 +++--- .../SettingsDevelopersWebhookDetail.tsx | 39 ++--- .../SettingsDevelopersWebhooksNew.tsx | 39 ++--- .../SettingsIntegrationDatabase.tsx | 8 +- ...tingsIntegrationEditDatabaseConnection.tsx | 13 +- ...ttingsIntegrationNewDatabaseConnection.tsx | 51 +++--- .../integrations/SettingsIntegrations.tsx | 7 +- .../components/SettingsAppearance.tsx | 10 +- .../ResetServerlessFunctionStatesEffect.tsx | 4 +- .../SettingsServerlessFunctionDetail.tsx | 47 +++--- .../SettingsServerlessFunctions.tsx | 37 +++-- .../SettingsServerlessFunctionsNew.tsx | 53 +++--- .../twenty-front/src/utils/title-utils.ts | 4 - .../src/display/banner/components/Banner.tsx | 17 +- 48 files changed, 582 insertions(+), 456 deletions(-) create mode 100644 packages/twenty-front/src/modules/information-banner/components/deleted-record/InformationBannerDeletedRecord.tsx create mode 100644 packages/twenty-front/src/modules/information-banner/constants/InformationBannerHeight.ts diff --git a/packages/twenty-front/src/modules/information-banner/components/InformationBanner.tsx b/packages/twenty-front/src/modules/information-banner/components/InformationBanner.tsx index 2581dd48934c..39d2437bf6f7 100644 --- a/packages/twenty-front/src/modules/information-banner/components/InformationBanner.tsx +++ b/packages/twenty-front/src/modules/information-banner/components/InformationBanner.tsx @@ -1,6 +1,6 @@ import { Button } from '@/ui/input/button/components/Button'; import styled from '@emotion/styled'; -import { Banner, IconComponent } from 'twenty-ui'; +import { Banner, BannerVariant, IconComponent } from 'twenty-ui'; const StyledBanner = styled(Banner)` position: absolute; @@ -14,26 +14,30 @@ const StyledText = styled.div` export const InformationBanner = ({ message, + variant = 'default', buttonTitle, buttonIcon, buttonOnClick, }: { message: string; - buttonTitle: string; + variant?: BannerVariant; + buttonTitle?: string; buttonIcon?: IconComponent; - buttonOnClick: () => void; + buttonOnClick?: () => void; }) => { return ( - + {message} -