mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-19 11:01:15 +00:00
feat(editor): Make logs applicable for all nodes (#14397)
Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <aditya@netroy.in>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { type LlmTokenUsageData, type IAiDataContent } from '@/Interface';
|
||||
import {
|
||||
type IRunData,
|
||||
type INodeExecutionData,
|
||||
type ITaskData,
|
||||
type ITaskDataConnections,
|
||||
@@ -28,16 +29,17 @@ function createNode(
|
||||
parent: TreeNode | undefined,
|
||||
nodeName: string,
|
||||
currentDepth: number,
|
||||
runIndex: number,
|
||||
r?: AIResult,
|
||||
children: TreeNode[] = [],
|
||||
): TreeNode {
|
||||
return {
|
||||
parent,
|
||||
node: nodeName,
|
||||
id: nodeName,
|
||||
id: `${nodeName}:${runIndex}`,
|
||||
depth: currentDepth,
|
||||
startTime: r?.data?.metadata?.startTime ?? 0,
|
||||
runIndex: r?.runIndex ?? 0,
|
||||
runIndex,
|
||||
children,
|
||||
consumedTokens: getConsumedTokens(r?.data),
|
||||
};
|
||||
@@ -47,8 +49,9 @@ export function getTreeNodeData(
|
||||
nodeName: string,
|
||||
workflow: Workflow,
|
||||
aiData: AIResult[] | undefined,
|
||||
runIndex?: number,
|
||||
): TreeNode[] {
|
||||
return getTreeNodeDataRec(undefined, nodeName, 0, workflow, aiData, undefined);
|
||||
return getTreeNodeDataRec(undefined, nodeName, 0, workflow, aiData, runIndex);
|
||||
}
|
||||
|
||||
function getTreeNodeDataRec(
|
||||
@@ -66,32 +69,27 @@ function getTreeNodeDataRec(
|
||||
) ?? [];
|
||||
|
||||
if (!connections) {
|
||||
return resultData.map((d) => createNode(parent, nodeName, currentDepth, d));
|
||||
return resultData.map((d) => createNode(parent, nodeName, currentDepth, d.runIndex, d));
|
||||
}
|
||||
|
||||
// Get the first level of children
|
||||
const connectedSubNodes = workflow.getParentNodes(nodeName, 'ALL_NON_MAIN', 1);
|
||||
|
||||
const treeNode = createNode(parent, nodeName, currentDepth);
|
||||
const children = connectedSubNodes.flatMap((name) => {
|
||||
// Only include sub-nodes which have data
|
||||
return (
|
||||
aiData
|
||||
?.filter(
|
||||
(data) => data.node === name && (runIndex === undefined || data.runIndex === runIndex),
|
||||
)
|
||||
.flatMap((data) =>
|
||||
getTreeNodeDataRec(treeNode, name, currentDepth + 1, workflow, aiData, data.runIndex),
|
||||
) ?? []
|
||||
);
|
||||
});
|
||||
const treeNode = createNode(parent, nodeName, currentDepth, runIndex ?? 0);
|
||||
|
||||
children.sort((a, b) => a.startTime - b.startTime);
|
||||
// Only include sub-nodes which have data
|
||||
const children = (aiData ?? []).flatMap((data) =>
|
||||
connectedSubNodes.includes(data.node) && (runIndex === undefined || data.runIndex === runIndex)
|
||||
? getTreeNodeDataRec(treeNode, data.node, currentDepth + 1, workflow, aiData, data.runIndex)
|
||||
: [],
|
||||
);
|
||||
|
||||
treeNode.children = children;
|
||||
|
||||
if (resultData.length) {
|
||||
return resultData.map((r) => createNode(parent, nodeName, currentDepth, r, children));
|
||||
return resultData.map((r) =>
|
||||
createNode(parent, nodeName, currentDepth, r.runIndex, r, children),
|
||||
);
|
||||
}
|
||||
|
||||
return [treeNode];
|
||||
@@ -102,31 +100,27 @@ export function createAiData(
|
||||
workflow: Workflow,
|
||||
getWorkflowResultDataByNodeName: (nodeName: string) => ITaskData[] | null,
|
||||
): AIResult[] {
|
||||
const result: AIResult[] = [];
|
||||
const connectedSubNodes = workflow.getParentNodes(nodeName, 'ALL_NON_MAIN');
|
||||
return workflow
|
||||
.getParentNodes(nodeName, 'ALL_NON_MAIN')
|
||||
.flatMap((node) =>
|
||||
(getWorkflowResultDataByNodeName(node) ?? []).map((task, index) => ({ node, task, index })),
|
||||
)
|
||||
.sort((a, b) => {
|
||||
// Sort the data by execution index or start time
|
||||
if (a.task.executionIndex !== undefined && b.task.executionIndex !== undefined) {
|
||||
return a.task.executionIndex - b.task.executionIndex;
|
||||
}
|
||||
|
||||
connectedSubNodes.forEach((node) => {
|
||||
const nodeRunData = getWorkflowResultDataByNodeName(node) ?? [];
|
||||
const aTime = a.task.startTime ?? 0;
|
||||
const bTime = b.task.startTime ?? 0;
|
||||
|
||||
nodeRunData.forEach((run, runIndex) => {
|
||||
const referenceData = {
|
||||
data: getReferencedData(run, false, true)[0],
|
||||
node,
|
||||
runIndex,
|
||||
};
|
||||
|
||||
result.push(referenceData);
|
||||
});
|
||||
});
|
||||
|
||||
// Sort the data by start time
|
||||
result.sort((a, b) => {
|
||||
const aTime = a.data?.metadata?.startTime ?? 0;
|
||||
const bTime = b.data?.metadata?.startTime ?? 0;
|
||||
return aTime - bTime;
|
||||
});
|
||||
|
||||
return result;
|
||||
return aTime - bTime;
|
||||
})
|
||||
.map(({ node, task, index }) => ({
|
||||
data: getReferencedData(task, false, true)[0],
|
||||
node,
|
||||
runIndex: index,
|
||||
}));
|
||||
}
|
||||
|
||||
export function getReferencedData(
|
||||
@@ -231,3 +225,44 @@ export function formatTokenUsageCount(
|
||||
|
||||
return usage.isEstimate ? `~${count}` : count.toLocaleString();
|
||||
}
|
||||
|
||||
export function createLogEntries(workflow: Workflow, runData: IRunData) {
|
||||
const runs = Object.entries(runData)
|
||||
.filter(([nodeName]) => workflow.getChildNodes(nodeName, 'ALL_NON_MAIN').length === 0)
|
||||
.flatMap(([nodeName, taskData]) =>
|
||||
taskData.map((task, runIndex) => ({ nodeName, task, runIndex })),
|
||||
)
|
||||
.sort((a, b) => {
|
||||
if (a.task.executionIndex !== undefined && b.task.executionIndex !== undefined) {
|
||||
return a.task.executionIndex - b.task.executionIndex;
|
||||
}
|
||||
|
||||
return a.nodeName === b.nodeName
|
||||
? a.runIndex - b.runIndex
|
||||
: a.task.startTime - b.task.startTime;
|
||||
});
|
||||
|
||||
return runs.flatMap(({ nodeName, runIndex, task }) => {
|
||||
if (workflow.getParentNodes(nodeName, 'ALL_NON_MAIN').length > 0) {
|
||||
return getTreeNodeData(
|
||||
nodeName,
|
||||
workflow,
|
||||
createAiData(nodeName, workflow, (node) => runData[node] ?? []),
|
||||
undefined,
|
||||
);
|
||||
}
|
||||
|
||||
return getTreeNodeData(
|
||||
nodeName,
|
||||
workflow,
|
||||
[
|
||||
{
|
||||
data: getReferencedData(task, false, true)[0],
|
||||
node: nodeName,
|
||||
runIndex,
|
||||
},
|
||||
],
|
||||
runIndex,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user