Refactor workflow-logic-function-interaction (#17699)
# Refactor workflow–logic function interaction ## Why Workflow code steps and standalone logic functions shared the same build layer and DB layer, which blurred two use cases: code steps belong to a workflow version; standalone functions are deployable units. That made workflow code steps harder to own and evolve. ## Goal Treat code steps as **workflow-owned**: build and run them in workflow context, and expose workflow-scoped APIs so the editor can load, test, and save code step source without going through the generic logic-function layer.
This commit is contained in:
+104
-4
@@ -1,6 +1,7 @@
|
||||
import { Test, type TestingModule } from '@nestjs/testing';
|
||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { AiAgentRoleService } from 'src/engine/metadata-modules/ai/ai-agent-role/ai-agent-role.service';
|
||||
import { AgentEntity } from 'src/engine/metadata-modules/ai/ai-agent/entities/agent.entity';
|
||||
import { createEmptyAllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-all-flat-entity-maps.constant';
|
||||
@@ -14,6 +15,7 @@ import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
|
||||
import { CodeStepBuildService } from 'src/modules/workflow/workflow-builder/workflow-version-step/code-step/services/code-step-build.service';
|
||||
import { WorkflowVersionStepOperationsWorkspaceService } from 'src/modules/workflow/workflow-builder/workflow-version-step/workflow-version-step-operations.workspace-service';
|
||||
import {
|
||||
type WorkflowAction,
|
||||
@@ -26,6 +28,8 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
|
||||
let service: WorkflowVersionStepOperationsWorkspaceService;
|
||||
let globalWorkspaceOrmManager: jest.Mocked<GlobalWorkspaceOrmManager>;
|
||||
let logicFunctionService: jest.Mocked<LogicFunctionService>;
|
||||
let applicationService: jest.Mocked<ApplicationService>;
|
||||
let codeStepBuildService: jest.Mocked<CodeStepBuildService>;
|
||||
let agentRepository: jest.Mocked<any>;
|
||||
let roleTargetRepository: jest.Mocked<any>;
|
||||
let roleRepository: jest.Mocked<any>;
|
||||
@@ -33,12 +37,53 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
|
||||
let workflowCommonWorkspaceService: jest.Mocked<WorkflowCommonWorkspaceService>;
|
||||
let aiAgentRoleService: jest.Mocked<AiAgentRoleService>;
|
||||
let workspaceCacheService: jest.Mocked<WorkspaceCacheService>;
|
||||
let flatEntityMapsCacheService: jest.Mocked<WorkspaceManyOrAllFlatEntityMapsCacheService>;
|
||||
|
||||
beforeEach(async () => {
|
||||
applicationService = {
|
||||
findWorkspaceTwentyStandardAndCustomApplicationOrThrow: jest
|
||||
.fn()
|
||||
.mockResolvedValue({
|
||||
workspaceCustomFlatApplication: {
|
||||
universalIdentifier: 'app-universal-id',
|
||||
},
|
||||
}),
|
||||
} as unknown as jest.Mocked<ApplicationService>;
|
||||
|
||||
codeStepBuildService = {
|
||||
seedCodeStepFiles: jest.fn().mockResolvedValue({
|
||||
sourceHandlerPath: 'workflow/logic-fn-id/src/index.ts',
|
||||
builtHandlerPath: 'workflow/logic-fn-id/src/index.mjs',
|
||||
checksum: 'seed-checksum',
|
||||
}),
|
||||
copySourceAndBuiltForNewCodeStep: jest.fn().mockResolvedValue(undefined),
|
||||
duplicateCodeStepLogicFunction: jest.fn().mockResolvedValue({
|
||||
id: 'new-function-id',
|
||||
name: 'Test Function',
|
||||
description: 'Test Description',
|
||||
workspaceId: mockWorkspaceId,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
deletedAt: null,
|
||||
runtime: LogicFunctionRuntime.NODE22,
|
||||
timeoutSeconds: 30,
|
||||
sourceHandlerPath: 'src/index.ts',
|
||||
builtHandlerPath: 'index.mjs',
|
||||
handlerName: 'main',
|
||||
checksum: null,
|
||||
toolInputSchema: null,
|
||||
isTool: false,
|
||||
universalIdentifier: 'universal-id',
|
||||
applicationId: 'application-id',
|
||||
cronTriggerSettings: null,
|
||||
databaseEventTriggerSettings: null,
|
||||
httpRouteTriggerSettings: null,
|
||||
}),
|
||||
} as unknown as jest.Mocked<CodeStepBuildService>;
|
||||
|
||||
logicFunctionService = {
|
||||
createOne: jest.fn(),
|
||||
destroyOne: jest.fn(),
|
||||
duplicateLogicFunction: jest.fn(),
|
||||
} as unknown as jest.Mocked<LogicFunctionService>;
|
||||
|
||||
agentRepository = {
|
||||
@@ -86,6 +131,14 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
|
||||
provide: LogicFunctionService,
|
||||
useValue: logicFunctionService,
|
||||
},
|
||||
{
|
||||
provide: ApplicationService,
|
||||
useValue: applicationService,
|
||||
},
|
||||
{
|
||||
provide: CodeStepBuildService,
|
||||
useValue: codeStepBuildService,
|
||||
},
|
||||
{
|
||||
provide: getRepositoryToken(AgentEntity),
|
||||
useValue: agentRepository,
|
||||
@@ -116,12 +169,12 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
|
||||
},
|
||||
{
|
||||
provide: WorkspaceManyOrAllFlatEntityMapsCacheService,
|
||||
useValue: {
|
||||
useValue: (flatEntityMapsCacheService = {
|
||||
flushFlatEntityMaps: jest.fn(),
|
||||
getOrRecomputeManyOrAllFlatEntityMaps: jest
|
||||
.fn()
|
||||
.mockResolvedValue(createEmptyAllFlatEntityMaps()),
|
||||
},
|
||||
} as unknown as jest.Mocked<WorkspaceManyOrAllFlatEntityMapsCacheService>),
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
@@ -310,6 +363,29 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
|
||||
nextStepIds: ['next-step'],
|
||||
} as unknown as WorkflowAction;
|
||||
|
||||
const mockExistingFlatLogicFunction: FlatLogicFunction = {
|
||||
id: 'function-id',
|
||||
name: 'Existing Function',
|
||||
description: 'Existing Description',
|
||||
workspaceId: mockWorkspaceId,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
deletedAt: null,
|
||||
runtime: LogicFunctionRuntime.NODE22,
|
||||
timeoutSeconds: 30,
|
||||
sourceHandlerPath: 'workflow/function-id/src/index.ts',
|
||||
builtHandlerPath: 'workflow/function-id/src/index.mjs',
|
||||
handlerName: 'main',
|
||||
checksum: 'existing-checksum',
|
||||
toolInputSchema: null,
|
||||
isTool: false,
|
||||
universalIdentifier: 'existing-universal-id',
|
||||
applicationId: 'application-id',
|
||||
cronTriggerSettings: null,
|
||||
databaseEventTriggerSettings: null,
|
||||
httpRouteTriggerSettings: null,
|
||||
};
|
||||
|
||||
const mockNewFlatLogicFunction: FlatLogicFunction = {
|
||||
id: 'new-function-id',
|
||||
name: 'Test Function',
|
||||
@@ -333,7 +409,25 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
|
||||
httpRouteTriggerSettings: null,
|
||||
};
|
||||
|
||||
logicFunctionService.duplicateLogicFunction.mockResolvedValue(
|
||||
const emptyMaps = createEmptyAllFlatEntityMaps();
|
||||
const flatLogicFunctionMapsKey = 'flatLogicFunctionMaps' as const;
|
||||
|
||||
flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps.mockResolvedValueOnce(
|
||||
{
|
||||
...emptyMaps,
|
||||
[flatLogicFunctionMapsKey]: {
|
||||
byUniversalIdentifier: {
|
||||
'existing-universal-id': mockExistingFlatLogicFunction,
|
||||
},
|
||||
universalIdentifierById: {
|
||||
'function-id': 'existing-universal-id',
|
||||
},
|
||||
universalIdentifiersByApplicationId: {},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
logicFunctionService.createOne.mockResolvedValue(
|
||||
mockNewFlatLogicFunction,
|
||||
);
|
||||
|
||||
@@ -358,6 +452,12 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
|
||||
expect(codeResult.settings.input.logicFunctionId).toBe('new-function-id');
|
||||
|
||||
expect(duplicateStep.nextStepIds).toEqual([]);
|
||||
expect(
|
||||
codeStepBuildService.duplicateCodeStepLogicFunction,
|
||||
).toHaveBeenCalledWith({
|
||||
existingLogicFunctionId: 'function-id',
|
||||
workspaceId: mockWorkspaceId,
|
||||
});
|
||||
});
|
||||
|
||||
it('should duplicate non-code step', async () => {
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { ApplicationModule } from 'src/engine/core-modules/application/application.module';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module';
|
||||
import { LogicFunctionModule } from 'src/engine/metadata-modules/logic-function/logic-function.module';
|
||||
|
||||
import { CodeStepBuildService } from './services/code-step-build.service';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ApplicationModule,
|
||||
WorkspaceManyOrAllFlatEntityMapsCacheModule,
|
||||
LogicFunctionModule,
|
||||
],
|
||||
providers: [CodeStepBuildService],
|
||||
exports: [CodeStepBuildService],
|
||||
})
|
||||
export class CodeStepBuildModule {}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
export const CODE_STEP_DEFAULT_INPUT_SCHEMA = {
|
||||
a: null,
|
||||
b: null,
|
||||
};
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
var main = async (params) => {
|
||||
const { a, b } = params;
|
||||
const message = `Hello, input: ${a} and ${b}`;
|
||||
return { message };
|
||||
};
|
||||
export {
|
||||
main
|
||||
};
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
export const main = async (params: {
|
||||
a: string;
|
||||
b: number;
|
||||
}): Promise<object> => {
|
||||
const { a, b } = params;
|
||||
|
||||
// Rename the parameters and code below with your own logic
|
||||
// This is just an example
|
||||
const message = `Hello, input: ${a} and ${b}`;
|
||||
|
||||
return { message };
|
||||
};
|
||||
+222
@@ -0,0 +1,222 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { LogicFunctionSourceBuilderService } from 'src/engine/core-modules/logic-function/logic-function-source-builder/logic-function-source-builder.service';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/services/logic-function.service';
|
||||
import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
|
||||
import { findFlatLogicFunctionOrThrow } from 'src/engine/metadata-modules/logic-function/utils/find-flat-logic-function-or-throw.util';
|
||||
import { fromCreateLogicFunctionInputToFlatLogicFunction } from 'src/engine/metadata-modules/logic-function/utils/from-create-logic-function-input-to-flat-logic-function.util';
|
||||
import {
|
||||
WorkflowActionType,
|
||||
type WorkflowAction,
|
||||
} from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type';
|
||||
|
||||
const WORKFLOW_BASE_FOLDER_PREFIX = 'workflow';
|
||||
|
||||
@Injectable()
|
||||
export class CodeStepBuildService {
|
||||
constructor(
|
||||
private readonly workspaceManyOrAllFlatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService,
|
||||
private readonly logicFunctionService: LogicFunctionService,
|
||||
private readonly applicationService: ApplicationService,
|
||||
private readonly logicFunctionSourceBuilderService: LogicFunctionSourceBuilderService,
|
||||
) {}
|
||||
|
||||
async duplicateCodeStepLogicFunction({
|
||||
existingLogicFunctionId,
|
||||
workspaceId,
|
||||
}: {
|
||||
existingLogicFunctionId: string;
|
||||
workspaceId: string;
|
||||
}): Promise<FlatLogicFunction> {
|
||||
const { flatLogicFunctionMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatLogicFunctionMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
const existingLogicFunction = findFlatLogicFunctionOrThrow({
|
||||
id: existingLogicFunctionId,
|
||||
flatLogicFunctionMaps,
|
||||
});
|
||||
|
||||
const resolvedOwnerFlatApplication = (
|
||||
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
|
||||
{ workspaceId },
|
||||
)
|
||||
).workspaceCustomFlatApplication;
|
||||
|
||||
const applicationUniversalIdentifier =
|
||||
resolvedOwnerFlatApplication.universalIdentifier;
|
||||
|
||||
const newId = v4();
|
||||
const newFlatLogicFunction =
|
||||
fromCreateLogicFunctionInputToFlatLogicFunction({
|
||||
createLogicFunctionInput: {
|
||||
name: existingLogicFunction.name,
|
||||
description: existingLogicFunction.description ?? undefined,
|
||||
timeoutSeconds: existingLogicFunction.timeoutSeconds,
|
||||
id: newId,
|
||||
},
|
||||
workspaceId,
|
||||
ownerFlatApplication: resolvedOwnerFlatApplication,
|
||||
});
|
||||
|
||||
await this.logicFunctionSourceBuilderService.copySourceAndBuilt({
|
||||
fromSourceHandlerPath: existingLogicFunction.sourceHandlerPath,
|
||||
fromBuiltHandlerPath: existingLogicFunction.builtHandlerPath,
|
||||
toSourceHandlerPath: newFlatLogicFunction.sourceHandlerPath,
|
||||
toBuiltHandlerPath: newFlatLogicFunction.builtHandlerPath,
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
});
|
||||
|
||||
const created = await this.logicFunctionService.createOne({
|
||||
input: {
|
||||
name: existingLogicFunction.name,
|
||||
description: existingLogicFunction.description ?? undefined,
|
||||
timeoutSeconds: existingLogicFunction.timeoutSeconds,
|
||||
id: newFlatLogicFunction.id,
|
||||
sourceHandlerPath: newFlatLogicFunction.sourceHandlerPath,
|
||||
builtHandlerPath: newFlatLogicFunction.builtHandlerPath,
|
||||
checksum: existingLogicFunction.checksum ?? undefined,
|
||||
},
|
||||
workspaceId,
|
||||
ownerFlatApplication: resolvedOwnerFlatApplication,
|
||||
});
|
||||
|
||||
if (!isDefined(created)) {
|
||||
throw new Error(
|
||||
'Failed to create logic function when duplicating code step',
|
||||
);
|
||||
}
|
||||
|
||||
return created;
|
||||
}
|
||||
|
||||
async buildCodeStepsFromSourceForSteps({
|
||||
workspaceId,
|
||||
steps,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
steps: WorkflowAction[];
|
||||
}): Promise<void> {
|
||||
const codeSteps = steps.filter(
|
||||
(
|
||||
step,
|
||||
): step is WorkflowAction & {
|
||||
type: typeof WorkflowActionType.CODE;
|
||||
settings: { input: { logicFunctionId: string } };
|
||||
} =>
|
||||
step.type === WorkflowActionType.CODE &&
|
||||
isDefined(
|
||||
(step.settings?.input as { logicFunctionId?: string })
|
||||
?.logicFunctionId,
|
||||
),
|
||||
);
|
||||
|
||||
if (codeSteps.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { flatLogicFunctionMaps, flatApplicationMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatLogicFunctionMaps', 'flatApplicationMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
for (const step of codeSteps) {
|
||||
const logicFunctionId = step.settings.input.logicFunctionId;
|
||||
const flatLogicFunction = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: logicFunctionId,
|
||||
flatEntityMaps: flatLogicFunctionMaps,
|
||||
});
|
||||
|
||||
if (
|
||||
!isDefined(flatLogicFunction) ||
|
||||
flatLogicFunction.deletedAt ||
|
||||
!this.isWorkflowCodeStepLogicFunction(flatLogicFunction)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const applicationUniversalIdentifier = isDefined(
|
||||
flatLogicFunction.applicationId,
|
||||
)
|
||||
? flatApplicationMaps.byId[flatLogicFunction.applicationId]
|
||||
?.universalIdentifier
|
||||
: undefined;
|
||||
|
||||
if (!isDefined(applicationUniversalIdentifier)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const { checksum } =
|
||||
await this.logicFunctionSourceBuilderService.buildFromSource({
|
||||
sourceHandlerPath: flatLogicFunction.sourceHandlerPath,
|
||||
builtHandlerPath: flatLogicFunction.builtHandlerPath,
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
});
|
||||
|
||||
await this.logicFunctionService.updateChecksum({
|
||||
id: flatLogicFunction.id,
|
||||
checksum,
|
||||
workspaceId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
isWorkflowCodeStepLogicFunction(
|
||||
flatLogicFunction: FlatLogicFunction,
|
||||
): boolean {
|
||||
return (
|
||||
flatLogicFunction.sourceHandlerPath.startsWith(
|
||||
`${WORKFLOW_BASE_FOLDER_PREFIX}/`,
|
||||
) ||
|
||||
flatLogicFunction.builtHandlerPath.startsWith(
|
||||
`${WORKFLOW_BASE_FOLDER_PREFIX}/`,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
async getFlatLogicFunctionForCodeStepOrNull({
|
||||
logicFunctionId,
|
||||
workspaceId,
|
||||
}: {
|
||||
logicFunctionId: string;
|
||||
workspaceId: string;
|
||||
}): Promise<FlatLogicFunction | null> {
|
||||
const { flatLogicFunctionMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatLogicFunctionMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
const flatLogicFunction = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: logicFunctionId,
|
||||
flatEntityMaps: flatLogicFunctionMaps,
|
||||
});
|
||||
|
||||
if (
|
||||
!isDefined(flatLogicFunction) ||
|
||||
flatLogicFunction.deletedAt ||
|
||||
!this.isWorkflowCodeStepLogicFunction(flatLogicFunction)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return flatLogicFunction;
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import { dirname } from 'path';
|
||||
|
||||
export const getLogicFunctionBaseFolderPath = (handlerPath: string): string => {
|
||||
return dirname(dirname(handlerPath));
|
||||
};
|
||||
|
||||
export const getRelativePathFromBase = (
|
||||
handlerPath: string,
|
||||
baseFolderPath: string,
|
||||
): string => {
|
||||
return handlerPath.replace(`${baseFolderPath}/`, '');
|
||||
};
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
|
||||
import { ASSET_PATH } from 'src/constants/assets-path';
|
||||
|
||||
export type CodeStepSeedProjectFile = {
|
||||
name: string;
|
||||
path: string;
|
||||
content: Buffer;
|
||||
};
|
||||
|
||||
const getAllFiles = async (
|
||||
rootDir: string,
|
||||
dir: string = rootDir,
|
||||
files: CodeStepSeedProjectFile[] = [],
|
||||
): Promise<CodeStepSeedProjectFile[]> => {
|
||||
const dirEntries = await fs.readdir(dir, { withFileTypes: true });
|
||||
|
||||
for (const entry of dirEntries) {
|
||||
const fullPath = path.join(dir, entry.name);
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
await getAllFiles(rootDir, fullPath, files);
|
||||
} else {
|
||||
files.push({
|
||||
path: path.relative(rootDir, dir),
|
||||
name: entry.name,
|
||||
content: await fs.readFile(fullPath),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
};
|
||||
|
||||
export const getCodeStepSeedProjectFiles = async (): Promise<
|
||||
CodeStepSeedProjectFile[]
|
||||
> => {
|
||||
const seedProjectPath = path.join(
|
||||
ASSET_PATH,
|
||||
'modules/workflow/workflow-builder/workflow-version-step/code-step/constants/seed-project',
|
||||
);
|
||||
|
||||
return getAllFiles(seedProjectPath);
|
||||
};
|
||||
+16
-10
@@ -15,7 +15,7 @@ import { Repository } from 'typeorm';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { getFlatFieldsFromFlatObjectMetadata } from 'src/engine/api/graphql/workspace-schema-builder/utils/get-flat-fields-for-flat-object-metadata.util';
|
||||
import { SEED_PROJECT_INPUT_SCHEMA } from 'src/engine/core-modules/logic-function/logic-function-drivers/constants/seed-project-input-schema';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { type WorkflowStepPositionInput } from 'src/engine/core-modules/workflow/dtos/update-workflow-step-position-input.dto';
|
||||
import { AiAgentRoleService } from 'src/engine/metadata-modules/ai/ai-agent-role/ai-agent-role.service';
|
||||
import { AgentEntity } from 'src/engine/metadata-modules/ai/ai-agent/entities/agent.entity';
|
||||
@@ -28,6 +28,8 @@ import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-t
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util';
|
||||
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
import { CODE_STEP_DEFAULT_INPUT_SCHEMA } from 'src/modules/workflow/workflow-builder/workflow-version-step/code-step/constants/seed-project/code-step-default-input-schema';
|
||||
import { CodeStepBuildService } from 'src/modules/workflow/workflow-builder/workflow-version-step/code-step/services/code-step-build.service';
|
||||
import {
|
||||
WorkflowVersionStepException,
|
||||
WorkflowVersionStepExceptionCode,
|
||||
@@ -65,6 +67,8 @@ export class WorkflowVersionStepOperationsWorkspaceService {
|
||||
constructor(
|
||||
private readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager,
|
||||
private readonly logicFunctionService: LogicFunctionService,
|
||||
private readonly applicationService: ApplicationService,
|
||||
private readonly codeStepBuildService: CodeStepBuildService,
|
||||
@InjectRepository(AgentEntity)
|
||||
private readonly agentRepository: Repository<AgentEntity>,
|
||||
@InjectRepository(RoleTargetEntity)
|
||||
@@ -151,8 +155,12 @@ export class WorkflowVersionStepOperationsWorkspaceService {
|
||||
|
||||
switch (type) {
|
||||
case WorkflowActionType.CODE: {
|
||||
const logicFunctionId = id ?? v4();
|
||||
|
||||
// createOne handles seeding source files with default seed project
|
||||
const newLogicFunction = await this.logicFunctionService.createOne({
|
||||
input: {
|
||||
id: logicFunctionId,
|
||||
name: 'A Logic Function Code Workflow Step',
|
||||
description: '',
|
||||
},
|
||||
@@ -184,7 +192,7 @@ export class WorkflowVersionStepOperationsWorkspaceService {
|
||||
},
|
||||
input: {
|
||||
logicFunctionId: newLogicFunction.id,
|
||||
logicFunctionInput: SEED_PROJECT_INPUT_SCHEMA,
|
||||
logicFunctionInput: CODE_STEP_DEFAULT_INPUT_SCHEMA,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -655,8 +663,8 @@ export class WorkflowVersionStepOperationsWorkspaceService {
|
||||
switch (step.type) {
|
||||
case WorkflowActionType.CODE: {
|
||||
const newLogicFunction =
|
||||
await this.logicFunctionService.duplicateLogicFunction({
|
||||
id: step.settings.input.logicFunctionId,
|
||||
await this.codeStepBuildService.duplicateCodeStepLogicFunction({
|
||||
existingLogicFunctionId: step.settings.input.logicFunctionId,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
@@ -928,12 +936,10 @@ export class WorkflowVersionStepOperationsWorkspaceService {
|
||||
switch (step.type) {
|
||||
case WorkflowActionType.CODE: {
|
||||
const newLogicFunction =
|
||||
await this.logicFunctionService.createLogicFunctionFromExistingLogicFunctionById(
|
||||
{
|
||||
id: step.settings.input.logicFunctionId,
|
||||
workspaceId,
|
||||
},
|
||||
);
|
||||
await this.codeStepBuildService.duplicateCodeStepLogicFunction({
|
||||
existingLogicFunctionId: step.settings.input.logicFunctionId,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
return {
|
||||
...step,
|
||||
|
||||
+5
@@ -2,10 +2,12 @@ import { Module } from '@nestjs/common';
|
||||
|
||||
import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
|
||||
|
||||
import { ApplicationModule } from 'src/engine/core-modules/application/application.module';
|
||||
import { AiAgentRoleModule } from 'src/engine/metadata-modules/ai/ai-agent-role/ai-agent-role.module';
|
||||
import { AgentEntity } from 'src/engine/metadata-modules/ai/ai-agent/entities/agent.entity';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module';
|
||||
import { LogicFunctionModule } from 'src/engine/metadata-modules/logic-function/logic-function.module';
|
||||
import { CodeStepBuildModule } from 'src/modules/workflow/workflow-builder/workflow-version-step/code-step/code-step-build.module';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-target.entity';
|
||||
import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
|
||||
@@ -24,6 +26,8 @@ import { WorkflowVersionStepWorkspaceService } from 'src/modules/workflow/workfl
|
||||
WorkflowSchemaModule,
|
||||
LogicFunctionModule,
|
||||
WorkflowCommonModule,
|
||||
ApplicationModule,
|
||||
CodeStepBuildModule,
|
||||
AiAgentRoleModule,
|
||||
WorkspaceCacheModule,
|
||||
NestjsQueryTypeOrmModule.forFeature([
|
||||
@@ -46,6 +50,7 @@ import { WorkflowVersionStepWorkspaceService } from 'src/modules/workflow/workfl
|
||||
WorkflowVersionStepWorkspaceService,
|
||||
WorkflowVersionStepOperationsWorkspaceService,
|
||||
WorkflowVersionStepHelpersWorkspaceService,
|
||||
CodeStepBuildModule,
|
||||
],
|
||||
})
|
||||
export class WorkflowVersionStepModule {}
|
||||
|
||||
Reference in New Issue
Block a user