Move workflow versions and steps building to workflow-builder folder (#10523)

We are starting to put too many services in common folder. Version and
step building should be separated into different services and go to the
builder folder. Today builder folder only manage schema.

We should:
- keep services responsible for only one action
- keep modules based on the actual action these provide rather than
having common module

This PR:
- creates a service for workflow version builder
- moves version and step builders to workflow builder folder rather than
commun
- creates separated folders for schema, version and steps

No logic has been added. Only modules created and functions moved.
This commit is contained in:
Thomas Trompette
2025-02-27 10:39:48 +01:00
committed by GitHub
parent 8bd9bc9d31
commit 83930551d8
21 changed files with 495 additions and 399 deletions

View File

@ -1,16 +1,23 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { ServerlessFunctionModule } from 'src/engine/metadata-modules/serverless-function/serverless-function.module';
import { WorkflowBuilderWorkspaceService } from 'src/modules/workflow/workflow-builder/workflow-builder.workspace-service';
import { WorkflowSchemaModule } from 'src/modules/workflow/workflow-builder/workflow-schema/workflow-schema.module';
import { WorkflowVersionStepModule } from 'src/modules/workflow/workflow-builder/workflow-version/workflow-step/workflow-version-step.module';
import { WorkflowVersionModule } from 'src/modules/workflow/workflow-builder/workflow-version/workflow-version.module';
@Module({
imports: [
TypeOrmModule.forFeature([ObjectMetadataEntity], 'metadata'),
ServerlessFunctionModule,
WorkflowSchemaModule,
WorkflowVersionModule,
WorkflowVersionStepModule,
NestjsQueryTypeOrmModule.forFeature([ObjectMetadataEntity], 'metadata'),
],
exports: [
WorkflowSchemaModule,
WorkflowVersionModule,
WorkflowVersionStepModule,
],
providers: [WorkflowBuilderWorkspaceService],
exports: [WorkflowBuilderWorkspaceService],
})
export class WorkflowBuilderModule {}

View File

@ -1,4 +1,4 @@
import { InputSchemaPropertyType } from 'src/modules/workflow/workflow-builder/types/input-schema.type';
import { InputSchemaPropertyType } from 'src/modules/workflow/workflow-builder/workflow-schema/types/input-schema.type';
export type Leaf = {
isLeaf: true;

View File

@ -2,8 +2,8 @@ import { v4 } from 'uuid';
import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { BaseOutputSchema } from 'src/modules/workflow/workflow-builder/types/output-schema.type';
import { generateFakeObjectRecord } from 'src/modules/workflow/workflow-builder/utils/generate-fake-object-record';
import { BaseOutputSchema } from 'src/modules/workflow/workflow-builder/workflow-schema/types/output-schema.type';
import { generateFakeObjectRecord } from 'src/modules/workflow/workflow-builder/workflow-schema/utils/generate-fake-object-record';
import { camelToTitleCase } from 'src/utils/camel-to-title-case';
export const generateFakeObjectRecordEvent = (

View File

@ -5,8 +5,8 @@ import {
Leaf,
Node,
RecordOutputSchema,
} from 'src/modules/workflow/workflow-builder/types/output-schema.type';
import { shouldGenerateFieldFakeValue } from 'src/modules/workflow/workflow-builder/utils/should-generate-field-fake-value';
} from 'src/modules/workflow/workflow-builder/workflow-schema/types/output-schema.type';
import { shouldGenerateFieldFakeValue } from 'src/modules/workflow/workflow-builder/workflow-schema/utils/should-generate-field-fake-value';
import { camelToTitleCase } from 'src/utils/camel-to-title-case';
const generateObjectRecordFields = (

View File

@ -0,0 +1,12 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { WorkflowSchemaWorkspaceService } from 'src/modules/workflow/workflow-builder/workflow-schema/workflow-schema.workspace-service';
@Module({
imports: [TypeOrmModule.forFeature([ObjectMetadataEntity], 'metadata')],
providers: [WorkflowSchemaWorkspaceService],
exports: [WorkflowSchemaWorkspaceService],
})
export class WorkflowSchemaModule {}

View File

@ -1,17 +1,16 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { isDefined } from 'twenty-shared';
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 { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { ServerlessFunctionService } from 'src/engine/metadata-modules/serverless-function/serverless-function.service';
import { generateFakeValue } from 'src/engine/utils/generate-fake-value';
import { OutputSchema } from 'src/modules/workflow/workflow-builder/types/output-schema.type';
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 { OutputSchema } from 'src/modules/workflow/workflow-builder/workflow-schema/types/output-schema.type';
import { generateFakeObjectRecord } from 'src/modules/workflow/workflow-builder/workflow-schema/utils/generate-fake-object-record';
import { generateFakeObjectRecordEvent } from 'src/modules/workflow/workflow-builder/workflow-schema/utils/generate-fake-object-record-event';
import {
WorkflowAction,
WorkflowActionType,
@ -22,9 +21,8 @@ import {
} from 'src/modules/workflow/workflow-trigger/types/workflow-trigger.type';
@Injectable()
export class WorkflowBuilderWorkspaceService {
export class WorkflowSchemaWorkspaceService {
constructor(
private readonly serverlessFunctionService: ServerlessFunctionService,
@InjectRepository(ObjectMetadataEntity, 'metadata')
private readonly objectMetadataRepository: Repository<ObjectMetadataEntity>,
) {}

View File

@ -0,0 +1,19 @@
import { Module } from '@nestjs/common';
import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { ServerlessFunctionModule } from 'src/engine/metadata-modules/serverless-function/serverless-function.module';
import { WorkflowSchemaModule } from 'src/modules/workflow/workflow-builder/workflow-schema/workflow-schema.module';
import { WorkflowVersionStepWorkspaceService } from 'src/modules/workflow/workflow-builder/workflow-version/workflow-step/workflow-version-step.workspace-service';
@Module({
imports: [
WorkflowSchemaModule,
ServerlessFunctionModule,
NestjsQueryTypeOrmModule.forFeature([ObjectMetadataEntity], 'metadata'),
],
providers: [WorkflowVersionStepWorkspaceService],
exports: [WorkflowVersionStepWorkspaceService],
})
export class WorkflowVersionStepModule {}

View File

@ -0,0 +1,448 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { isDefined } from 'twenty-shared';
import { Repository } from 'typeorm';
import { v4 } from 'uuid';
import { BASE_TYPESCRIPT_PROJECT_INPUT_SCHEMA } from 'src/engine/core-modules/serverless/drivers/constants/base-typescript-project-input-schema';
import { WorkflowActionDTO } from 'src/engine/core-modules/workflow/dtos/workflow-step.dto';
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 { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
import {
WorkflowVersionStepException,
WorkflowVersionStepExceptionCode,
} from 'src/modules/workflow/common/exceptions/workflow-version-step.exception';
import { WorkflowVersionWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity';
import { WorkflowSchemaWorkspaceService } from 'src/modules/workflow/workflow-builder/workflow-schema/workflow-schema.workspace-service';
import { BaseWorkflowActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-settings.type';
import {
WorkflowAction,
WorkflowActionType,
} from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type';
const TRIGGER_STEP_ID = 'trigger';
const BASE_STEP_DEFINITION: BaseWorkflowActionSettings = {
outputSchema: {},
errorHandlingOptions: {
continueOnFailure: {
value: false,
},
retryOnFailure: {
value: false,
},
},
};
@Injectable()
export class WorkflowVersionStepWorkspaceService {
constructor(
private readonly twentyORMManager: TwentyORMManager,
private readonly workflowSchemaWorkspaceService: WorkflowSchemaWorkspaceService,
private readonly serverlessFunctionService: ServerlessFunctionService,
@InjectRepository(ObjectMetadataEntity, 'metadata')
private readonly objectMetadataRepository: Repository<ObjectMetadataEntity>,
) {}
async createWorkflowVersionStep({
workspaceId,
workflowVersionId,
stepType,
}: {
workspaceId: string;
workflowVersionId: string;
stepType: WorkflowActionType;
}): Promise<WorkflowActionDTO> {
const newStep = await this.getStepDefaultDefinition({
type: stepType,
workspaceId,
});
const enrichedNewStep = await this.enrichOutputSchema({
step: newStep,
workspaceId,
});
const workflowVersionRepository =
await this.twentyORMManager.getRepository<WorkflowVersionWorkspaceEntity>(
'workflowVersion',
);
const workflowVersion = await workflowVersionRepository.findOne({
where: {
id: workflowVersionId,
},
});
if (!isDefined(workflowVersion)) {
throw new WorkflowVersionStepException(
'WorkflowVersion not found',
WorkflowVersionStepExceptionCode.NOT_FOUND,
);
}
await workflowVersionRepository.update(workflowVersion.id, {
steps: [...(workflowVersion.steps || []), enrichedNewStep],
});
return enrichedNewStep;
}
async updateWorkflowVersionStep({
workspaceId,
workflowVersionId,
step,
}: {
workspaceId: string;
workflowVersionId: string;
step: WorkflowAction;
}): Promise<WorkflowAction> {
const workflowVersionRepository =
await this.twentyORMManager.getRepository<WorkflowVersionWorkspaceEntity>(
'workflowVersion',
);
const workflowVersion = await workflowVersionRepository.findOne({
where: {
id: workflowVersionId,
},
});
if (!isDefined(workflowVersion)) {
throw new WorkflowVersionStepException(
'WorkflowVersion not found',
WorkflowVersionStepExceptionCode.NOT_FOUND,
);
}
if (!isDefined(workflowVersion.steps)) {
throw new WorkflowVersionStepException(
"Can't update step from undefined steps",
WorkflowVersionStepExceptionCode.UNDEFINED,
);
}
const enrichedNewStep = await this.enrichOutputSchema({
step,
workspaceId,
});
const updatedSteps = workflowVersion.steps.map((existingStep) => {
if (existingStep.id === step.id) {
return enrichedNewStep;
} else {
return existingStep;
}
});
await workflowVersionRepository.update(workflowVersion.id, {
steps: updatedSteps,
});
return enrichedNewStep;
}
async deleteWorkflowVersionStep({
workspaceId,
workflowVersionId,
stepId,
}: {
workspaceId: string;
workflowVersionId: string;
stepId: string;
}): Promise<WorkflowActionDTO> {
const workflowVersionRepository =
await this.twentyORMManager.getRepository<WorkflowVersionWorkspaceEntity>(
'workflowVersion',
);
const workflowVersion = await workflowVersionRepository.findOne({
where: {
id: workflowVersionId,
},
});
if (!isDefined(workflowVersion)) {
throw new WorkflowVersionStepException(
'WorkflowVersion not found',
WorkflowVersionStepExceptionCode.NOT_FOUND,
);
}
if (!isDefined(workflowVersion.steps)) {
throw new WorkflowVersionStepException(
"Can't delete step from undefined steps",
WorkflowVersionStepExceptionCode.UNDEFINED,
);
}
const stepToDelete = workflowVersion.steps.filter(
(step) => step.id === stepId,
)?.[0];
if (!isDefined(stepToDelete)) {
throw new WorkflowVersionStepException(
"Can't delete not existing step",
WorkflowVersionStepExceptionCode.NOT_FOUND,
);
}
const workflowVersionUpdates =
stepId === TRIGGER_STEP_ID
? { trigger: null }
: { steps: workflowVersion.steps.filter((step) => step.id !== stepId) };
await workflowVersionRepository.update(
workflowVersion.id,
workflowVersionUpdates,
);
await this.runWorkflowVersionStepDeletionSideEffects({
step: stepToDelete,
workspaceId,
});
return stepToDelete;
}
async duplicateStep({
step,
workspaceId,
}: {
step: WorkflowAction;
workspaceId: string;
}): Promise<WorkflowAction> {
switch (step.type) {
case WorkflowActionType.CODE: {
await this.serverlessFunctionService.usePublishedVersionAsDraft({
id: step.settings.input.serverlessFunctionId,
version: step.settings.input.serverlessFunctionVersion,
workspaceId,
});
return {
...step,
settings: {
...step.settings,
input: {
...step.settings.input,
serverlessFunctionVersion: 'draft',
},
},
};
}
default: {
return step;
}
}
}
private async enrichOutputSchema({
step,
workspaceId,
}: {
step: WorkflowAction;
workspaceId: string;
}): Promise<WorkflowAction> {
// We don't enrich on the fly for code workflow action. OutputSchema is computed and updated when testing the serverless function
if (step.type === WorkflowActionType.CODE) {
return step;
}
const result = { ...step };
const outputSchema =
await this.workflowSchemaWorkspaceService.computeStepOutputSchema({
step,
workspaceId,
});
result.settings = {
...result.settings,
outputSchema: outputSchema || {},
};
return result;
}
private async runWorkflowVersionStepDeletionSideEffects({
step,
workspaceId,
}: {
step: WorkflowAction;
workspaceId: string;
}) {
switch (step.type) {
case WorkflowActionType.CODE: {
if (
!(await this.serverlessFunctionService.hasServerlessFunctionPublishedVersion(
step.settings.input.serverlessFunctionId,
))
) {
await this.serverlessFunctionService.deleteOneServerlessFunction({
id: step.settings.input.serverlessFunctionId,
workspaceId,
});
}
break;
}
}
}
private async getStepDefaultDefinition({
type,
workspaceId,
}: {
type: WorkflowActionType;
workspaceId: string;
}): Promise<WorkflowAction> {
const newStepId = v4();
switch (type) {
case WorkflowActionType.CODE: {
const newServerlessFunction =
await this.serverlessFunctionService.createOneServerlessFunction(
{
name: 'A Serverless Function Code Workflow Step',
description: '',
},
workspaceId,
);
if (!isDefined(newServerlessFunction)) {
throw new WorkflowVersionStepException(
'Fail to create Code Step',
WorkflowVersionStepExceptionCode.FAILURE,
);
}
return {
id: newStepId,
name: 'Code - Serverless Function',
type: WorkflowActionType.CODE,
valid: false,
settings: {
...BASE_STEP_DEFINITION,
outputSchema: {
link: {
isLeaf: true,
icon: 'IconVariable',
tab: 'test',
label: 'Generate Function Output',
},
_outputSchemaType: 'LINK',
},
input: {
serverlessFunctionId: newServerlessFunction.id,
serverlessFunctionVersion: 'draft',
serverlessFunctionInput: BASE_TYPESCRIPT_PROJECT_INPUT_SCHEMA,
},
},
};
}
case WorkflowActionType.SEND_EMAIL: {
return {
id: newStepId,
name: 'Send Email',
type: WorkflowActionType.SEND_EMAIL,
valid: false,
settings: {
...BASE_STEP_DEFINITION,
input: {
connectedAccountId: '',
email: '',
subject: '',
body: '',
},
},
};
}
case WorkflowActionType.CREATE_RECORD: {
const activeObjectMetadataItem =
await this.objectMetadataRepository.findOne({
where: { workspaceId, isActive: true, isSystem: false },
});
return {
id: newStepId,
name: 'Create Record',
type: WorkflowActionType.CREATE_RECORD,
valid: false,
settings: {
...BASE_STEP_DEFINITION,
input: {
objectName: activeObjectMetadataItem?.nameSingular || '',
objectRecord: {},
},
},
};
}
case WorkflowActionType.UPDATE_RECORD: {
const activeObjectMetadataItem =
await this.objectMetadataRepository.findOne({
where: { workspaceId, isActive: true, isSystem: false },
});
return {
id: newStepId,
name: 'Update Record',
type: WorkflowActionType.UPDATE_RECORD,
valid: false,
settings: {
...BASE_STEP_DEFINITION,
input: {
objectName: activeObjectMetadataItem?.nameSingular || '',
objectRecord: {},
objectRecordId: '',
fieldsToUpdate: [],
},
},
};
}
case WorkflowActionType.DELETE_RECORD: {
const activeObjectMetadataItem =
await this.objectMetadataRepository.findOne({
where: { workspaceId, isActive: true, isSystem: false },
});
return {
id: newStepId,
name: 'Delete Record',
type: WorkflowActionType.DELETE_RECORD,
valid: false,
settings: {
...BASE_STEP_DEFINITION,
input: {
objectName: activeObjectMetadataItem?.nameSingular || '',
objectRecordId: '',
},
},
};
}
case WorkflowActionType.FIND_RECORDS: {
const activeObjectMetadataItem =
await this.objectMetadataRepository.findOne({
where: { workspaceId, isActive: true, isSystem: false },
});
return {
id: newStepId,
name: 'Search Records',
type: WorkflowActionType.FIND_RECORDS,
valid: false,
settings: {
...BASE_STEP_DEFINITION,
input: {
objectName: activeObjectMetadataItem?.nameSingular || '',
limit: 1,
},
},
};
}
default:
throw new WorkflowVersionStepException(
`WorkflowActionType '${type}' unknown`,
WorkflowVersionStepExceptionCode.UNKNOWN,
);
}
}
}

View File

@ -0,0 +1,28 @@
import { Module } from '@nestjs/common';
import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { ServerlessFunctionModule } from 'src/engine/metadata-modules/serverless-function/serverless-function.module';
import { WorkflowSchemaModule } from 'src/modules/workflow/workflow-builder/workflow-schema/workflow-schema.module';
import { WorkflowVersionStepModule } from 'src/modules/workflow/workflow-builder/workflow-version/workflow-step/workflow-version-step.module';
import { WorkflowVersionStepWorkspaceService } from 'src/modules/workflow/workflow-builder/workflow-version/workflow-step/workflow-version-step.workspace-service';
import { WorkflowVersionWorkspaceService } from 'src/modules/workflow/workflow-builder/workflow-version/workflow-version.workspace-service';
@Module({
imports: [
WorkflowVersionStepModule,
WorkflowSchemaModule,
ServerlessFunctionModule,
NestjsQueryTypeOrmModule.forFeature([ObjectMetadataEntity], 'metadata'),
],
providers: [
WorkflowVersionWorkspaceService,
WorkflowVersionStepWorkspaceService,
],
exports: [
WorkflowVersionWorkspaceService,
WorkflowVersionStepWorkspaceService,
],
})
export class WorkflowVersionModule {}

View File

@ -0,0 +1,151 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { isDefined } from 'twenty-shared';
import { Repository } from 'typeorm';
import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/workspace-event-emitter';
import {
WorkflowVersionStepException,
WorkflowVersionStepExceptionCode,
} from 'src/modules/workflow/common/exceptions/workflow-version-step.exception';
import {
WorkflowVersionStatus,
WorkflowVersionWorkspaceEntity,
} from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity';
import { assertWorkflowVersionHasSteps } from 'src/modules/workflow/common/utils/assert-workflow-version-has-steps';
import { assertWorkflowVersionIsDraft } from 'src/modules/workflow/common/utils/assert-workflow-version-is-draft.util';
import { assertWorkflowVersionTriggerIsDefined } from 'src/modules/workflow/common/utils/assert-workflow-version-trigger-is-defined.util';
import { WorkflowVersionStepWorkspaceService } from 'src/modules/workflow/workflow-builder/workflow-version/workflow-step/workflow-version-step.workspace-service';
import { WorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type';
@Injectable()
export class WorkflowVersionWorkspaceService {
constructor(
private readonly twentyORMManager: TwentyORMManager,
private readonly workflowVersionStepWorkspaceService: WorkflowVersionStepWorkspaceService,
@InjectRepository(ObjectMetadataEntity, 'metadata')
private readonly objectMetadataRepository: Repository<ObjectMetadataEntity>,
private readonly workspaceEventEmitter: WorkspaceEventEmitter,
) {}
async createDraftFromWorkflowVersion({
workspaceId,
workflowId,
workflowVersionIdToCopy,
}: {
workspaceId: string;
workflowId: string;
workflowVersionIdToCopy: string;
}) {
const workflowVersionRepository =
await this.twentyORMManager.getRepository<WorkflowVersionWorkspaceEntity>(
'workflowVersion',
);
const workflowVersionToCopy = await workflowVersionRepository.findOne({
where: {
id: workflowVersionIdToCopy,
workflowId,
},
});
if (!isDefined(workflowVersionToCopy)) {
throw new WorkflowVersionStepException(
'WorkflowVersion to copy not found',
WorkflowVersionStepExceptionCode.NOT_FOUND,
);
}
assertWorkflowVersionTriggerIsDefined(workflowVersionToCopy);
assertWorkflowVersionHasSteps(workflowVersionToCopy);
let draftWorkflowVersion = await workflowVersionRepository.findOne({
where: {
workflowId,
status: WorkflowVersionStatus.DRAFT,
},
});
if (!isDefined(draftWorkflowVersion)) {
const workflowVersionsCount = await workflowVersionRepository.count({
where: {
workflowId,
},
});
draftWorkflowVersion = await workflowVersionRepository.save({
workflowId,
name: `v${workflowVersionsCount + 1}`,
status: WorkflowVersionStatus.DRAFT,
});
await this.emitWorkflowVersionCreationEvent({
workflowVersion: draftWorkflowVersion,
workspaceId,
});
}
assertWorkflowVersionIsDraft(draftWorkflowVersion);
const newWorkflowVersionTrigger = workflowVersionToCopy.trigger;
const newWorkflowVersionSteps: WorkflowAction[] = [];
for (const step of workflowVersionToCopy.steps) {
const duplicatedStep =
await this.workflowVersionStepWorkspaceService.duplicateStep({
step,
workspaceId,
});
newWorkflowVersionSteps.push(duplicatedStep);
}
await workflowVersionRepository.update(draftWorkflowVersion.id, {
steps: newWorkflowVersionSteps,
trigger: newWorkflowVersionTrigger,
});
return draftWorkflowVersion.id;
}
private async emitWorkflowVersionCreationEvent({
workflowVersion,
workspaceId,
}: {
workflowVersion: WorkflowVersionWorkspaceEntity;
workspaceId: string;
}) {
const objectMetadata = await this.objectMetadataRepository.findOne({
where: {
nameSingular: 'workflowVersion',
workspaceId,
},
});
if (!objectMetadata) {
throw new WorkflowVersionStepException(
'Object metadata not found',
WorkflowVersionStepExceptionCode.FAILURE,
);
}
this.workspaceEventEmitter.emitDatabaseBatchEvent({
objectMetadataNameSingular: 'workflowVersion',
action: DatabaseEventAction.CREATED,
events: [
{
recordId: workflowVersion.id,
objectMetadata,
properties: {
after: workflowVersion,
},
},
],
workspaceId,
});
}
}