fix(editor): Waiting executions broken - Chat, Form, Wait (no-changelog) (#15343)

This commit is contained in:
Suguru Inoue
2025-05-13 17:01:00 +02:00
committed by GitHub
parent 3176f6fc89
commit 694af6c9f0
10 changed files with 279 additions and 58 deletions

View File

@@ -11,6 +11,7 @@ import {
type ITaskDataConnections,
type NodeConnectionType,
type Workflow,
type ITaskStartedData,
type IRunExecutionData,
} from 'n8n-workflow';
import { type LogEntrySelection } from '../CanvasChat/types/logs';
@@ -397,17 +398,7 @@ function getTreeNodeDataRecV2(
runIndex: number | undefined,
): LogEntry[] {
const treeNode = createNodeV2(node, context, runIndex ?? 0, runData);
const children = getChildNodes(treeNode, node, runIndex, context).sort((a, b) => {
// Sort the data by execution index or start time
if (a.runData.executionIndex !== undefined && b.runData.executionIndex !== undefined) {
return a.runData.executionIndex - b.runData.executionIndex;
}
const aTime = a.runData.startTime ?? 0;
const bTime = b.runData.startTime ?? 0;
return aTime - bTime;
});
const children = getChildNodes(treeNode, node, runIndex, context).sort(sortLogEntries);
treeNode.children = children;
@@ -483,23 +474,15 @@ function createLogTreeRec(context: LogTreeCreationContext) {
? [] // skip sub nodes and disabled nodes
: taskData.map((task, runIndex) => ({
nodeName,
task,
runData: task,
runIndex,
nodeHasMultipleRuns: taskData.length > 1,
})),
)
.sort((a, b) => {
if (a.task.executionIndex !== undefined && b.task.executionIndex !== undefined) {
return a.task.executionIndex - b.task.executionIndex;
}
.sort(sortLogEntries);
return a.nodeName === b.nodeName
? a.runIndex - b.runIndex
: a.task.startTime - b.task.startTime;
});
return runs.flatMap(({ nodeName, runIndex, task, nodeHasMultipleRuns }) =>
getTreeNodeDataV2(nodeName, task, nodeHasMultipleRuns ? runIndex : undefined, context),
return runs.flatMap(({ nodeName, runIndex, runData, nodeHasMultipleRuns }) =>
getTreeNodeDataV2(nodeName, runData, nodeHasMultipleRuns ? runIndex : undefined, context),
);
}
@@ -595,6 +578,65 @@ export function flattenLogEntries(
return ret;
}
function sortLogEntries<T extends { runData: ITaskData }>(a: T, b: T) {
// We rely on execution index only when startTime is different
// Because it is reset to 0 when execution is waited, and therefore not necessarily unique
if (a.runData.startTime === b.runData.startTime) {
return a.runData.executionIndex - b.runData.executionIndex;
}
return a.runData.startTime - b.runData.startTime;
}
export function mergeStartData(
startData: { [nodeName: string]: ITaskStartedData[] },
response: IExecutionResponse,
): IExecutionResponse {
if (!response.data) {
return response;
}
const nodeNames = [
...new Set(
Object.keys(startData).concat(Object.keys(response.data.resultData.runData)),
).values(),
];
const runData = Object.fromEntries(
nodeNames.map<[string, ITaskData[]]>((nodeName) => {
const tasks = response.data?.resultData.runData[nodeName] ?? [];
const mergedTasks = tasks.concat(
(startData[nodeName] ?? [])
.filter((task) =>
// To remove duplicate runs, we check start time in addition to execution index
// because nodes such as Wait and Form emits multiple websocket events with
// different execution index for a single run
tasks.every(
(t) => t.startTime < task.startTime && t.executionIndex !== task.executionIndex,
),
)
.map<ITaskData>((task) => ({
...task,
executionTime: 0,
executionStatus: 'running',
})),
);
return [nodeName, mergedTasks];
}),
);
return {
...response,
data: {
...response.data,
resultData: {
...response.data.resultData,
runData,
},
},
};
}
export function hasSubExecution(entry: LogEntry): boolean {
return !!entry.runData.metadata?.subExecution;
}