Create Workflow Form action (#10509)
- create form action - add `pendingEvent` to executor output - when receiving pendingEvent, exit workflow execution - let the workflow in running status for now before taking a decision
This commit is contained in:
@ -33,7 +33,6 @@ import {
|
||||
const TRIGGER_STEP_ID = 'trigger';
|
||||
|
||||
const BASE_STEP_DEFINITION: BaseWorkflowActionSettings = {
|
||||
input: {},
|
||||
outputSchema: {},
|
||||
errorHandlingOptions: {
|
||||
continueOnFailure: {
|
||||
|
||||
@ -7,6 +7,7 @@ import {
|
||||
WorkflowStepExecutorExceptionCode,
|
||||
} from 'src/modules/workflow/workflow-executor/exceptions/workflow-step-executor.exception';
|
||||
import { CodeWorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/code/code.workflow-action';
|
||||
import { FormWorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/form/form.workflow-action';
|
||||
import { SendEmailWorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/mail-sender/send-email.workflow-action';
|
||||
import { CreateRecordWorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/create-record.workflow-action';
|
||||
import { DeleteRecordWorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/delete-record.workflow-action';
|
||||
@ -23,6 +24,7 @@ export class WorkflowExecutorFactory {
|
||||
private readonly updateRecordWorkflowAction: UpdateRecordWorkflowAction,
|
||||
private readonly deleteRecordWorkflowAction: DeleteRecordWorkflowAction,
|
||||
private readonly findRecordsWorkflowAction: FindRecordsWorkflowAction,
|
||||
private readonly formWorkflowAction: FormWorkflowAction,
|
||||
) {}
|
||||
|
||||
get(stepType: WorkflowActionType): WorkflowExecutor {
|
||||
@ -39,6 +41,8 @@ export class WorkflowExecutorFactory {
|
||||
return this.deleteRecordWorkflowAction;
|
||||
case WorkflowActionType.FIND_RECORDS:
|
||||
return this.findRecordsWorkflowAction;
|
||||
case WorkflowActionType.FORM:
|
||||
return this.formWorkflowAction;
|
||||
default:
|
||||
throw new WorkflowStepExecutorException(
|
||||
`Workflow step executor not found for step type '${stepType}'`,
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
export type WorkflowExecutorOutput = {
|
||||
result?: object;
|
||||
error?: string;
|
||||
pendingEvent?: boolean;
|
||||
};
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { FormWorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/form/form.workflow-action';
|
||||
|
||||
@Module({
|
||||
providers: [FormWorkflowAction],
|
||||
exports: [FormWorkflowAction],
|
||||
})
|
||||
export class FormActionModule {}
|
||||
@ -0,0 +1,32 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { WorkflowExecutor } from 'src/modules/workflow/workflow-executor/interfaces/workflow-executor.interface';
|
||||
|
||||
import {
|
||||
WorkflowStepExecutorException,
|
||||
WorkflowStepExecutorExceptionCode,
|
||||
} from 'src/modules/workflow/workflow-executor/exceptions/workflow-step-executor.exception';
|
||||
import { WorkflowExecutorInput } from 'src/modules/workflow/workflow-executor/types/workflow-executor-input';
|
||||
import { WorkflowExecutorOutput } from 'src/modules/workflow/workflow-executor/types/workflow-executor-output.type';
|
||||
import { isWorkflowFormAction } from 'src/modules/workflow/workflow-executor/workflow-actions/form/guards/is-workflow-form-action.guard';
|
||||
|
||||
@Injectable()
|
||||
export class FormWorkflowAction implements WorkflowExecutor {
|
||||
async execute({
|
||||
currentStepIndex,
|
||||
steps,
|
||||
}: WorkflowExecutorInput): Promise<WorkflowExecutorOutput> {
|
||||
const step = steps[currentStepIndex];
|
||||
|
||||
if (!isWorkflowFormAction(step)) {
|
||||
throw new WorkflowStepExecutorException(
|
||||
'Step is not a form action',
|
||||
WorkflowStepExecutorExceptionCode.INVALID_STEP_TYPE,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
pendingEvent: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
import {
|
||||
WorkflowAction,
|
||||
WorkflowActionType,
|
||||
WorkflowFormAction,
|
||||
} from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type';
|
||||
|
||||
export const isWorkflowFormAction = (
|
||||
action: WorkflowAction,
|
||||
): action is WorkflowFormAction => action.type === WorkflowActionType.FORM;
|
||||
@ -0,0 +1,12 @@
|
||||
import { BaseWorkflowActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-settings.type';
|
||||
|
||||
export type FormFieldMetadata = {
|
||||
label: string;
|
||||
type: string;
|
||||
placeholder?: string;
|
||||
settings?: Record<string, any>;
|
||||
};
|
||||
|
||||
export type WorkflowFormActionSettings = BaseWorkflowActionSettings & {
|
||||
input: FormFieldMetadata[];
|
||||
};
|
||||
@ -1,5 +1,6 @@
|
||||
import { OutputSchema } from 'src/modules/workflow/workflow-builder/types/output-schema.type';
|
||||
import { WorkflowCodeActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/code/types/workflow-code-action-settings.type';
|
||||
import { WorkflowFormActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/form/types/workflow-form-action-settings.type';
|
||||
import { WorkflowSendEmailActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/mail-sender/types/workflow-send-email-action-settings.type';
|
||||
import {
|
||||
WorkflowCreateRecordActionSettings,
|
||||
@ -9,7 +10,6 @@ import {
|
||||
} from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/types/workflow-record-crud-action-settings.type';
|
||||
|
||||
export type BaseWorkflowActionSettings = {
|
||||
input: object;
|
||||
outputSchema: OutputSchema;
|
||||
errorHandlingOptions: {
|
||||
retryOnFailure: {
|
||||
@ -27,4 +27,5 @@ export type WorkflowActionSettings =
|
||||
| WorkflowCreateRecordActionSettings
|
||||
| WorkflowUpdateRecordActionSettings
|
||||
| WorkflowDeleteRecordActionSettings
|
||||
| WorkflowFindRecordsActionSettings;
|
||||
| WorkflowFindRecordsActionSettings
|
||||
| WorkflowFormActionSettings;
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { WorkflowCodeActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/code/types/workflow-code-action-settings.type';
|
||||
import { WorkflowFormActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/form/types/workflow-form-action-settings.type';
|
||||
import { WorkflowSendEmailActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/mail-sender/types/workflow-send-email-action-settings.type';
|
||||
import {
|
||||
WorkflowCreateRecordActionSettings,
|
||||
@ -15,6 +16,7 @@ export enum WorkflowActionType {
|
||||
UPDATE_RECORD = 'UPDATE_RECORD',
|
||||
DELETE_RECORD = 'DELETE_RECORD',
|
||||
FIND_RECORDS = 'FIND_RECORDS',
|
||||
FORM = 'FORM',
|
||||
}
|
||||
|
||||
type BaseWorkflowAction = {
|
||||
@ -55,10 +57,16 @@ export type WorkflowFindRecordsAction = BaseWorkflowAction & {
|
||||
settings: WorkflowFindRecordsActionSettings;
|
||||
};
|
||||
|
||||
export type WorkflowFormAction = BaseWorkflowAction & {
|
||||
type: WorkflowActionType.FORM;
|
||||
settings: WorkflowFormActionSettings;
|
||||
};
|
||||
|
||||
export type WorkflowAction =
|
||||
| WorkflowCodeAction
|
||||
| WorkflowSendEmailAction
|
||||
| WorkflowCreateRecordAction
|
||||
| WorkflowUpdateRecordAction
|
||||
| WorkflowDeleteRecordAction
|
||||
| WorkflowFindRecordsAction;
|
||||
| WorkflowFindRecordsAction
|
||||
| WorkflowFormAction;
|
||||
|
||||
@ -4,6 +4,7 @@ import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/s
|
||||
import { WorkflowCommonModule } from 'src/modules/workflow/common/workflow-common.module';
|
||||
import { WorkflowExecutorFactory } from 'src/modules/workflow/workflow-executor/factories/workflow-executor.factory';
|
||||
import { CodeActionModule } from 'src/modules/workflow/workflow-executor/workflow-actions/code/code-action.module';
|
||||
import { FormActionModule } from 'src/modules/workflow/workflow-executor/workflow-actions/form/form-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';
|
||||
@ -15,6 +16,7 @@ import { WorkflowRunModule } from 'src/modules/workflow/workflow-runner/workflow
|
||||
CodeActionModule,
|
||||
SendEmailActionModule,
|
||||
RecordCRUDActionModule,
|
||||
FormActionModule,
|
||||
WorkflowRunModule,
|
||||
],
|
||||
providers: [
|
||||
|
||||
@ -77,6 +77,16 @@ export class WorkflowExecutorWorkspaceService implements WorkflowExecutor {
|
||||
output: actionOutput,
|
||||
};
|
||||
|
||||
if (actionOutput.pendingEvent) {
|
||||
await this.workflowRunWorkspaceService.saveWorkflowRunState({
|
||||
workflowRunId,
|
||||
stepOutput,
|
||||
context,
|
||||
});
|
||||
|
||||
return actionOutput;
|
||||
}
|
||||
|
||||
if (actionOutput.result) {
|
||||
const updatedContext = {
|
||||
...context,
|
||||
|
||||
@ -67,12 +67,17 @@ export class RunWorkflowJob {
|
||||
|
||||
await this.throttleExecution(workflowVersion.workflowId);
|
||||
|
||||
const { error } = await this.workflowExecutorWorkspaceService.execute({
|
||||
workflowRunId,
|
||||
currentStepIndex: 0,
|
||||
steps: workflowVersion.steps,
|
||||
context,
|
||||
});
|
||||
const { error, pendingEvent } =
|
||||
await this.workflowExecutorWorkspaceService.execute({
|
||||
workflowRunId,
|
||||
currentStepIndex: 0,
|
||||
steps: workflowVersion.steps,
|
||||
context,
|
||||
});
|
||||
|
||||
if (pendingEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.workflowRunWorkspaceService.endWorkflowRun({
|
||||
workflowRunId,
|
||||
|
||||
Reference in New Issue
Block a user