diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-create-many.post-query.hook.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-create-many.post-query.hook.ts index 7334f00a4..04ef8e8a4 100644 --- a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-create-many.post-query.hook.ts +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-create-many.post-query.hook.ts @@ -8,6 +8,7 @@ import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; import { WorkspaceQueryHookType } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type'; import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; +import { RecordPositionService } from 'src/engine/core-modules/record-position/services/record-position.service'; 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'; @@ -29,6 +30,7 @@ export class WorkflowCreateManyPostQueryHook private readonly workspaceEventEmitter: WorkspaceEventEmitter, @InjectRepository(ObjectMetadataEntity, 'metadata') private readonly objectMetadataRepository: Repository, + private readonly recordPositionService: RecordPositionService, ) {} async execute( @@ -41,11 +43,21 @@ export class WorkflowCreateManyPostQueryHook 'workflowVersion', ); + const position = await this.recordPositionService.buildRecordPosition({ + value: 'first', + objectMetadata: { + isCustom: false, + nameSingular: 'workflowVersion', + }, + workspaceId: authContext.workspace.id, + }); + const workflowVersionsToCreate = payload.map((workflow) => { return workflowVersionRepository.create({ workflowId: workflow.id, status: WorkflowVersionStatus.DRAFT, name: 'v1', + position, }); }); diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-create-one.post-query.hook.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-create-one.post-query.hook.ts index e8009ee39..681f4dec2 100644 --- a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-create-one.post-query.hook.ts +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-create-one.post-query.hook.ts @@ -8,6 +8,7 @@ import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; import { WorkspaceQueryHookType } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type'; import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; +import { RecordPositionService } from 'src/engine/core-modules/record-position/services/record-position.service'; 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'; @@ -29,6 +30,7 @@ export class WorkflowCreateOnePostQueryHook private readonly workspaceEventEmitter: WorkspaceEventEmitter, @InjectRepository(ObjectMetadataEntity, 'metadata') private readonly objectMetadataRepository: Repository, + private readonly recordPositionService: RecordPositionService, ) {} async execute( @@ -43,10 +45,20 @@ export class WorkflowCreateOnePostQueryHook 'workflowVersion', ); + const position = await this.recordPositionService.buildRecordPosition({ + value: 'first', + objectMetadata: { + isCustom: false, + nameSingular: 'workflowVersion', + }, + workspaceId: authContext.workspace.id, + }); + const workflowVersionToCreate = await workflowVersionRepository.create({ workflowId: workflow.id, status: WorkflowVersionStatus.DRAFT, name: 'v1', + position, }); await workflowVersionRepository.save(workflowVersionToCreate); diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-query-hook.module.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-query-hook.module.ts index d1cc87294..d7d2fc7e9 100644 --- a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-query-hook.module.ts +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-query-hook.module.ts @@ -2,7 +2,9 @@ import { Module } from '@nestjs/common'; import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm'; +import { RecordPositionModule } from 'src/engine/core-modules/record-position/record-position.module'; 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 { WorkflowCreateManyPostQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-create-many.post-query.hook'; import { WorkflowCreateManyPreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-create-many.pre-query.hook'; import { WorkflowCreateOnePostQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-create-one.post-query.hook'; @@ -25,12 +27,12 @@ import { WorkflowVersionUpdateManyPreQueryHook } from 'src/modules/workflow/comm import { WorkflowVersionUpdateOnePreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-version-update-one.pre-query.hook'; import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service'; import { WorkflowVersionValidationWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-version-validation.workspace-service'; -import { ServerlessFunctionModule } from 'src/engine/metadata-modules/serverless-function/serverless-function.module'; @Module({ imports: [ NestjsQueryTypeOrmModule.forFeature([ObjectMetadataEntity], 'metadata'), ServerlessFunctionModule, + RecordPositionModule, ], providers: [ WorkflowCreateOnePreQueryHook, diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version-create-many.pre-query.hook.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version-create-many.pre-query.hook.ts index 51849295a..25f80c23e 100644 --- a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version-create-many.pre-query.hook.ts +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version-create-many.pre-query.hook.ts @@ -1,37 +1,26 @@ import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; -import { - CreateManyResolverArgs, - CreateOneResolverArgs, -} from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; +import { CreateManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; -import { WorkflowVersionValidationWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-version-validation.workspace-service'; +import { + WorkflowQueryValidationException, + WorkflowQueryValidationExceptionCode, +} from 'src/modules/workflow/common/exceptions/workflow-query-validation.exception'; import { WorkflowVersionWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity'; @WorkspaceQueryHook(`workflowVersion.createMany`) export class WorkflowVersionCreateManyPreQueryHook implements WorkspaceQueryHookInstance { - constructor( - private readonly workflowVersionValidationWorkspaceService: WorkflowVersionValidationWorkspaceService, - ) {} - async execute( _authContext: AuthContext, _objectName: string, - payload: CreateManyResolverArgs, + _payload: CreateManyResolverArgs, ): Promise> { - await Promise.all( - payload.data.map(async (workflowVersion) => { - await this.workflowVersionValidationWorkspaceService.validateWorkflowVersionForCreateOne( - { - data: workflowVersion, - } satisfies CreateOneResolverArgs, - ); - }), + throw new WorkflowQueryValidationException( + 'Method not allowed.', + WorkflowQueryValidationExceptionCode.FORBIDDEN, ); - - return payload; } } diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version-create-one.pre-query.hook.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version-create-one.pre-query.hook.ts index 0741ec96d..71a08f046 100644 --- a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version-create-one.pre-query.hook.ts +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version-create-one.pre-query.hook.ts @@ -3,26 +3,24 @@ import { CreateOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; -import { WorkflowVersionValidationWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-version-validation.workspace-service'; +import { + WorkflowQueryValidationException, + WorkflowQueryValidationExceptionCode, +} from 'src/modules/workflow/common/exceptions/workflow-query-validation.exception'; import { WorkflowVersionWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity'; @WorkspaceQueryHook(`workflowVersion.createOne`) export class WorkflowVersionCreateOnePreQueryHook implements WorkspaceQueryHookInstance { - constructor( - private readonly workflowVersionValidationWorkspaceService: WorkflowVersionValidationWorkspaceService, - ) {} - async execute( _authContext: AuthContext, _objectName: string, - payload: CreateOneResolverArgs, + _payload: CreateOneResolverArgs, ): Promise> { - await this.workflowVersionValidationWorkspaceService.validateWorkflowVersionForCreateOne( - payload, + throw new WorkflowQueryValidationException( + 'Method not allowed.', + WorkflowQueryValidationExceptionCode.FORBIDDEN, ); - - return payload; } } diff --git a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version/workflow-version.module.ts b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version/workflow-version.module.ts index 6fc67af17..7830946dc 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version/workflow-version.module.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version/workflow-version.module.ts @@ -2,6 +2,7 @@ import { Module } from '@nestjs/common'; import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm'; +import { RecordPositionModule } from 'src/engine/core-modules/record-position/record-position.module'; 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'; @@ -15,6 +16,7 @@ import { WorkflowVersionWorkspaceService } from 'src/modules/workflow/workflow-b ServerlessFunctionModule, WorkflowVersionStepModule, NestjsQueryTypeOrmModule.forFeature([ObjectMetadataEntity], 'metadata'), + RecordPositionModule, ], providers: [WorkflowVersionWorkspaceService], exports: [WorkflowVersionWorkspaceService], diff --git a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version/workflow-version.workspace-service.ts b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version/workflow-version.workspace-service.ts index 52199dcd1..9c1019b90 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version/workflow-version.workspace-service.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version/workflow-version.workspace-service.ts @@ -1,10 +1,11 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; -import { Repository } from 'typeorm'; import { isDefined } from 'twenty-shared/utils'; +import { Repository } from 'typeorm'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; +import { RecordPositionService } from 'src/engine/core-modules/record-position/services/record-position.service'; 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'; @@ -30,6 +31,7 @@ export class WorkflowVersionWorkspaceService { @InjectRepository(ObjectMetadataEntity, 'metadata') private readonly objectMetadataRepository: Repository, private readonly workspaceEventEmitter: WorkspaceEventEmitter, + private readonly recordPositionService: RecordPositionService, ) {} async createDraftFromWorkflowVersion({ @@ -77,10 +79,20 @@ export class WorkflowVersionWorkspaceService { }, }); + const position = await this.recordPositionService.buildRecordPosition({ + value: 'first', + objectMetadata: { + isCustom: false, + nameSingular: 'workflowVersion', + }, + workspaceId, + }); + draftWorkflowVersion = await workflowVersionRepository.save({ workflowId, name: `v${workflowVersionsCount + 1}`, status: WorkflowVersionStatus.DRAFT, + position, }); await this.emitWorkflowVersionCreationEvent({ diff --git a/packages/twenty-server/src/modules/workflow/workflow-runner/workflow-run/workflow-run.module.ts b/packages/twenty-server/src/modules/workflow/workflow-runner/workflow-run/workflow-run.module.ts index 55a987bc9..00d43bf22 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-runner/workflow-run/workflow-run.module.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-runner/workflow-run/workflow-run.module.ts @@ -1,11 +1,13 @@ import { Module } from '@nestjs/common'; +import { RecordPositionModule } from 'src/engine/core-modules/record-position/record-position.module'; +import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/scoped-workspace-context.factory'; import { WorkflowCommonModule } from 'src/modules/workflow/common/workflow-common.module'; import { WorkflowRunWorkspaceService } from 'src/modules/workflow/workflow-runner/workflow-run/workflow-run.workspace-service'; @Module({ - imports: [WorkflowCommonModule], - providers: [WorkflowRunWorkspaceService], + imports: [WorkflowCommonModule, RecordPositionModule], + providers: [WorkflowRunWorkspaceService, ScopedWorkspaceContextFactory], exports: [WorkflowRunWorkspaceService], }) export class WorkflowRunModule {} diff --git a/packages/twenty-server/src/modules/workflow/workflow-runner/workflow-run/workflow-run.workspace-service.ts b/packages/twenty-server/src/modules/workflow/workflow-runner/workflow-run/workflow-run.workspace-service.ts index 022b77981..7cfb40e55 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-runner/workflow-run/workflow-run.workspace-service.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-runner/workflow-run/workflow-run.workspace-service.ts @@ -1,6 +1,8 @@ import { Injectable } from '@nestjs/common'; +import { RecordPositionService } from 'src/engine/core-modules/record-position/services/record-position.service'; import { ActorMetadata } from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type'; +import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/scoped-workspace-context.factory'; import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; import { StepOutput, @@ -21,6 +23,8 @@ export class WorkflowRunWorkspaceService { constructor( private readonly twentyORMManager: TwentyORMManager, private readonly workflowCommonWorkspaceService: WorkflowCommonWorkspaceService, + private readonly recordPositionService: RecordPositionService, + private readonly scopedWorkspaceContextFactory: ScopedWorkspaceContextFactory, ) {} async createWorkflowRun({ @@ -64,6 +68,25 @@ export class WorkflowRunWorkspaceService { }, }); + const workspaceId = + this.scopedWorkspaceContextFactory.create()?.workspaceId; + + if (!workspaceId) { + throw new WorkflowRunException( + 'Workspace id is invalid', + WorkflowRunExceptionCode.WORKFLOW_RUN_INVALID, + ); + } + + const position = await this.recordPositionService.buildRecordPosition({ + value: 'first', + objectMetadata: { + isCustom: false, + nameSingular: 'workflowRun', + }, + workspaceId, + }); + return ( await workflowRunRepository.save({ name: `#${workflowRunCount + 1} - ${workflow.name}`, @@ -71,6 +94,7 @@ export class WorkflowRunWorkspaceService { createdBy, workflowId: workflow.id, status: WorkflowRunStatus.NOT_STARTED, + position, }) ).id; }