From faeea2b887406bd6001fd5e1592fbe101e9a9a3a Mon Sep 17 00:00:00 2001 From: Thomas Trompette Date: Wed, 13 Nov 2024 15:21:40 +0100 Subject: [PATCH] Create record action (#8460) - Add create record action - Migrate all step name => action in a common folder - Separate types --- .../compute-step-output-schema-input.dto.ts | 4 +- .../resolvers/workflow-builder.resolver.ts | 2 +- .../workflow-version.workspace-entity.ts | 4 +- .../workflow-builder.workspace-service.ts | 24 ++++++---- .../factories/workflow-action.factory.ts | 10 +++-- .../interfaces/workflow-action.interface.ts | 2 +- .../types/workflow-action.type.ts | 30 ------------- .../types/workflow-step-settings.type.ts | 45 ------------------- .../code/code-action.module.ts | 12 +++++ .../code}/code.workflow-action.ts | 10 ++--- .../types/workflow-code-action-input.type.ts | 7 +++ .../workflow-code-action-settings.type.ts | 6 +++ .../send-email-action.exception.ts} | 8 ++-- .../mail-sender/send-email-action.module.ts | 17 +++++++ .../send-email.workflow-action.ts | 31 ++++++------- .../workflow-send-email-action-input.type.ts | 6 +++ ...orkflow-send-email-action-settings.type.ts | 6 +++ .../record-crud/record-crud-action.module.ts | 9 ++++ .../record-crud.workflow-action.ts | 45 +++++++++++++++++++ .../workflow-record-crud-action-input.type.ts | 31 +++++++++++++ ...rkflow-record-crud-action-settings.type.ts | 6 +++ .../types/workflow-action-result.type.ts | 0 .../types/workflow-action-settings.type.ts | 23 ++++++++++ .../types/workflow-action.type.ts | 38 ++++++++++++++++ .../workflow-executor.module.ts | 14 +++--- .../workflow-executor.workspace-service.ts | 4 +- .../types/workflow-trigger.type.ts | 2 +- 27 files changed, 268 insertions(+), 128 deletions(-) delete mode 100644 packages/twenty-server/src/modules/workflow/workflow-executor/types/workflow-action.type.ts delete mode 100644 packages/twenty-server/src/modules/workflow/workflow-executor/types/workflow-step-settings.type.ts create mode 100644 packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/code-action.module.ts rename packages/twenty-server/src/modules/{serverless/workflow-actions => workflow/workflow-executor/workflow-actions/code}/code.workflow-action.ts (80%) create mode 100644 packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/types/workflow-code-action-input.type.ts create mode 100644 packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/types/workflow-code-action-settings.type.ts rename packages/twenty-server/src/modules/{mail-sender/exceptions/mail-sender.exception.ts => workflow/workflow-executor/workflow-actions/mail-sender/exceptions/send-email-action.exception.ts} (50%) create mode 100644 packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/mail-sender/send-email-action.module.ts rename packages/twenty-server/src/modules/{mail-sender/workflow-actions => workflow/workflow-executor/workflow-actions/mail-sender}/send-email.workflow-action.ts (81%) create mode 100644 packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/mail-sender/types/workflow-send-email-action-input.type.ts create mode 100644 packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/mail-sender/types/workflow-send-email-action-settings.type.ts create mode 100644 packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/record-crud/record-crud-action.module.ts create mode 100644 packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/record-crud/record-crud.workflow-action.ts create mode 100644 packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/record-crud/types/workflow-record-crud-action-input.type.ts create mode 100644 packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/record-crud/types/workflow-record-crud-action-settings.type.ts rename packages/twenty-server/src/modules/workflow/workflow-executor/{ => workflow-actions}/types/workflow-action-result.type.ts (100%) create mode 100644 packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-settings.type.ts create mode 100644 packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type.ts diff --git a/packages/twenty-server/src/engine/core-modules/workflow/dtos/compute-step-output-schema-input.dto.ts b/packages/twenty-server/src/engine/core-modules/workflow/dtos/compute-step-output-schema-input.dto.ts index 6b23c95bb117..ecdf7a002f45 100644 --- a/packages/twenty-server/src/engine/core-modules/workflow/dtos/compute-step-output-schema-input.dto.ts +++ b/packages/twenty-server/src/engine/core-modules/workflow/dtos/compute-step-output-schema-input.dto.ts @@ -2,8 +2,8 @@ import { Field, InputType } from '@nestjs/graphql'; import graphqlTypeJson from 'graphql-type-json'; +import { WorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type'; import { WorkflowTrigger } from 'src/modules/workflow/workflow-trigger/types/workflow-trigger.type'; -import { WorkflowStep } from 'src/modules/workflow/workflow-executor/types/workflow-action.type'; @InputType() export class ComputeStepOutputSchemaInput { @@ -11,5 +11,5 @@ export class ComputeStepOutputSchemaInput { description: 'Step JSON format', nullable: false, }) - step: WorkflowTrigger | WorkflowStep; + step: WorkflowTrigger | WorkflowAction; } diff --git a/packages/twenty-server/src/engine/core-modules/workflow/resolvers/workflow-builder.resolver.ts b/packages/twenty-server/src/engine/core-modules/workflow/resolvers/workflow-builder.resolver.ts index 6f5ce7a5ef90..61fdc5075144 100644 --- a/packages/twenty-server/src/engine/core-modules/workflow/resolvers/workflow-builder.resolver.ts +++ b/packages/twenty-server/src/engine/core-modules/workflow/resolvers/workflow-builder.resolver.ts @@ -10,7 +10,7 @@ import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorat import { UserAuthGuard } from 'src/engine/guards/user-auth.guard'; import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard'; import { WorkflowBuilderWorkspaceService } from 'src/modules/workflow/workflow-builder/workflow-builder.workspace-service'; -import { OutputSchema } from 'src/modules/workflow/workflow-executor/types/workflow-step-settings.type'; +import { OutputSchema } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-settings.type'; @Resolver() @UseGuards(WorkspaceAuthGuard, UserAuthGuard) diff --git a/packages/twenty-server/src/modules/workflow/common/standard-objects/workflow-version.workspace-entity.ts b/packages/twenty-server/src/modules/workflow/common/standard-objects/workflow-version.workspace-entity.ts index 2d526cf9206c..cdc466fb828b 100644 --- a/packages/twenty-server/src/modules/workflow/common/standard-objects/workflow-version.workspace-entity.ts +++ b/packages/twenty-server/src/modules/workflow/common/standard-objects/workflow-version.workspace-entity.ts @@ -21,7 +21,7 @@ import { FavoriteWorkspaceEntity } from 'src/modules/favorite/standard-objects/f import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity'; import { WorkflowRunWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity'; import { WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity'; -import { WorkflowStep } from 'src/modules/workflow/workflow-executor/types/workflow-action.type'; +import { WorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type'; import { WorkflowTrigger } from 'src/modules/workflow/workflow-trigger/types/workflow-trigger.type'; export enum WorkflowVersionStatus { @@ -98,7 +98,7 @@ export class WorkflowVersionWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconSettingsAutomation', }) @WorkspaceIsNullable() - steps: WorkflowStep[] | null; + steps: WorkflowAction[] | null; @WorkspaceField({ standardId: WORKFLOW_VERSION_STANDARD_FIELD_IDS.status, diff --git a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-builder.workspace-service.ts b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-builder.workspace-service.ts index 0b6ea72fe9e0..17e595c0deee 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-builder.workspace-service.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-builder.workspace-service.ts @@ -5,24 +5,24 @@ import { join } from 'path'; import { Repository } from 'typeorm'; +import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; +import { checkStringIsDatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/utils/check-string-is-database-event-action'; import { INDEX_FILE_NAME } from 'src/engine/core-modules/serverless/drivers/constants/index-file-name'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { ServerlessFunctionService } from 'src/engine/metadata-modules/serverless-function/serverless-function.service'; import { CodeIntrospectionService } from 'src/modules/code-introspection/code-introspection.service'; import { generateFakeObjectRecord } from 'src/modules/workflow/workflow-builder/utils/generate-fake-object-record'; +import { generateFakeObjectRecordEvent } from 'src/modules/workflow/workflow-builder/utils/generate-fake-object-record-event'; +import { WorkflowSendEmailStepOutputSchema } from 'src/modules/workflow/workflow-executor/workflow-actions/mail-sender/send-email.workflow-action'; import { + WorkflowAction, WorkflowActionType, - WorkflowStep, -} from 'src/modules/workflow/workflow-executor/types/workflow-action.type'; -import { WorkflowSendEmailStepOutputSchema } from 'src/modules/workflow/workflow-executor/types/workflow-step-settings.type'; +} from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type'; import { WorkflowTrigger, WorkflowTriggerType, } from 'src/modules/workflow/workflow-trigger/types/workflow-trigger.type'; import { isDefined } from 'src/utils/is-defined'; -import { checkStringIsDatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/utils/check-string-is-database-event-action'; -import { generateFakeObjectRecordEvent } from 'src/modules/workflow/workflow-builder/utils/generate-fake-object-record-event'; -import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; @Injectable() export class WorkflowBuilderWorkspaceService { @@ -37,7 +37,7 @@ export class WorkflowBuilderWorkspaceService { step, workspaceId, }: { - step: WorkflowTrigger | WorkflowStep; + step: WorkflowTrigger | WorkflowAction; workspaceId: string; }): Promise { const stepType = step.type; @@ -57,7 +57,7 @@ export class WorkflowBuilderWorkspaceService { return {}; } - return await this.computeManualTriggerOutputSchema({ + return await this.computeRecordOutputSchema({ objectType, workspaceId, objectMetadataRepository: this.objectMetadataRepository, @@ -78,6 +78,12 @@ export class WorkflowBuilderWorkspaceService { codeIntrospectionService: this.codeIntrospectionService, }); } + case WorkflowActionType.RECORD_CRUD: + return await this.computeRecordOutputSchema({ + objectType: step.settings.input.objectName, + workspaceId, + objectMetadataRepository: this.objectMetadataRepository, + }); default: return {}; } @@ -116,7 +122,7 @@ export class WorkflowBuilderWorkspaceService { ); } - private async computeManualTriggerOutputSchema({ + private async computeRecordOutputSchema({ objectType, workspaceId, objectMetadataRepository, diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/factories/workflow-action.factory.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/factories/workflow-action.factory.ts index 5c23d81d31f4..c3592568a75c 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-executor/factories/workflow-action.factory.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/factories/workflow-action.factory.ts @@ -2,19 +2,21 @@ import { Injectable } from '@nestjs/common'; import { WorkflowAction } from 'src/modules/workflow/workflow-executor/interfaces/workflow-action.interface'; -import { WorkflowActionType } from 'src/modules/workflow/workflow-executor/types/workflow-action.type'; import { WorkflowStepExecutorException, WorkflowStepExecutorExceptionCode, } from 'src/modules/workflow/workflow-executor/exceptions/workflow-step-executor.exception'; -import { CodeWorkflowAction } from 'src/modules/serverless/workflow-actions/code.workflow-action'; -import { SendEmailWorkflowAction } from 'src/modules/mail-sender/workflow-actions/send-email.workflow-action'; +import { CodeWorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/code/code.workflow-action'; +import { SendEmailWorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/mail-sender/send-email.workflow-action'; +import { RecordCRUDWorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/record-crud.workflow-action'; +import { WorkflowActionType } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type'; @Injectable() export class WorkflowActionFactory { constructor( private readonly codeWorkflowAction: CodeWorkflowAction, private readonly sendEmailWorkflowAction: SendEmailWorkflowAction, + private readonly recordCRUDWorkflowAction: RecordCRUDWorkflowAction, ) {} get(stepType: WorkflowActionType): WorkflowAction { @@ -23,6 +25,8 @@ export class WorkflowActionFactory { return this.codeWorkflowAction; case WorkflowActionType.SEND_EMAIL: return this.sendEmailWorkflowAction; + case WorkflowActionType.RECORD_CRUD: + return this.recordCRUDWorkflowAction; default: throw new WorkflowStepExecutorException( `Workflow step executor not found for step type '${stepType}'`, diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/interfaces/workflow-action.interface.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/interfaces/workflow-action.interface.ts index 499baaed8486..e86aa5d264f6 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-executor/interfaces/workflow-action.interface.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/interfaces/workflow-action.interface.ts @@ -1,4 +1,4 @@ -import { WorkflowActionResult } from 'src/modules/workflow/workflow-executor/types/workflow-action-result.type'; +import { WorkflowActionResult } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-result.type'; export interface WorkflowAction { execute(workflowStepInput: unknown): Promise; diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/types/workflow-action.type.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/types/workflow-action.type.ts deleted file mode 100644 index 435901dc7d91..000000000000 --- a/packages/twenty-server/src/modules/workflow/workflow-executor/types/workflow-action.type.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { - WorkflowCodeStepSettings, - WorkflowSendEmailStepSettings, - WorkflowStepSettings, -} from 'src/modules/workflow/workflow-executor/types/workflow-step-settings.type'; - -export enum WorkflowActionType { - CODE = 'CODE', - SEND_EMAIL = 'SEND_EMAIL', -} - -type BaseWorkflowStep = { - id: string; - name: string; - type: WorkflowActionType; - settings: WorkflowStepSettings; - valid: boolean; -}; - -export type WorkflowCodeStep = BaseWorkflowStep & { - type: WorkflowActionType.CODE; - settings: WorkflowCodeStepSettings; -}; - -export type WorkflowSendEmailStep = BaseWorkflowStep & { - type: WorkflowActionType.SEND_EMAIL; - settings: WorkflowSendEmailStepSettings; -}; - -export type WorkflowStep = WorkflowCodeStep | WorkflowSendEmailStep; diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/types/workflow-step-settings.type.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/types/workflow-step-settings.type.ts deleted file mode 100644 index 4e812b436b20..000000000000 --- a/packages/twenty-server/src/modules/workflow/workflow-executor/types/workflow-step-settings.type.ts +++ /dev/null @@ -1,45 +0,0 @@ -export type OutputSchema = object; - -type BaseWorkflowStepSettings = { - input: object; - outputSchema: OutputSchema; - errorHandlingOptions: { - retryOnFailure: { - value: boolean; - }; - continueOnFailure: { - value: boolean; - }; - }; -}; - -export type WorkflowCodeStepInput = { - serverlessFunctionId: string; - serverlessFunctionVersion: string; - serverlessFunctionInput: { - [key: string]: any; - }; -}; - -export type WorkflowCodeStepSettings = BaseWorkflowStepSettings & { - input: WorkflowCodeStepInput; -}; - -export type WorkflowSendEmailStepInput = { - connectedAccountId: string; - email: string; - subject?: string; - body?: string; -}; - -export type WorkflowSendEmailStepOutputSchema = { - success: boolean; -}; - -export type WorkflowSendEmailStepSettings = BaseWorkflowStepSettings & { - input: WorkflowSendEmailStepInput; -}; - -export type WorkflowStepSettings = - | WorkflowSendEmailStepSettings - | WorkflowCodeStepSettings; diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/code-action.module.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/code-action.module.ts new file mode 100644 index 000000000000..c7994cbd3068 --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/code-action.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common'; + +import { ServerlessFunctionModule } from 'src/engine/metadata-modules/serverless-function/serverless-function.module'; +import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/scoped-workspace-context.factory'; +import { CodeWorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/code/code.workflow-action'; + +@Module({ + imports: [ServerlessFunctionModule], + providers: [ScopedWorkspaceContextFactory, CodeWorkflowAction], + exports: [CodeWorkflowAction], +}) +export class CodeActionModule {} diff --git a/packages/twenty-server/src/modules/serverless/workflow-actions/code.workflow-action.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/code.workflow-action.ts similarity index 80% rename from packages/twenty-server/src/modules/serverless/workflow-actions/code.workflow-action.ts rename to packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/code.workflow-action.ts index 39a66a87b289..af4081f52ed7 100644 --- a/packages/twenty-server/src/modules/serverless/workflow-actions/code.workflow-action.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/code.workflow-action.ts @@ -8,8 +8,8 @@ import { WorkflowStepExecutorException, WorkflowStepExecutorExceptionCode, } from 'src/modules/workflow/workflow-executor/exceptions/workflow-step-executor.exception'; -import { WorkflowActionResult } from 'src/modules/workflow/workflow-executor/types/workflow-action-result.type'; -import { WorkflowCodeStepInput } from 'src/modules/workflow/workflow-executor/types/workflow-step-settings.type'; +import { WorkflowCodeActionInput } from 'src/modules/workflow/workflow-executor/workflow-actions/code/types/workflow-code-action-input.type'; +import { WorkflowActionResult } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-result.type'; @Injectable() export class CodeWorkflowAction implements WorkflowAction { @@ -19,7 +19,7 @@ export class CodeWorkflowAction implements WorkflowAction { ) {} async execute( - workflowStepInput: WorkflowCodeStepInput, + workflowActionInput: WorkflowCodeActionInput, ): Promise { try { const { workspaceId } = this.scopedWorkspaceContextFactory.create(); @@ -33,9 +33,9 @@ export class CodeWorkflowAction implements WorkflowAction { const result = await this.serverlessFunctionService.executeOneServerlessFunction( - workflowStepInput.serverlessFunctionId, + workflowActionInput.serverlessFunctionId, workspaceId, - workflowStepInput.serverlessFunctionInput, + workflowActionInput.serverlessFunctionInput, ); if (result.error) { diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/types/workflow-code-action-input.type.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/types/workflow-code-action-input.type.ts new file mode 100644 index 000000000000..39562603f78c --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/types/workflow-code-action-input.type.ts @@ -0,0 +1,7 @@ +export type WorkflowCodeActionInput = { + serverlessFunctionId: string; + serverlessFunctionVersion: string; + serverlessFunctionInput: { + [key: string]: any; + }; +}; diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/types/workflow-code-action-settings.type.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/types/workflow-code-action-settings.type.ts new file mode 100644 index 000000000000..c76181d0a5bf --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/types/workflow-code-action-settings.type.ts @@ -0,0 +1,6 @@ +import { WorkflowCodeActionInput } from 'src/modules/workflow/workflow-executor/workflow-actions/code/types/workflow-code-action-input.type'; +import { BaseWorkflowActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-settings.type'; + +export type WorkflowCodeActionSettings = BaseWorkflowActionSettings & { + input: WorkflowCodeActionInput; +}; diff --git a/packages/twenty-server/src/modules/mail-sender/exceptions/mail-sender.exception.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/mail-sender/exceptions/send-email-action.exception.ts similarity index 50% rename from packages/twenty-server/src/modules/mail-sender/exceptions/mail-sender.exception.ts rename to packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/mail-sender/exceptions/send-email-action.exception.ts index 01e1b2ed932f..18eb09486193 100644 --- a/packages/twenty-server/src/modules/mail-sender/exceptions/mail-sender.exception.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/mail-sender/exceptions/send-email-action.exception.ts @@ -1,13 +1,13 @@ import { CustomException } from 'src/utils/custom-exception'; -export class MailSenderException extends CustomException { - code: MailSenderExceptionCode; - constructor(message: string, code: MailSenderExceptionCode) { +export class SendEmailActionException extends CustomException { + code: SendEmailActionExceptionCode; + constructor(message: string, code: SendEmailActionExceptionCode) { super(message, code); } } -export enum MailSenderExceptionCode { +export enum SendEmailActionExceptionCode { PROVIDER_NOT_SUPPORTED = 'PROVIDER_NOT_SUPPORTED', CONNECTED_ACCOUNT_NOT_FOUND = 'CONNECTED_ACCOUNT_NOT_FOUND', } diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/mail-sender/send-email-action.module.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/mail-sender/send-email-action.module.ts new file mode 100644 index 000000000000..c56692f5521d --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/mail-sender/send-email-action.module.ts @@ -0,0 +1,17 @@ +import { Module } from '@nestjs/common'; + +import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/scoped-workspace-context.factory'; +import { OAuth2ClientManagerModule } from 'src/modules/connected-account/oauth2-client-manager/oauth2-client-manager.module'; +import { GmailClientProvider } from 'src/modules/messaging/message-import-manager/drivers/gmail/providers/gmail-client.provider'; +import { SendEmailWorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/mail-sender/send-email.workflow-action'; + +@Module({ + imports: [OAuth2ClientManagerModule], + providers: [ + GmailClientProvider, + ScopedWorkspaceContextFactory, + SendEmailWorkflowAction, + ], + exports: [SendEmailWorkflowAction], +}) +export class SendEmailActionModule {} diff --git a/packages/twenty-server/src/modules/mail-sender/workflow-actions/send-email.workflow-action.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/mail-sender/send-email.workflow-action.ts similarity index 81% rename from packages/twenty-server/src/modules/mail-sender/workflow-actions/send-email.workflow-action.ts rename to packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/mail-sender/send-email.workflow-action.ts index b833120bb81b..917d0766c67a 100644 --- a/packages/twenty-server/src/modules/mail-sender/workflow-actions/send-email.workflow-action.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/mail-sender/send-email.workflow-action.ts @@ -9,22 +9,23 @@ import { WorkflowAction } from 'src/modules/workflow/workflow-executor/interface import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/scoped-workspace-context.factory'; import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; -import { - MailSenderException, - MailSenderExceptionCode, -} from 'src/modules/mail-sender/exceptions/mail-sender.exception'; import { GmailClientProvider } from 'src/modules/messaging/message-import-manager/drivers/gmail/providers/gmail-client.provider'; import { WorkflowStepExecutorException, WorkflowStepExecutorExceptionCode, } from 'src/modules/workflow/workflow-executor/exceptions/workflow-step-executor.exception'; -import { WorkflowActionResult } from 'src/modules/workflow/workflow-executor/types/workflow-action-result.type'; import { - WorkflowSendEmailStepInput, - WorkflowSendEmailStepOutputSchema, -} from 'src/modules/workflow/workflow-executor/types/workflow-step-settings.type'; + SendEmailActionException, + SendEmailActionExceptionCode, +} from 'src/modules/workflow/workflow-executor/workflow-actions/mail-sender/exceptions/send-email-action.exception'; +import { WorkflowSendEmailActionInput } from 'src/modules/workflow/workflow-executor/workflow-actions/mail-sender/types/workflow-send-email-action-input.type'; +import { WorkflowActionResult } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-result.type'; import { isDefined } from 'src/utils/is-defined'; +export type WorkflowSendEmailStepOutputSchema = { + success: boolean; +}; + @Injectable() export class SendEmailWorkflowAction implements WorkflowAction { private readonly logger = new Logger(SendEmailWorkflowAction.name); @@ -54,9 +55,9 @@ export class SendEmailWorkflowAction implements WorkflowAction { }); if (!isDefined(connectedAccount)) { - throw new MailSenderException( + throw new SendEmailActionException( `Connected Account '${connectedAccountId}' not found`, - MailSenderExceptionCode.CONNECTED_ACCOUNT_NOT_FOUND, + SendEmailActionExceptionCode.CONNECTED_ACCOUNT_NOT_FOUND, ); } @@ -64,20 +65,20 @@ export class SendEmailWorkflowAction implements WorkflowAction { case 'google': return await this.gmailClientProvider.getGmailClient(connectedAccount); default: - throw new MailSenderException( + throw new SendEmailActionException( `Provider ${connectedAccount.provider} is not supported`, - MailSenderExceptionCode.PROVIDER_NOT_SUPPORTED, + SendEmailActionExceptionCode.PROVIDER_NOT_SUPPORTED, ); } } async execute( - workflowStepInput: WorkflowSendEmailStepInput, + workflowActionInput: WorkflowSendEmailActionInput, ): Promise { const emailProvider = await this.getEmailClient( - workflowStepInput.connectedAccountId, + workflowActionInput.connectedAccountId, ); - const { email, body, subject } = workflowStepInput; + const { email, body, subject } = workflowActionInput; try { const emailSchema = z.string().trim().email('Invalid email'); diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/mail-sender/types/workflow-send-email-action-input.type.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/mail-sender/types/workflow-send-email-action-input.type.ts new file mode 100644 index 000000000000..495cdaeb9dfc --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/mail-sender/types/workflow-send-email-action-input.type.ts @@ -0,0 +1,6 @@ +export type WorkflowSendEmailActionInput = { + connectedAccountId: string; + email: string; + subject?: string; + body?: string; +}; diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/mail-sender/types/workflow-send-email-action-settings.type.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/mail-sender/types/workflow-send-email-action-settings.type.ts new file mode 100644 index 000000000000..f2d5b3403352 --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/mail-sender/types/workflow-send-email-action-settings.type.ts @@ -0,0 +1,6 @@ +import { WorkflowSendEmailActionInput } from 'src/modules/workflow/workflow-executor/workflow-actions/mail-sender/types/workflow-send-email-action-input.type'; +import { BaseWorkflowActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-settings.type'; + +export type WorkflowSendEmailActionSettings = BaseWorkflowActionSettings & { + input: WorkflowSendEmailActionInput; +}; diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/record-crud/record-crud-action.module.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/record-crud/record-crud-action.module.ts new file mode 100644 index 000000000000..4f978fb5687d --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/record-crud/record-crud-action.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; + +import { RecordCRUDWorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/record-crud.workflow-action'; + +@Module({ + providers: [RecordCRUDWorkflowAction], + exports: [RecordCRUDWorkflowAction], +}) +export class RecordCRUDActionModule {} diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/record-crud/record-crud.workflow-action.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/record-crud/record-crud.workflow-action.ts new file mode 100644 index 000000000000..44c688626b5b --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/record-crud/record-crud.workflow-action.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common'; + +import { WorkflowAction } from 'src/modules/workflow/workflow-executor/interfaces/workflow-action.interface'; + +import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; +import { + WorkflowCreateRecordActionInput, + WorkflowRecordCRUDActionInput, + WorkflowRecordCRUDType, +} from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/types/workflow-record-crud-action-input.type'; +import { WorkflowActionResult } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-result.type'; + +@Injectable() +export class RecordCRUDWorkflowAction implements WorkflowAction { + constructor(private readonly twentyORMManager: TwentyORMManager) {} + + async execute( + workflowActionInput: WorkflowRecordCRUDActionInput, + ): Promise { + switch (workflowActionInput.type) { + case WorkflowRecordCRUDType.CREATE: + return this.createRecord(workflowActionInput); + default: + throw new Error( + `Unknown record operation type: ${workflowActionInput.type}`, + ); + } + } + + private async createRecord( + workflowActionInput: WorkflowCreateRecordActionInput, + ): Promise { + const repository = await this.twentyORMManager.getRepository( + workflowActionInput.objectName, + ); + + const objectRecord = await repository.create( + workflowActionInput.objectRecord, + ); + + const createdObjectRecord = await repository.save(objectRecord); + + return { result: createdObjectRecord }; + } +} diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/record-crud/types/workflow-record-crud-action-input.type.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/record-crud/types/workflow-record-crud-action-input.type.ts new file mode 100644 index 000000000000..43bb9ffbdad6 --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/record-crud/types/workflow-record-crud-action-input.type.ts @@ -0,0 +1,31 @@ +type ObjectRecord = Record; + +export enum WorkflowRecordCRUDType { + CREATE = 'create', + UPDATE = 'update', + DELETE = 'delete', +} + +export type WorkflowCreateRecordActionInput = { + type: WorkflowRecordCRUDType.CREATE; + objectName: string; + objectRecord: ObjectRecord; +}; + +export type WorkflowUpdateRecordActionInput = { + type: WorkflowRecordCRUDType.UPDATE; + objectName: string; + objectRecord: ObjectRecord; + objectRecordId: string; +}; + +export type WorkflowDeleteRecordActionInput = { + type: WorkflowRecordCRUDType.DELETE; + objectName: string; + objectRecordId: string; +}; + +export type WorkflowRecordCRUDActionInput = + | WorkflowCreateRecordActionInput + | WorkflowUpdateRecordActionInput + | WorkflowDeleteRecordActionInput; diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/record-crud/types/workflow-record-crud-action-settings.type.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/record-crud/types/workflow-record-crud-action-settings.type.ts new file mode 100644 index 000000000000..cfda46c08cb4 --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/record-crud/types/workflow-record-crud-action-settings.type.ts @@ -0,0 +1,6 @@ +import { WorkflowRecordCRUDActionInput } from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/types/workflow-record-crud-action-input.type'; +import { BaseWorkflowActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-settings.type'; + +export type WorkflowRecordCRUDActionSettings = BaseWorkflowActionSettings & { + input: WorkflowRecordCRUDActionInput; +}; diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/types/workflow-action-result.type.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-result.type.ts similarity index 100% rename from packages/twenty-server/src/modules/workflow/workflow-executor/types/workflow-action-result.type.ts rename to packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-result.type.ts diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-settings.type.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-settings.type.ts new file mode 100644 index 000000000000..221809cb3491 --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-settings.type.ts @@ -0,0 +1,23 @@ +import { WorkflowCodeActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/code/types/workflow-code-action-settings.type'; +import { WorkflowSendEmailActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/mail-sender/types/workflow-send-email-action-settings.type'; +import { WorkflowRecordCRUDActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/types/workflow-record-crud-action-settings.type'; + +export type OutputSchema = object; + +export type BaseWorkflowActionSettings = { + input: object; + outputSchema: OutputSchema; + errorHandlingOptions: { + retryOnFailure: { + value: boolean; + }; + continueOnFailure: { + value: boolean; + }; + }; +}; + +export type WorkflowActionSettings = + | WorkflowSendEmailActionSettings + | WorkflowCodeActionSettings + | WorkflowRecordCRUDActionSettings; diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type.ts new file mode 100644 index 000000000000..1ce3baefa038 --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type.ts @@ -0,0 +1,38 @@ +import { WorkflowCodeActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/code/types/workflow-code-action-settings.type'; +import { WorkflowSendEmailActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/mail-sender/types/workflow-send-email-action-settings.type'; +import { WorkflowRecordCRUDActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/types/workflow-record-crud-action-settings.type'; +import { WorkflowActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-settings.type'; + +export enum WorkflowActionType { + CODE = 'CODE', + SEND_EMAIL = 'SEND_EMAIL', + RECORD_CRUD = 'RECORD_CRUD', +} + +type BaseWorkflowAction = { + id: string; + name: string; + type: WorkflowActionType; + settings: WorkflowActionSettings; + valid: boolean; +}; + +export type WorkflowCodeAction = BaseWorkflowAction & { + type: WorkflowActionType.CODE; + settings: WorkflowCodeActionSettings; +}; + +export type WorkflowSendEmailAction = BaseWorkflowAction & { + type: WorkflowActionType.SEND_EMAIL; + settings: WorkflowSendEmailActionSettings; +}; + +export type WorkflowRecordCRUDAction = BaseWorkflowAction & { + type: WorkflowActionType.RECORD_CRUD; + settings: WorkflowRecordCRUDActionSettings; +}; + +export type WorkflowAction = + | WorkflowCodeAction + | WorkflowSendEmailAction + | WorkflowRecordCRUDAction; diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-executor.module.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-executor.module.ts index 4cfc2d9888d7..08dea7f338e2 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-executor.module.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-executor.module.ts @@ -1,26 +1,24 @@ import { Module } from '@nestjs/common'; -import { ServerlessFunctionModule } from 'src/engine/metadata-modules/serverless-function/serverless-function.module'; import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/scoped-workspace-context.factory'; -import { SendEmailWorkflowAction } from 'src/modules/mail-sender/workflow-actions/send-email.workflow-action'; -import { MessagingGmailDriverModule } from 'src/modules/messaging/message-import-manager/drivers/gmail/messaging-gmail-driver.module'; -import { CodeWorkflowAction } from 'src/modules/serverless/workflow-actions/code.workflow-action'; import { WorkflowCommonModule } from 'src/modules/workflow/common/workflow-common.module'; import { WorkflowActionFactory } from 'src/modules/workflow/workflow-executor/factories/workflow-action.factory'; +import { CodeActionModule } from 'src/modules/workflow/workflow-executor/workflow-actions/code/code-action.module'; +import { SendEmailActionModule } from 'src/modules/workflow/workflow-executor/workflow-actions/mail-sender/send-email-action.module'; +import { RecordCRUDActionModule } from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/record-crud-action.module'; import { WorkflowExecutorWorkspaceService } from 'src/modules/workflow/workflow-executor/workspace-services/workflow-executor.workspace-service'; @Module({ imports: [ WorkflowCommonModule, - ServerlessFunctionModule, - MessagingGmailDriverModule, + CodeActionModule, + SendEmailActionModule, + RecordCRUDActionModule, ], providers: [ WorkflowExecutorWorkspaceService, ScopedWorkspaceContextFactory, WorkflowActionFactory, - CodeWorkflowAction, - SendEmailWorkflowAction, ], exports: [WorkflowExecutorWorkspaceService], }) diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workspace-services/workflow-executor.workspace-service.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workspace-services/workflow-executor.workspace-service.ts index 5290c5d4d049..a64f8bd6ad8e 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-executor/workspace-services/workflow-executor.workspace-service.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workspace-services/workflow-executor.workspace-service.ts @@ -5,8 +5,8 @@ import { WorkflowRunStatus, } from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity'; import { WorkflowActionFactory } from 'src/modules/workflow/workflow-executor/factories/workflow-action.factory'; -import { WorkflowStep } from 'src/modules/workflow/workflow-executor/types/workflow-action.type'; import { resolveInput } from 'src/modules/workflow/workflow-executor/utils/variable-resolver.util'; +import { WorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type'; const MAX_RETRIES_ON_FAILURE = 3; @@ -27,7 +27,7 @@ export class WorkflowExecutorWorkspaceService { attemptCount = 1, }: { currentStepIndex: number; - steps: WorkflowStep[]; + steps: WorkflowAction[]; output: WorkflowExecutorOutput; context: Record; attemptCount?: number; diff --git a/packages/twenty-server/src/modules/workflow/workflow-trigger/types/workflow-trigger.type.ts b/packages/twenty-server/src/modules/workflow/workflow-trigger/types/workflow-trigger.type.ts index 164d47b74e23..1222c32f4d71 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-trigger/types/workflow-trigger.type.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-trigger/types/workflow-trigger.type.ts @@ -1,4 +1,4 @@ -import { OutputSchema } from 'src/modules/workflow/workflow-executor/types/workflow-step-settings.type'; +import { OutputSchema } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-settings.type'; export enum WorkflowTriggerType { DATABASE_EVENT = 'DATABASE_EVENT',