mirror of
https://github.com/n8n-io/n8n.git
synced 2024-09-20 14:57:31 -07:00
fix(editor): Fix an issue with zoom and canvas nodes connections (#5548)
This commit is contained in:
parent
f965469e13
commit
4998ab2350
|
@ -18,7 +18,8 @@ interface N8nPlusEndpointParams extends EndpointRepresentationParams {
|
|||
}
|
||||
export const PlusStalkOverlay = 'plus-stalk';
|
||||
export const HoverMessageOverlay = 'hover-message';
|
||||
|
||||
export const N8nPlusEndpointType = 'N8nPlus';
|
||||
export const EVENT_PLUS_ENDPOINT_CLICK = 'eventPlusEndpointClick';
|
||||
export class N8nPlusEndpoint extends EndpointRepresentation<ComputedN8nPlusEndpoint> {
|
||||
params: N8nPlusEndpointParams;
|
||||
label: string;
|
||||
|
@ -38,7 +39,7 @@ export class N8nPlusEndpoint extends EndpointRepresentation<ComputedN8nPlusEndpo
|
|||
this.bindEvents();
|
||||
}
|
||||
|
||||
static type = 'N8nPlus';
|
||||
static type = N8nPlusEndpointType;
|
||||
type = N8nPlusEndpoint.type;
|
||||
|
||||
setupOverlays() {
|
||||
|
@ -100,7 +101,7 @@ export class N8nPlusEndpoint extends EndpointRepresentation<ComputedN8nPlusEndpo
|
|||
};
|
||||
fireClickEvent = (endpoint: Endpoint) => {
|
||||
if (endpoint === this.endpoint) {
|
||||
this.instance.fire('plusEndpointClick', this.endpoint);
|
||||
this.instance.fire(EVENT_PLUS_ENDPOINT_CLICK, this.endpoint);
|
||||
}
|
||||
};
|
||||
setHoverMessageVisible = (endpoint: Endpoint) => {
|
||||
|
|
|
@ -28,6 +28,9 @@ import {
|
|||
PLACEHOLDER_TRIGGER_NODE_SIZE,
|
||||
CONNECTOR_FLOWCHART_TYPE,
|
||||
GRID_SIZE,
|
||||
CONNECTOR_PAINT_STYLE_DEFAULT,
|
||||
CONNECTOR_PAINT_STYLE_PRIMARY,
|
||||
CONNECTOR_ARROW_OVERLAYS,
|
||||
} from '@/utils/nodeViewUtils';
|
||||
import { PointXY } from '@jsplumb/util';
|
||||
|
||||
|
@ -153,6 +156,13 @@ export const useCanvasStore = defineStore('canvas', () => {
|
|||
container,
|
||||
connector: CONNECTOR_FLOWCHART_TYPE,
|
||||
resizeObserver: false,
|
||||
endpoint: {
|
||||
type: 'Dot',
|
||||
options: { radius: 5 },
|
||||
},
|
||||
paintStyle: CONNECTOR_PAINT_STYLE_DEFAULT,
|
||||
hoverPaintStyle: CONNECTOR_PAINT_STYLE_PRIMARY,
|
||||
connectionOverlays: CONNECTOR_ARROW_OVERLAYS,
|
||||
dragOptions: {
|
||||
cursor: 'pointer',
|
||||
grid: { w: GRID_SIZE, h: GRID_SIZE },
|
||||
|
|
|
@ -161,7 +161,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue, { ComponentInstance } from 'vue';
|
||||
import Vue from 'vue';
|
||||
import { mapStores } from 'pinia';
|
||||
|
||||
import {
|
||||
|
@ -299,7 +299,11 @@ import {
|
|||
BrowserJsPlumbInstance,
|
||||
ready,
|
||||
} from '@jsplumb/browser-ui';
|
||||
import { N8nPlusEndpoint } from '@/plugins/endpoints/N8nPlusEndpointType';
|
||||
import {
|
||||
N8nPlusEndpoint,
|
||||
N8nPlusEndpointType,
|
||||
EVENT_PLUS_ENDPOINT_CLICK,
|
||||
} from '@/plugins/endpoints/N8nPlusEndpointType';
|
||||
import { usePostHogStore } from '@/stores/posthog';
|
||||
|
||||
interface AddNodeOptions {
|
||||
|
@ -1939,12 +1943,13 @@ export default mixins(
|
|||
// current node. But only if it's added manually by the user (not by undo/redo mechanism)
|
||||
if (trackHistory) {
|
||||
this.deselectAllNodes();
|
||||
if (showDetail) {
|
||||
setTimeout(() => {
|
||||
this.nodeSelectedByName(newNodeData.name, nodeTypeName !== STICKY_NODE_TYPE);
|
||||
this.nodeSelectedByName(
|
||||
newNodeData.name,
|
||||
showDetail && nodeTypeName !== STICKY_NODE_TYPE,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return newNodeData;
|
||||
},
|
||||
|
@ -2051,23 +2056,12 @@ export default mixins(
|
|||
}
|
||||
this.historyStore.stopRecordingUndo();
|
||||
},
|
||||
initNodeView() {
|
||||
this.instance?.importDefaults({
|
||||
endpoint: {
|
||||
type: 'Dot',
|
||||
options: { radius: 5 },
|
||||
},
|
||||
paintStyle: NodeViewUtils.CONNECTOR_PAINT_STYLE_DEFAULT,
|
||||
hoverPaintStyle: NodeViewUtils.CONNECTOR_PAINT_STYLE_PRIMARY,
|
||||
connectionOverlays: NodeViewUtils.CONNECTOR_ARROW_OVERLAYS,
|
||||
});
|
||||
|
||||
const insertNodeAfterSelected = (info: {
|
||||
insertNodeAfterSelected(info: {
|
||||
sourceId: string;
|
||||
index: number;
|
||||
eventSource: string;
|
||||
connection?: Connection;
|
||||
}) => {
|
||||
}) {
|
||||
// Get the node and set it as active that new nodes
|
||||
// which get created get automatically connected
|
||||
// to it.
|
||||
|
@ -2085,9 +2079,8 @@ export default mixins(
|
|||
}
|
||||
|
||||
this.onToggleNodeCreator({ source: info.eventSource, createNodeActive: true });
|
||||
};
|
||||
|
||||
this.instance.bind(EVENT_CONNECTION_ABORT, (connection: Connection) => {
|
||||
},
|
||||
onEventConnectionAbort(connection: Connection) {
|
||||
try {
|
||||
if (this.dropPrevented) {
|
||||
this.dropPrevented = false;
|
||||
|
@ -2107,7 +2100,7 @@ export default mixins(
|
|||
return;
|
||||
}
|
||||
|
||||
insertNodeAfterSelected({
|
||||
this.insertNodeAfterSelected({
|
||||
sourceId: connection.parameters.nodeId,
|
||||
index: connection.parameters.index,
|
||||
eventSource: 'node_connection_drop',
|
||||
|
@ -2115,9 +2108,8 @@ export default mixins(
|
|||
} catch (e) {
|
||||
console.error(e); // eslint-disable-line no-console
|
||||
}
|
||||
});
|
||||
|
||||
this.instance.bind(INTERCEPT_BEFORE_DROP, (info: BeforeDropParams) => {
|
||||
},
|
||||
onInterceptBeforeDrop(info: BeforeDropParams) {
|
||||
try {
|
||||
const sourceInfo = info.connection.endpoints[0].parameters;
|
||||
const targetInfo = info.dropEndpoint.parameters;
|
||||
|
@ -2139,9 +2131,8 @@ export default mixins(
|
|||
console.error(e); // eslint-disable-line no-console
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
this.instance.bind(EVENT_CONNECTION, (info: ConnectionEstablishedParams) => {
|
||||
},
|
||||
onEventConnection(info: ConnectionEstablishedParams) {
|
||||
try {
|
||||
const sourceInfo = info.sourceEndpoint.parameters;
|
||||
const targetInfo = info.targetEndpoint.parameters;
|
||||
|
@ -2188,7 +2179,7 @@ export default mixins(
|
|||
this.__deleteJSPlumbConnection(info.connection);
|
||||
},
|
||||
() => {
|
||||
insertNodeAfterSelected({
|
||||
this.insertNodeAfterSelected({
|
||||
sourceId: info.sourceEndpoint.parameters.nodeId,
|
||||
index: sourceInfo.index,
|
||||
connection: info.connection,
|
||||
|
@ -2209,9 +2200,8 @@ export default mixins(
|
|||
} catch (e) {
|
||||
console.error(e); // eslint-disable-line no-console
|
||||
}
|
||||
});
|
||||
|
||||
this.instance.bind(EVENT_DRAG_MOVE, () => {
|
||||
},
|
||||
onDragMove() {
|
||||
this.instance?.connections.forEach((connection) => {
|
||||
NodeViewUtils.showOrHideItemsLabel(connection);
|
||||
NodeViewUtils.showOrHideMidpointArrow(connection);
|
||||
|
@ -2221,8 +2211,8 @@ export default mixins(
|
|||
this.instance?.repaint(overlay.canvas);
|
||||
});
|
||||
});
|
||||
});
|
||||
this.instance.bind(EVENT_CONNECTION_MOUSEOVER, (connection: Connection) => {
|
||||
},
|
||||
onConnectionMouseOver(connection: Connection) {
|
||||
try {
|
||||
if (this.exitTimer !== undefined) {
|
||||
clearTimeout(this.exitTimer);
|
||||
|
@ -2249,8 +2239,8 @@ export default mixins(
|
|||
} catch (e) {
|
||||
console.error(e); // eslint-disable-line no-console
|
||||
}
|
||||
});
|
||||
this.instance.bind(EVENT_CONNECTION_MOUSEOUT, (connection: Connection) => {
|
||||
},
|
||||
onConnectionMouseOut(connection: Connection) {
|
||||
try {
|
||||
if (this.exitTimer) return;
|
||||
|
||||
|
@ -2272,9 +2262,8 @@ export default mixins(
|
|||
} catch (e) {
|
||||
console.error(e); // eslint-disable-line no-console
|
||||
}
|
||||
});
|
||||
|
||||
this.instance.bind(EVENT_CONNECTION_MOVED, (info: ConnectionMovedParams) => {
|
||||
},
|
||||
onConnectionMoved(info: ConnectionMovedParams) {
|
||||
try {
|
||||
// When a connection gets moved from one node to another it for some reason
|
||||
// calls the "connection" event but not the "connectionDetached" one. So we listen
|
||||
|
@ -2302,19 +2291,19 @@ export default mixins(
|
|||
} catch (e) {
|
||||
console.error(e); // eslint-disable-line no-console
|
||||
}
|
||||
});
|
||||
this.instance.bind(EVENT_ENDPOINT_MOUSEOVER, (endpoint: Endpoint, mouse) => {
|
||||
},
|
||||
onEndpointMouseOver(endpoint: Endpoint, mouse) {
|
||||
// This event seems bugged. It gets called constantly even when the mouse is not over the endpoint
|
||||
// if the endpoint has a connection attached to it. So we need to check if the mouse is actually over
|
||||
// the endpoint.
|
||||
if (!endpoint.isTarget || mouse.target !== endpoint.endpoint.canvas) return;
|
||||
this.instance.setHover(endpoint, true);
|
||||
});
|
||||
this.instance.bind(EVENT_ENDPOINT_MOUSEOUT, (endpoint: Endpoint) => {
|
||||
},
|
||||
onEndpointMouseOut(endpoint: Endpoint) {
|
||||
if (!endpoint.isTarget) return;
|
||||
this.instance.setHover(endpoint, false);
|
||||
});
|
||||
this.instance.bind(EVENT_CONNECTION_DETACHED, async (info: ConnectionDetachedParams) => {
|
||||
},
|
||||
async onConnectionDetached(info: ConnectionDetachedParams) {
|
||||
try {
|
||||
const connectionInfo: [IConnection, IConnection] | null = getConnectionInfo(info);
|
||||
NodeViewUtils.resetInputLabelPosition(info.targetEndpoint);
|
||||
|
@ -2348,8 +2337,8 @@ export default mixins(
|
|||
} catch (e) {
|
||||
console.error(e); // eslint-disable-line no-console
|
||||
}
|
||||
});
|
||||
this.instance.bind(EVENT_CONNECTION_DRAG, (connection: Connection) => {
|
||||
},
|
||||
onConnectionDrag(connection: Connection) {
|
||||
// The overlays are visible by default so we need to hide the midpoint arrow
|
||||
// manually
|
||||
connection.overlays['midpoint-arrow']?.setVisible(false);
|
||||
|
@ -2420,27 +2409,77 @@ export default mixins(
|
|||
} catch (e) {
|
||||
console.error(e); // eslint-disable-line no-console
|
||||
}
|
||||
});
|
||||
this.instance.bind(
|
||||
[EVENT_CONNECTION_DRAG, EVENT_CONNECTION_ABORT, EVENT_CONNECTION_DETACHED],
|
||||
(connection: Connection) => {
|
||||
},
|
||||
onConnectionDragAbortDetached(connection: Connection) {
|
||||
Object.values(this.instance?.endpointsByElement)
|
||||
.flatMap((endpoints) => Object.values(endpoints))
|
||||
.filter((endpoint) => endpoint.endpoint.type === 'N8nPlus')
|
||||
.forEach((endpoint) =>
|
||||
setTimeout(() => endpoint.instance.revalidate(endpoint.element), 0),
|
||||
);
|
||||
.forEach((endpoint) => setTimeout(() => endpoint.instance.revalidate(endpoint.element), 0));
|
||||
},
|
||||
);
|
||||
this.instance.bind('plusEndpointClick', (endpoint: Endpoint) => {
|
||||
onPlusEndpointClick(endpoint: Endpoint) {
|
||||
if (endpoint && endpoint.__meta) {
|
||||
insertNodeAfterSelected({
|
||||
this.insertNodeAfterSelected({
|
||||
sourceId: endpoint.__meta.nodeId,
|
||||
index: endpoint.__meta.index,
|
||||
eventSource: 'plus_endpoint',
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
bindCanvasEvents() {
|
||||
this.instance.bind(EVENT_CONNECTION_ABORT, this.onEventConnectionAbort);
|
||||
|
||||
this.instance.bind(INTERCEPT_BEFORE_DROP, this.onInterceptBeforeDrop);
|
||||
|
||||
this.instance.bind(EVENT_CONNECTION, this.onEventConnection);
|
||||
|
||||
this.instance.bind(EVENT_DRAG_MOVE, this.onDragMove);
|
||||
this.instance.bind(EVENT_CONNECTION_MOUSEOVER, this.onConnectionMouseOver);
|
||||
this.instance.bind(EVENT_CONNECTION_MOUSEOUT, this.onConnectionMouseOut);
|
||||
|
||||
this.instance.bind(EVENT_CONNECTION_MOVED, this.onConnectionMoved);
|
||||
this.instance.bind(EVENT_ENDPOINT_MOUSEOVER, this.onEndpointMouseOver);
|
||||
this.instance.bind(EVENT_ENDPOINT_MOUSEOUT, this.onEndpointMouseOut);
|
||||
this.instance.bind(EVENT_CONNECTION_DETACHED, this.onConnectionDetached);
|
||||
this.instance.bind(EVENT_CONNECTION_DRAG, this.onConnectionDrag);
|
||||
this.instance.bind(
|
||||
[EVENT_CONNECTION_DRAG, EVENT_CONNECTION_ABORT, EVENT_CONNECTION_DETACHED],
|
||||
this.onConnectionDragAbortDetached,
|
||||
);
|
||||
this.instance.bind(EVENT_PLUS_ENDPOINT_CLICK, this.onPlusEndpointClick);
|
||||
},
|
||||
unbindCanvasEvents() {
|
||||
this.instance.unbind(EVENT_CONNECTION_ABORT, this.onEventConnectionAbort);
|
||||
|
||||
this.instance.unbind(INTERCEPT_BEFORE_DROP, this.onInterceptBeforeDrop);
|
||||
|
||||
this.instance.unbind(EVENT_CONNECTION, this.onEventConnection);
|
||||
|
||||
this.instance.unbind(EVENT_DRAG_MOVE, this.onDragMove);
|
||||
this.instance.unbind(EVENT_CONNECTION_MOUSEOVER, this.onConnectionMouseOver);
|
||||
this.instance.unbind(EVENT_CONNECTION_MOUSEOUT, this.onConnectionMouseOut);
|
||||
|
||||
this.instance.unbind(EVENT_CONNECTION_MOVED, this.onConnectionMoved);
|
||||
this.instance.unbind(EVENT_ENDPOINT_MOUSEOVER, this.onEndpointMouseOver);
|
||||
this.instance.unbind(EVENT_ENDPOINT_MOUSEOUT, this.onEndpointMouseOut);
|
||||
this.instance.unbind(EVENT_CONNECTION_DETACHED, this.onConnectionDetached);
|
||||
this.instance.unbind(EVENT_CONNECTION_DRAG, this.onConnectionDrag);
|
||||
|
||||
this.instance.unbind(EVENT_CONNECTION_DRAG, this.onConnectionDragAbortDetached);
|
||||
this.instance.unbind(EVENT_CONNECTION_ABORT, this.onConnectionDragAbortDetached);
|
||||
this.instance.unbind(EVENT_CONNECTION_DETACHED, this.onConnectionDragAbortDetached);
|
||||
this.instance.unbind(EVENT_PLUS_ENDPOINT_CLICK, this.onPlusEndpointClick);
|
||||
|
||||
// Get all the endpoints and unbind the events
|
||||
const elements = this.instance.getManagedElements();
|
||||
for (const element of Object.values(elements)) {
|
||||
const endpoints = element.endpoints;
|
||||
for (const endpoint of endpoints || []) {
|
||||
const endpointInstance = endpoint?.endpoint;
|
||||
if (endpointInstance && endpointInstance.type === N8nPlusEndpointType) {
|
||||
(endpointInstance as N8nPlusEndpoint).unbindEvents();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
async newWorkflow(): Promise<void> {
|
||||
this.startLoading();
|
||||
|
@ -3826,7 +3865,7 @@ export default mixins(
|
|||
ready(async () => {
|
||||
try {
|
||||
try {
|
||||
this.initNodeView();
|
||||
this.bindCanvasEvents();
|
||||
} catch {} // This will break if mounted after jsplumb has been initiated from executions preview, so continue if it breaks
|
||||
await this.initView();
|
||||
if (window.top) {
|
||||
|
@ -3894,8 +3933,7 @@ export default mixins(
|
|||
this.showTriggerCreator('trigger_placeholder_button');
|
||||
}
|
||||
this.uiStore.addFirstStepOnLoad = false;
|
||||
|
||||
this.initNodeView();
|
||||
this.bindCanvasEvents();
|
||||
document.addEventListener('keydown', this.keyDown);
|
||||
document.addEventListener('keyup', this.keyUp);
|
||||
window.addEventListener('message', this.onPostMessageReceived);
|
||||
|
@ -3918,6 +3956,7 @@ export default mixins(
|
|||
this.canvasStore.isDemo = this.isDemo;
|
||||
},
|
||||
deactivated() {
|
||||
this.unbindCanvasEvents();
|
||||
document.removeEventListener('keydown', this.keyDown);
|
||||
document.removeEventListener('keyup', this.keyUp);
|
||||
window.removeEventListener('message', this.onPostMessageReceived);
|
||||
|
@ -3936,7 +3975,6 @@ export default mixins(
|
|||
dataPinningEventBus.$off('pin-data', this.addPinDataConnections);
|
||||
dataPinningEventBus.$off('unpin-data', this.removePinDataConnections);
|
||||
nodeViewEventBus.$off('saveWorkflow', this.saveCurrentWorkflowExternal);
|
||||
this.instance.unbind();
|
||||
},
|
||||
destroyed() {
|
||||
this.resetWorkspace();
|
||||
|
|
Loading…
Reference in a new issue