feat(editor): Add context menu to canvas v2 (no-changelog) (#10088)

This commit is contained in:
Elias Meire
2024-07-18 13:00:54 +02:00
committed by GitHub
parent 45affe5d89
commit 5b440a7679
16 changed files with 573 additions and 168 deletions

View File

@@ -24,6 +24,7 @@ import type {
IWorkflowDataUpdate,
IWorkflowDb,
IWorkflowTemplate,
NodeCreatorOpenSource,
ToggleNodeCreatorOptions,
XYPosition,
} from '@/Interface';
@@ -40,6 +41,7 @@ import {
NODE_CREATOR_OPEN_SOURCES,
PLACEHOLDER_EMPTY_WORKFLOW_ID,
START_NODE_TYPE,
STICKY_NODE_TYPE,
VIEWS,
} from '@/constants';
import { useSourceControlStore } from '@/stores/sourceControl.store';
@@ -80,6 +82,7 @@ import * as NodeViewUtils from '@/utils/nodeViewUtils';
import { tryToParseNumber } from '@/utils/typesUtils';
import { useTemplatesStore } from '@/stores/templates.store';
import { createEventBus } from 'n8n-design-system';
import type { PinDataSource } from '@/composables/usePinnedData';
const NodeCreation = defineAsyncComponent(
async () => await import('@/components/Node/NodeCreation.vue'),
@@ -133,9 +136,11 @@ const {
revertRenameNode,
setNodeActive,
setNodeSelected,
toggleNodeDisabled,
toggleNodesDisabled,
toggleNodesPinned,
setNodeParameters,
deleteNode,
deleteNodes,
revertDeleteNode,
addNodes,
createConnection,
@@ -438,6 +443,10 @@ function onDeleteNode(id: string) {
deleteNode(id, { trackHistory: true });
}
function onDeleteNodes(ids: string[]) {
deleteNodes(ids);
}
function onRevertDeleteNode({ node }: { node: INodeUi }) {
revertDeleteNode(node);
}
@@ -447,7 +456,15 @@ function onToggleNodeDisabled(id: string) {
return;
}
toggleNodeDisabled(id);
toggleNodesDisabled([id]);
}
function onToggleNodesDisabled(ids: string[]) {
if (!checkIfEditingIsAllowed()) {
return;
}
toggleNodesDisabled(ids);
}
function onSetNodeActive(id: string) {
@@ -458,12 +475,77 @@ function onSetNodeSelected(id?: string) {
setNodeSelected(id);
}
function onCopyNodes(_ids: string[]) {
// @TODO: implement this
}
function onCutNodes(_ids: string[]) {
// @TODO: implement this
}
function onDuplicateNodes(_ids: string[]) {
// @TODO: implement this
}
function onPinNodes(ids: string[], source: PinDataSource) {
if (!checkIfEditingIsAllowed()) {
return;
}
toggleNodesPinned(ids, source);
}
async function onSaveWorkflow() {
await workflowHelpers.saveCurrentWorkflow();
}
async function onCreateWorkflow() {
await router.push({ name: VIEWS.NEW_WORKFLOW });
}
function onRenameNode(parameterData: IUpdateInformation) {
if (parameterData.name === 'name' && parameterData.oldValue) {
void renameNode(parameterData.oldValue as string, parameterData.value as string);
}
}
async function onOpenRenameNodeModal(id: string) {
const currentName = workflowsStore.getNodeById(id)?.name ?? '';
try {
const promptResponsePromise = message.prompt(
i18n.baseText('nodeView.prompt.newName') + ':',
i18n.baseText('nodeView.prompt.renameNode') + `: ${currentName}`,
{
customClass: 'rename-prompt',
confirmButtonText: i18n.baseText('nodeView.prompt.rename'),
cancelButtonText: i18n.baseText('nodeView.prompt.cancel'),
inputErrorMessage: i18n.baseText('nodeView.prompt.invalidName'),
inputValue: currentName,
inputValidator: (value: string) => {
if (!value.trim()) {
return i18n.baseText('nodeView.prompt.invalidName');
}
return true;
},
},
);
// Wait till input is displayed
await nextTick();
// Focus and select input content
const nameInput = document.querySelector<HTMLInputElement>('.rename-prompt .el-input__inner');
nameInput?.focus();
nameInput?.select();
const promptResponse = await promptResponsePromise;
if (promptResponse.action === MODAL_CONFIRM) {
await renameNode(currentName, promptResponse.value, { trackHistory: true });
}
} catch (e) {}
}
async function onRevertRenameNode({
currentName,
newName,
@@ -626,10 +708,18 @@ async function onOpenSelectiveNodeCreator(node: string, connectionType: NodeConn
nodeCreatorStore.openSelectiveNodeCreator({ node, connectionType });
}
function onOpenNodeCreatorFromCanvas(source: NodeCreatorOpenSource) {
onOpenNodeCreator({ createNodeActive: true, source });
}
function onOpenNodeCreator(options: ToggleNodeCreatorOptions) {
nodeCreatorStore.openNodeCreator(options);
}
function onCreateSticky() {
void onAddNodesAndConnections({ nodes: [{ type: STICKY_NODE_TYPE }], connections: [] });
}
function onClickConnectionAdd(connection: Connection) {
nodeCreatorStore.openNodeCreatorForConnectingNode({
connection,
@@ -1156,6 +1246,7 @@ onBeforeUnmount(() => {
@update:node:active="onSetNodeActive"
@update:node:selected="onSetNodeSelected"
@update:node:enabled="onToggleNodeDisabled"
@update:node:name="onOpenRenameNodeModal"
@update:node:parameters="onUpdateNodeParameters"
@run:node="onRunWorkflowToNode"
@delete:node="onDeleteNode"
@@ -1164,6 +1255,17 @@ onBeforeUnmount(() => {
@delete:connection="onDeleteConnection"
@click:connection:add="onClickConnectionAdd"
@click:pane="onClickPane"
@create:node="onOpenNodeCreatorFromCanvas"
@create:sticky="onCreateSticky"
@delete:nodes="onDeleteNodes"
@update:nodes:enabled="onToggleNodesDisabled"
@update:nodes:pin="onPinNodes"
@duplicate:nodes="onDuplicateNodes"
@copy:nodes="onCopyNodes"
@cut:nodes="onCutNodes"
@run:workflow="onRunWorkflow"
@save:workflow="onSaveWorkflow"
@create:workflow="onCreateWorkflow"
>
<div :class="$style.executionButtons">
<CanvasRunWorkflowButton