From c97bd48a77643b9c2a5d7218e21b957af15cee0b Mon Sep 17 00:00:00 2001
From: autologie <suguru@n8n.io>
Date: Thu, 16 Jan 2025 10:30:41 +0100
Subject: [PATCH] fix(editor): Show connector label above the line when it's
 straight (#12622)

---
 .../canvas/elements/edges/CanvasEdge.test.ts  | 40 +++++++++++++++++--
 .../canvas/elements/edges/CanvasEdge.vue      |  8 +++-
 .../elements/edges/utils/getEdgeRenderData.ts |  3 ++
 .../render-types/CanvasHandleMainOutput.vue   |  4 +-
 4 files changed, 48 insertions(+), 7 deletions(-)

diff --git a/packages/editor-ui/src/components/canvas/elements/edges/CanvasEdge.test.ts b/packages/editor-ui/src/components/canvas/elements/edges/CanvasEdge.test.ts
index 0e0ac01dfa..c8cad29247 100644
--- a/packages/editor-ui/src/components/canvas/elements/edges/CanvasEdge.test.ts
+++ b/packages/editor-ui/src/components/canvas/elements/edges/CanvasEdge.test.ts
@@ -1,10 +1,10 @@
-import CanvasEdge, { type CanvasEdgeProps } from './CanvasEdge.vue';
 import { createComponentRenderer } from '@/__tests__/render';
 import { createTestingPinia } from '@pinia/testing';
-import { setActivePinia } from 'pinia';
+import userEvent from '@testing-library/user-event';
 import { Position } from '@vue-flow/core';
 import { NodeConnectionType } from 'n8n-workflow';
-import userEvent from '@testing-library/user-event';
+import { setActivePinia } from 'pinia';
+import CanvasEdge, { type CanvasEdgeProps } from './CanvasEdge.vue';
 
 const DEFAULT_PROPS = {
 	sourceX: 0,
@@ -151,4 +151,38 @@ describe('CanvasEdge', () => {
 
 		expect(edge).toHaveAttribute('d', 'M0,0 C62.5,0 -162.5,-100 -100,-100');
 	});
+
+	it('should render a label above the connector when it is straight', () => {
+		const { container } = renderComponent({
+			props: {
+				...DEFAULT_PROPS,
+				sourceY: 50,
+				targetY: 50,
+			},
+		});
+
+		const label = container.querySelector('.vue-flow__edge-label');
+
+		expect(label).toHaveAttribute(
+			'style',
+			'transform: translate(-50%, -150%) translate(50px, 50px);',
+		);
+	});
+
+	it("should render a label in the middle of the connector when it isn't straight", () => {
+		const { container } = renderComponent({
+			props: {
+				...DEFAULT_PROPS,
+				sourceY: 0,
+				targetY: 100,
+			},
+		});
+
+		const label = container.querySelector('.vue-flow__edge-label');
+
+		expect(label).toHaveAttribute(
+			'style',
+			'transform: translate(-50%, -50%) translate(50px, 50px);',
+		);
+	});
 });
diff --git a/packages/editor-ui/src/components/canvas/elements/edges/CanvasEdge.vue b/packages/editor-ui/src/components/canvas/elements/edges/CanvasEdge.vue
index e688c32c9f..e3b8d178ac 100644
--- a/packages/editor-ui/src/components/canvas/elements/edges/CanvasEdge.vue
+++ b/packages/editor-ui/src/components/canvas/elements/edges/CanvasEdge.vue
@@ -5,7 +5,7 @@ import { isValidNodeConnectionType } from '@/utils/typeGuards';
 import type { Connection, EdgeProps } from '@vue-flow/core';
 import { BaseEdge, EdgeLabelRenderer } from '@vue-flow/core';
 import { NodeConnectionType } from 'n8n-workflow';
-import { computed, useCssModule, toRef } from 'vue';
+import { computed, toRef, useCssModule } from 'vue';
 import CanvasEdgeToolbar from './CanvasEdgeToolbar.vue';
 import { getEdgeRenderData } from './utils';
 
@@ -70,9 +70,13 @@ const edgeLabelStyle = computed(() => ({
 	color: edgeColor.value,
 }));
 
+const isConnectorStraight = computed(() => renderData.value.isConnectorStraight);
+
 const edgeToolbarStyle = computed(() => {
+	const translateY = isConnectorStraight.value ? '-150%' : '-50%';
+
 	return {
-		transform: `translate(-50%, -50%) translate(${labelPosition.value[0]}px,${labelPosition.value[1]}px)`,
+		transform: `translate(-50%, ${translateY}) translate(${labelPosition.value[0]}px, ${labelPosition.value[1]}px)`,
 		...(props.hovered ? { zIndex: 1 } : {}),
 	};
 });
diff --git a/packages/editor-ui/src/components/canvas/elements/edges/utils/getEdgeRenderData.ts b/packages/editor-ui/src/components/canvas/elements/edges/utils/getEdgeRenderData.ts
index 848ce5a875..5fcfede7e4 100644
--- a/packages/editor-ui/src/components/canvas/elements/edges/utils/getEdgeRenderData.ts
+++ b/packages/editor-ui/src/components/canvas/elements/edges/utils/getEdgeRenderData.ts
@@ -21,12 +21,14 @@ export function getEdgeRenderData(
 	} = {},
 ) {
 	const { targetX, targetY, sourceX, sourceY, sourcePosition, targetPosition } = props;
+	const isConnectorStraight = sourceY === targetY;
 
 	if (!isRightOfSourceHandle(sourceX, targetX) || connectionType !== NodeConnectionType.Main) {
 		const segment = getBezierPath(props);
 		return {
 			segments: [segment],
 			labelPosition: [segment[1], segment[2]],
+			isConnectorStraight,
 		};
 	}
 
@@ -59,5 +61,6 @@ export function getEdgeRenderData(
 	return {
 		segments: [firstSegment, secondSegment],
 		labelPosition: [firstSegmentTargetX, firstSegmentTargetY],
+		isConnectorStraight,
 	};
 }
diff --git a/packages/editor-ui/src/components/canvas/elements/handles/render-types/CanvasHandleMainOutput.vue b/packages/editor-ui/src/components/canvas/elements/handles/render-types/CanvasHandleMainOutput.vue
index 7886c13418..89c83b4887 100644
--- a/packages/editor-ui/src/components/canvas/elements/handles/render-types/CanvasHandleMainOutput.vue
+++ b/packages/editor-ui/src/components/canvas/elements/handles/render-types/CanvasHandleMainOutput.vue
@@ -132,9 +132,9 @@ function onClickAdd() {
 
 .runDataLabel {
 	position: absolute;
-	top: 0;
+	top: 50%;
 	left: 50%;
-	transform: translate(-50%, -50%);
+	transform: translate(-50%, -150%);
 	font-size: var(--font-size-xs);
 	color: var(--color-success);
 }