From a6c8ee4a82e6055766dc1307f79c774c17bb5f4d Mon Sep 17 00:00:00 2001 From: Charlie Kolb Date: Fri, 8 Nov 2024 08:31:58 +0100 Subject: [PATCH 1/2] fix(editor): Cap NDV Output View Tab Index to prevent rare edge case (#11614) --- packages/editor-ui/src/components/RunData.vue | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/editor-ui/src/components/RunData.vue b/packages/editor-ui/src/components/RunData.vue index 6000807958..351fdd8890 100644 --- a/packages/editor-ui/src/components/RunData.vue +++ b/packages/editor-ui/src/components/RunData.vue @@ -386,7 +386,10 @@ const currentOutputIndex = computed(() => { return props.overrideOutputs[0]; } - return outputIndex.value; + // In some cases nodes may switch their outputCount while the user still + // has a higher outputIndex selected. We could adjust outputIndex directly, + // but that loses data as we can keep the user selection if the branch reappears. + return Math.min(outputIndex.value, maxOutputIndex.value); }); const branches = computed(() => { const capitalize = (name: string) => name.charAt(0).toLocaleUpperCase() + name.slice(1); From 0db658c6d060952eb9b4496a5fbd7e07fcf3082f Mon Sep 17 00:00:00 2001 From: Tomi Turtiainen <10324676+tomi@users.noreply.github.com> Date: Fri, 8 Nov 2024 09:35:18 +0200 Subject: [PATCH 2/2] perf(core): Remove unneeded execution data from runner data response (no-changelog) (#11627) --- .../data-request-response-builder.test.ts | 70 ++++++++++++++++++- .../data-request-response-stripper.test.ts | 20 +----- .../data-request-response-builder.ts | 28 +++++++- .../data-request-response-stripper.ts | 14 +--- 4 files changed, 100 insertions(+), 32 deletions(-) diff --git a/packages/cli/src/runners/task-managers/__tests__/data-request-response-builder.test.ts b/packages/cli/src/runners/task-managers/__tests__/data-request-response-builder.test.ts index b8868983ed..ae01cdd776 100644 --- a/packages/cli/src/runners/task-managers/__tests__/data-request-response-builder.test.ts +++ b/packages/cli/src/runners/task-managers/__tests__/data-request-response-builder.test.ts @@ -1,6 +1,12 @@ import type { PartialAdditionalData, TaskData } from '@n8n/task-runner'; import { mock } from 'jest-mock-extended'; -import type { Workflow } from 'n8n-workflow'; +import type { + IExecuteContextData, + INode, + INodeExecutionData, + IRunExecutionData, + Workflow, +} from 'n8n-workflow'; import { DataRequestResponseBuilder } from '../data-request-response-builder'; @@ -19,6 +25,22 @@ const additionalData = mock({ restartExecutionId: undefined, }); +const node = mock(); +const outputItems: INodeExecutionData[] = [ + { + json: { + uid: 'abb74fd4-bef2-4fae-9d53-ea24e9eb3032', + email: 'Dan.Schmidt31@yahoo.com', + firstname: 'Toni', + lastname: 'Schuster', + password: 'Q!D6C2', + }, + pairedItem: { + item: 0, + }, + }, +]; + const workflow: TaskData['workflow'] = mock({ id: '1', name: 'Test Workflow', @@ -30,9 +52,39 @@ const workflow: TaskData['workflow'] = mock({ staticData: {}, }); +const contextData = mock(); +const metadata = { + '0': [], +}; + +const runExecutionData = mock({ + executionData: { + contextData, + metadata, + nodeExecutionStack: [ + { + node, + data: { + main: [outputItems], + }, + source: {}, + }, + ], + waitingExecution: { + node: { + '0': { + main: [], + }, + }, + }, + waitingExecutionSource: {}, + }, +}); + const taskData = mock({ additionalData, workflow, + runExecutionData, }); describe('DataRequestResponseBuilder', () => { @@ -71,4 +123,20 @@ describe('DataRequestResponseBuilder', () => { staticData: workflow.staticData, }); }); + + it('clears nodeExecutionStack, waitingExecution and waitingExecutionSource from runExecutionData', () => { + const result = builder.buildFromTaskData(taskData); + + expect(result.runExecutionData).toStrictEqual({ + startData: runExecutionData.startData, + resultData: runExecutionData.resultData, + executionData: { + contextData, + metadata, + nodeExecutionStack: [], + waitingExecution: {}, + waitingExecutionSource: null, + }, + }); + }); }); diff --git a/packages/cli/src/runners/task-managers/__tests__/data-request-response-stripper.test.ts b/packages/cli/src/runners/task-managers/__tests__/data-request-response-stripper.test.ts index a37b9bdc7a..d100fc1430 100644 --- a/packages/cli/src/runners/task-managers/__tests__/data-request-response-stripper.test.ts +++ b/packages/cli/src/runners/task-managers/__tests__/data-request-response-stripper.test.ts @@ -115,24 +115,8 @@ const taskData: DataRequestResponse = { contextData: {}, nodeExecutionStack: [], metadata: {}, - waitingExecution: { - [codeNode.name]: { - '0': { - main: [codeNodeInputItems], - }, - }, - }, - waitingExecutionSource: { - [codeNode.name]: { - '0': { - main: [ - { - previousNode: debugHelperNode.name, - }, - ], - }, - }, - }, + waitingExecution: {}, + waitingExecutionSource: {}, }, }, runIndex: 0, diff --git a/packages/cli/src/runners/task-managers/data-request-response-builder.ts b/packages/cli/src/runners/task-managers/data-request-response-builder.ts index 7df3b9e012..7809a94a8d 100644 --- a/packages/cli/src/runners/task-managers/data-request-response-builder.ts +++ b/packages/cli/src/runners/task-managers/data-request-response-builder.ts @@ -1,5 +1,10 @@ import type { DataRequestResponse, PartialAdditionalData, TaskData } from '@n8n/task-runner'; -import type { IWorkflowExecuteAdditionalData, Workflow, WorkflowParameters } from 'n8n-workflow'; +import type { + IRunExecutionData, + IWorkflowExecuteAdditionalData, + Workflow, + WorkflowParameters, +} from 'n8n-workflow'; /** * Transforms TaskData to DataRequestResponse. The main purpose of the @@ -20,7 +25,7 @@ export class DataRequestResponseBuilder { mode: taskData.mode, envProviderState: taskData.envProviderState, node: taskData.node, - runExecutionData: taskData.runExecutionData, + runExecutionData: this.buildRunExecutionData(taskData.runExecutionData), runIndex: taskData.runIndex, selfData: taskData.selfData, siblingParameters: taskData.siblingParameters, @@ -59,4 +64,23 @@ export class DataRequestResponseBuilder { staticData: workflow.staticData, }; } + + private buildRunExecutionData(runExecutionData: IRunExecutionData) { + return { + startData: runExecutionData.startData, + resultData: runExecutionData.resultData, + executionData: runExecutionData.executionData + ? { + contextData: runExecutionData.executionData.contextData, + metadata: runExecutionData.executionData.metadata, + + // These are related to workflow execution and are not something + // that are accessible by nodes, so we always omit them + nodeExecutionStack: [], + waitingExecution: {}, + waitingExecutionSource: null, + } + : undefined, + }; + } } diff --git a/packages/cli/src/runners/task-managers/data-request-response-stripper.ts b/packages/cli/src/runners/task-managers/data-request-response-stripper.ts index b924a87c5f..721f51d3c1 100644 --- a/packages/cli/src/runners/task-managers/data-request-response-stripper.ts +++ b/packages/cli/src/runners/task-managers/data-request-response-stripper.ts @@ -52,17 +52,9 @@ export class DataRequestResponseStripper { runData: this.stripRunData(runExecutionData.resultData.runData), pinData: this.stripPinData(runExecutionData.resultData.pinData), }, - executionData: runExecutionData.executionData - ? { - // TODO: Figure out what these two are and can they be stripped - contextData: runExecutionData.executionData?.contextData, - nodeExecutionStack: runExecutionData.executionData.nodeExecutionStack, - - metadata: runExecutionData.executionData.metadata, - waitingExecution: runExecutionData.executionData.waitingExecution, - waitingExecutionSource: runExecutionData.executionData.waitingExecutionSource, - } - : undefined, + // TODO: We could send `runExecutionData.contextData` only if requested, + // since it's only needed if $input.context or $("node").context is used. + executionData: runExecutionData.executionData, }; }