n8n-editor-ui
Version:
Workflow Editor UI for n8n
2,303 lines • 105 kB
JavaScript
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/NodeCreation-B3OlpxPo.js","assets/_plugin-vue_export-helper-BwBpWJRZ.js","assets/src-DgvumQTi.js","assets/preload-helper-CR0ecmWK.js","assets/truncate-B1HVeveJ.js","assets/_MapCache-ficiegRb.js","assets/vue.runtime.esm-bundler-tP5dCd7J.js","assets/chunk-6z4oVpB-.js","assets/CalendarDate-zWqgZMlk.js","assets/sanitize-html-Cc45ZKm8.js","assets/empty-BuGRxzl4.js","assets/path-browserify-BtCDmZ3_.js","assets/en-CF30SCh2.js","assets/src-CMoPZtHv.css","assets/nodeCreator.store-FJrC_Pu6.js","assets/constants-BbpucWL4.js","assets/merge-k8vSyyXH.js","assets/builder.store-sBTWwxRU.js","assets/_baseOrderBy-B_6CV8x6.js","assets/dateformat-CM9k0--B.js","assets/useDebounce-Bnb8W2LR.js","assets/nodeIcon-DI2Acud1.js","assets/useRunWorkflow-BQJbxiOd.js","assets/useCanvasOperations-CAHezq7d.js","assets/usePinnedData-CL2qWhwp.js","assets/folders.store-BjAwtSH4.js","assets/executions.store-CXjGPxs0.js","assets/retry-dP46utx2.js","assets/uniqBy-BwIeMDu6.js","assets/sortByProperty-CV1aCzkS.js","assets/ProjectIcon-A2WPT9dM.js","assets/ProjectIcon-DT95ZcDW.css","assets/versions.store-BwdT833-.js","assets/assistant.store-bS9AHOoo.js","assets/KeyboardShortcutTooltip-B4E72qs1.js","assets/KeyboardShortcutTooltip-pRLqnHdh.css","assets/NodeIcon-BVhrZNYI.js","assets/NodeIcon-BDxr0f30.css","assets/useCommandBar-DX5Sf1tf.js","assets/usePageRedirectionHelper-fGNB6ZKK.js","assets/chat.store-BGFxJU_3.js","assets/fileUtils-D_SiS8no.js","assets/constants-DLTaaipl.js","assets/dataTable.store-B4A4ieSD.js","assets/CredentialIcon-FEnE25SA.js","assets/CredentialIcon-bZrcXcyJ.css","assets/useRecentResources-BAGmp8Wq.js","assets/useCommandBar-eK4Fv9lH.css","assets/chatPanel.store-4qGv1TCZ.js","assets/useActions-O8-gYbRP.js","assets/NodeCreation-CKa3G1zA.css","assets/NodeDetailsView-CtdFNdcE.js","assets/RunData-B4jIonVZ.js","assets/NDVEmptyState-CpUQ-969.js","assets/NDVEmptyState-Bho0_Ev8.css","assets/vue-json-pretty-DGKuDe33.js","assets/useClipboard-CyG-SBdG.js","assets/schemaPreview.store-BFprwUEe.js","assets/useExecutionHelpers-BhJEW8lu.js","assets/dateFormatter-DDfPHI9I.js","assets/externalSecrets.ee.store-D27nc9Y2.js","assets/RunDataHtml-CkjC7YuF.js","assets/RunDataHtml-Bu3RZcuV.css","assets/RunData-CGWkR8tE.css","assets/ParameterInputList-B4xJHjua.js","assets/exports-hpMZaOPT.js","assets/vue-Dg_43WEg.js","assets/date-picker-B6nJ4qMb.js","assets/dialog-D5O6wJX0.js","assets/VirtualSchema-D2LnRq9K.js","assets/Draggable-04Tfmp_H.js","assets/Draggable-DfBtatxg.css","assets/useTelemetryContext-5Wb7vBCv.js","assets/useTelemetryContext-BpnKRIT7.css","assets/nodeTransforms-Lk_uXh7p.js","assets/TextWithHighlights-DjzuDrgO.js","assets/TextWithHighlights-BgbTzzK2.css","assets/VirtualSchema-CwutU4vj.css","assets/VueMarkdown-D9lDzMKr.js","assets/ParameterInputList-C1BdtAjc.css","assets/NodeSettings-iHP6f-9G.js","assets/col-Cd5kWzv_.js","assets/CommunityNodeUpdateInfo-Cd_-b5Xu.js","assets/semver-CVsBQkSJ.js","assets/CommunityNodeUpdateInfo-kPDiipF5.css","assets/NodeSettings-BIOqhOCE.css","assets/core-BbiIkN91.js","assets/core-6W4wWNc1.js","assets/useLogsTreeExpand-WR32ACA6.js","assets/AnimatedSpinner-wiGFgffA.js","assets/AnimatedSpinner-CoP6Lyme.css","assets/useLogsTreeExpand-nZMKe2ps.css","assets/CopyInput-DKOPkUXT.js","assets/CopyInput-BiDmlr9B.css","assets/useExecutionData-4UjwITsD.js","assets/TriggerPanel-BJOFVjKr.js","assets/RunDataParsedAiContent-Dl9d2Tx7.js","assets/RunDataParsedAiContent-CvjNCtpG.css","assets/TriggerPanel-BjsM2DGf.css","assets/NodeDetailsView-Dy4A-9xj.css","assets/NodeDetailsViewV2-Bpi8Lz1W.js","assets/useKeybindings-CKeFso4-.js","assets/NodeDetailsViewV2-CgELKnqG.css","assets/SetupWorkflowCredentialsButton-BW4TsLh4.js"])))=>i.map(i=>d[i]);
import { C as computed, Cn as toDisplayString, D as createElementBlock, E as createCommentVNode, G as nextTick, Gt as unref, It as ref, J as onBeforeUnmount, K as onActivated, L as h, M as createVNode, N as defineAsyncComponent, P as defineComponent, T as createBlock, Vt as toRef, W as mergeProps, Y as onDeactivated, Z as onMounted, _ as Fragment, _t as watch, at as renderSlot, bn as normalizeStyle, bt as withCtx, c as useCssModule, et as openBlock, h as withModifiers, it as renderList, j as createTextVNode, mt as useTemplateRef, nt as provide, q as onBeforeMount, vn as normalizeClass, w as createBaseVNode, y as Suspense } from "./vue.runtime.esm-bundler-tP5dCd7J.js";
import { Q as refThrottled, _t as useI18n, at as useThrottleFn, b as useActiveElement } from "./_MapCache-ficiegRb.js";
import { C as N8nResizeWrapper_default, R as N8nInfoTip_default, Sn as N8nButton_default, T as N8nRadioButtons_default, bn as N8nCallout_default, c as N8nInlineTextEdit_default, ct as useDeviceSupport, st as N8nKeyboardShortcut_default, tt as CanvasThinkingPill_default, wn as N8nIcon_default, xn as N8nText_default, xt as N8nIconButton_default, yt as N8nInput_default } from "./src-DgvumQTi.js";
import "./en-CF30SCh2.js";
import { t as __vitePreload } from "./preload-helper-CR0ecmWK.js";
import { t as __plugin_vue_export_helper_default } from "./_plugin-vue_export-helper-BwBpWJRZ.js";
import { T as createEventBus, _ as onBeforeRouteLeave, v as useRoute, y as useRouter } from "./truncate-B1HVeveJ.js";
import "./date-picker-B6nJ4qMb.js";
import { $i as nodeViewEventBus, Dr as useUsersStore, Gn as useNodeHelpers, Kn as injectWorkflowState, M as useNDVStore, Mi as isValueExpression, N as useWorkflowsStore, Nt as useNodeTypesStore, O as useTelemetry, Vi as hasFocusOnInput, Vn as useTagsStore, W as getBounds, Wi as isFocusableEl, Wn as useEnvironmentsStore, Xn as useProjectsStore, Xr as useHistoryStore, Y as getNodeViewTab, Yn as useDocumentTitle, Yr as CanvasNodeRenderType, Z as getNodesWithNormalizedPosition, Zn as useSourceControlStore, b as useExternalHooks, ft as getRectOfNodes, gn as useCredentialsStore, gr as useCanvasStore, gs as useSettingsStore, gt as useVueFlow, h as useNpsSurveyStore, in as getSampleWorkflowByTemplateId, m as useMessage, n as useWorkflowSaving, oa as useUIStore, qn as useWorkflowState, r as useFocusPanelStore, si as historyBus, t as useBuilderStore, ta as htmlEditorEventBus, v as useToast } from "./builder.store-sBTWwxRU.js";
import { A as HtmlEditor_default, C as SqlEditor_default, O as CodeNodeEditor_default, _ as isValidParameterOption, a as ParameterOptions_default, g as getParameterTypeOption, k as JsEditor_default, l as CssEditor_default, m as formatAsExpression, s as useResolvedExpression, u as useNodeSettingsParameters, w as ExpressionEditorModalInput_default, y as parseFromExpression } from "./ParameterInputList-B4xJHjua.js";
import "./empty-BuGRxzl4.js";
import "./col-Cd5kWzv_.js";
import "./dialog-D5O6wJX0.js";
import "./sanitize-html-Cc45ZKm8.js";
import "./CalendarDate-zWqgZMlk.js";
import "./path-browserify-BtCDmZ3_.js";
import { $a as EVALUATION_NODE_TYPE, Da as jsonParse, Gn as PRODUCTION_ONLY_TRIGGER_NODE_TYPES, L as DRAG_EVENT_DATA_KEY, Lo as MAIN_HEADER_TABS, Oo as getResourcePermissions, Qi as getNodeOutputs, Ro as VIEWS, Ss as WORKFLOW_SETTINGS_MODAL_KEY, St as NODE_CREATOR_OPEN_SOURCES, Xo as FROM_AI_PARAMETERS_MODAL_KEY, Ya as AI_TRANSFORM_NODE_TYPE, Zi as getNodeInputs, bc as EnterpriseEditionFeature, ec as ExpressionLocalResolveContextSymbol, eo as EVALUATION_TRIGGER_NODE_TYPE, io as HTML_NODE_TYPE, j as VALID_WORKFLOW_IMPORT_URL_REGEX, rc as WorkflowStateKey, rs as MODAL_CONFIRM, sr as STICKY_NODE_TYPE, ua as isTriggerNode, va as isResourceLocatorValue, wn as MANUAL_CHAT_TRIGGER_NODE_TYPE, zo as ABOUT_MODAL_KEY, zt as CHAT_TRIGGER_NODE_TYPE } from "./constants-BbpucWL4.js";
import "./merge-k8vSyyXH.js";
import { r as useRootStore } from "./_baseOrderBy-B_6CV8x6.js";
import "./dateformat-CM9k0--B.js";
import "./useDebounce-Bnb8W2LR.js";
import "./assistant.store-bS9AHOoo.js";
import "./chatPanel.store-4qGv1TCZ.js";
import "./retry-dP46utx2.js";
import { t as useExecutionsStore } from "./executions.store-CXjGPxs0.js";
import { i as usePushConnectionStore, n as useAgentRequestStore, t as useRunWorkflow } from "./useRunWorkflow-BQJbxiOd.js";
import "./usePinnedData-CL2qWhwp.js";
import { t as useNodeCreatorStore, u as shouldIgnoreCanvasShortcut } from "./nodeCreator.store-FJrC_Pu6.js";
import "./nodeIcon-DI2Acud1.js";
import { a as useLogsStore, i as useExperimentalNdvStore, n as useParentFolder, r as canvasEventBus, t as useCanvasOperations } from "./useCanvasOperations-CAHezq7d.js";
import "./folders.store-BjAwtSH4.js";
import { t as NodeIcon_default } from "./NodeIcon-BVhrZNYI.js";
import { t as KeyboardShortcutTooltip_default } from "./KeyboardShortcutTooltip-B4E72qs1.js";
import { c as ExperimentalCanvasNodeSettings_default, d as CanvasRunWorkflowButton_default, l as useGlobalLinkActions, n as Canvas_default, o as useContextMenuItems, s as useExpressionResolveCtx, t as useCanvasMapping, u as useWorkflowExtraction } from "./useCanvasMapping-xYnYeFUG.js";
import "./versions.store-BwdT833-.js";
import "./usePageRedirectionHelper-fGNB6ZKK.js";
import "./dataTable.store-B4A4ieSD.js";
import { t as useClipboard } from "./useClipboard-CyG-SBdG.js";
import { s as JsonEditor_default } from "./RunData-B4jIonVZ.js";
import "./NDVEmptyState-CpUQ-969.js";
import "./exports-hpMZaOPT.js";
import { t as useExternalSecretsStore } from "./externalSecrets.ee.store-D27nc9Y2.js";
import "./uniqBy-BwIeMDu6.js";
import "./semver-CVsBQkSJ.js";
import "./CommunityNodeUpdateInfo-Cd_-b5Xu.js";
import "./RunDataHtml-CkjC7YuF.js";
import "./VueMarkdown-D9lDzMKr.js";
import "./Draggable-04Tfmp_H.js";
import { n as NodeExecuteButton_default } from "./VirtualSchema-D2LnRq9K.js";
import "./TextWithHighlights-DjzuDrgO.js";
import { t as useTelemetryContext } from "./useTelemetryContext-5Wb7vBCv.js";
import "./schemaPreview.store-BFprwUEe.js";
import { a as needsAgentInput } from "./nodeTransforms-Lk_uXh7p.js";
import "./vue-json-pretty-DGKuDe33.js";
import "./dateFormatter-DDfPHI9I.js";
import "./useExecutionHelpers-BhJEW8lu.js";
import "./NodeSettings-iHP6f-9G.js";
import "./useActions-O8-gYbRP.js";
import "./vue-Dg_43WEg.js";
import { t as sourceControlEventBus } from "./sourceControl.eventBus-Bry8gLG7.js";
import { t as useKeybindings } from "./useKeybindings-CKeFso4-.js";
import { t as useBeforeUnload } from "./useBeforeUnload-Dmmheunz.js";
import { t as useAITemplatesStarterCollectionStore } from "./aiTemplatesStarterCollection.store-DkHa_nSs.js";
import { t as useExecutionData } from "./useExecutionData-4UjwITsD.js";
import { t as useExecutionDebugging } from "./useExecutionDebugging-B73NIPYJ.js";
import { t as useReadyToRunWorkflowsStore } from "./readyToRunWorkflows.store-B6Onw3Wt.js";
var WorkflowCanvas_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
inheritAttrs: false,
__name: "WorkflowCanvas",
props: {
id: { default: "canvas" },
workflow: {},
workflowObject: {},
fallbackNodes: { default: () => [] },
showFallbackNodes: {
type: Boolean,
default: true
},
eventBus: { default: () => createEventBus() },
readOnly: { type: Boolean },
executing: { type: Boolean },
suppressInteraction: {
type: Boolean,
default: false
}
},
setup(__props, { expose: __expose }) {
const props = __props;
const canvasRef = useTemplateRef("canvas");
const $style = useCssModule();
const { onNodesInitialized, viewport, viewportRef, getNodes, fitBounds } = useVueFlow(props.id);
const workflow = toRef(props, "workflow");
const workflowObject = toRef(props, "workflowObject");
const { nodes: mappedNodes, connections: mappedConnections } = useCanvasMapping({
nodes: computed(() => {
return props.showFallbackNodes ? [...props.workflow.nodes, ...props.fallbackNodes] : props.workflow.nodes;
}),
connections: computed(() => props.workflow.connections),
workflowObject
});
const initialFitViewDone = ref(false);
const { off } = onNodesInitialized(() => {
if (!initialFitViewDone.value) {
props.eventBus.emit("fitView");
initialFitViewDone.value = true;
off();
}
});
const mappedNodesThrottled = refThrottled(mappedNodes, 200);
const mappedConnectionsThrottled = refThrottled(mappedConnections, 200);
__expose({
executeContextMenuAction: (action, nodeIds) => canvasRef.value?.executeContextMenuAction(action, nodeIds),
ensureNodesAreVisible: (ids) => {
const canvasElement = viewportRef.value;
if (!canvasElement) return;
const targetNodes = getNodes.value.filter((node) => ids.includes(node.id));
if (targetNodes.length === 0) return;
const insertionDone = onNodesInitialized(() => {
const vp = viewport.value;
const canvasWidth = canvasElement.clientWidth;
const canvasHeight = canvasElement.clientHeight;
const nodesRect = getRectOfNodes(targetNodes);
const screenX = nodesRect.x * vp.zoom + vp.x;
const screenY = nodesRect.y * vp.zoom + vp.y;
const screenWidth = nodesRect.width * vp.zoom;
const screenHeight = nodesRect.height * vp.zoom;
if (!(screenX >= 0 && screenY >= 0 && screenX + screenWidth <= canvasWidth && screenY + screenHeight <= canvasHeight)) {
const viewportRect = {
x: -vp.x / vp.zoom,
y: -vp.y / vp.zoom,
width: canvasWidth / vp.zoom,
height: canvasHeight / vp.zoom
};
const minX = Math.min(viewportRect.x, nodesRect.x);
const minY = Math.min(viewportRect.y, nodesRect.y);
const maxX = Math.max(viewportRect.x + viewportRect.width, nodesRect.x + nodesRect.width);
const maxY = Math.max(viewportRect.y + viewportRect.height, nodesRect.y + nodesRect.height);
fitBounds({
x: minX,
y: minY,
width: maxX - minX,
height: maxY - minY
}, {
padding: .15,
duration: 100
});
}
props.eventBus.emit("nodes:select", { ids });
insertionDone.off();
});
}
});
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", {
class: normalizeClass(unref($style).wrapper),
"data-test-id": "canvas-wrapper"
}, [createBaseVNode("div", {
id: "canvas",
class: normalizeClass(unref($style).canvas)
}, [workflow.value ? (openBlock(), createBlock(Canvas_default, mergeProps({
key: 0,
id: _ctx.id,
ref: "canvas",
nodes: _ctx.executing ? unref(mappedNodesThrottled) : unref(mappedNodes),
connections: _ctx.executing ? unref(mappedConnectionsThrottled) : unref(mappedConnections),
"event-bus": _ctx.eventBus,
"read-only": _ctx.readOnly,
executing: _ctx.executing,
"suppress-interaction": _ctx.suppressInteraction
}, _ctx.$attrs), null, 16, [
"id",
"nodes",
"connections",
"event-bus",
"read-only",
"executing",
"suppress-interaction"
])) : createCommentVNode("", true)], 2), renderSlot(_ctx.$slots, "default")], 2);
};
}
});
var WorkflowCanvas_vue_vue_type_style_index_0_lang_module_default = {
wrapper: "_wrapper_rs56d_123",
canvas: "_canvas_rs56d_131"
};
var WorkflowCanvas_default = /* @__PURE__ */ __plugin_vue_export_helper_default(WorkflowCanvas_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": WorkflowCanvas_vue_vue_type_style_index_0_lang_module_default }]]);
var ExperimentalNodeDetailsDrawer_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
__name: "ExperimentalNodeDetailsDrawer",
props: {
node: {},
nodeIds: {},
isReadOnly: { type: Boolean }
},
emits: ["openNdv", "contextMenuAction"],
setup(__props, { emit: __emit }) {
const emit = __emit;
const expressionResolveCtx = useExpressionResolveCtx(computed(() => __props.node));
const contextMenuItems = useContextMenuItems(computed(() => __props.nodeIds));
const ndvStore = useNDVStore();
const ndvCloseTimes = ref(0);
const nodeSettingsViewKey = computed(() => [__props.node.id, ndvCloseTimes.value].join("|"));
watch(() => ndvStore.activeNodeName, (name, oldName) => {
if (name === null && oldName !== null) ndvCloseTimes.value += 1;
});
provide(ExpressionLocalResolveContextSymbol, expressionResolveCtx);
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", { class: normalizeClass(_ctx.$style.component) }, [_ctx.nodeIds.length > 1 ? (openBlock(), createBlock(unref(N8nText_default), {
key: 0,
tag: "div",
color: "text-base",
class: normalizeClass(_ctx.$style.multipleNodes)
}, {
default: withCtx(() => [createBaseVNode("div", null, toDisplayString(_ctx.nodeIds.length) + " nodes selected", 1), createBaseVNode("ul", { class: normalizeClass(_ctx.$style.multipleNodesActions) }, [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(contextMenuItems), (action) => {
return openBlock(), createElementBlock("li", {
key: action.id,
class: normalizeClass(_ctx.$style.multipleNodesAction)
}, [createVNode(unref(N8nButton_default), {
type: "secondary",
disabled: action.disabled,
onClick: ($event) => emit("contextMenuAction", action.id, _ctx.nodeIds)
}, {
default: withCtx(() => [createTextVNode(toDisplayString(action.label) + " ", 1), action.shortcut ? (openBlock(), createBlock(unref(N8nKeyboardShortcut_default), mergeProps({
key: 0,
ref_for: true
}, action.shortcut), null, 16)) : createCommentVNode("", true)]),
_: 2
}, 1032, ["disabled", "onClick"])], 2);
}), 128))], 2)]),
_: 1
}, 8, ["class"])) : _ctx.node ? (openBlock(), createBlock(ExperimentalCanvasNodeSettings_default, {
key: nodeSettingsViewKey.value,
"node-id": _ctx.node.id,
"is-read-only": _ctx.isReadOnly
}, null, 8, ["node-id", "is-read-only"])) : createCommentVNode("", true)], 2);
};
}
});
var ExperimentalNodeDetailsDrawer_vue_vue_type_style_index_0_lang_module_default = {
component: "_component_17fl4_123",
multipleNodes: "_multipleNodes_17fl4_128",
multipleNodesActions: "_multipleNodesActions_17fl4_138",
multipleNodesAction: "_multipleNodesAction_17fl4_138"
};
var ExperimentalNodeDetailsDrawer_default = /* @__PURE__ */ __plugin_vue_export_helper_default(ExperimentalNodeDetailsDrawer_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": ExperimentalNodeDetailsDrawer_vue_vue_type_style_index_0_lang_module_default }]]);
var ExperimentalFocusPanelHeader_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
__name: "ExperimentalFocusPanelHeader",
props: {
node: {},
parameter: {},
isExecutable: { type: Boolean },
readOnly: { type: Boolean }
},
emits: [
"execute",
"openNdv",
"clearParameter",
"renameNode"
],
setup(__props, { emit: __emit }) {
const emit = __emit;
const nodeTypesStore = useNodeTypesStore();
const i18n = useI18n();
const nodeType = computed(() => nodeTypesStore.getNodeType(__props.node.type, __props.node.typeVersion));
return (_ctx, _cache) => {
return openBlock(), createBlock(unref(N8nText_default), {
tag: "header",
size: "small",
bold: "",
class: normalizeClass(_ctx.$style.component)
}, {
default: withCtx(() => [
createVNode(NodeIcon_default, {
"node-type": nodeType.value,
size: 16
}, null, 8, ["node-type"]),
createBaseVNode("div", { class: normalizeClass(_ctx.$style.breadcrumbs) }, [_ctx.parameter ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
createVNode(unref(N8nText_default), {
size: "small",
color: "text-base",
bold: ""
}, {
default: withCtx(() => [createTextVNode(toDisplayString(_ctx.node.name), 1)]),
_: 1
}),
createVNode(unref(N8nText_default), {
size: "small",
color: "text-light"
}, {
default: withCtx(() => _cache[4] || (_cache[4] = [createTextVNode("/")])),
_: 1
}),
createTextVNode(" " + toDisplayString(_ctx.parameter.displayName), 1)
], 64)) : (openBlock(), createBlock(unref(N8nInlineTextEdit_default), {
key: 1,
"model-value": _ctx.node.name,
"min-width": 0,
"max-width": 500,
placeholder: unref(i18n).baseText("ndv.title.rename.placeholder"),
"read-only": _ctx.readOnly,
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => emit("renameNode", $event))
}, null, 8, [
"model-value",
"placeholder",
"read-only"
]))], 2),
_ctx.parameter ? (openBlock(), createBlock(unref(N8nIconButton_default), {
key: 0,
icon: "x",
size: "small",
type: "tertiary",
text: "",
onClick: _cache[1] || (_cache[1] = ($event) => emit("clearParameter"))
})) : (openBlock(), createBlock(unref(N8nIconButton_default), {
key: 1,
icon: "expand",
size: "small",
type: "tertiary",
text: "",
onClick: _cache[2] || (_cache[2] = ($event) => emit("openNdv"))
})),
_ctx.isExecutable ? (openBlock(), createBlock(NodeExecuteButton_default, {
key: 2,
"data-test-id": "node-execute-button",
"node-name": _ctx.node.name,
tooltip: `Execute ${_ctx.node.name}`,
type: "secondary",
size: "small",
icon: "play",
square: true,
"hide-label": true,
"telemetry-source": "focus",
onExecute: _cache[3] || (_cache[3] = ($event) => emit("execute"))
}, null, 8, ["node-name", "tooltip"])) : createCommentVNode("", true)
]),
_: 1
}, 8, ["class"]);
};
}
});
var ExperimentalFocusPanelHeader_vue_vue_type_style_index_0_lang_module_default = {
component: "_component_hvb6m_123",
breadcrumbs: "_breadcrumbs_hvb6m_131"
};
var ExperimentalFocusPanelHeader_default = /* @__PURE__ */ __plugin_vue_export_helper_default(ExperimentalFocusPanelHeader_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": ExperimentalFocusPanelHeader_vue_vue_type_style_index_0_lang_module_default }]]);
var FocusPanel_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
name: "FocusPanel",
__name: "FocusPanel",
props: { isCanvasReadOnly: { type: Boolean } },
emits: [
"focus",
"saveKeyboardShortcut",
"contextMenuAction"
],
setup(__props, { emit: __emit }) {
const props = __props;
const emit = __emit;
const inputField = ref();
const wrapperRef = useTemplateRef("wrapper");
const locale = useI18n();
const nodeHelpers = useNodeHelpers();
const focusPanelStore = useFocusPanelStore();
const workflowsStore = useWorkflowsStore();
const workflowState = injectWorkflowState();
const nodeTypesStore = useNodeTypesStore();
const telemetry = useTelemetry();
const nodeSettingsParameters = useNodeSettingsParameters();
const environmentsStore = useEnvironmentsStore();
const experimentalNdvStore = useExperimentalNdvStore();
const ndvStore = useNDVStore();
const deviceSupport = useDeviceSupport();
const vueFlow = useVueFlow(workflowsStore.workflowId);
const activeElement = useActiveElement();
const { renameNode } = useCanvasOperations();
useTelemetryContext({ view_shown: "focus_panel" });
const resolvedParameter = computed(() => focusPanelStore.resolvedParameter);
const inputValue = ref("");
const focusPanelActive = computed(() => focusPanelStore.focusPanelActive);
const focusPanelWidth = computed(() => focusPanelStore.focusPanelWidth);
const isDisabled = computed(() => {
if (!resolvedParameter.value) return false;
return !!resolvedParameter.value.parameter.disabledOptions && nodeSettingsParameters.shouldDisplayNodeParameter(resolvedParameter.value.node.parameters, resolvedParameter.value.node, resolvedParameter.value.parameter, resolvedParameter.value.parameterPath.split(".").slice(1, -1).join("."), "disabledOptions");
});
const isDisplayed = computed(() => {
if (!resolvedParameter.value) return true;
return nodeSettingsParameters.shouldDisplayNodeParameter(resolvedParameter.value.node.parameters, resolvedParameter.value.node, resolvedParameter.value.parameter, resolvedParameter.value.parameterPath.split(".").slice(1, -1).join("."), "displayOptions");
});
const node = computed(() => {
if (!experimentalNdvStore.isNdvInFocusPanelEnabled || resolvedParameter.value) return resolvedParameter.value?.node;
const selected = vueFlow.getSelectedNodes.value[0];
return selected?.data?.render.type === CanvasNodeRenderType.Default ? workflowsStore.allNodes.find((n) => n.id === selected.id) : void 0;
});
const multipleNodesSelected = computed(() => vueFlow.getSelectedNodes.value.length > 1);
const isExecutable = computed(() => {
if (!node.value) return false;
if (!isDisplayed.value) return false;
const foreignCredentials = nodeHelpers.getForeignCredentialsIfSharingEnabled(node.value.credentials);
return nodeHelpers.isNodeExecutable(node.value, !props.isCanvasReadOnly, foreignCredentials);
});
const { workflowRunData } = useExecutionData({ node });
const hasNodeRun = computed(() => {
if (!node.value) return true;
const parentNode = workflowsStore.workflowObject.getParentNodes(node.value.name, "main", 1)[0];
return Boolean(parentNode && workflowRunData.value && Object.prototype.hasOwnProperty.bind(workflowRunData.value)(parentNode));
});
function getTypeOption(optionName) {
return resolvedParameter.value ? getParameterTypeOption(resolvedParameter.value.parameter, optionName) : void 0;
}
const codeEditorMode = computed(() => {
return resolvedParameter.value?.node.parameters.mode;
});
const editorType = computed(() => {
return getTypeOption("editor") ?? void 0;
});
const editorLanguage = computed(() => {
if (editorType.value === "json" || resolvedParameter.value?.parameter.type === "json") return "json";
return getTypeOption("editorLanguage") ?? "javaScript";
});
const editorRows = computed(() => getTypeOption("rows"));
const isToolNode = computed(() => resolvedParameter.value ? nodeTypesStore.isToolNode(resolvedParameter.value?.node.type) : false);
const isHtmlNode = computed(() => !!resolvedParameter.value && resolvedParameter.value.node.type === "n8n-nodes-base.html");
const expressionModeEnabled = computed(() => resolvedParameter.value && isValueExpression(resolvedParameter.value.parameter, resolvedParameter.value.value));
const expression = computed(() => {
if (!expressionModeEnabled.value) return "";
return isResourceLocatorValue(resolvedParameter.value) ? resolvedParameter.value.value : resolvedParameter.value;
});
const shouldCaptureForPosthog = computed(() => resolvedParameter.value?.node.type === AI_TRANSFORM_NODE_TYPE);
const isReadOnly = computed(() => props.isCanvasReadOnly || isDisabled.value);
const resolvedAdditionalExpressionData = computed(() => {
return { $vars: environmentsStore.variablesAsObject };
});
const targetNodeParameterContext = computed(() => {
if (!resolvedParameter.value) return void 0;
return {
nodeName: resolvedParameter.value.node.name,
parameterPath: resolvedParameter.value.parameterPath
};
});
const isNodeExecuting = computed(() => workflowState.executingNode.isNodeExecuting(node.value?.name ?? ""));
const selectedNodeIds = computed(() => vueFlow.getSelectedNodes.value.map((n) => n.id));
const emptyTitle = computed(() => experimentalNdvStore.isNdvInFocusPanelEnabled ? locale.baseText("nodeView.focusPanel.v2.noParameters.title") : locale.baseText("nodeView.focusPanel.noParameters.title"));
const emptySubtitle = computed(() => experimentalNdvStore.isNdvInFocusPanelEnabled ? locale.baseText("nodeView.focusPanel.v2.noParameters.subtitle") : locale.baseText("nodeView.focusPanel.noParameters.subtitle"));
const { resolvedExpression } = useResolvedExpression({
expression,
additionalData: resolvedAdditionalExpressionData,
stringifyObject: resolvedParameter.value && resolvedParameter.value.parameter.type !== "multiOptions"
});
function valueChanged(value) {
if (resolvedParameter.value === void 0) return;
nodeSettingsParameters.updateNodeParameter(toRef(resolvedParameter.value.node.parameters), {
value,
name: resolvedParameter.value.parameterPath
}, value, resolvedParameter.value.node, isToolNode.value);
}
async function setFocus() {
await nextTick();
if (inputField.value) {
if (hasFocusOnInput(inputField.value)) inputField.value.focusOnInput();
else if (isFocusableEl(inputField.value)) inputField.value.focus();
}
emit("focus");
}
function optionSelected(command) {
if (!resolvedParameter.value) return;
switch (command) {
case "resetValue":
if (typeof resolvedParameter.value.parameter.default === "string") valueChanged(resolvedParameter.value.parameter.default);
setFocus();
break;
case "addExpression": {
const newValue = formatAsExpression(resolvedParameter.value.value, resolvedParameter.value.parameter.type);
valueChanged(typeof newValue === "string" ? newValue : newValue.value);
setFocus();
break;
}
case "removeExpression": {
const newValue = parseFromExpression(resolvedParameter.value.value, resolvedExpression.value, resolvedParameter.value.parameter.type, resolvedParameter.value.parameter.default, (resolvedParameter.value.parameter.options ?? []).filter(isValidParameterOption));
if (typeof newValue === "string") valueChanged(newValue);
else if (newValue && typeof newValue.value === "string") valueChanged(newValue.value);
setFocus();
break;
}
case "formatHtml":
htmlEditorEventBus.emit("format-html");
break;
}
}
function closeFocusPanel() {
if (experimentalNdvStore.isNdvInFocusPanelEnabled && resolvedParameter.value) {
focusPanelStore.unsetParameters();
telemetry.track("User removed focused param", {
source: "closeIcon",
parameters: focusPanelStore.focusedNodeParametersInTelemetryFormat
});
return;
}
telemetry.track("User closed focus panel", {
source: "closeIcon",
parameters: focusPanelStore.focusedNodeParametersInTelemetryFormat
});
focusPanelStore.closeFocusPanel();
}
function onExecute() {
telemetry.track("User executed node from focus panel", focusPanelStore.focusedNodeParametersInTelemetryFormat[0]);
}
function onInputChange(val) {
inputValue.value = val;
valueChanged(val);
}
function focusWithDelay() {
setTimeout(() => {
setFocus();
}, 50);
}
function handleKeydown(event) {
if (event.key === "s" && deviceSupport.isCtrlKeyPressed(event)) {
event.stopPropagation();
event.preventDefault();
if (isReadOnly.value) return;
emit("saveKeyboardShortcut", event);
}
}
const registerKeyboardListener = () => {
document.addEventListener("keydown", handleKeydown, true);
};
const unregisterKeyboardListener = () => {
document.removeEventListener("keydown", handleKeydown, true);
};
watch([() => focusPanelStore.lastFocusTimestamp, () => expressionModeEnabled.value], () => focusWithDelay());
watch(() => focusPanelStore.focusPanelActive, (newValue) => {
if (newValue) registerKeyboardListener();
else unregisterKeyboardListener();
}, { immediate: true });
watch(() => resolvedParameter.value, (newValue) => {
if (newValue) {
const value = newValue.value;
if (typeof value === "string" && value !== inputValue.value) inputValue.value = value;
}
}, { immediate: true });
watch(activeElement, (active) => {
if (!node.value || !active || !wrapperRef.value?.contains(active)) return;
const path = active.closest(".parameter-input")?.getAttribute("data-parameter-path");
if (!path) return;
telemetry.track("User focused focus panel", {
node_id: node.value.id,
node_type: node.value.type,
parameter_path: path
});
});
function onResize(event) {
focusPanelStore.updateWidth(event.width);
}
const onResizeThrottle = useThrottleFn(onResize, 10);
function onOpenNdv() {
if (node.value) ndvStore.setActiveNodeName(node.value.name, "focus_panel");
}
function onRenameNode(value) {
if (node.value) renameNode(node.value.name, value);
}
return (_ctx, _cache) => {
return focusPanelActive.value ? (openBlock(), createElementBlock("div", {
key: 0,
ref: "wrapper",
"data-test-id": "focus-panel",
class: normalizeClass([
_ctx.$style.wrapper,
"ignore-key-press-canvas",
{ [_ctx.$style.isNdvInFocusPanelEnabled]: unref(experimentalNdvStore).isNdvInFocusPanelEnabled }
]),
onKeydown: _cache[10] || (_cache[10] = withModifiers(() => {}, ["stop"]))
}, [createVNode(unref(N8nResizeWrapper_default), {
width: focusPanelWidth.value,
"supported-directions": ["left"],
"min-width": 300,
"max-width": unref(experimentalNdvStore).isNdvInFocusPanelEnabled ? void 0 : 1e3,
"grid-size": 8,
style: normalizeStyle({ width: `${focusPanelWidth.value}px` }),
onResize: unref(onResizeThrottle)
}, {
default: withCtx(() => [createBaseVNode("div", { class: normalizeClass(_ctx.$style.container) }, [unref(experimentalNdvStore).isNdvInFocusPanelEnabled && node.value && !multipleNodesSelected.value ? (openBlock(), createBlock(ExperimentalFocusPanelHeader_default, {
key: 0,
node: node.value,
parameter: resolvedParameter.value?.parameter,
"is-executable": isExecutable.value,
"read-only": _ctx.isCanvasReadOnly,
onExecute,
onOpenNdv,
onClearParameter: closeFocusPanel,
onRenameNode
}, null, 8, [
"node",
"parameter",
"is-executable",
"read-only"
])) : createCommentVNode("", true), resolvedParameter.value ? (openBlock(), createElementBlock("div", {
key: 1,
class: normalizeClass(_ctx.$style.content),
"data-test-id": "focus-parameter"
}, [!unref(experimentalNdvStore).isNdvInFocusPanelEnabled ? (openBlock(), createElementBlock("div", {
key: 0,
class: normalizeClass(_ctx.$style.tabHeader)
}, [createBaseVNode("div", { class: normalizeClass(_ctx.$style.tabHeaderText) }, [createVNode(unref(N8nText_default), {
color: "text-dark",
size: "small"
}, {
default: withCtx(() => [createTextVNode(toDisplayString(resolvedParameter.value.parameter.displayName), 1)]),
_: 1
}), createVNode(unref(N8nText_default), {
color: "text-base",
size: "xsmall"
}, {
default: withCtx(() => [createTextVNode(toDisplayString(resolvedParameter.value.node.name), 1)]),
_: 1
})], 2), createBaseVNode("div", { class: normalizeClass(_ctx.$style.buttonWrapper) }, [createVNode(NodeExecuteButton_default, {
"data-test-id": "node-execute-button",
"node-name": resolvedParameter.value.node.name,
tooltip: `Execute ${resolvedParameter.value.node.name}`,
disabled: !isExecutable.value,
size: "small",
icon: "play",
square: true,
"hide-label": true,
"telemetry-source": "focus",
onExecute
}, null, 8, [
"node-name",
"tooltip",
"disabled"
]), createVNode(unref(N8nIcon_default), {
class: normalizeClass(_ctx.$style.closeButton),
icon: "x",
color: "text-base",
size: "xlarge",
onClick: closeFocusPanel
}, null, 8, ["class"])], 2)], 2)) : createCommentVNode("", true), createBaseVNode("div", { class: normalizeClass(_ctx.$style.parameterDetailsWrapper) }, [createBaseVNode("div", { class: normalizeClass(_ctx.$style.parameterOptionsWrapper) }, [createBaseVNode("div", { class: normalizeClass(_ctx.$style.noExecutionDataTip) }, [!hasNodeRun.value && !isNodeExecuting.value ? (openBlock(), createBlock(unref(N8nInfoTip_default), {
key: 0,
class: normalizeClass(_ctx.$style.delayedShow),
bold: true
}, {
default: withCtx(() => [createTextVNode(toDisplayString(unref(locale).baseText("nodeView.focusPanel.noExecutionData")), 1)]),
_: 1
}, 8, ["class"])) : createCommentVNode("", true)], 2), isDisplayed.value ? (openBlock(), createBlock(ParameterOptions_default, {
key: 0,
parameter: resolvedParameter.value.parameter,
value: resolvedParameter.value.value,
"is-read-only": isReadOnly.value,
"onUpdate:modelValue": optionSelected
}, null, 8, [
"parameter",
"value",
"is-read-only"
])) : createCommentVNode("", true)], 2), typeof resolvedParameter.value.value === "string" ? (openBlock(), createElementBlock("div", {
key: 0,
class: normalizeClass(_ctx.$style.editorContainer)
}, [!isDisplayed.value ? (openBlock(), createElementBlock("div", {
key: 0,
class: normalizeClass([_ctx.$style.content, _ctx.$style.emptyContent])
}, [createBaseVNode("div", { class: normalizeClass(_ctx.$style.emptyText) }, [createVNode(unref(N8nText_default), { color: "text-base" }, {
default: withCtx(() => [createTextVNode(toDisplayString(unref(locale).baseText("nodeView.focusPanel.missingParameter")), 1)]),
_: 1
})], 2)], 2)) : expressionModeEnabled.value ? (openBlock(), createBlock(ExpressionEditorModalInput_default, {
key: 1,
ref_key: "inputField",
ref: inputField,
modelValue: inputValue.value,
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => inputValue.value = $event),
class: normalizeClass(_ctx.$style.editor),
"is-read-only": isReadOnly.value,
path: resolvedParameter.value.parameterPath,
"data-test-id": "expression-modal-input",
"target-node-parameter-context": targetNodeParameterContext.value,
onChange: _cache[1] || (_cache[1] = ($event) => onInputChange($event.value))
}, null, 8, [
"modelValue",
"class",
"is-read-only",
"path",
"target-node-parameter-context"
])) : ["json", "string"].includes(resolvedParameter.value.parameter.type) ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [editorType.value === "codeNodeEditor" ? (openBlock(), createBlock(CodeNodeEditor_default, {
key: 0,
id: resolvedParameter.value.parameterPath,
ref_key: "inputField",
ref: inputField,
modelValue: inputValue.value,
"onUpdate:modelValue": [_cache[2] || (_cache[2] = ($event) => inputValue.value = $event), onInputChange],
class: normalizeClass(_ctx.$style.heightFull),
mode: codeEditorMode.value,
"default-value": resolvedParameter.value.parameter.default,
language: editorLanguage.value,
"is-read-only": isReadOnly.value,
"target-node-parameter-context": targetNodeParameterContext.value,
"fill-parent": "",
"disable-ask-ai": true
}, null, 8, [
"id",
"modelValue",
"class",
"mode",
"default-value",
"language",
"is-read-only",
"target-node-parameter-context"
])) : editorType.value === "htmlEditor" ? (openBlock(), createBlock(HtmlEditor_default, {
key: 1,
ref_key: "inputField",
ref: inputField,
modelValue: inputValue.value,
"onUpdate:modelValue": [_cache[3] || (_cache[3] = ($event) => inputValue.value = $event), onInputChange],
"is-read-only": isReadOnly.value,
rows: editorRows.value,
"disable-expression-coloring": !isHtmlNode.value,
"disable-expression-completions": !isHtmlNode.value,
fullscreen: "",
"target-node-parameter-context": targetNodeParameterContext.value
}, null, 8, [
"modelValue",
"is-read-only",
"rows",
"disable-expression-coloring",
"disable-expression-completions",
"target-node-parameter-context"
])) : editorType.value === "cssEditor" ? (openBlock(), createBlock(CssEditor_default, {
key: 2,
ref_key: "inputField",
ref: inputField,
modelValue: inputValue.value,
"onUpdate:modelValue": [_cache[4] || (_cache[4] = ($event) => inputValue.value = $event), onInputChange],
"is-read-only": isReadOnly.value,
rows: editorRows.value,
fullscreen: "",
"target-node-parameter-context": targetNodeParameterContext.value
}, null, 8, [
"modelValue",
"is-read-only",
"rows",
"target-node-parameter-context"
])) : editorType.value === "sqlEditor" ? (openBlock(), createBlock(SqlEditor_default, {
key: 3,
ref_key: "inputField",
ref: inputField,
modelValue: inputValue.value,
"onUpdate:modelValue": [_cache[5] || (_cache[5] = ($event) => inputValue.value = $event), onInputChange],
dialect: getTypeOption("sqlDialect"),
"is-read-only": isReadOnly.value,
rows: editorRows.value,
fullscreen: "",
"target-node-parameter-context": targetNodeParameterContext.value
}, null, 8, [
"modelValue",
"dialect",
"is-read-only",
"rows",
"target-node-parameter-context"
])) : editorType.value === "jsEditor" ? (openBlock(), createBlock(JsEditor_default, {
key: 4,
ref_key: "inputField",
ref: inputField,
modelValue: inputValue.value,
"onUpdate:modelValue": [_cache[6] || (_cache[6] = ($event) => inputValue.value = $event), onInputChange],
"is-read-only": isReadOnly.value,
rows: editorRows.value,
"posthog-capture": shouldCaptureForPosthog.value,
"fill-parent": ""
}, null, 8, [
"modelValue",
"is-read-only",
"rows",
"posthog-capture"
])) : resolvedParameter.value.parameter.type === "json" ? (openBlock(), createBlock(JsonEditor_default, {
key: 5,
ref_key: "inputField",
ref: inputField,
modelValue: inputValue.value,
"onUpdate:modelValue": [_cache[7] || (_cache[7] = ($event) => inputValue.value = $event), onInputChange],
"is-read-only": isReadOnly.value,
rows: editorRows.value,
fullscreen: "",
"fill-parent": ""
}, null, 8, [
"modelValue",
"is-read-only",
"rows"
])) : (openBlock(), createBlock(unref(N8nInput_default), {
key: 6,
ref_key: "inputField",
ref: inputField,
modelValue: inputValue.value,
"onUpdate:modelValue": [_cache[8] || (_cache[8] = ($event) => inputValue.value = $event), onInputChange],
class: normalizeClass(_ctx.$style.editor),
readonly: isReadOnly.value,
type: "textarea",
resize: "none"
}, null, 8, [
"modelValue",
"class",
"readonly"
]))], 64)) : createCommentVNode("", true)], 2)) : createCommentVNode("", true)], 2)], 2)) : node.value && unref(experimentalNdvStore).isNdvInFocusPanelEnabled ? (openBlock(), createBlock(ExperimentalNodeDetailsDrawer_default, {
key: 2,
node: node.value,
"node-ids": selectedNodeIds.value,
"is-read-only": isReadOnly.value,
onOpenNdv,
onContextMenuAction: _cache[9] || (_cache[9] = (action, nodeIds) => emit("contextMenuAction", action, nodeIds))
}, null, 8, [
"node",
"node-ids",
"is-read-only"
])) : (openBlock(), createElementBlock("div", {
key: 3,
class: normalizeClass([_ctx.$style.content, _ctx.$style.emptyContent])
}, [createBaseVNode("div", { class: normalizeClass(_ctx.$style.focusParameterWrapper) }, [
createBaseVNode("div", { class: normalizeClass(_ctx.$style.iconWrapper) }, [createVNode(unref(N8nIcon_default), {
class: normalizeClass(_ctx.$style.forceHover),
icon: "panel-right",
size: "medium"
}, null, 8, ["class"]), createVNode(unref(N8nIcon_default), {
class: normalizeClass(_ctx.$style.pointerIcon),
icon: "mouse-pointer",
color: "text-dark",
size: "large"
}, null, 8, ["class"])], 2),
createVNode(unref(N8nIcon_default), {
icon: "ellipsis-vertical",
size: "small",
color: "text-base"
}),
createVNode(unref(N8nRadioButtons_default), {
size: "small",
"model-value": "expression",
disabled: true,
options: [{
label: unref(locale).baseText("parameterInput.fixed"),
value: "fixed"
}, {
label: unref(locale).baseText("parameterInput.expression"),
value: "expression"
}]
}, null, 8, ["options"])
], 2), createBaseVNode("div", { class: normalizeClass(_ctx.$style.emptyText) }, [createVNode(unref(N8nText_default), {
color: "text-base",
size: "medium",
bold: true
}, {
default: withCtx(() => [createTextVNode(toDisplayString(emptyTitle.value), 1)]),
_: 1
}), createVNode(unref(N8nText_default), {
color: "text-base",
size: "small"
}, {
default: withCtx(() => [createTextVNode(toDisplayString(emptySubtitle.value), 1)]),
_: 1
})], 2)], 2))], 2)]),
_: 1
}, 8, [
"width",
"max-width",
"style",
"onResize"
])], 34)) : createCommentVNode("", true);
};
}
});
var FocusPanel_vue_vue_type_style_index_0_lang_module_default = {
wrapper: "_wrapper_1aqcs_123",
container: "_container_1aqcs_135",
content: "_content_1aqcs_141",
emptyContent: "_emptyContent_1aqcs_147",
isNdvInFocusPanelEnabled: "_isNdvInFocusPanelEnabled_1aqcs_152",
emptyText: "_emptyText_1aqcs_155",
focusParameterWrapper: "_focusParameterWrapper_1aqcs_161",
iconWrapper: "_iconWrapper_1aqcs_168",
pointerIcon: "_pointerIcon_1aqcs_172",
tabHeader: "_tabHeader_1aqcs_182",
tabHeaderText: "_tabHeaderText_1aqcs_189",
buttonWrapper: "_buttonWrapper_1aqcs_194",
parameterDetailsWrapper: "_parameterDetailsWrapper_1aqcs_199",
parameterOptionsWrapper: "_parameterOptionsWrapper_1aqcs_206",
noExecutionDataTip: "_noExecutionDataTip_1aqcs_210",
editorContainer: "_editorContainer_1aqcs_213",
editor: "_editor_1aqcs_213",
delayedShow: "_delayedShow_1aqcs_228",
triggerShow: "_triggerShow_1aqcs_1",
closeButton: "_closeButton_1aqcs_239",
heightFull: "_heightFull_1aqcs_243",
forceHover: "_forceHover_1aqcs_247"
};
var FocusPanel_default = /* @__PURE__ */ __plugin_vue_export_helper_default(FocusPanel_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": FocusPanel_vue_vue_type_style_index_0_lang_module_default }]]);
var CanvasStopCurrentExecutionButton_default = /* @__PURE__ */ defineComponent({
__name: "CanvasStopCurrentExecutionButton",
props: { stopping: { type: Boolean } },
setup(__props) {
const props = __props;
const i18n = useI18n();
const title = computed(() => props.stopping ? i18n.baseText("nodeView.stoppingCurrentExecution") : i18n.baseText("nodeView.stopCurrentExecution"));
return (_ctx, _cache) => {
return openBlock(), createBlock(unref(N8nIconButton_default), {
icon: "square",
size: "large",
class: "stop-execution",
type: "secondary",
title: title.value,
loading: _ctx.stopping,
"data-test-id": "stop-execution-button"
}, null, 8, ["title", "loading"]);
};
}
});
var CanvasStopWaitingForWebhookButton_default = /* @__PURE__ */ defineComponent({
__name: "CanvasStopWaitingForWebhookButton",
setup(__props) {
const i18n = useI18n();
return (_ctx, _cache) => {
return openBlock(), createBlock(unref(N8nIconButton_default), {
class: "stop-execution",
icon: "square",
size: "large",
title: unref(i18n).baseText("nodeView.stopWaitingForWebhookCall"),
type: "secondary",
"data-test-id": "stop-execution-waiting-for-webhook-button"
}, null, 8, ["title"]);
};
}
});
var _hoisted_1 = { "data-action": "reload" };
var _hoisted_2 = {
href: "https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.wait/",
target: "_blank"
};
var NodeViewUnfinishedWorkflowMessage_default = /* @__PURE__ */ defineComponent({
__name: "NodeViewUnfinishedWorkflowMessage",
setup(__props) {
const i18 = useI18n();
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", null, [
createBaseVNode("a", _hoisted_1, toDisplayString(unref(i18).baseText("nodeView.refresh")), 1),
createTextVNode(" " + toDisplayString(unref(i18).baseText("nodeView.toSeeTheLatestStatus")) + ". ", 1),
_cache[0] || (_cache[0] = createBaseVNode("br", null, null, -1)),
createBaseVNode("a", _hoisted_2, toDisplayString(unref(i18).baseText("nodeView.moreInfo")), 1)
]);
};
}
});
var CanvasChatButton_default = /* @__PURE__ */ defineComponent({
__name: "CanvasChatButton",
props: {
label: {},
type: {}
},
setup(__props) {
return (_ctx, _cache) => {
return openBlock(), createBlock(unref(N8nButton_default), {
label: _ctx.label,
size: "large",
icon: "message-circle",
type: _ctx.type,
"data-test-id": "workflow-chat-button"
}, null, 8, ["label", "type"]);
};
}
});
var NodeView_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
name: "NodeView",
__name: "NodeView",
setup(__props) {
const LazyNodeCreation = defineAsyncComponent(async () => await __vitePreload(() => import("./NodeCreation-B3OlpxPo.js"), __vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50])));
const LazyNodeDetailsView = defineAsyncComponent(async () => await __vitePreload(() => import("./NodeDetailsView-CtdFNdcE.js"), __vite__mapDeps([51,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,52,22,23,24,25,26,27,28,53,54,55,33,56,57,48,58,59,60,61,62,63,64,65,66,67,68,69,70,71,36,37,72,73,74,75,76,77,78,79,80,81,43,82,83,84,49,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99])));
const LazyNodeDetailsViewV2 = defineAsyncComponent(async () => await __vitePreload(() => import("./NodeDetailsViewV2-Bpi8Lz1W.js"), __vite__mapDeps([100,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,52,22,23,24,25,26,27,28,53,54,55,33,56,57,48,58,59,60,61,62,63,64,65,66,67,68,69,70,71,36,37,72,73,74,75,76,77,78,79,80,81,43,82,83,84,49,85,86,87,88,89,90,91,92,93,101,94,95,96,97,98,102])));
const LazySetupWorkflowCredentialsButton = defineAsyncComponent(async () => await __vitePreload(() => import("./SetupWorkflowCredentialsButton-BW4TsLh4.js"), __vite__mapDeps([103,1,2,3,4,5,6,7,8,9,10,11,12,13,15,16,17,18,19,20,74])));
const $style = useCssModule();
const router = useRouter();
const route = useRoute();
const i18n = useI18n();
const telemetry = useTelemetry();
const externalHooks = useExternalHooks();
const toast = useToast();
const message = useMessage();
const documentTitle = useDocumentTitle();
const workflowSaving = useWorkflowSaving({ router });
const nodeHelpers = useNodeHelpers();
const clipboard = useClipboard({ onPaste: onClipboardPaste });
const nodeTypesStore = useNodeTypesStore();
const uiStore = useUIStore();
const workflowsStore = useWorkflowsStore();
const sourceControlStore = useSourceControlStore();
const nodeCreatorStore = useNodeCreatorStore();
const settingsStore = useSettingsStore();
const credentialsStore = useCredentialsStore();
const environmentsStore = useEnvironmentsStore();
const externalSecretsStore = useExternalSecretsStore();
const rootStore = useRootStore();
const executionsStore = useExecutionsStore();
const canvasStore = useCanvasStore();
const npsSurveyStore = useNpsSurveyStore();
const historyStore = useHistoryStore();
const projectsStore = useProjectsStore();
const usersStore = useUsersStore();
const tagsStore = useTagsStore();
const pushConnectionStore = usePushConnectionStore();
const ndvStore = useNDVStore();
const focusPanelStore = useFocusPanelStore();
const builderStore = useBuilderStore();
const agentRequestStore = useAgentRequestStore();
const logsStore = useLogsStore();
const aiTemplatesStarterCollectionStore = useAITemplatesStarterCollectionStore();
const readyToRunWorkflowsStore = useReadyToRunWorkflowsStore();
const experimentalNdvStore = useExperimentalNdvStore();
const workflowState = useWorkflowState();
provide(WorkflowStateKey, workflowState);
const { addBeforeUnloadEventBindings, removeBeforeUnloadEventBindings } = useBeforeUnload({ route });
const { registerCustomAction, unregisterCustomAction } = useGlobalLinkActions();
const { runWorkflow, runEntireWorkflow, stopCurrentExecution, stopWaitingForWebhook } = useRunWorkflow({ router });
const { updateNodePosition, updateNodesPosition, tidyUp, revertUpdateNodePosition, renameNode, revertRenameNode, revertReplaceNodeParameters, setNodeActive, setNodeSelected, toggleNodesDisabled, revertToggleNodeDisabled, toggleNodesPinned, setNodeParameters, deleteNode, deleteNodes, copyNodes, cutNodes, duplicateNodes, revertDeleteNode, revertAddNode, createConnection, revertCreateConnection, deleteConnection, revertDeleteConnection, revalidateNodeInputConnections, revalidateNodeOutputConnections, setNodeActiveByName, clearNodeActive, tryToOpenSubworkflowInNewTab, importWorkflowData, fetchWorkflowDataFromUrl, resetWorkspace, initializeWorkspace, openExecution, editableWorkflow, editableWorkflowObject, lastClickPosition, startChat, addNodesAndConnections, fitView, openWorkflowTemplate, openWorkflowTemplateFromJSON } = useCanvasOperations();
const { extractWorkflow } = useWorkflowExtraction();
const { applyExecutionData } = useExecutionDebugging();
const { fetchAndSetParentFolder } = useParentFolder();
useKeybindings({ ctrl_alt_o: () => uiStore.openModal(ABOUT_MODAL_KEY) });
const canvasRef = useTemplateRef("canvas");
const isLoading = ref(true);
const readOnlyNotification = ref(null);
const isProductionExecutionPreview = ref(false);
const isExecutionPreview = ref(false);
const canOpenNDV = ref(true);
const hideNodeIssues = ref(false);
const fallbackNodes = ref([]);
const initializedWorkflowId = ref();
const workflowId = computed(() => {
const name = route.params.name;
return Array.isArray(name) ? name[0] : name;
});
const routeNodeId = computed(() => {
const nodeId = route.params.nodeId;
return Array.isArray(nodeId) ? nodeId[0] : nodeId;
});
const isNewWorkflowRoute = computed(() => {
return route.query.new === "true";
});
const isWorkflowRoute = computed(() => !!route?.meta?.nodeView || isDemoRoute.value);
const isDemoRoute = computed(() => route.name === VIEWS.DEMO);
const isReadOnlyRoute = computed(() => !!route?.meta?.readOnlyCanvas);
const isReadOnlyEnvironment = computed(() => {
return sourceControlStore.preferences.branchReadOnly;
});
const isNDVV2 = computed(() => true);
const isCanvasReadOnly = computed(() => {
return isDemoRoute.value || isReadOnlyEnvironment.value || !(workflowPermissions.value.update ?? projectPermissions.value.workflow.update) || editableWorkflow.value.isArchived || builderStore.streaming;
});
const showFallbackNodes = computed(() => triggerNodes.value.length === 0);
const keyBindingsEnabled = computed(() => {
return !ndvStore.activeNode && uiStore.activeModals.length === 0;
});
const isLogsPanelOpen = computed(() => logsStore.isOpen);
async function initializeData() {
const loadPromises = (() => {
if (settingsStore.isPreviewMode && isDemoRoute.value) return [];
const promises = [
workflowsStore.fetchActiveWorkflows(),
credentialsStore.fetchCredentialTypes(true),
loadCredentials()
];
if (settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Variables]) promises.push(environmentsStore.fetchAllVariables());
if (settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.ExternalSecrets]) promises.push(externalSecretsStore.fetchAllSecrets());
return promises;
})();
if (nodeTypesStore.allNodeTypes.length === 0) loadPromises.push(nodeTypesStore.getNodeTypes());
try {
await Promise.all(loadPromises);
nodeTypesStore.fetchCommunityNodePreviews();
} catch (error) {
toast.showError(error, i18n.baseText("nodeView.showError.mounted1.title"), i18n.baseText("nodeView.showError.mounted1.message") + ":");
return;
}
}
async function initializeRoute(force = false) {
if (route.query.action === "addEvaluationTrigger") nodeCreatorStore.openNodeCreatorForTriggerNodes(NODE_CREATOR_OPEN_SOURCES.ADD_EVALUATION_TRIGGER_BUTTON);
else if (route.query.action === "addEvaluationNode") nodeCreatorStore.openNodeCreatorForActions(EVALUATION_NODE_TYPE, NODE_CREATOR_OPEN_SOURCES.ADD_EVALUATION_NODE_BUTTON);
else if (route.query.action === "executeEvaluation") {
if (evaluationTriggerNode.value) runEntireWorkflow("node", evaluationTriggerNode.value.name);
}
const isAlreadyInitialized = !force && initializedWorkflowId.value && initializedWorkflowId.value === workflowId.value;
if (uiStore.isBlankRedirect) uiStore.isBlankRedirect = false;
else if (route.name === VIEWS.TEMPLATE_IMPORT) {
const loadWorkflowFromJSON = route.query.fromJson === "true";
const templateId = route.params.id;
if (!templateId) return;
if (loadWorkflowFromJSON) {
const workflow = getSampleWorkflowByTemplateId(templateId.toString());
if (!workflow) {
toast.showError(new Error(i18n.baseText("nodeView.couldntLoadWorkflow.invalidWorkflowObject")), i18n.baseText("nodeView.couldntImportWorkflow"));
await router.replace({ name: VIEWS.NEW_WORKFLOW });
return;
}
await openWorkflowTemplateFromJSON(workflow);
} else await openWorkflowTemplate(templateId.toString());
} else if (isWorkflowRoute.value) {
if (!isAlreadyInitialized) {
historyStore.reset();
if (isDemoRoute.value) return await initializeWorkspaceForNewWorkflow();
if (isNewWorkflowRoute.value) if (!await workflowsStore.checkWorkflowExists(workflowId.value) && route.meta?.nodeView === true) return await initializeWorkspaceForNewWorkflow();
else await router.replace({
...route,
query: {
...route.query,
new: void 0
}
});
await initializeWorkspaceForExistingWorkflow(workflowId.value);
nextTick(() => {
updateNodesIssues();
});
}
if (route.name === VIEWS.EXECUTION_DEBUG) await initializeDebugMode();
}
}
async function initializeWorkspaceForNewWorkflow() {
resetWorkspace();
const parentFolderId = route.query.parentFolderId;
await workflowState.getNewWorkflowDataAndMakeShareable(void 0, projectsStore.currentProjectId, parentFolderId);
workflowState.setWorkflowId(workflowId.value);
await projectsStore.refreshCurrentProject();
await fetchAndSetParentFolder(parentFolderId);
uiStore.nodeViewInitialized = true;
initializedWorkflowId.value = workflowId.value;
fitView();
}
async function initializeWorkspaceForExistingWorkflow(id) {
try {
const workflowData = await workflowsStore.fetchWorkflow(id);
await openWorkflow(workflowData);
if (workflowData.parentFolder) workflowsStore.setParentFolder(workflowData.parentFolder);
if (workflowData.meta?.onboardingId) trackOpenWorkflowFromOnboardingTemplate();
if (workflowData.meta?.templateId?.startsWith("035_template_onboarding")) aiTemplatesStarterCollectionStore.trackUserOpenedWorkflow(workflowData.meta.templateId.split("-").pop() ?? "");
if (workflowData.meta?.templateId?.startsWith("37_onboarding_experiments_batch_aug11")) readyToRunWorkflowsStore.trackOpenWorkflow(workflowData.meta.templateId.split("-").pop() ?? "");
await projectsStore.setProjectNavActiveIdByWorkflowHomeProject(workflowData.homeProject, workflowData.sharedWithProjects);
workflowsStore.fetchLastSuccessfulExecution();
} catch (error) {
if (error.httpStatusCode === 404) return await router.replace({
name: VIEWS.ENTITY_NOT_FOUND,
params: { entityType: "workflow" }
});
if (error.httpStatusCode === 403) return await router.replace({
name: VIEWS.ENTITY_UNAUTHORIZED,
params: { entityType: "workflow" }
});
toast.showError(error, i18n.baseText("openWorkflow.workflowNotFoundError"));
router.push({ name: VIEWS.NEW_WORKFLOW });
} finally {
uiStore.nodeViewInitialized = true;
initializedWorkflowId.value = workflowId.value;
}
}
function updateNodesIssues() {
nodeHelpers.updateNodesInputIssues();
nodeHelpers.updateNodesCredentialsIssues();
nodeHelpers.updateNodesParameterIssues();
}
async function openWorkflow(data) {
resetWorkspace();
documentTitle.setDocumentTitle(data.name, "IDLE");
await initializeWorkspace(data);
externalHooks.run("workflow.open", {
workflowId: data.id,
workflowName: data.name
});
fitView();
}
function trackOpenWorkflowFromOnboardingTemplate() {
telemetry.track(`User opened workflow from onboarding template with ID ${editableWorkflow.value.meta?.onboardingId}`, { workflow_id: workflowId.value });
}
const triggerNodes = computed(() => {
return editableWorkflow.value.nodes.filter((node) => nodeTypesStore.isTriggerNode(node.type));
});
const containsTriggerNodes = computed(() => triggerNodes.value.length > 0);
const allTriggerNodesDisabled = computed(() => {
return triggerNodes.value.filter((node) => node.disabled).length === triggerNodes.value.length;
});
function onTidyUp(event, options) {
tidyUp(event, options);
}
function onExtractWorkflow(nodeIds) {
extractWorkflow(nodeIds);
}
function onUpdateNodesPosition(events) {
updateNodesPosition(events, { trackHistory: true });
}
function onUpdateNodePosition(id, position) {
updateNodePosition(id, position, { trackHistory: true });
}
function onRevertNodePosition({ nodeName, position }) {
revertUpdateNodePosition(nodeName, {
x: position[0],
y: position[1]
});
}
function onDeleteNode(id) {
const matchedFallbackNode = fallbackNodes.value.findIndex((node) => node.id === id);
if (matchedFallbackNode >= 0) fallbackNodes.value.splice(matchedFallbackNode, 1);
else deleteNode(id, { trackHistory: true });
}
function onDeleteNodes(ids) {
deleteNodes(ids);
}
function onRevertDeleteNode({ node }) {
revertDeleteNode(node);
}
function onToggleNodeDisabled(id) {
if (!checkIfEditingIsAllowed()) return;
toggleNodesDisabled([id]);
}
function onRevertToggleNodeDisabled({ nodeName }) {
revertToggleNodeDisabled(nodeName);
}
function onToggleNodesDisabled(ids) {
if (!checkIfEditingIsAllowed()) return;
toggleNodesDisabled(ids);
}
function onClickNode(_id, event) {
lastClickPosition.value = [event.x, event.y];
closeNodeCreator();
}
function onSetNodeActivated(id, event) {
if (event?.metaKey || event?.ctrlKey) {
if (tryToOpenSubworkflowInNewTab(id)) return;
}
setNodeActive(id, "canvas_default_view");
}
function onOpenSubWorkflow(id) {
tryToOpenSubworkflowInNewTab(id);
}
function onSetNodeDeactivated() {
clearNodeActive();
}
function onSetNodeSelected(id) {
closeNodeCreator();
setNodeSelected(id);
}
async function onCopyNodes(ids) {
await copyNodes(ids);
toast.showMessage({
title: i18n.baseText("generic.copiedToClipboard"),
type: "success"
});
}
async function onClipboardPaste(plainTextData) {
if (getNodeViewTab(route) !== MAIN_HEADER_TABS.WORKFLOW || !keyBindingsEnabled.value || !checkIfEditingIsAllowed()) return;
let workflowData = null;
if (plainTextData.match(VALID_WORKFLOW_IMPORT_URL_REGEX)) {
if (await message.confirm(i18n.baseText("nodeView.confirmMessage.onClipboardPasteEvent.message", { interpolate: { plainTextData } }), i18n.baseText("nodeView.confirmMessage.onClipboardPasteEvent.headline"), {
type: "warning",
confirmButtonText: i18n.baseText("nodeView.confirmMessage.onClipboardPasteEvent.confirmButtonText"),
cancelButtonText: i18n.baseText("nodeView.confirmMessage.onClipboardPasteEvent.cancelButtonText")
}) !== "confirm") return;
workflowData = await fetchWorkflowDataFromUrl(plainTextData);
} else workflowData = jsonParse(plainTextData, { fallbackValue: null });
if (!workflowData) return;
const ids = (await importWorkflowData(workflowData, "paste", {
importTags: false,
viewport: viewportBoundaries.value
})).nodes?.map((node) => node.id) ?? [];
canvasRef.value?.ensureNodesAreVisible(ids);
}
async function onCutNodes(ids) {
if (isCanvasReadOnly.value) await copyNodes(ids);
else await cutNodes(ids);
}
async function onDuplicateNodes(ids) {
if (!checkIfEditingIsAllowed()) return;
const newIds = await duplicateNodes(ids, { viewport: viewportBoundaries.value });
canvasRef.value?.ensureNodesAreVisible(newIds);
}
function onPinNodes(ids, source) {
if (!checkIfEditingIsAllowed()) return;
toggleNodesPinned(ids, source);
}
async function onSaveWorkflow() {
const workflowIsSaved = !uiStore.stateIsDirty && workflowsStore.isWorkflowSaved[workflowsStore.workflowId];
const workflowIsArchived = workflowsStore.workflow.isArchived;
if (workflowIsSaved || workflowIsArchived) return;
if (await workflowSaving.saveCurrentWorkflow()) canvasEventBus.emit("saved:workflow");
}
function onContextMenuAction(action, nodeIds) {
canvasRef.value?.executeContextMenuAction(action, nodeIds);
}
function addWorkflowSavedEventBindings() {
canvasEventBus.on("saved:workflow", npsSurveyStore.fetchPromptsData);
canvasEventBus.on("saved:workflow", onSaveFromWithinNDV);
}
function removeWorkflowSavedEventBindings() {
canvasEventBus.off("saved:workflow", npsSurveyStore.fetchPromptsData);
canvasEventBus.off("saved:workflow", onSaveFromWithinNDV);
canvasEventBus.off("saved:workflow", onSaveFromWithinExecutionDebug);
}
async function onSaveFromWithinNDV() {
if (ndvStore.activeNodeName) toast.showMessage({
title: i18n.baseText("generic.workflowSaved"),
type: "success"
});
}
async function onCreateWorkflow() {
await router.push({ name: VIEWS.NEW_WORKFLOW });
}
function onRenameNode(name) {
if (ndvStore.activeNode?.name) renameNode(ndvStore.activeNode.name, name);
}
async function onOpenRenameNodeModal(id) {
const currentName = workflowsStore.getNodeById(id)?.name ?? "";
const activeElement = document.activeElement;
if (activeElement && shouldIgnoreCanvasShortcut(activeElement)) return;
if (!keyBindingsEnabled.value || document.querySelector(".rename-prompt")) return;
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) => {
if (!value.trim()) return i18n.baseText("nodeView.prompt.invalidName");
return true;
}
});
await nextTick();
const nameInput = document.querySelector(".rename-prompt .el-input__inner");
nameInput?.focus();
nameInput?.select();
let shouldSaveAfterRename = false;
const handleKeyDown = (e) => {
if (e.key === " ") e.stopPropagation();
if ((e.ctrlKey || e.metaKey) && e.key === "s") {
e.preventDefault();
shouldSaveAfterRename = true;
nameInput?.dispatchEvent(new KeyboardEvent("keydown", { key: "Enter" }));
}
};
nameInput?.addEventListener("keydown", handleKeyDown);
const promptResponse = await promptResponsePromise;
nameInput?.removeEventListener("keydown", handleKeyDown);
if (promptResponse.action === "confirm") {
await renameNode(currentName, promptResponse.value, { trackHistory: true });
if (shouldSaveAfterRename) await onSaveWorkflow();
}
} catch (e) {}
}
async function onRevertRenameNode({ currentName, newName }) {
await revertRenameNode(currentName, newName);
}
async function onRevertReplaceNodeParameters({ nodeId, currentProperties, newProperties }) {
await revertReplaceNodeParameters(nodeId, currentProperties, newProperties);
}
function onUpdateNodeParameters(id, parameters) {
setNodeParameters(id, parameters);
}
function onUpdateNodeInputs(id) {
revalidateNodeInputConnections(id);
}
function onUpdateNodeOutputs(id) {
revalidateNodeOutputConnections(id);
}
function onClickNodeAdd(source, sourceHandle) {
nodeCreatorStore.openNodeCreatorForConnectingNode({
connection: {
source,
sourceHandle
},
eventSource: NODE_CREATOR_OPEN_SOURCES.PLUS_ENDPOINT
});
}
async function loadCredentials() {
let options;
if (workflowId.value && !isNewWorkflowRoute.value) options = { workflowId: workflowId.value };
else {
const projectId = (typeof route.query?.projectId === "string" ? route.query?.projectId : void 0) ?? projectsStore.personalProject?.id;
if (projectId === void 0) throw new Error("Could not find projectId in the query nor could I find the personal project in the project store");
options = { projectId };
}
await credentialsStore.fetchAllCredentialsForWorkflow(options);
}
function onCreateConnection(connection) {
createConnection(connection, { trackHistory: true });
}
function onRevertCreateConnection({ connection }) {
revertCreateConnection(connection);
}
function onCreateConnectionCancelled(event, position, mouseEvent) {
if ((mouseEvent?.target).classList?.contains("clickable")) return;
uiStore.lastInteractedWithNodeId = event.nodeId;
uiStore.lastInteractedWithNodeHandle = event.handleId;
uiStore.lastCancelledConnectionPosition = [position.x, position.y];
setTimeout(() => {
if (!event.nodeId) return;
nodeCreatorStore.openNodeCreatorForConnectingNode({
connection: {
source: event.nodeId,
sourceHandle: event.handleId
},
eventSource: NODE_CREATOR_OPEN_SOURCES.NODE_CONNECTION_DROP
});
});
}
function onDeleteConnection(connection) {
deleteConnection(connection, { trackHistory: true });
}
function onRevertDeleteConnection({ connection }) {
revertDeleteConnection(connection);
}
async function importWorkflowExact({ workflow: workflowData }) {
if (!workflowData.nodes || !workflowData.connections) throw new Error("Invalid workflow object");
resetWorkspace();
await initializeData();
await initializeWorkspace({
...workflowData,
nodes: getNodesWithNormalizedPosition(workflowData.nodes)
});
fitView();
}
async function onImportWorkflowDataEvent(data) {
const workflowData = data.data;
const trackEvents = typeof data.trackEvents === "boolean" ? data.trackEvents : void 0;
const setStateDirty = typeof data.setStateDirty === "boolean" ? data.setStateDirty : void 0;
await importWorkflowData(workflowData, "file", {
viewport: viewportBoundaries.value,
regenerateIds: data.regenerateIds === true || data.regenerateIds === void 0,
trackEvents,
setStateDirty
});
await nextTick();
fitView();
selectNodes(workflowData.nodes?.map((node) => node.id) ?? []);
if (data.tidyUp) {
const nodesIdsToTidyUp = data.nodesIdsToTidyUp;
setTimeout(async () => {
canvasEventBus.emit("tidyUp", {
source: "import-workflow-data",
nodeIdsFilter: nodesIdsToTidyUp,
trackEvents
});
await nextTick();
fitView();
}, 0);
}
}
async function onImportWorkflowUrlEvent(data) {
const workflowData = await fetchWorkflowDataFromUrl(data.url);
if (!workflowData) return;
await importWorkflowData(workflowData, "url", { viewport: viewportBoundaries.value });
canvasRef.value?.ensureNodesAreVisible(workflowData.nodes?.map((node) => node.id) ?? []);
}
function addImportEventBindings() {
nodeViewEventBus.on("importWorkflowData", onImportWorkflowDataEvent);
nodeViewEventBus.on("importWorkflowUrl", onImportWorkflowUrlEvent);
nodeViewEventBus.on("openChat", onOpenChat);
}
function removeImportEventBindings() {
nodeViewEventBus.off("importWorkflowData", onImportWorkflowDataEvent);
nodeViewEventBus.off("importWorkflowUrl", onImportWorkflowUrlEvent);
nodeViewEventBus.off("openChat", onOpenChat);
}
const nodeCreatorReplaceTargetId = ref(void 0);
function onNodeCreatorClose() {
nodeCreatorReplaceTargetId.value = void 0;
}
async function onAddNodesAndConnections({ nodes, connections }, dragAndDrop = false, position) {
if (!checkIfEditingIsAllowed()) return;
if (nodeCreatorReplaceTargetId.value !== void 0) {
uiStore.resetLastInteractedWith();
nodes = nodes.map((x) => ({
...x,
openDetail: false
}));
}
const { addedNodes } = await addNodesAndConnections(nodes, connections, {
dragAndDrop,
position,
viewport: viewportBoundaries.value,
telemetry: true,
replaceNodeId: nodeCreatorReplaceTargetId.value
});
if (addedNodes.length > 0) {
const lastAddedNodeId = addedNodes[addedNodes.length - 1].id;
selectNodes([lastAddedNodeId]);
}
}
async function onRevertAddNode({ node }) {
await revertAddNode(node.name);
}
function onSwitchActiveNode(nodeName) {
const node = workflowsStore.getNodeByName(nodeName);
if (!node) return;
setNodeActiveByName(nodeName, "other");
selectNodes([node.id]);
}
function onOpenSelectiveNodeCreator(node, connectionType, connectionIndex = 0) {
nodeCreatorStore.openSelectiveNodeCreator({
node,
connectionType,
connectionIndex
});
}
function onToggleNodeCreator(options) {
nodeCreatorStore.setNodeCreatorState(options);
if (!options.createNodeActive) {
nodeCreatorReplaceTargetId.value = void 0;
if (!options.hasAddedNodes) uiStore.resetLastInteractedWith();
}
}
function onOpenNodeCreatorFromCanvas(source) {
onToggleNodeCreator({
createNodeActive: true,
source
});
}
function onOpenNodeCreatorForTriggerNodes(source) {
nodeCreatorStore.openNodeCreatorForTriggerNodes(source);
}
function onToggleFocusPanel() {
focusPanelStore.toggleFocusPanel();
telemetry.track(`User ${focusPanelStore.focusPanelActive ? "opened" : "closed"} focus panel`, {
source: "canvasKeyboardShortcut",
parameters: focusPanelStore.focusedNodeParametersInTelemetryFormat,
parameterCount: focusPanelStore.focusedNodeParametersInTelemetryFormat.length
});
}
function closeNodeCreator() {
if (nodeCreatorStore.isCreateNodeActive) nodeCreatorStore.isCreateNodeActive = false;
}
function onCreateSticky() {
onAddNodesAndConnections({
nodes: [{ type: STICKY_NODE_TYPE }],
connections: []
});
}
function onClickConnectionAdd(connection) {
nodeCreatorStore.openNodeCreatorForConnectingNode({
connection,
eventSource: NODE_CREATOR_OPEN_SOURCES.NODE_CONNECTION_ACTION
});
}
function onClickReplaceNode(nodeId) {
const node = workflowsStore.getNodeById(nodeId);
if (!node) return;
const nodeType = nodeTypesStore.getNodeType(node.type);
if (!nodeType) return;
nodeCreatorReplaceTargetId.value = nodeId;
if (isTriggerNode(nodeType)) nodeCreatorStore.openNodeCreatorForTriggerNodes(NODE_CREATOR_OPEN_SOURCES.REPLACE_NODE_ACTION);
else {
const inputs = getNodeInputs(editableWorkflowObject.value, node, nodeType).map((output) => typeof output === "string" ? output : output.type);
const outputs = getNodeOutputs(editableWorkflowObject.value, node, nodeType).map((output) => typeof output === "string" ? output : output.type);
if (inputs[0] && outputs[0] && inputs[0] !== outputs[0]) nodeCreatorStore.openNodeCreatorForRegularNodes(NODE_CREATOR_OPEN_SOURCES.REPLACE_NODE_ACTION);
else nodeCreatorStore.openSelectiveNodeCreator({
connectionType: inputs[0] ?? outputs[0],
node: node.name
});
}
}
const workflowPermissions = computed(() => {
return workflowId.value ? getResourcePermissions(workflowsStore.getWorkflowById(workflowId.value)?.scopes).workflow : {};
});
const projectPermissions = computed(() => {
return getResourcePermissions((route.query?.projectId ? projectsStore.myProjects.find((p) => p.id === route.query.projectId) : projectsStore.currentProject ?? projectsStore.personalProject)?.scopes);
});
const isStoppingExecution = ref(false);
const isWorkflowRunning = computed(() => workflowsStore.isWorkflowRunning);
const isExecutionWaitingForWebhook = computed(() => workflowsStore.executionWaitingForWebhook);
const isExecutionDisabled = computed(() => {
if (containsChatTriggerNodes.value && isOnlyChatTriggerNodeActive.value && !chatTriggerNodePinnedData.value) return true;
return !containsTriggerNodes.value || allTriggerNodesDisabled.value;
});
const isRunWorkflowButtonVisible = computed(() => !isOnlyChatTriggerNodeActive.value || chatTriggerNodePinnedData.value);
const isStopExecutionButtonVisible = computed(() => isWorkflowRunning.value && !isExecutionWaitingForWebhook.value);
const isStopWaitingForWebhookButtonVisible = computed(() => isWorkflowRunning.value && isExecutionWaitingForWebhook.value);
async function onRunWorkflowToNode(id) {
const node = workflowsStore.getNodeById(id);
if (!node) return;
if (needsAgentInput(node) && nodeTypesStore.isToolNode(node.type)) uiStore.openModalWithData({
name: FROM_AI_PARAMETERS_MODAL_KEY,
data: { nodeName: node.name }
});
else {
trackRunWorkflowToNode(node);
agentRequestStore.clearAgentRequests(workflowsStore.workflowId, node.id);
runWorkflow({
destinationNode: {
nodeName: node.name,
mode: "inclusive"
},
source: "Node.executeNode"
});
}
}
function copyWebhookUrl(id, webhookType) {
const webhookUrl = workflowsStore.getWebhookUrl(id, webhookType);
if (!webhookUrl) return;
clipboard.copy(webhookUrl);
toast.showMessage({
title: i18n.baseText("nodeWebhooks.showMessage.title"),
type: "success"
});
}
async function onCopyTestUrl(id) {
const node = workflowsStore.getNodeById(id);
if (PRODUCTION_ONLY_TRIGGER_NODE_TYPES.includes(node?.type ?? "")) {
toast.showMessage({
title: i18n.baseText("nodeWebhooks.showMessage.testWebhookUrl"),
type: "warning"
});
return;
}
copyWebhookUrl(id, "test");
}
async function onCopyProductionUrl(id) {
if (!workflowsStore.workflow.active) {
toast.showMessage({
title: i18n.baseText("nodeWebhooks.showMessage.not.active"),
type: "warning"
});
return;
}
copyWebhookUrl(id, "production");
}
function trackRunWorkflowToNode(node) {
const telemetryPayload = {
node_type: node.type,
workflow_id: workflowsStore.workflowId,
source: "canvas",
push_ref: ndvStore.pushRef
};
telemetry.track("User clicked execute node button", telemetryPayload);
externalHooks.run("nodeView.onRunNode", telemetryPayload);
}
async function onOpenExecution(executionId, nodeId) {
canvasStore.startLoading();
resetWorkspace();
await initializeData();
const data = await openExecution(executionId, nodeId);
if (!data) return;
nextTick(() => {
updateNodesIssues();
});
canvasStore.stopLoading();
fitView();
canvasEventBus.emit("open:execution", data);
externalHooks.run("execution.open", {
workflowId: data.workflowData.id,
workflowName: data.workflowData.name,
executionId
});
telemetry.track("User opened read-only execution", {
workflow_id: data.workflowData.id,
execution_mode: data.mode,
execution_finished: data.finished
});
}
function onExecutionOpenedWithError(data) {
if (!data.finished && data.data?.resultData?.error) {
let nodeErrorFound = false;
if (data.data.resultData.runData) {
const runData = data.data.resultData.runData;
errorCheck: for (const nodeName of Object.keys(runData)) for (const taskData of runData[nodeName]) if (taskData.error) {
nodeErrorFound = true;
break errorCheck;
}
}
if (!nodeErrorFound && (data.data.resultData.error.stack ?? data.data.resultData.error.message)) {
console.error(`Execution ${data.id} error:`);
console.error(data.data.resultData.error.stack);
toast.showMessage({
title: i18n.baseText("nodeView.showError.workflowError"),
message: data.data.resultData.error.message,
type: "error",
duration: 0
});
}
}
}
function onExecutionOpenedWithWaitTill(data) {
if (data.waitTill) toast.showMessage({
title: i18n.baseText("nodeView.thisExecutionHasntFinishedYet"),
message: h(NodeViewUnfinishedWorkflowMessage_default),
type: "warning",
duration: 0
});
}
function addExecutionOpenedEventBindings() {
canvasEventBus.on("open:execution", onExecutionOpenedWithError);
canvasEventBus.on("open:execution", onExecutionOpenedWithWaitTill);
}
function removeExecutionOpenedEventBindings() {
canvasEventBus.off("open:execution", onExecutionOpenedWithError);
canvasEventBus.off("open:execution", onExecutionOpenedWithWaitTill);
}
async function onStopExecution() {
isStoppingExecution.value = true;
await stopCurrentExecution();
isStoppingExecution.value = false;
}
async function onStopWaitingForWebhook() {
await stopWaitingForWebhook();
}
function onRunWorkflowButtonMouseEnter() {
nodeViewEventBus.emit("runWorkflowButton:mouseenter");
}
function onRunWorkflowButtonMouseLeave() {
nodeViewEventBus.emit("runWorkflowButton:mouseleave");
}
const chatTriggerNode = computed(() => {
return editableWorkflow.value.nodes.find((node) => node.type === CHAT_TRIGGER_NODE_TYPE);
});
const containsChatTriggerNodes = computed(() => {
return !isExecutionWaitingForWebhook.value && !!editableWorkflow.value.nodes.find((node) => ["@n8n/n8n-nodes-langchain.manualChatTrigger", "@n8n/n8n-nodes-langchain.chatTrigger"].includes(node.type) && node.disabled !== true);
});
const isOnlyChatTriggerNodeActive = computed(() => {
return triggerNodes.value.every((node) => node.disabled || node.type === "@n8n/n8n-nodes-langchain.chatTrigger");
});
const chatTriggerNodePinnedData = computed(() => {
if (!chatTriggerNode.value) return null;
return workflowsStore.pinDataByNodeName(chatTriggerNode.value.name);
});
function onOpenChat() {
startChat("main");
}
const evaluationTriggerNode = computed(() => {
return editableWorkflow.value.nodes.find((node) => node.type === EVALUATION_TRIGGER_NODE_TYPE);
});
function addUndoRedoEventBindings() {
historyBus.on("nodeMove", onRevertNodePosition);
historyBus.on("revertAddNode", onRevertAddNode);
historyBus.on("revertRemoveNode", onRevertDeleteNode);
historyBus.on("revertAddConnection", onRevertCreateConnection);
historyBus.on("revertRemoveConnection", onRevertDeleteConnection);
historyBus.on("revertRenameNode", onRevertRenameNode);
historyBus.on("revertReplaceNodeParameters", onRevertReplaceNodeParameters);
historyBus.on("enableNodeToggle", onRevertToggleNodeDisabled);
}
function removeUndoRedoEventBindings() {
historyBus.off("nodeMove", onRevertNodePosition);
historyBus.off("revertAddNode", onRevertAddNode);
historyBus.off("revertRemoveNode", onRevertDeleteNode);
historyBus.off("revertAddConnection", onRevertCreateConnection);
historyBus.off("revertRemoveConnection", onRevertDeleteConnection);
historyBus.off("revertRenameNode", onRevertRenameNode);
historyBus.off("revertReplaceNodeParameters", onRevertReplaceNodeParameters);
historyBus.off("enableNodeToggle", onRevertToggleNodeDisabled);
}
async function onSourceControlPull() {
try {
await Promise.all([
environmentsStore.fetchAllVariables(),
tagsStore.fetchAll(),
loadCredentials(),
projectsStore.getAvailableProjects()
]);
if (workflowId.value && !uiStore.stateIsDirty) {
const workflowData = await workflowsStore.fetchWorkflow(workflowId.value);
if (workflowData) {
documentTitle.setDocumentTitle(workflowData.name, "IDLE");
await openWorkflow(workflowData);
}
}
} catch (error) {
console.error(error);
}
}
function addSourceControlEventBindings() {
sourceControlEventBus.on("pull", onSourceControlPull);
}
function removeSourceControlEventBindings() {
sourceControlEventBus.off("pull", onSourceControlPull);
}
function addCommandBarEventBindings() {
canvasEventBus.on("create:sticky", onCreateSticky);
}
function removeCommandBarEventBindings() {
canvasEventBus.off("create:sticky", onCreateSticky);
}
function addPostMessageEventBindings() {
window.addEventListener("message", onPostMessageReceived);
}
function removePostMessageEventBindings() {
window.removeEventListener("message", onPostMessageReceived);
}
function emitPostMessageReady() {
if (window.parent) window.parent.postMessage(JSON.stringify({
command: "n8nReady",
version: rootStore.versionCli
}), "*");
}
async function onPostMessageReceived(messageEvent) {
if (!messageEvent || typeof messageEvent.data !== "string" || !messageEvent.data?.includes?.("\"command\"")) return;
try {
const json = JSON.parse(messageEvent.data);
if (json && json.command === "openWorkflow") try {
if (json.projectId) await projectsStore.fetchAndSetProject(json.projectId);
await importWorkflowExact(json);
canOpenNDV.value = json.canOpenNDV ?? true;
hideNodeIssues.value = json.hideNodeIssues ?? false;
isExecutionPreview.value = false;
} catch (e) {
if (window.top) window.top.postMessage(JSON.stringify({
command: "error",
message: i18n.baseText("openWorkflow.workflowImportError")
}), "*");
toast.showError(e, i18n.baseText("openWorkflow.workflowImportError"));
}
else if (json && json.command === "openExecution") try {
if (json.projectId) await projectsStore.fetchAndSetProject(json.projectId);
isProductionExecutionPreview.value = json.executionMode !== "manual" && json.executionMode !== "evaluation";
await onOpenExecution(json.executionId, json.nodeId);
canOpenNDV.value = json.canOpenNDV ?? true;
hideNodeIssues.value = json.hideNodeIssues ?? false;
isExecutionPreview.value = true;
} catch (e) {
if (window.top) window.top.postMessage(JSON.stringify({
command: "error",
message: i18n.baseText("nodeView.showError.openExecution.title")
}), "*");
toast.showMessage({
title: i18n.baseText("nodeView.showError.openExecution.title"),
message: e.message,
type: "error"
});
}
else if (json?.command === "setActiveExecution") executionsStore.activeExecution = await executionsStore.fetchExecution(json.executionId);
} catch (e) {}
}
function checkIfEditingIsAllowed() {
if (!initializedWorkflowId.value) return true;
if (readOnlyNotification.value?.visible) return false;
if (!(workflowPermissions.value.update ?? projectPermissions.value.workflow.update)) return false;
if (isReadOnlyRoute.value || isReadOnlyEnvironment.value) {
const messageContext = isReadOnlyRoute.value ? "executions" : "workflows";
readOnlyNotification.value = toast.showMessage({
title: i18n.baseText(isReadOnlyEnvironment.value ? `readOnlyEnv.showMessage.${messageContext}.title` : "readOnly.showMessage.executions.title"),
message: i18n.baseText(isReadOnlyEnvironment.value ? `readOnlyEnv.showMessage.${messageContext}.message` : "readOnly.showMessage.executions.message"),
type: "info"
});
return false;
}
return true;
}
function checkIfRouteIsAllowed() {
if (isReadOnlyEnvironment.value && [VIEWS.NEW_WORKFLOW, VIEWS.TEMPLATE_IMPORT].find((view) => view === route.name)) nextTick(async () => {
resetWorkspace();
uiStore.stateIsDirty = false;
await router.replace({ name: VIEWS.HOMEPAGE });
});
}
async function initializeDebugMode() {
documentTitle.setDocumentTitle(workflowsStore.workflowName, "DEBUG");
if (!workflowsStore.isInDebugMode) {
await applyExecutionData(route.params.executionId);
workflowsStore.isInDebugMode = true;
}
canvasEventBus.on("saved:workflow", onSaveFromWithinExecutionDebug);
}
async function onSaveFromWithinExecutionDebug() {
if (route.name !== VIEWS.EXECUTION_DEBUG) return;
await router.replace({
name: VIEWS.WORKFLOW,
params: { name: workflowId.value }
});
}
const viewportTransform = ref({
x: 0,
y: 0,
zoom: 1
});
const viewportDimensions = ref({
width: 0,
height: 0
});
const viewportBoundaries = computed(() => getBounds(viewportTransform.value, viewportDimensions.value));
function onViewportChange(viewport, dimensions) {
viewportTransform.value = viewport;
viewportDimensions.value = dimensions;
uiStore.nodeViewOffsetPosition = [viewport.x, viewport.y];
}
function selectNodes(ids) {
setTimeout(() => canvasEventBus.emit("nodes:select", { ids }));
}
function onClickPane(position) {
lastClickPosition.value = [position.x, position.y];
onSetNodeSelected();
}
function onSelectionEnd(position) {
lastClickPosition.value = [position.x, position.y];
}
async function onDragAndDrop(position, event) {
if (!event.dataTransfer) return;
const dropData = jsonParse(event.dataTransfer.getData(DRAG_EVENT_DATA_KEY));
if (dropData) {
await onAddNodesAndConnections(dropData, true, [position.x, position.y]);
onToggleNodeCreator({
createNodeActive: false,
hasAddedNodes: true
});
}
}
function registerCustomActions() {
registerCustomAction({
key: "openNodeDetail",
action: ({ node }) => {
setNodeActiveByName(node, "other");
}
});
registerCustomAction({
key: "openSelectiveNodeCreator",
action: ({ creatorview: creatorView, connectiontype: connectionType, node }) => {
nodeCreatorStore.openSelectiveNodeCreator({
node,
connectionType,
creatorView
});
}
});
registerCustomAction({
key: "showNodeCreator",
action: () => {
ndvStore.unsetActiveNodeName();
nextTick(() => {
onOpenNodeCreatorForTriggerNodes(NODE_CREATOR_OPEN_SOURCES.TAB);
});
}
});
}
function unregisterCustomActions() {
unregisterCustomAction("openNodeDetail");
unregisterCustomAction("openSelectiveNodeCreator");
unregisterCustomAction("showNodeCreator");
}
function showAddFirstStepIfEnabled() {
if (uiStore.addFirstStepOnLoad) {
onOpenNodeCreatorForTriggerNodes(NODE_CREATOR_OPEN_SOURCES.TRIGGER_PLACEHOLDER_BUTTON);
uiStore.addFirstStepOnLoad = false;
}
}
function updateNodeRoute(nodeId) {
const nodeUi = workflowsStore.findNodeByPartialId(nodeId);
if (nodeUi) setNodeActive(nodeUi.id, "other");
else {
toast.showToast({
title: i18n.baseText("nodeView.showMessage.ndvUrl.missingNodes.title"),
message: i18n.baseText("nodeView.showMessage.ndvUrl.missingNodes.content"),
type: "warning"
});
router.replace({
name: route.name,
params: { name: workflowId.value },
query: route.query
});
}
}
watch([() => route.name, () => route.params.name], async ([newRouteName, newWorkflowId], [oldRouteName, oldWorkflowId]) => {
await initializeRoute(newRouteName === VIEWS.NEW_WORKFLOW && oldRouteName === VIEWS.WORKFLOW || newRouteName === VIEWS.WORKFLOW && oldRouteName === VIEWS.NEW_WORKFLOW || newWorkflowId !== oldWorkflowId);
});
watch(() => {
return isLoading.value || isCanvasReadOnly.value || editableWorkflow.value.nodes.length !== 0;
}, (isReadOnlyOrLoading) => {
if (isReadOnlyOrLoading) {
fallbackNodes.value = [];
return;
}
const addNodesItem = {
id: CanvasNodeRenderType.AddNodes,
name: CanvasNodeRenderType.AddNodes,
type: CanvasNodeRenderType.AddNodes,
typeVersion: 1,
position: [0, 0],
parameters: {}
};
const choicePromptItem = {
id: CanvasNodeRenderType.ChoicePrompt,
name: CanvasNodeRenderType.ChoicePrompt,
type: CanvasNodeRenderType.ChoicePrompt,
typeVersion: 1,
position: [0, 0],
parameters: {},
draggable: false
};
fallbackNodes.value = builderStore.isAIBuilderEnabled ? [choicePromptItem] : [addNodesItem];
});
watch(() => route.params.nodeId, async (newId) => {
if (typeof newId !== "string" || newId === "") ndvStore.unsetActiveNodeName();
else updateNodeRoute(newId);
});
watch(() => ndvStore.activeNode, async (val) => {
if (![VIEWS.WORKFLOW].includes(String(route.name))) return;
const nodeId = val?.id ? workflowsStore.getPartialIdForNode(val?.id) : "";
if (nodeId !== route.params.nodeId) await router.replace({
name: route.name,
params: {
name: workflowId.value,
nodeId
},
query: route.query
});
});
onBeforeRouteLeave(async (to, from, next) => {
if (focusPanelStore.focusPanelActive) focusPanelStore.closeFocusPanel();
if (isReadOnlyEnvironment.value) {
next();
return;
}
const toNodeViewTab = getNodeViewTab(to);
const isNavigatingBetweenWorkflows = [VIEWS.WORKFLOW, VIEWS.NEW_WORKFLOW].includes(from.name) && [VIEWS.WORKFLOW, VIEWS.NEW_WORKFLOW].includes(to.name) && from.params.name !== to.params.name;
if ((toNodeViewTab === MAIN_HEADER_TABS.EXECUTIONS || from.name === VIEWS.TEMPLATE_IMPORT || toNodeViewTab === MAIN_HEADER_TABS.WORKFLOW && from.name === VIEWS.EXECUTION_DEBUG) && !isNavigatingBetweenWorkflows) {
next();
return;
}
await useWorkflowSaving({ router }).promptSaveUnsavedWorkflowChanges(next, { async confirm() {
if (from.name === VIEWS.NEW_WORKFLOW) {
const savedWorkflowId = workflowsStore.workflowId;
await router.replace({
name: VIEWS.WORKFLOW,
params: { name: savedWorkflowId }
});
await router.push(to);
return false;
}
workflowState.setWorkflowId("");
return true;
} });
});
onBeforeMount(() => {
if (!isDemoRoute.value) pushConnectionStore.pushConnect();
addPostMessageEventBindings();
});
onMounted(() => {
canvasStore.startLoading();
documentTitle.reset();
resetWorkspace();
initializeData().then(() => {
initializeRoute().then(() => {
toast.showNotificationForViews([VIEWS.WORKFLOW, VIEWS.NEW_WORKFLOW]);
if (route.query.settings) {
uiStore.openModal(WORKFLOW_SETTINGS_MODAL_KEY);
router.replace({ query: { settings: void 0 } });
}
}).finally(() => {
isLoading.value = false;
canvasStore.stopLoading();
externalHooks.run("nodeView.mount").catch(() => {});
setTimeout(() => {
if (routeNodeId.value) updateNodeRoute(routeNodeId.value);
}, 500);
emitPostMessageReady();
});
usersStore.showPersonalizationSurvey();
checkIfRouteIsAllowed();
});
addSourceControlEventBindings();
addWorkflowSavedEventBindings();
addBeforeUnloadEventBindings();
addImportEventBindings();
addExecutionOpenedEventBindings();
addCommandBarEventBindings();
registerCustomActions();
});
onActivated(() => {
addUndoRedoEventBindings();
showAddFirstStepIfEnabled();
});
onDeactivated(() => {
uiStore.closeModal(WORKFLOW_SETTINGS_MODAL_KEY);
removeUndoRedoEventBindings();
toast.clearAllStickyNotifications();
});
onBeforeUnmount(() => {
removeSourceControlEventBindings();
removePostMessageEventBindings();
removeWorkflowSavedEventBindings();
removeBeforeUnloadEventBindings();
removeImportEventBindings();
removeExecutionOpenedEventBindings();
removeCommandBarEventBindings();
unregisterCustomActions();
if (!isDemoRoute.value) pushConnectionStore.pushDisconnect();
});
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", { class: normalizeClass(unref($style).wrapper) }, [unref(editableWorkflow) && unref(editableWorkflowObject) && !isLoading.value ? (openBlock(), createBlock(WorkflowCanvas_default, {
key: 0,
id: unref(editableWorkflow).id,
ref: "canvas",
workflow: unref(editableWorkflow),
"workflow-object": unref(editableWorkflowObject),
"fallback-nodes": fallbackNodes.value,
"show-fallback-nodes": showFallbackNodes.value,
"event-bus": unref(canvasEventBus),
"read-only": isCanvasReadOnly.value,
executing: isWorkflowRunning.value,
"key-bindings": keyBindingsEnabled.value,
"suppress-interaction": unref(experimentalNdvStore).isMapperOpen,
"onUpdate:nodes:position": onUpdateNodesPosition,
"onUpdate:node:position": onUpdateNodePosition,
"onUpdate:node:activated": onSetNodeActivated,
"onUpdate:node:deactivated": onSetNodeDeactivated,
"onUpdate:node:selected": onSetNodeSelected,
"onUpdate:node:enabled": onToggleNodeDisabled,
"onUpdate:node:name": onOpenRenameNodeModal,
"onUpdate:node:parameters": onUpdateNodeParameters,
"onUpdate:node:inputs": onUpdateNodeInputs,
"onUpdate:node:outputs": onUpdateNodeOutputs,
"onUpdate:logsOpen": _cache[3] || (_cache[3] = ($event) => unref(logsStore).toggleOpen($event)),
"onUpdate:logs:inputOpen": unref(logsStore).toggleInputOpen,
"onUpdate:logs:outputOpen": unref(logsStore).toggleOutputOpen,
"onUpdate:hasRangeSelection": unref(canvasStore).setHasRangeSelection,
"onOpen:subWorkflow": onOpenSubWorkflow,
"onClick:node": onClickNode,
"onClick:node:add": onClickNodeAdd,
"onRun:node": onRunWorkflowToNode,
"onCopy:production:url": onCopyProductionUrl,
"onCopy:test:url": onCopyTestUrl,
"onDelete:node": onDeleteNode,
"onCreate:connection": onCreateConnection,
"onCreate:connection:cancelled": onCreateConnectionCancelled,
"onDelete:connection": onDeleteConnection,
"onClick:connection:add": onClickConnectionAdd,
"onClick:pane": onClickPane,
"onCreate:node": onOpenNodeCreatorFromCanvas,
"onCreate:sticky": onCreateSticky,
"onDelete:nodes": onDeleteNodes,
"onUpdate:nodes:enabled": onToggleNodesDisabled,
"onUpdate:nodes:pin": onPinNodes,
"onDuplicate:nodes": onDuplicateNodes,
"onCopy:nodes": onCopyNodes,
"onCut:nodes": onCutNodes,
"onReplace:node": onClickReplaceNode,
"onRun:workflow": _cache[4] || (_cache[4] = ($event) => unref(runEntireWorkflow)("main")),
"onSave:workflow": onSaveWorkflow,
"onCreate:workflow": onCreateWorkflow,
"onViewport:change": onViewportChange,
"onSelection:end": onSelectionEnd,
onDragAndDrop,
onTidyUp,
"onToggle:focusPanel": onToggleFocusPanel,
onExtractWorkflow,
onStartChat: _cache[5] || (_cache[5] = ($event) => unref(startChat)())
}, {
default: withCtx(() => [
!isCanvasReadOnly.value ? (openBlock(), createBlock(Suspense, { key: 0 }, {
default: withCtx(() => [createVNode(unref(LazySetupWorkflowCredentialsButton), { class: normalizeClass(unref($style).setupCredentialsButtonWrapper) }, null, 8, ["class"])]),
_: 1
})) : createCommentVNode("", true),
!isCanvasReadOnly.value ? (openBlock(), createElementBlock("div", {
key: 1,
class: normalizeClass(unref($style).executionButtons)
}, [
isRunWorkflowButtonVisible.value ? (openBlock(), createBlock(CanvasRunWorkflowButton_default, {
key: 0,
"waiting-for-webhook": isExecutionWaitingForWebhook.value,
disabled: isExecutionDisabled.value,
executing: isWorkflowRunning.value,
"trigger-nodes": triggerNodes.value,
"get-node-type": unref(nodeTypesStore).getNodeType,
"selected-trigger-node-name": unref(workflowsStore).selectedTriggerNodeName,
onMouseenter: onRunWorkflowButtonMouseEnter,
onMouseleave: onRunWorkflowButtonMouseLeave,
onExecute: _cache[0] || (_cache[0] = ($event) => unref(runEntireWorkflow)("main")),
onSelectTriggerNode: unref(workflowsStore).setSelectedTriggerNodeName
}, null, 8, [
"waiting-for-webhook",
"disabled",
"executing",
"trigger-nodes",
"get-node-type",
"selected-trigger-node-name",
"onSelectTriggerNode"
])) : createCommentVNode("", true),
containsChatTriggerNodes.value ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [isLogsPanelOpen.value ? (openBlock(), createBlock(CanvasChatButton_default, {
key: 0,
type: "tertiary",
label: unref(i18n).baseText("chat.hide"),
class: normalizeClass(unref($style).chatButton),
onClick: _cache[1] || (_cache[1] = ($event) => unref(logsStore).toggleOpen(false))
}, null, 8, ["label", "class"])) : (openBlock(), createBlock(KeyboardShortcutTooltip_default, {
key: 1,
label: unref(i18n).baseText("chat.open"),
shortcut: { keys: ["c"] }
}, {
default: withCtx(() => [createVNode(CanvasChatButton_default, {
type: isRunWorkflowButtonVisible.value ? "secondary" : "primary",
label: unref(i18n).baseText("chat.open"),
class: normalizeClass(unref($style).chatButton),
onClick: onOpenChat
}, null, 8, [
"type",
"label",
"class"
])]),
_: 1
}, 8, ["label"]))], 64)) : createCommentVNode("", true),
isStopExecutionButtonVisible.value ? (openBlock(), createBlock(CanvasStopCurrentExecutionButton_default, {
key: 2,
stopping: isStoppingExecution.value,
onClick: onStopExecution
}, null, 8, ["stopping"])) : createCommentVNode("", true),
isStopWaitingForWebhookButtonVisible.value ? (openBlock(), createBlock(CanvasStopWaitingForWebhookButton_default, {
key: 3,
onClick: onStopWaitingForWebhook
})) : createCommentVNode("", true)
], 2)) : createCommentVNode("", true),
isReadOnlyEnvironment.value ? (openBlock(), createBlock(unref(N8nCallout_default), {
key: 2,
theme: "warning",
icon: "lock",
class: normalizeClass(unref($style).readOnlyEnvironmentNotification)
}, {
default: withCtx(() => [createTextVNode(toDisplayString(unref(i18n).baseText("readOnlyEnv.cantEditOrRun")), 1)]),
_: 1
}, 8, ["class"])) : createCommentVNode("", true),
unref(builderStore).streaming ? (openBlock(), createBlock(unref(CanvasThinkingPill_default), {
key: 3,
class: normalizeClass(unref($style).thinkingPill),
"show-stop": "",
onStop: unref(builderStore).abortStreaming
}, null, 8, ["class", "onStop"])) : createCommentVNode("", true),
(openBlock(), createBlock(Suspense, null, {
default: withCtx(() => [!isCanvasReadOnly.value ? (openBlock(), createBlock(unref(LazyNodeCreation), {
key: 0,
"create-node-active": unref(nodeCreatorStore).isCreateNodeActive,
"node-view-scale": viewportTransform.value.zoom,
"focus-panel-active": unref(focusPanelStore).focusPanelActive,
onToggleNodeCreator,
onAddNodes: onAddNodesAndConnections,
onClose: onNodeCreatorClose
}, null, 8, [
"create-node-active",
"node-view-scale",
"focus-panel-active"
])) : createCommentVNode("", true)]),
_: 1
})),
(openBlock(), createBlock(Suspense, null, {
default: withCtx(() => [!isNDVV2.value ? (openBlock(), createBlock(unref(LazyNodeDetailsView), {
key: 0,
"workflow-object": unref(editableWorkflowObject),
"read-only": isCanvasReadOnly.value,
"is-production-execution-preview": isProductionExecutionPreview.value,
renaming: false,
onValueChanged: _cache[2] || (_cache[2] = ($event) => onRenameNode($event.value)),
onStopExecution,
onSwitchSelectedNode: onSwitchActiveNode,
onOpenConnectionNodeCreator: onOpenSelectiveNodeCreator,
onSaveKeyboardShortcut: onSaveWorkflow
}, null, 8, [
"workflow-object",
"read-only",
"is-production-execution-preview"
])) : createCommentVNode("", true)]),
_: 1
})),
(openBlock(), createBlock(Suspense, null, {
default: withCtx(() => [isNDVV2.value ? (openBlock(), createBlock(unref(LazyNodeDetailsViewV2), {
key: 0,
"workflow-object": unref(editableWorkflowObject),
"read-only": isCanvasReadOnly.value,
"is-production-execution-preview": isProductionExecutionPreview.value,
onRenameNode,
onStopExecution,
onSwitchSelectedNode: onSwitchActiveNode,
onOpenConnectionNodeCreator: onOpenSelectiveNodeCreator,
onSaveKeyboardShortcut: onSaveWorkflow
}, null, 8, [
"workflow-object",
"read-only",
"is-production-execution-preview"
])) : createCommentVNode("", true)]),
_: 1
}))
]),
_: 1
}, 8, [
"id",
"workflow",
"workflow-object",
"fallback-nodes",
"show-fallback-nodes",
"event-bus",
"read-only",
"executing",
"key-bindings",
"suppress-interaction",
"onUpdate:logs:inputOpen",
"onUpdate:logs:outputOpen",
"onUpdate:hasRangeSelection"
])) : createCommentVNode("", true), !isLoading.value && (unref(experimentalNdvStore).isNdvInFocusPanelEnabled ? !isCanvasReadOnly.value : true) ? (openBlock(), createBlock(FocusPanel_default, {
key: 1,
"is-canvas-read-only": isCanvasReadOnly.value,
onSaveKeyboardShortcut: onSaveWorkflow,
onContextMenuAction
}, null, 8, ["is-canvas-read-only"])) : createCommentVNode("", true)], 2);
};
}
});
var NodeView_vue_vue_type_style_index_0_lang_module_default = {
wrapper: "_wrapper_1ahwb_123",
executionButtons: "_executionButtons_1ahwb_128",
chatButton: "_chatButton_1ahwb_165",
setupCredentialsButtonWrapper: "_setupCredentialsButtonWrapper_1ahwb_169",
readOnlyEnvironmentNotification: "_readOnlyEnvironmentNotification_1ahwb_175",
thinkingPill: "_thinkingPill_1ahwb_182"
};
var NodeView_default = /* @__PURE__ */ __plugin_vue_export_helper_default(NodeView_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": NodeView_vue_vue_type_style_index_0_lang_module_default }]]);
export { NodeView_default as default };