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 TRIGGER_STEP_ID = 'trigger';
|
||||||
|
|
||||||
const BASE_STEP_DEFINITION: BaseWorkflowActionSettings = {
|
const BASE_STEP_DEFINITION: BaseWorkflowActionSettings = {
|
||||||
input: {},
|
|
||||||
outputSchema: {},
|
outputSchema: {},
|
||||||
errorHandlingOptions: {
|
errorHandlingOptions: {
|
||||||
continueOnFailure: {
|
continueOnFailure: {
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import {
|
|||||||
WorkflowStepExecutorExceptionCode,
|
WorkflowStepExecutorExceptionCode,
|
||||||
} from 'src/modules/workflow/workflow-executor/exceptions/workflow-step-executor.exception';
|
} 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 { 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 { 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 { 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';
|
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 updateRecordWorkflowAction: UpdateRecordWorkflowAction,
|
||||||
private readonly deleteRecordWorkflowAction: DeleteRecordWorkflowAction,
|
private readonly deleteRecordWorkflowAction: DeleteRecordWorkflowAction,
|
||||||
private readonly findRecordsWorkflowAction: FindRecordsWorkflowAction,
|
private readonly findRecordsWorkflowAction: FindRecordsWorkflowAction,
|
||||||
|
private readonly formWorkflowAction: FormWorkflowAction,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
get(stepType: WorkflowActionType): WorkflowExecutor {
|
get(stepType: WorkflowActionType): WorkflowExecutor {
|
||||||
@ -39,6 +41,8 @@ export class WorkflowExecutorFactory {
|
|||||||
return this.deleteRecordWorkflowAction;
|
return this.deleteRecordWorkflowAction;
|
||||||
case WorkflowActionType.FIND_RECORDS:
|
case WorkflowActionType.FIND_RECORDS:
|
||||||
return this.findRecordsWorkflowAction;
|
return this.findRecordsWorkflowAction;
|
||||||
|
case WorkflowActionType.FORM:
|
||||||
|
return this.formWorkflowAction;
|
||||||
default:
|
default:
|
||||||
throw new WorkflowStepExecutorException(
|
throw new WorkflowStepExecutorException(
|
||||||
`Workflow step executor not found for step type '${stepType}'`,
|
`Workflow step executor not found for step type '${stepType}'`,
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
export type WorkflowExecutorOutput = {
|
export type WorkflowExecutorOutput = {
|
||||||
result?: object;
|
result?: object;
|
||||||
error?: string;
|
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 { 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 { 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 { WorkflowSendEmailActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/mail-sender/types/workflow-send-email-action-settings.type';
|
||||||
import {
|
import {
|
||||||
WorkflowCreateRecordActionSettings,
|
WorkflowCreateRecordActionSettings,
|
||||||
@ -9,7 +10,6 @@ import {
|
|||||||
} from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/types/workflow-record-crud-action-settings.type';
|
} from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/types/workflow-record-crud-action-settings.type';
|
||||||
|
|
||||||
export type BaseWorkflowActionSettings = {
|
export type BaseWorkflowActionSettings = {
|
||||||
input: object;
|
|
||||||
outputSchema: OutputSchema;
|
outputSchema: OutputSchema;
|
||||||
errorHandlingOptions: {
|
errorHandlingOptions: {
|
||||||
retryOnFailure: {
|
retryOnFailure: {
|
||||||
@ -27,4 +27,5 @@ export type WorkflowActionSettings =
|
|||||||
| WorkflowCreateRecordActionSettings
|
| WorkflowCreateRecordActionSettings
|
||||||
| WorkflowUpdateRecordActionSettings
|
| WorkflowUpdateRecordActionSettings
|
||||||
| WorkflowDeleteRecordActionSettings
|
| 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 { 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 { WorkflowSendEmailActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/mail-sender/types/workflow-send-email-action-settings.type';
|
||||||
import {
|
import {
|
||||||
WorkflowCreateRecordActionSettings,
|
WorkflowCreateRecordActionSettings,
|
||||||
@ -15,6 +16,7 @@ export enum WorkflowActionType {
|
|||||||
UPDATE_RECORD = 'UPDATE_RECORD',
|
UPDATE_RECORD = 'UPDATE_RECORD',
|
||||||
DELETE_RECORD = 'DELETE_RECORD',
|
DELETE_RECORD = 'DELETE_RECORD',
|
||||||
FIND_RECORDS = 'FIND_RECORDS',
|
FIND_RECORDS = 'FIND_RECORDS',
|
||||||
|
FORM = 'FORM',
|
||||||
}
|
}
|
||||||
|
|
||||||
type BaseWorkflowAction = {
|
type BaseWorkflowAction = {
|
||||||
@ -55,10 +57,16 @@ export type WorkflowFindRecordsAction = BaseWorkflowAction & {
|
|||||||
settings: WorkflowFindRecordsActionSettings;
|
settings: WorkflowFindRecordsActionSettings;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type WorkflowFormAction = BaseWorkflowAction & {
|
||||||
|
type: WorkflowActionType.FORM;
|
||||||
|
settings: WorkflowFormActionSettings;
|
||||||
|
};
|
||||||
|
|
||||||
export type WorkflowAction =
|
export type WorkflowAction =
|
||||||
| WorkflowCodeAction
|
| WorkflowCodeAction
|
||||||
| WorkflowSendEmailAction
|
| WorkflowSendEmailAction
|
||||||
| WorkflowCreateRecordAction
|
| WorkflowCreateRecordAction
|
||||||
| WorkflowUpdateRecordAction
|
| WorkflowUpdateRecordAction
|
||||||
| WorkflowDeleteRecordAction
|
| 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 { WorkflowCommonModule } from 'src/modules/workflow/common/workflow-common.module';
|
||||||
import { WorkflowExecutorFactory } from 'src/modules/workflow/workflow-executor/factories/workflow-executor.factory';
|
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 { 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 { 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 { 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';
|
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,
|
CodeActionModule,
|
||||||
SendEmailActionModule,
|
SendEmailActionModule,
|
||||||
RecordCRUDActionModule,
|
RecordCRUDActionModule,
|
||||||
|
FormActionModule,
|
||||||
WorkflowRunModule,
|
WorkflowRunModule,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
|
|||||||
@ -77,6 +77,16 @@ export class WorkflowExecutorWorkspaceService implements WorkflowExecutor {
|
|||||||
output: actionOutput,
|
output: actionOutput,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (actionOutput.pendingEvent) {
|
||||||
|
await this.workflowRunWorkspaceService.saveWorkflowRunState({
|
||||||
|
workflowRunId,
|
||||||
|
stepOutput,
|
||||||
|
context,
|
||||||
|
});
|
||||||
|
|
||||||
|
return actionOutput;
|
||||||
|
}
|
||||||
|
|
||||||
if (actionOutput.result) {
|
if (actionOutput.result) {
|
||||||
const updatedContext = {
|
const updatedContext = {
|
||||||
...context,
|
...context,
|
||||||
|
|||||||
@ -67,12 +67,17 @@ export class RunWorkflowJob {
|
|||||||
|
|
||||||
await this.throttleExecution(workflowVersion.workflowId);
|
await this.throttleExecution(workflowVersion.workflowId);
|
||||||
|
|
||||||
const { error } = await this.workflowExecutorWorkspaceService.execute({
|
const { error, pendingEvent } =
|
||||||
workflowRunId,
|
await this.workflowExecutorWorkspaceService.execute({
|
||||||
currentStepIndex: 0,
|
workflowRunId,
|
||||||
steps: workflowVersion.steps,
|
currentStepIndex: 0,
|
||||||
context,
|
steps: workflowVersion.steps,
|
||||||
});
|
context,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (pendingEvent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await this.workflowRunWorkspaceService.endWorkflowRun({
|
await this.workflowRunWorkspaceService.endWorkflowRun({
|
||||||
workflowRunId,
|
workflowRunId,
|
||||||
|
|||||||
Reference in New Issue
Block a user