mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
feat(editor): Add undo/redo create connection in new canvas (no-changelog) (#10141)
This commit is contained in:
parent
7e1eeb4c31
commit
ada1256898
|
@ -708,6 +708,24 @@ describe('useCanvasOperations', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('revertCreateConnection', () => {
|
||||||
|
it('deletes connection if both source and target nodes exist', () => {
|
||||||
|
const connection: [IConnection, IConnection] = [
|
||||||
|
{ node: 'sourceNode', type: NodeConnectionType.Main, index: 0 },
|
||||||
|
{ node: 'targetNode', type: NodeConnectionType.Main, index: 0 },
|
||||||
|
];
|
||||||
|
const testNode = createTestNode();
|
||||||
|
|
||||||
|
const removeConnectionSpy = vi.spyOn(workflowsStore, 'removeConnection');
|
||||||
|
vi.spyOn(workflowsStore, 'getNodeByName').mockReturnValue(testNode);
|
||||||
|
vi.spyOn(workflowsStore, 'getNodeById').mockReturnValue(testNode);
|
||||||
|
|
||||||
|
canvasOperations.revertCreateConnection(connection);
|
||||||
|
|
||||||
|
expect(removeConnectionSpy).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('isConnectionAllowed', () => {
|
describe('isConnectionAllowed', () => {
|
||||||
it('should return false if source and target nodes are the same', () => {
|
it('should return false if source and target nodes are the same', () => {
|
||||||
const node = mockNode({ id: '1', type: 'testType', name: 'Test Node' });
|
const node = mockNode({ id: '1', type: 'testType', name: 'Test Node' });
|
||||||
|
|
|
@ -30,6 +30,7 @@ import {
|
||||||
WEBHOOK_NODE_TYPE,
|
WEBHOOK_NODE_TYPE,
|
||||||
} from '@/constants';
|
} from '@/constants';
|
||||||
import {
|
import {
|
||||||
|
AddConnectionCommand,
|
||||||
AddNodeCommand,
|
AddNodeCommand,
|
||||||
MoveNodeCommand,
|
MoveNodeCommand,
|
||||||
RemoveConnectionCommand,
|
RemoveConnectionCommand,
|
||||||
|
@ -55,6 +56,7 @@ import {
|
||||||
getUniqueNodeName,
|
getUniqueNodeName,
|
||||||
mapCanvasConnectionToLegacyConnection,
|
mapCanvasConnectionToLegacyConnection,
|
||||||
mapLegacyConnectionsToCanvasConnections,
|
mapLegacyConnectionsToCanvasConnections,
|
||||||
|
mapLegacyConnectionToCanvasConnection,
|
||||||
parseCanvasConnectionHandleString,
|
parseCanvasConnectionHandleString,
|
||||||
} from '@/utils/canvasUtilsV2';
|
} from '@/utils/canvasUtilsV2';
|
||||||
import * as NodeViewUtils from '@/utils/nodeViewUtils';
|
import * as NodeViewUtils from '@/utils/nodeViewUtils';
|
||||||
|
@ -949,13 +951,21 @@ export function useCanvasOperations({
|
||||||
* Connection operations
|
* Connection operations
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function createConnection(connection: Connection) {
|
function createConnection(connection: Connection, { trackHistory = false } = {}) {
|
||||||
const sourceNode = workflowsStore.getNodeById(connection.source);
|
const sourceNode = workflowsStore.getNodeById(connection.source);
|
||||||
const targetNode = workflowsStore.getNodeById(connection.target);
|
const targetNode = workflowsStore.getNodeById(connection.target);
|
||||||
if (!sourceNode || !targetNode) {
|
if (!sourceNode || !targetNode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (trackHistory) {
|
||||||
|
historyStore.pushCommandToUndo(
|
||||||
|
new AddConnectionCommand(
|
||||||
|
mapCanvasConnectionToLegacyConnection(sourceNode, targetNode, connection),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const mappedConnection = mapCanvasConnectionToLegacyConnection(
|
const mappedConnection = mapCanvasConnectionToLegacyConnection(
|
||||||
sourceNode,
|
sourceNode,
|
||||||
targetNode,
|
targetNode,
|
||||||
|
@ -976,6 +986,19 @@ export function useCanvasOperations({
|
||||||
uiStore.stateIsDirty = true;
|
uiStore.stateIsDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function revertCreateConnection(connection: [IConnection, IConnection]) {
|
||||||
|
const sourceNodeName = connection[0].node;
|
||||||
|
const sourceNode = workflowsStore.getNodeByName(sourceNodeName);
|
||||||
|
const targetNodeName = connection[1].node;
|
||||||
|
const targetNode = workflowsStore.getNodeByName(targetNodeName);
|
||||||
|
|
||||||
|
if (!sourceNode || !targetNode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteConnection(mapLegacyConnectionToCanvasConnection(sourceNode, targetNode, connection));
|
||||||
|
}
|
||||||
|
|
||||||
function deleteConnection(
|
function deleteConnection(
|
||||||
connection: Connection,
|
connection: Connection,
|
||||||
{ trackHistory = false, trackBulk = true } = {},
|
{ trackHistory = false, trackBulk = true } = {},
|
||||||
|
@ -1607,6 +1630,7 @@ export function useCanvasOperations({
|
||||||
revertDeleteNode,
|
revertDeleteNode,
|
||||||
addConnections,
|
addConnections,
|
||||||
createConnection,
|
createConnection,
|
||||||
|
revertCreateConnection,
|
||||||
deleteConnection,
|
deleteConnection,
|
||||||
revertDeleteConnection,
|
revertDeleteConnection,
|
||||||
isConnectionAllowed,
|
isConnectionAllowed,
|
||||||
|
|
|
@ -74,6 +74,32 @@ export function mapLegacyConnectionsToCanvasConnections(
|
||||||
return mappedConnections;
|
return mappedConnections;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function mapLegacyConnectionToCanvasConnection(
|
||||||
|
sourceNode: INodeUi,
|
||||||
|
targetNode: INodeUi,
|
||||||
|
legacyConnection: [IConnection, IConnection],
|
||||||
|
): Connection {
|
||||||
|
const source = sourceNode.id;
|
||||||
|
const sourceHandle = createCanvasConnectionHandleString({
|
||||||
|
mode: CanvasConnectionMode.Output,
|
||||||
|
type: legacyConnection[0].type,
|
||||||
|
index: legacyConnection[0].index,
|
||||||
|
});
|
||||||
|
const target = targetNode.id;
|
||||||
|
const targetHandle = createCanvasConnectionHandleString({
|
||||||
|
mode: CanvasConnectionMode.Input,
|
||||||
|
type: legacyConnection[1].type,
|
||||||
|
index: legacyConnection[1].index,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
source,
|
||||||
|
sourceHandle,
|
||||||
|
target,
|
||||||
|
targetHandle,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function parseCanvasConnectionHandleString(handle: string | null | undefined) {
|
export function parseCanvasConnectionHandleString(handle: string | null | undefined) {
|
||||||
const [mode, type, index] = (handle ?? '').split('/');
|
const [mode, type, index] = (handle ?? '').split('/');
|
||||||
|
|
||||||
|
|
|
@ -149,6 +149,7 @@ const {
|
||||||
revertDeleteNode,
|
revertDeleteNode,
|
||||||
addNodes,
|
addNodes,
|
||||||
createConnection,
|
createConnection,
|
||||||
|
revertCreateConnection,
|
||||||
deleteConnection,
|
deleteConnection,
|
||||||
revertDeleteConnection,
|
revertDeleteConnection,
|
||||||
setNodeActiveByName,
|
setNodeActiveByName,
|
||||||
|
@ -689,7 +690,11 @@ async function loadCredentials() {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function onCreateConnection(connection: Connection) {
|
function onCreateConnection(connection: Connection) {
|
||||||
createConnection(connection);
|
createConnection(connection, { trackHistory: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
function onRevertCreateConnection({ connection }: { connection: [IConnection, IConnection] }) {
|
||||||
|
revertCreateConnection(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onCreateConnectionCancelled(event: ConnectStartEvent) {
|
function onCreateConnectionCancelled(event: ConnectStartEvent) {
|
||||||
|
@ -974,7 +979,7 @@ function addUndoRedoEventBindings() {
|
||||||
// historyBus.on('nodeMove', onMoveNode);
|
// historyBus.on('nodeMove', onMoveNode);
|
||||||
// historyBus.on('revertAddNode', onRevertAddNode);
|
// historyBus.on('revertAddNode', onRevertAddNode);
|
||||||
historyBus.on('revertRemoveNode', onRevertDeleteNode);
|
historyBus.on('revertRemoveNode', onRevertDeleteNode);
|
||||||
// historyBus.on('revertAddConnection', onRevertAddConnection);
|
historyBus.on('revertAddConnection', onRevertCreateConnection);
|
||||||
historyBus.on('revertRemoveConnection', onRevertDeleteConnection);
|
historyBus.on('revertRemoveConnection', onRevertDeleteConnection);
|
||||||
historyBus.on('revertRenameNode', onRevertRenameNode);
|
historyBus.on('revertRenameNode', onRevertRenameNode);
|
||||||
// historyBus.on('enableNodeToggle', onRevertEnableToggle);
|
// historyBus.on('enableNodeToggle', onRevertEnableToggle);
|
||||||
|
@ -984,7 +989,7 @@ function removeUndoRedoEventBindings() {
|
||||||
// historyBus.off('nodeMove', onMoveNode);
|
// historyBus.off('nodeMove', onMoveNode);
|
||||||
// historyBus.off('revertAddNode', onRevertAddNode);
|
// historyBus.off('revertAddNode', onRevertAddNode);
|
||||||
historyBus.off('revertRemoveNode', onRevertDeleteNode);
|
historyBus.off('revertRemoveNode', onRevertDeleteNode);
|
||||||
// historyBus.off('revertAddConnection', onRevertAddConnection);
|
historyBus.off('revertAddConnection', onRevertCreateConnection);
|
||||||
historyBus.off('revertRemoveConnection', onRevertDeleteConnection);
|
historyBus.off('revertRemoveConnection', onRevertDeleteConnection);
|
||||||
historyBus.off('revertRenameNode', onRevertRenameNode);
|
historyBus.off('revertRenameNode', onRevertRenameNode);
|
||||||
// historyBus.off('enableNodeToggle', onRevertEnableToggle);
|
// historyBus.off('enableNodeToggle', onRevertEnableToggle);
|
||||||
|
|
Loading…
Reference in a new issue