feat(editor): Add capability to open NDV and rename node (no-changelog) (#9712)
This commit is contained in:
@@ -6,14 +6,16 @@ import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||
import { useUIStore } from '@/stores/ui.store';
|
||||
import { useHistoryStore } from '@/stores/history.store';
|
||||
import { createPinia, setActivePinia } from 'pinia';
|
||||
import { createTestNode } from '@/__tests__/mocks';
|
||||
import { createTestNode, createTestWorkflowObject } from '@/__tests__/mocks';
|
||||
import type { Connection } from '@vue-flow/core';
|
||||
import type { IConnection } from 'n8n-workflow';
|
||||
import { NodeConnectionType } from 'n8n-workflow';
|
||||
import { useNDVStore } from '@/stores/ndv.store';
|
||||
|
||||
describe('useCanvasOperations', () => {
|
||||
let workflowsStore: ReturnType<typeof useWorkflowsStore>;
|
||||
let uiStore: ReturnType<typeof useUIStore>;
|
||||
let ndvStore: ReturnType<typeof useNDVStore>;
|
||||
let historyStore: ReturnType<typeof useHistoryStore>;
|
||||
let canvasOperations: ReturnType<typeof useCanvasOperations>;
|
||||
|
||||
@@ -23,6 +25,7 @@ describe('useCanvasOperations', () => {
|
||||
|
||||
workflowsStore = useWorkflowsStore();
|
||||
uiStore = useUIStore();
|
||||
ndvStore = useNDVStore();
|
||||
historyStore = useHistoryStore();
|
||||
canvasOperations = useCanvasOperations();
|
||||
});
|
||||
@@ -134,6 +137,93 @@ describe('useCanvasOperations', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('renameNode', () => {
|
||||
it('should rename node', async () => {
|
||||
const oldName = 'Old Node';
|
||||
const newName = 'New Node';
|
||||
|
||||
const workflowObject = createTestWorkflowObject();
|
||||
workflowObject.renameNode = vi.fn();
|
||||
|
||||
vi.spyOn(workflowsStore, 'getCurrentWorkflow').mockReturnValue(workflowObject);
|
||||
|
||||
workflowsStore.getNodeByName = vi.fn().mockReturnValue({ name: oldName });
|
||||
ndvStore.activeNodeName = oldName;
|
||||
|
||||
await canvasOperations.renameNode(oldName, newName);
|
||||
|
||||
expect(workflowObject.renameNode).toHaveBeenCalledWith(oldName, newName);
|
||||
expect(ndvStore.activeNodeName).toBe(newName);
|
||||
});
|
||||
|
||||
it('should not rename node when new name is same as old name', async () => {
|
||||
const oldName = 'Old Node';
|
||||
workflowsStore.getNodeByName = vi.fn().mockReturnValue({ name: oldName });
|
||||
ndvStore.activeNodeName = oldName;
|
||||
|
||||
await canvasOperations.renameNode(oldName, oldName);
|
||||
|
||||
expect(ndvStore.activeNodeName).toBe(oldName);
|
||||
});
|
||||
});
|
||||
|
||||
describe('revertRenameNode', () => {
|
||||
it('should revert node renaming', async () => {
|
||||
const oldName = 'Old Node';
|
||||
const currentName = 'New Node';
|
||||
workflowsStore.getNodeByName = vi.fn().mockReturnValue({ name: currentName });
|
||||
ndvStore.activeNodeName = currentName;
|
||||
|
||||
await canvasOperations.revertRenameNode(currentName, oldName);
|
||||
|
||||
expect(ndvStore.activeNodeName).toBe(oldName);
|
||||
});
|
||||
|
||||
it('should not revert node renaming when old name is same as new name', async () => {
|
||||
const oldName = 'Old Node';
|
||||
workflowsStore.getNodeByName = vi.fn().mockReturnValue({ name: oldName });
|
||||
ndvStore.activeNodeName = oldName;
|
||||
|
||||
await canvasOperations.revertRenameNode(oldName, oldName);
|
||||
|
||||
expect(ndvStore.activeNodeName).toBe(oldName);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setNodeActive', () => {
|
||||
it('should set active node name when node exists', () => {
|
||||
const nodeId = 'node1';
|
||||
const nodeName = 'Node 1';
|
||||
workflowsStore.getNodeById = vi.fn().mockReturnValue({ name: nodeName });
|
||||
ndvStore.activeNodeName = '';
|
||||
|
||||
canvasOperations.setNodeActive(nodeId);
|
||||
|
||||
expect(ndvStore.activeNodeName).toBe(nodeName);
|
||||
});
|
||||
|
||||
it('should not change active node name when node does not exist', () => {
|
||||
const nodeId = 'node1';
|
||||
workflowsStore.getNodeById = vi.fn().mockReturnValue(undefined);
|
||||
ndvStore.activeNodeName = 'Existing Node';
|
||||
|
||||
canvasOperations.setNodeActive(nodeId);
|
||||
|
||||
expect(ndvStore.activeNodeName).toBe('Existing Node');
|
||||
});
|
||||
});
|
||||
|
||||
describe('setNodeActiveByName', () => {
|
||||
it('should set active node name', () => {
|
||||
const nodeName = 'Node 1';
|
||||
ndvStore.activeNodeName = '';
|
||||
|
||||
canvasOperations.setNodeActiveByName(nodeName);
|
||||
|
||||
expect(ndvStore.activeNodeName).toBe(nodeName);
|
||||
});
|
||||
});
|
||||
|
||||
describe('createConnection', () => {
|
||||
it('should not create a connection if source node does not exist', () => {
|
||||
const addConnectionSpy = vi
|
||||
|
||||
@@ -6,15 +6,22 @@ import { useHistoryStore } from '@/stores/history.store';
|
||||
import { useUIStore } from '@/stores/ui.store';
|
||||
import { useTelemetry } from '@/composables/useTelemetry';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
import { MoveNodeCommand, RemoveConnectionCommand, RemoveNodeCommand } from '@/models/history';
|
||||
import {
|
||||
MoveNodeCommand,
|
||||
RemoveConnectionCommand,
|
||||
RemoveNodeCommand,
|
||||
RenameNodeCommand,
|
||||
} from '@/models/history';
|
||||
import type { Connection } from '@vue-flow/core';
|
||||
import { mapCanvasConnectionToLegacyConnection } from '@/utils/canvasUtilsV2';
|
||||
import { getUniqueNodeName, mapCanvasConnectionToLegacyConnection } from '@/utils/canvasUtilsV2';
|
||||
import type { IConnection } from 'n8n-workflow';
|
||||
import { useNDVStore } from '@/stores/ndv.store';
|
||||
|
||||
export function useCanvasOperations() {
|
||||
const workflowsStore = useWorkflowsStore();
|
||||
const historyStore = useHistoryStore();
|
||||
const uiStore = useUIStore();
|
||||
const ndvStore = useNDVStore();
|
||||
|
||||
const telemetry = useTelemetry();
|
||||
const externalHooks = useExternalHooks();
|
||||
@@ -51,6 +58,45 @@ export function useCanvasOperations() {
|
||||
}
|
||||
}
|
||||
|
||||
async function renameNode(currentName: string, newName: string, { trackHistory = false } = {}) {
|
||||
if (currentName === newName) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (trackHistory) {
|
||||
historyStore.startRecordingUndo();
|
||||
}
|
||||
|
||||
newName = getUniqueNodeName(newName, workflowsStore.canvasNames);
|
||||
|
||||
// Rename the node and update the connections
|
||||
const workflow = workflowsStore.getCurrentWorkflow(true);
|
||||
workflow.renameNode(currentName, newName);
|
||||
|
||||
if (trackHistory) {
|
||||
historyStore.pushCommandToUndo(new RenameNodeCommand(currentName, newName));
|
||||
}
|
||||
|
||||
// Update also last selected node and execution data
|
||||
workflowsStore.renameNodeSelectedAndExecution({ old: currentName, new: newName });
|
||||
|
||||
workflowsStore.setNodes(Object.values(workflow.nodes));
|
||||
workflowsStore.setConnections(workflow.connectionsBySourceNode);
|
||||
|
||||
const isRenamingActiveNode = ndvStore.activeNodeName === currentName;
|
||||
if (isRenamingActiveNode) {
|
||||
ndvStore.activeNodeName = newName;
|
||||
}
|
||||
|
||||
if (trackHistory) {
|
||||
historyStore.stopRecordingUndo();
|
||||
}
|
||||
}
|
||||
|
||||
async function revertRenameNode(currentName: string, previousName: string) {
|
||||
await renameNode(currentName, previousName);
|
||||
}
|
||||
|
||||
function deleteNode(id: string, { trackHistory = false, trackBulk = true } = {}) {
|
||||
const node = workflowsStore.getNodeById(id);
|
||||
if (!node) {
|
||||
@@ -100,6 +146,19 @@ export function useCanvasOperations() {
|
||||
}
|
||||
}
|
||||
|
||||
function setNodeActive(id: string) {
|
||||
const node = workflowsStore.getNodeById(id);
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
ndvStore.activeNodeName = node.name;
|
||||
}
|
||||
|
||||
function setNodeActiveByName(name: string) {
|
||||
ndvStore.activeNodeName = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connection operations
|
||||
*/
|
||||
@@ -204,6 +263,10 @@ export function useCanvasOperations() {
|
||||
|
||||
return {
|
||||
updateNodePosition,
|
||||
setNodeActive,
|
||||
setNodeActiveByName,
|
||||
renameNode,
|
||||
revertRenameNode,
|
||||
deleteNode,
|
||||
revertDeleteNode,
|
||||
trackDeleteNode,
|
||||
|
||||
Reference in New Issue
Block a user