From ab27f91944d6cb27e69f972e52f054a827290608 Mon Sep 17 00:00:00 2001 From: oleg Date: Mon, 12 May 2025 09:56:42 +0200 Subject: [PATCH] fix(editor): Sort start start nodes for manual execution by Y position (#15254) --- .../src/composables/useRunWorkflow.test.ts | 33 +++++++++++++++++++ .../src/composables/useRunWorkflow.ts | 17 +++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/packages/frontend/editor-ui/src/composables/useRunWorkflow.test.ts b/packages/frontend/editor-ui/src/composables/useRunWorkflow.test.ts index e0a243e213..63cdb46fa3 100644 --- a/packages/frontend/editor-ui/src/composables/useRunWorkflow.test.ts +++ b/packages/frontend/editor-ui/src/composables/useRunWorkflow.test.ts @@ -822,4 +822,37 @@ describe('useRunWorkflow({ router })', () => { await waitFor(() => expect(markStoppedSpy).toHaveBeenCalled()); }); }); + + describe('sortNodesByYPosition()', () => { + const getNodeUi = (name: string, position: [number, number]) => { + return { + name, + position, + type: 'n8n-nodes-base.test', + typeVersion: 1, + id: name, + parameters: {}, + }; + }; + it('should sort nodes by Y position in ascending order', () => { + const { sortNodesByYPosition } = useRunWorkflow({ router }); + + const topNode = 'topNode'; + const middleNode = 'middleNode'; + const bottomNode = 'bottomNode'; + + vi.mocked(workflowsStore.getNodeByName).mockImplementation((name) => { + if (name === topNode) return getNodeUi(topNode, [100, 50]); + if (name === middleNode) return getNodeUi(middleNode, [200, 200]); + if (name === bottomNode) return getNodeUi(bottomNode, [150, 350]); + return null; + }); + + // Test with different order of input nodes + const result = sortNodesByYPosition([bottomNode, topNode, middleNode]); + + // Should be sorted by Y position (top to bottom) + expect(result).toEqual([topNode, middleNode, bottomNode]); + }); + }); }); diff --git a/packages/frontend/editor-ui/src/composables/useRunWorkflow.ts b/packages/frontend/editor-ui/src/composables/useRunWorkflow.ts index 179aea756d..a134a46b2a 100644 --- a/packages/frontend/editor-ui/src/composables/useRunWorkflow.ts +++ b/packages/frontend/editor-ui/src/composables/useRunWorkflow.ts @@ -60,6 +60,20 @@ export function useRunWorkflow(useRunWorkflowOpts: { router: ReturnType { + const nodeA = workflowsStore.getNodeByName(a)?.position ?? [0, 0]; + const nodeB = workflowsStore.getNodeByName(b)?.position ?? [0, 0]; + + const nodeAYPosition = nodeA[1]; + const nodeBYPosition = nodeB[1]; + + if (nodeAYPosition === nodeBYPosition) return 0; + + return nodeAYPosition > nodeBYPosition ? 1 : -1; + }); + } + // Starts to execute a workflow on server async function runWorkflowApi(runData: IStartRunData): Promise { if (!pushConnectionStore.isConnected) { @@ -223,7 +237,7 @@ export function useRunWorkflow(useRunWorkflowOpts: { router: ReturnType { + const startNodes: StartNodeData[] = sortNodesByYPosition(startNodeNames).map((name) => { // Find for each start node the source data let sourceData = get(runData, [name, 0, 'source', 0], null); if (sourceData === null) { @@ -519,5 +533,6 @@ export function useRunWorkflow(useRunWorkflowOpts: { router: ReturnType