merge master

This commit is contained in:
Mutasem Aldmour 2024-11-08 11:18:55 +01:00
commit ee4becce2f
No known key found for this signature in database
GPG key ID: 3DFA8122BB7FD6B8
5 changed files with 104 additions and 33 deletions

View file

@ -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<PartialAdditionalData>({
restartExecutionId: undefined,
});
const node = mock<INode>();
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<Workflow>({
id: '1',
name: 'Test Workflow',
@ -30,9 +52,39 @@ const workflow: TaskData['workflow'] = mock<Workflow>({
staticData: {},
});
const contextData = mock<IExecuteContextData>();
const metadata = {
'0': [],
};
const runExecutionData = mock<IRunExecutionData>({
executionData: {
contextData,
metadata,
nodeExecutionStack: [
{
node,
data: {
main: [outputItems],
},
source: {},
},
],
waitingExecution: {
node: {
'0': {
main: [],
},
},
},
waitingExecutionSource: {},
},
});
const taskData = mock<TaskData>({
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,
},
});
});
});

View file

@ -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,

View file

@ -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,
};
}
}

View file

@ -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,
};
}

View file

@ -388,7 +388,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);