mirror of
https://github.com/twentyhq/twenty.git
synced 2026-06-12 01:46:39 -04:00
fix: guard against undefined logicFunctionId when destroying workflow CODE steps (#21256)
## Summary - Adds `isDefined` guard in `handleLogicFunctionSubEntities` to skip CODE steps with undefined `logicFunctionId` instead of crashing - Adds same guard in `runWorkflowVersionStepDeletionSideEffects` for consistency - Rejects CODE steps in `create_complete_workflow` AI tool at runtime to prevent creating workflows with missing logic functions in the first place Fixes `"Logic function with id undefined not found"` INTERNAL_SERVER_ERROR when destroying workflows whose CODE steps were created via `create_complete_workflow` without a proper logic function. ## Test plan - [x] Destroy a workflow that has a CODE step with undefined logicFunctionId → should succeed silently - [x] Try creating a workflow with a CODE step via `create_complete_workflow` tool → should return error message - [x] Normal workflow destroy with valid CODE steps still deletes the logic function
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { isDefined, isValidUuid } from 'twenty-shared/utils';
|
||||
|
||||
import { CommandMenuItemService } from 'src/engine/metadata-modules/command-menu-item/command-menu-item.service';
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
@@ -378,8 +378,17 @@ export class WorkflowCommonWorkspaceService {
|
||||
for (const workflowVersion of workflowVersions) {
|
||||
for (const step of workflowVersion.steps ?? []) {
|
||||
if (step.type === WorkflowActionType.CODE) {
|
||||
const logicFunctionId = step.settings.input.logicFunctionId;
|
||||
|
||||
if (!isValidUuid(logicFunctionId)) {
|
||||
this.logger.warn(
|
||||
`Skipping destroy for CODE step with undefined logicFunctionId in workflow ${workflowId}`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
await this.logicFunctionFromSourceService.deleteOneWithSource({
|
||||
id: step.settings.input.logicFunctionId,
|
||||
id: logicFunctionId,
|
||||
workspaceId,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
|
||||
nextStepIds: [],
|
||||
settings: {
|
||||
input: {
|
||||
logicFunctionId: 'function-id',
|
||||
logicFunctionId: '550e8400-e29b-41d4-a716-446655440000',
|
||||
},
|
||||
outputSchema: {},
|
||||
errorHandlingOptions: {
|
||||
@@ -206,7 +206,7 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
|
||||
expect(
|
||||
logicFunctionFromSourceService.deleteOneWithSource,
|
||||
).toHaveBeenCalledWith({
|
||||
id: 'function-id',
|
||||
id: '550e8400-e29b-41d4-a716-446655440000',
|
||||
workspaceId: mockWorkspaceId,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -91,6 +91,10 @@ export class WorkflowVersionStepOperationsWorkspaceService {
|
||||
}) {
|
||||
switch (step.type) {
|
||||
case WorkflowActionType.CODE: {
|
||||
if (!isValidUuid(step.settings.input.logicFunctionId)) {
|
||||
break;
|
||||
}
|
||||
|
||||
await this.logicFunctionFromSourceService.deleteOneWithSource({
|
||||
id: step.settings.input.logicFunctionId,
|
||||
workspaceId,
|
||||
|
||||
@@ -9,6 +9,10 @@ import { type RolePermissionConfig } from 'src/engine/twenty-orm/types/role-perm
|
||||
import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util';
|
||||
import { WorkflowVersionStatus } from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity';
|
||||
import { WorkflowStatus } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity';
|
||||
import {
|
||||
WorkflowVersionStepException,
|
||||
WorkflowVersionStepExceptionCode,
|
||||
} from 'src/modules/workflow/common/exceptions/workflow-version-step.exception';
|
||||
import { type WorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type';
|
||||
import {
|
||||
type WorkflowToolContext,
|
||||
@@ -116,6 +120,16 @@ This is the most efficient way for AI to create workflows as it handles all the
|
||||
activate?: boolean;
|
||||
}) => {
|
||||
try {
|
||||
const codeSteps = parameters.steps.filter(
|
||||
(step) => step.type === ('CODE' as string),
|
||||
);
|
||||
|
||||
if (codeSteps.length > 0) {
|
||||
throw new WorkflowVersionStepException(
|
||||
'CODE steps cannot be created via create_complete_workflow because it does not create the underlying logic function. Use create_workflow_version_step instead.',
|
||||
WorkflowVersionStepExceptionCode.INVALID_REQUEST,
|
||||
);
|
||||
}
|
||||
const workflowId = await createWorkflow({
|
||||
deps,
|
||||
context,
|
||||
|
||||
Reference in New Issue
Block a user