From dfd785bc0894257eb6e62b0dd8f71248c27aae53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=A4=95=E0=A4=BE=E0=A4=B0=E0=A4=A4=E0=A5=8B=E0=A4=AB?= =?UTF-8?q?=E0=A5=8D=E0=A4=AB=E0=A5=87=E0=A4=B2=E0=A4=B8=E0=A5=8D=E0=A4=95?= =?UTF-8?q?=E0=A5=8D=E0=A4=B0=E0=A4=BF=E0=A4=AA=E0=A5=8D=E0=A4=9F=E2=84=A2?= Date: Tue, 5 Nov 2024 15:06:23 +0100 Subject: [PATCH] fix(editor): Do not overwrite the webhookId in the new canvas (#11562) --- packages/editor-ui/src/Interface.ts | 47 +------------- .../composables/useCanvasOperations.test.ts | 65 ++++++++++++++++++- .../src/composables/useCanvasOperations.ts | 3 +- 3 files changed, 66 insertions(+), 49 deletions(-) diff --git a/packages/editor-ui/src/Interface.ts b/packages/editor-ui/src/Interface.ts index b6691ac76b..aec2889070 100644 --- a/packages/editor-ui/src/Interface.ts +++ b/packages/editor-ui/src/Interface.ts @@ -8,7 +8,7 @@ import type { IVersionNotificationSettings, } from '@n8n/api-types'; import type { Scope } from '@n8n/permissions'; -import type { IMenuItem, NodeCreatorTag } from 'n8n-design-system'; +import type { NodeCreatorTag } from 'n8n-design-system'; import type { GenericValue, IConnections, @@ -888,51 +888,6 @@ export interface RootState { export interface NodeMetadataMap { [nodeName: string]: INodeMetadata; } -export interface IRootState { - activeExecutions: IExecutionsCurrentSummaryExtended[]; - activeWorkflows: string[]; - activeActions: string[]; - activeCredentialType: string | null; - baseUrl: string; - defaultLocale: string; - endpointForm: string; - endpointFormTest: string; - endpointFormWaiting: string; - endpointWebhook: string; - endpointWebhookTest: string; - endpointWebhookWaiting: string; - executionId: string | null; - executingNode: string[]; - executionWaitingForWebhook: boolean; - pushConnectionActive: boolean; - saveDataErrorExecution: string; - saveDataSuccessExecution: string; - saveManualExecutions: boolean; - timezone: string; - stateIsDirty: boolean; - executionTimeout: number; - maxExecutionTimeout: number; - versionCli: string; - oauthCallbackUrls: object; - n8nMetadata: object; - workflowExecutionData: IExecutionResponse | null; - workflowExecutionPairedItemMappings: { [itemId: string]: Set }; - lastSelectedNode: string | null; - lastSelectedNodeOutputIndex: number | null; - nodeViewOffsetPosition: XYPosition; - nodeViewMoveInProgress: boolean; - selectedNodes: INodeUi[]; - pushRef: string; - urlBaseEditor: string; - urlBaseWebhook: string; - workflow: IWorkflowDb; - workflowsById: IWorkflowsMap; - sidebarMenuItems: IMenuItem[]; - instanceId: string; - nodeMetadata: NodeMetadataMap; - subworkflowExecutionError: Error | null; - binaryDataMode: string; -} export interface CommunityPackageMap { [name: string]: PublicInstalledPackage; diff --git a/packages/editor-ui/src/composables/useCanvasOperations.test.ts b/packages/editor-ui/src/composables/useCanvasOperations.test.ts index 7128c223fe..9b6a819238 100644 --- a/packages/editor-ui/src/composables/useCanvasOperations.test.ts +++ b/packages/editor-ui/src/composables/useCanvasOperations.test.ts @@ -1,5 +1,10 @@ import { setActivePinia } from 'pinia'; -import type { IConnection, Workflow } from 'n8n-workflow'; +import type { + IConnection, + INodeTypeDescription, + IWebhookDescription, + Workflow, +} from 'n8n-workflow'; import { NodeConnectionType, NodeHelpers } from 'n8n-workflow'; import { useCanvasOperations } from '@/composables/useCanvasOperations'; import type { CanvasNode } from '@/types'; @@ -23,7 +28,13 @@ import { useCredentialsStore } from '@/stores/credentials.store'; import { waitFor } from '@testing-library/vue'; import { createTestingPinia } from '@pinia/testing'; import { mockedStore } from '@/__tests__/utils'; -import { SET_NODE_TYPE, STICKY_NODE_TYPE, STORES } from '@/constants'; +import { + FORM_TRIGGER_NODE_TYPE, + SET_NODE_TYPE, + STICKY_NODE_TYPE, + STORES, + WEBHOOK_NODE_TYPE, +} from '@/constants'; import type { Connection } from '@vue-flow/core'; import { useClipboard } from '@/composables/useClipboard'; import { createCanvasConnectionHandleString } from '@/utils/canvasUtilsV2'; @@ -1889,6 +1900,56 @@ describe('useCanvasOperations', () => { expect(vi.mocked(useClipboard().copy).mock.calls).toMatchSnapshot(); }); }); + + describe('resolveNodeWebhook', () => { + const nodeTypeDescription = mock({ + webhooks: [mock()], + }); + + it("should set webhookId if it doesn't already exist", () => { + const node = mock({ webhookId: undefined }); + + const { resolveNodeWebhook } = useCanvasOperations({ router }); + resolveNodeWebhook(node, nodeTypeDescription); + + expect(node.webhookId).toBeDefined(); + }); + + it('should not set webhookId if it already exists', () => { + const node = mock({ webhookId: 'random-id' }); + + const { resolveNodeWebhook } = useCanvasOperations({ router }); + resolveNodeWebhook(node, nodeTypeDescription); + + expect(node.webhookId).toBe('random-id'); + }); + + it("should not set webhookId if node description doesn't define any webhooks", () => { + const node = mock({ webhookId: undefined }); + + const { resolveNodeWebhook } = useCanvasOperations({ router }); + resolveNodeWebhook(node, mock({ webhooks: [] })); + + expect(node.webhookId).toBeUndefined(); + }); + + test.each([WEBHOOK_NODE_TYPE, FORM_TRIGGER_NODE_TYPE])( + 'should update the webhook path, if the node type is %s, and the path parameter is empty', + (nodeType) => { + const node = mock({ + webhookId: 'random-id', + type: nodeType, + parameters: { path: '' }, + }); + + const { resolveNodeWebhook } = useCanvasOperations({ router }); + resolveNodeWebhook(node, nodeTypeDescription); + + expect(node.webhookId).toBe('random-id'); + expect(node.parameters.path).toBe('random-id'); + }, + ); + }); }); function buildImportNodes() { diff --git a/packages/editor-ui/src/composables/useCanvasOperations.ts b/packages/editor-ui/src/composables/useCanvasOperations.ts index 27dccaf305..2d811a539e 100644 --- a/packages/editor-ui/src/composables/useCanvasOperations.ts +++ b/packages/editor-ui/src/composables/useCanvasOperations.ts @@ -1080,7 +1080,7 @@ export function useCanvasOperations({ router }: { router: ReturnType