diff --git a/packages/frontend/editor-ui/src/app/composables/useWorkflowSaving.test.ts b/packages/frontend/editor-ui/src/app/composables/useWorkflowSaving.test.ts index 7e7c4be0b0c..ac04752bb54 100644 --- a/packages/frontend/editor-ui/src/app/composables/useWorkflowSaving.test.ts +++ b/packages/frontend/editor-ui/src/app/composables/useWorkflowSaving.test.ts @@ -350,6 +350,56 @@ describe('useWorkflowSaving', () => { expect(webHookIdsPreSave).not.toEqual(webHookIdsPostSave); expect(pathsPreSave).not.toEqual(pathsPostSave); }); + + it('should preserve expression-based webhook paths when resetWebhookUrls is true', async () => { + const workflow: WorkflowDataUpdate = { + name: 'Expression webhook test', + active: false, + nodes: [ + { + parameters: { + path: '={{ $json.customPath }}', + options: {}, + }, + id: 'node-with-expression', + name: 'Webhook with expression', + type: 'n8n-nodes-base.webhook', + typeVersion: 2, + position: [680, 20], + webhookId: 'original-webhook-id-1', + }, + { + parameters: { + path: 'static-path', + options: {}, + }, + id: 'node-without-expression', + name: 'Webhook with static path', + type: 'n8n-nodes-base.webhook', + typeVersion: 2, + position: [700, 40], + webhookId: 'original-webhook-id-2', + }, + ], + connections: {}, + }; + + const { saveAsNewWorkflow } = useWorkflowSaving({ router }); + const expressionPath = workflow.nodes![0].parameters.path; + const staticPath = workflow.nodes![1].parameters.path; + + await saveAsNewWorkflow({ + name: workflow.name, + resetWebhookUrls: true, + data: workflow, + }); + + // Expression-based path should be preserved + expect(workflow.nodes![0].parameters.path).toBe(expressionPath); + // Static path should be replaced with new webhook ID + expect(workflow.nodes![1].parameters.path).not.toBe(staticPath); + expect(workflow.nodes![1].parameters.path).toBe(workflow.nodes![1].webhookId); + }); }); describe('saveCurrentWorkflow', () => { diff --git a/packages/frontend/editor-ui/src/app/composables/useWorkflowSaving.ts b/packages/frontend/editor-ui/src/app/composables/useWorkflowSaving.ts index 078ec3c1410..ca5364aed14 100644 --- a/packages/frontend/editor-ui/src/app/composables/useWorkflowSaving.ts +++ b/packages/frontend/editor-ui/src/app/composables/useWorkflowSaving.ts @@ -17,7 +17,7 @@ import { useCanvasStore } from '@/app/stores/canvas.store'; import type { IUpdateInformation, IWorkflowDb } from '@/Interface'; import type { ITag } from '@n8n/rest-api-client/api/tags'; import type { WorkflowDataCreate, WorkflowDataUpdate } from '@n8n/rest-api-client/api/workflows'; -import type { IDataObject, IWorkflowSettings } from 'n8n-workflow'; +import { isExpression, type IDataObject, type IWorkflowSettings } from 'n8n-workflow'; import { useToast } from './useToast'; import { useExternalHooks } from './useExternalHooks'; import { useTelemetry } from './useTelemetry'; @@ -298,7 +298,11 @@ export function useWorkflowSaving({ workflowDataRequest.nodes = workflowDataRequest.nodes!.map((node) => { if (node.webhookId) { const newId = nodeHelpers.assignWebhookId(node); - node.parameters.path = newId; + + if (!isExpression(node.parameters.path)) { + node.parameters.path = newId; + } + changedNodes[node.name] = node.webhookId; } return node;