2922 lines
		
	
	
		
			119 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			2922 lines
		
	
	
		
			119 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
| const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/NodeCreation-iNUuiza-.js","assets/index--OJ5nhDf.js","assets/index-DXNU_2Fk.css","assets/NodeCreation-C4gQlPqI.css","assets/NodeDetailsView-BKEGFeZ7.js","assets/TriggerPanel-C-c5cPsc.js","assets/RunDataParsedAiContent-Byf4f3hM.js","assets/core-Br-UFy15.js","assets/RunDataParsedAiContent-wfIiKsq7.css","assets/ConsumedTokensDetails.vue_vue_type_script_setup_true_lang-CSmXlf80.js","assets/InfoAccordion-u7XlbH6a.js","assets/InfoAccordion-dxudNqVC.css","assets/TriggerPanel-DiD8pi0I.css","assets/useWorkflowActivate-7Rw9KyzM.js","assets/global-link-actions--TiC75iP.js","assets/useExecutionDebugging-Bve-aaKO.js","assets/useBeforeUnload-ZtUpNFCu.js","assets/canvas-DbK7UyVG.js","assets/readyToRunWorkflows.store-Dhb8bhvk.js","assets/NodeDetailsView-CjdovDgq.css","assets/NodeDetailsViewV2-XPdbzrLu.js","assets/NodeDetailsViewV2-J_3cfdea.css","assets/SetupWorkflowCredentialsButton-DMIEMB5C.js"])))=>i.map(i=>d[i]);
 | |
| import { d as defineComponent, aq as createEventBus, as as useCssModule, cx as useVueFlow, b_ as toRef, x as computed, cy as useCanvasMapping, r as ref, cz as refThrottled, h as createElementBlock, g as openBlock, n as normalizeClass, l as unref, j as createBaseVNode, X as renderSlot, e as createBlock, f as createCommentVNode, cA as Canvas, K as mergeProps, _ as _export_sfc, a1 as useWorkflowsStore, cB as useExpressionResolveCtx, p as N8nText, w as withCtx, k as createTextVNode, t as toDisplayString, cC as _sfc_main$b, i as createVNode, aa as _sfc_main$c, bO as provide, cD as ExpressionLocalResolveContextSymbol, ad as useNodeTypesStore, bX as NodeIcon, F as Fragment, cE as _sfc_main$d, aG as useTemplateRef, bL as useNodeHelpers, cF as useFocusPanelStore, cG as useNodeSettingsParameters, cH as useEnvironmentsStore, cI as useExperimentalNdvStore, aY as useNDVStore, cJ as useDeviceSupport, cv as useActiveElement, cK as useTelemetryContext, cL as HTML_NODE_TYPE, cM as isValueExpression, cN as isResourceLocatorValue, cO as AI_TRANSFORM_NODE_TYPE, cP as useResolvedExpression, a7 as watch, cl as useThrottleFn, B as withModifiers, N as N8nIcon, cQ as InfoTip, c as useI18n, cR as __unplugin_components_2, cS as __unplugin_components_3, cT as __unplugin_components_4, cU as __unplugin_components_5, cV as __unplugin_components_6, cW as __unplugin_components_7, cX as __unplugin_components_8, cY as __unplugin_components_9, cZ as N8nInput, O as N8nRadioButtons, ap as normalizeStyle, ch as N8nResizeWrapper, c_ as getParameterTypeOption, c$ as htmlEditorEventBus, d0 as parseFromExpression, d1 as isValidParameterOption, d2 as formatAsExpression, al as useTelemetry, Y as nextTick, d3 as hasFocusOnInput, d4 as isFocusableEl, bB as isChatNode, d5 as truncateBeforeLast, q as N8nButton, ab as I18nT, cg as KeyboardShortcutTooltip, aM as N8nActionDropdown, d6 as reactive, o as onMounted, c7 as onUnmounted, d7 as _sfc_main$e, D as useI18n$1, b as useRouter, a2 as useRoute, a as useToast, ax as useDocumentTitle, az as useWorkflowHelpers, ay as useWorkflowSaving, Q as useUIStore, af as useSourceControlStore, d8 as useNodeCreatorStore, v as useSettingsStore, d9 as useCredentialsStore, da as useExternalSecretsStore, at as useRootStore, aZ as useExecutionsStore, co as useCanvasStore, aw as useNpsSurveyStore, db as useHistoryStore, au as useProjectsStore, u as useUsersStore, ar as useTagsStore, a0 as usePushConnectionStore, bk as useTemplatesStore, dc as useBuilderStore, av as useFoldersStore, dd as usePostHog, de as useAgentRequestStore, bK as useLogsStore, bM as useRunWorkflow, bP as useCanvasOperations, df as useWorkflowExtraction, ca as useClipboard, bn as useKeybindings, bu as ABOUT_MODAL_KEY, a3 as PLACEHOLDER_EMPTY_WORKFLOW_ID, dg as NEW_WORKFLOW_ID, V as VIEWS, dh as NDV_UI_OVERHAUL_EXPERIMENT, bQ as START_NODE_TYPE, di as getNodeViewTab, L as MAIN_HEADER_TABS, dj as VALID_WORKFLOW_IMPORT_URL_REGEX, am as useMessage, an as MODAL_CONFIRM, dk as jsonParse, aB as getResourcePermissions, bH as CHAT_TRIGGER_NODE_TYPE, bG as MANUAL_CHAT_TRIGGER_NODE_TYPE, dl as EVALUATION_TRIGGER_NODE_TYPE, dm as getBounds, dn as onBeforeRouteLeave, b1 as onBeforeMount, ak as WORKFLOW_SETTINGS_MODAL_KEY, bp as useExternalHooks, dp as onActivated, dq as onDeactivated, W as onBeforeUnmount, dr as Suspense, ds as defineAsyncComponent, z as N8nCallout, aU as __vitePreload, aE as EnterpriseEditionFeature, dt as NODE_CREATOR_OPEN_SOURCES, du as EVALUATION_NODE_TYPE, dv as getSampleWorkflowByTemplateId, dw as tryToParseNumber, aO as nodeViewEventBus, bC as NodeConnectionTypes, dx as createCanvasConnectionHandleString, dy as CanvasConnectionMode, dz as isValidNodeConnectionType, dA as sourceControlEventBus, dB as getNodesWithNormalizedPosition, aW as h, dC as CanvasNodeRenderType, dD as shouldIgnoreCanvasShortcut, b0 as STICKY_NODE_TYPE, dE as needsAgentInput, dF as FROM_AI_PARAMETERS_MODAL_KEY, dG as historyBus, dH as DRAG_EVENT_DATA_KEY } from "./index--OJ5nhDf.js";
 | |
| import { g as globalLinkActionsEventBus } from "./global-link-actions--TiC75iP.js";
 | |
| import { u as useExecutionDebugging } from "./useExecutionDebugging-Bve-aaKO.js";
 | |
| import { u as useBeforeUnload } from "./useBeforeUnload-ZtUpNFCu.js";
 | |
| import { c as canvasEventBus } from "./canvas-DbK7UyVG.js";
 | |
| import { u as useAITemplatesStarterCollectionStore, a as useReadyToRunWorkflowsStore } from "./readyToRunWorkflows.store-Dhb8bhvk.js";
 | |
| const _sfc_main$a = /* @__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 }
 | |
|   },
 | |
|   setup(__props) {
 | |
|     const props = __props;
 | |
|     const $style = useCssModule();
 | |
|     const { onNodesInitialized } = useVueFlow(props.id);
 | |
|     const workflow = toRef(props, "workflow");
 | |
|     const workflowObject = toRef(props, "workflowObject");
 | |
|     const nodes = computed(() => {
 | |
|       return props.showFallbackNodes ? [...props.workflow.nodes, ...props.fallbackNodes] : props.workflow.nodes;
 | |
|     });
 | |
|     const connections = computed(() => props.workflow.connections);
 | |
|     const { nodes: mappedNodes, connections: mappedConnections } = useCanvasMapping({
 | |
|       nodes,
 | |
|       connections,
 | |
|       workflowObject
 | |
|     });
 | |
|     const initialFitViewDone = ref(false);
 | |
|     onNodesInitialized(() => {
 | |
|       if (!initialFitViewDone.value || props.showFallbackNodes) {
 | |
|         props.eventBus.emit("fitView");
 | |
|         initialFitViewDone.value = true;
 | |
|       }
 | |
|     });
 | |
|     const mappedNodesThrottled = refThrottled(mappedNodes, 200);
 | |
|     const mappedConnectionsThrottled = refThrottled(mappedConnections, 200);
 | |
|     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, mergeProps({
 | |
|             key: 0,
 | |
|             id: _ctx.id,
 | |
|             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
 | |
|           }, _ctx.$attrs), null, 16, ["id", "nodes", "connections", "event-bus", "read-only", "executing"])) : createCommentVNode("", true)
 | |
|         ], 2),
 | |
|         renderSlot(_ctx.$slots, "default")
 | |
|       ], 2);
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const wrapper$2 = "_wrapper_jyurh_123";
 | |
| const canvas = "_canvas_jyurh_131";
 | |
| const style0$6 = {
 | |
|   wrapper: wrapper$2,
 | |
|   canvas
 | |
| };
 | |
| const cssModules$6 = {
 | |
|   "$style": style0$6
 | |
| };
 | |
| const WorkflowCanvas = /* @__PURE__ */ _export_sfc(_sfc_main$a, [["__cssModules", cssModules$6]]);
 | |
| function useExecutionData({ node }) {
 | |
|   const workflowsStore = useWorkflowsStore();
 | |
|   const workflowExecution = computed(() => {
 | |
|     return workflowsStore.getWorkflowExecution;
 | |
|   });
 | |
|   const workflowRunData = computed(() => {
 | |
|     if (workflowExecution.value === null) {
 | |
|       return null;
 | |
|     }
 | |
|     const executionData = workflowExecution.value.data;
 | |
|     if (!executionData?.resultData?.runData) {
 | |
|       return null;
 | |
|     }
 | |
|     return executionData.resultData.runData;
 | |
|   });
 | |
|   const hasNodeRun = computed(() => {
 | |
|     if (workflowsStore.subWorkflowExecutionError) return true;
 | |
|     return Boolean(
 | |
|       node.value && workflowRunData.value && Object.prototype.hasOwnProperty.bind(workflowRunData.value)(node.value.name)
 | |
|     );
 | |
|   });
 | |
|   return {
 | |
|     workflowExecution,
 | |
|     workflowRunData,
 | |
|     hasNodeRun
 | |
|   };
 | |
| }
 | |
| const _sfc_main$9 = /* @__PURE__ */ defineComponent({
 | |
|   __name: "ExperimentalNodeDetailsDrawer",
 | |
|   props: {
 | |
|     node: {},
 | |
|     nodes: {}
 | |
|   },
 | |
|   emits: ["openNdv"],
 | |
|   setup(__props, { emit: __emit }) {
 | |
|     const emit = __emit;
 | |
|     const expressionResolveCtx = useExpressionResolveCtx(computed(() => __props.node));
 | |
|     provide(ExpressionLocalResolveContextSymbol, expressionResolveCtx);
 | |
|     return (_ctx, _cache) => {
 | |
|       const _component_N8nIconButton = _sfc_main$c;
 | |
|       return openBlock(), createElementBlock("div", {
 | |
|         class: normalizeClass(_ctx.$style.component)
 | |
|       }, [
 | |
|         _ctx.nodes.length > 1 ? (openBlock(), createBlock(unref(N8nText), {
 | |
|           key: 0,
 | |
|           color: "text-base"
 | |
|         }, {
 | |
|           default: withCtx(() => [
 | |
|             createTextVNode(toDisplayString(_ctx.nodes.length) + " nodes selected ", 1)
 | |
|           ]),
 | |
|           _: 1
 | |
|         })) : _ctx.node ? (openBlock(), createBlock(_sfc_main$b, {
 | |
|           key: _ctx.node.id,
 | |
|           "node-id": _ctx.node.id
 | |
|         }, {
 | |
|           actions: withCtx(() => [
 | |
|             createVNode(_component_N8nIconButton, {
 | |
|               icon: "maximize-2",
 | |
|               type: "secondary",
 | |
|               text: "",
 | |
|               size: "mini",
 | |
|               "icon-size": "large",
 | |
|               "aria-label": "Expand",
 | |
|               onClick: _cache[0] || (_cache[0] = ($event) => emit("openNdv"))
 | |
|             })
 | |
|           ]),
 | |
|           _: 1
 | |
|         }, 8, ["node-id"])) : createCommentVNode("", true)
 | |
|       ], 2);
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const component$2 = "_component_1u8pj_123";
 | |
| const style0$5 = {
 | |
|   component: component$2
 | |
| };
 | |
| const cssModules$5 = {
 | |
|   "$style": style0$5
 | |
| };
 | |
| const ExperimentalNodeDetailsDrawer = /* @__PURE__ */ _export_sfc(_sfc_main$9, [["__cssModules", cssModules$5]]);
 | |
| const _sfc_main$8 = /* @__PURE__ */ defineComponent({
 | |
|   __name: "ExperimentalFocusPanelHeader",
 | |
|   props: {
 | |
|     node: {},
 | |
|     parameter: {},
 | |
|     isExecutable: { type: Boolean }
 | |
|   },
 | |
|   emits: ["execute", "openNdv", "clearParameter"],
 | |
|   setup(__props, { emit: __emit }) {
 | |
|     const nodeTypesStore = useNodeTypesStore();
 | |
|     const nodeType = computed(() => nodeTypesStore.getNodeType(__props.node.type, __props.node.typeVersion));
 | |
|     const emit = __emit;
 | |
|     return (_ctx, _cache) => {
 | |
|       return openBlock(), createBlock(unref(N8nText), {
 | |
|         tag: "div",
 | |
|         size: "small",
 | |
|         bold: "",
 | |
|         class: normalizeClass(_ctx.$style.component)
 | |
|       }, {
 | |
|         default: withCtx(() => [
 | |
|           createVNode(NodeIcon, {
 | |
|             "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), {
 | |
|                 size: "small",
 | |
|                 color: "text-base",
 | |
|                 bold: ""
 | |
|               }, {
 | |
|                 default: withCtx(() => [
 | |
|                   createTextVNode(toDisplayString(_ctx.node.name), 1)
 | |
|                 ]),
 | |
|                 _: 1
 | |
|               }),
 | |
|               createVNode(unref(N8nText), {
 | |
|                 size: "small",
 | |
|                 color: "text-light"
 | |
|               }, {
 | |
|                 default: withCtx(() => _cache[3] || (_cache[3] = [
 | |
|                   createTextVNode("/")
 | |
|                 ])),
 | |
|                 _: 1
 | |
|               }),
 | |
|               createTextVNode(" " + toDisplayString(_ctx.parameter.displayName), 1)
 | |
|             ], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
 | |
|               createTextVNode(toDisplayString(_ctx.node.name), 1)
 | |
|             ], 64))
 | |
|           ], 2),
 | |
|           _ctx.parameter ? (openBlock(), createBlock(unref(_sfc_main$c), {
 | |
|             key: 0,
 | |
|             icon: "x",
 | |
|             size: "small",
 | |
|             type: "tertiary",
 | |
|             text: "",
 | |
|             onClick: _cache[0] || (_cache[0] = ($event) => emit("clearParameter"))
 | |
|           })) : (openBlock(), createBlock(unref(_sfc_main$c), {
 | |
|             key: 1,
 | |
|             icon: "maximize-2",
 | |
|             size: "small",
 | |
|             type: "tertiary",
 | |
|             text: "",
 | |
|             onClick: _cache[1] || (_cache[1] = ($event) => emit("openNdv"))
 | |
|           })),
 | |
|           _ctx.isExecutable ? (openBlock(), createBlock(_sfc_main$d, {
 | |
|             key: 2,
 | |
|             "data-test-id": "node-execute-button",
 | |
|             "node-name": _ctx.node.name,
 | |
|             tooltip: `Execute ${_ctx.node.name}`,
 | |
|             size: "small",
 | |
|             icon: "play",
 | |
|             square: true,
 | |
|             "hide-label": true,
 | |
|             "telemetry-source": "focus",
 | |
|             onExecute: _cache[2] || (_cache[2] = ($event) => emit("execute"))
 | |
|           }, null, 8, ["node-name", "tooltip"])) : createCommentVNode("", true)
 | |
|         ]),
 | |
|         _: 1
 | |
|       }, 8, ["class"]);
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const component$1 = "_component_dktdl_123";
 | |
| const breadcrumbs = "_breadcrumbs_dktdl_131";
 | |
| const style0$4 = {
 | |
|   component: component$1,
 | |
|   breadcrumbs
 | |
| };
 | |
| const cssModules$4 = {
 | |
|   "$style": style0$4
 | |
| };
 | |
| const ExperimentalFocusPanelHeader = /* @__PURE__ */ _export_sfc(_sfc_main$8, [["__cssModules", cssModules$4]]);
 | |
| const _sfc_main$7 = /* @__PURE__ */ defineComponent({
 | |
|   ...{ name: "FocusPanel" },
 | |
|   __name: "FocusPanel",
 | |
|   props: {
 | |
|     isCanvasReadOnly: { type: Boolean }
 | |
|   },
 | |
|   emits: ["focus", "saveKeyboardShortcut"],
 | |
|   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 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();
 | |
|     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]?.id;
 | |
|       return selected ? workflowsStore.allNodes.find((n) => n.id === selected) : 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 === HTML_NODE_TYPE
 | |
|     );
 | |
|     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(() => workflowsStore.isNodeExecuting(node.value?.name ?? ""));
 | |
|     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);
 | |
|           }
 | |
|           void setFocus();
 | |
|           break;
 | |
|         }
 | |
|         case "addExpression": {
 | |
|           const newValue = formatAsExpression(
 | |
|             resolvedParameter.value.value,
 | |
|             resolvedParameter.value.parameter.type
 | |
|           );
 | |
|           valueChanged(typeof newValue === "string" ? newValue : newValue.value);
 | |
|           void 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);
 | |
|           }
 | |
|           void 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(() => {
 | |
|         void 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");
 | |
|       }
 | |
|     }
 | |
|     return (_ctx, _cache) => {
 | |
|       const _component_NodeExecuteButton = _sfc_main$d;
 | |
|       const _component_N8nIcon = N8nIcon;
 | |
|       const _component_ParameterOptions = __unplugin_components_2;
 | |
|       const _component_ExpressionEditorModalInput = __unplugin_components_3;
 | |
|       const _component_CodeNodeEditor = __unplugin_components_4;
 | |
|       const _component_HtmlEditor = __unplugin_components_5;
 | |
|       const _component_CssEditor = __unplugin_components_6;
 | |
|       const _component_SqlEditor = __unplugin_components_7;
 | |
|       const _component_JsEditor = __unplugin_components_8;
 | |
|       const _component_JsonEditor = __unplugin_components_9;
 | |
|       const _component_N8nRadioButtons = N8nRadioButtons;
 | |
|       return focusPanelActive.value ? (openBlock(), createElementBlock("div", {
 | |
|         key: 0,
 | |
|         ref: "wrapper",
 | |
|         class: normalizeClass(_ctx.$style.wrapper),
 | |
|         onKeydown: _cache[9] || (_cache[9] = withModifiers(() => {
 | |
|         }, ["stop"]))
 | |
|       }, [
 | |
|         createVNode(unref(N8nResizeWrapper), {
 | |
|           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, {
 | |
|                 key: 0,
 | |
|                 node: node.value,
 | |
|                 parameter: resolvedParameter.value?.parameter,
 | |
|                 "is-executable": isExecutable.value,
 | |
|                 onExecute,
 | |
|                 onOpenNdv,
 | |
|                 onClearParameter: closeFocusPanel
 | |
|               }, null, 8, ["node", "parameter", "is-executable"])) : createCommentVNode("", true),
 | |
|               resolvedParameter.value ? (openBlock(), createElementBlock("div", {
 | |
|                 key: 1,
 | |
|                 class: normalizeClass(_ctx.$style.content)
 | |
|               }, [
 | |
|                 !unref(experimentalNdvStore).isNdvInFocusPanelEnabled ? (openBlock(), createElementBlock("div", {
 | |
|                   key: 0,
 | |
|                   class: normalizeClass(_ctx.$style.tabHeader)
 | |
|                 }, [
 | |
|                   createBaseVNode("div", {
 | |
|                     class: normalizeClass(_ctx.$style.tabHeaderText)
 | |
|                   }, [
 | |
|                     createVNode(unref(N8nText), {
 | |
|                       color: "text-dark",
 | |
|                       size: "small"
 | |
|                     }, {
 | |
|                       default: withCtx(() => [
 | |
|                         createTextVNode(toDisplayString(resolvedParameter.value.parameter.displayName), 1)
 | |
|                       ]),
 | |
|                       _: 1
 | |
|                     }),
 | |
|                     createVNode(unref(N8nText), {
 | |
|                       color: "text-base",
 | |
|                       size: "xsmall"
 | |
|                     }, {
 | |
|                       default: withCtx(() => [
 | |
|                         createTextVNode(toDisplayString(resolvedParameter.value.node.name), 1)
 | |
|                       ]),
 | |
|                       _: 1
 | |
|                     })
 | |
|                   ], 2),
 | |
|                   createBaseVNode("div", {
 | |
|                     class: normalizeClass(_ctx.$style.buttonWrapper)
 | |
|                   }, [
 | |
|                     createVNode(_component_NodeExecuteButton, {
 | |
|                       "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(_component_N8nIcon, {
 | |
|                       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(InfoTip), {
 | |
|                         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(_component_ParameterOptions, {
 | |
|                       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), { color: "text-base" }, {
 | |
|                           default: withCtx(() => [
 | |
|                             createTextVNode(toDisplayString(unref(locale).baseText("nodeView.focusPanel.missingParameter")), 1)
 | |
|                           ]),
 | |
|                           _: 1
 | |
|                         })
 | |
|                       ], 2)
 | |
|                     ], 2)) : expressionModeEnabled.value ? (openBlock(), createBlock(_component_ExpressionEditorModalInput, {
 | |
|                       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(_component_CodeNodeEditor, {
 | |
|                         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(_component_HtmlEditor, {
 | |
|                         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(_component_CssEditor, {
 | |
|                         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(_component_SqlEditor, {
 | |
|                         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(_component_JsEditor, {
 | |
|                         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(_component_JsonEditor, {
 | |
|                         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), {
 | |
|                         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, {
 | |
|                 key: 2,
 | |
|                 node: node.value,
 | |
|                 nodes: unref(vueFlow).getSelectedNodes.value,
 | |
|                 onOpenNdv
 | |
|               }, null, 8, ["node", "nodes"])) : (openBlock(), createElementBlock("div", {
 | |
|                 key: 3,
 | |
|                 class: normalizeClass([_ctx.$style.content, _ctx.$style.emptyContent])
 | |
|               }, [
 | |
|                 createBaseVNode("div", {
 | |
|                   class: normalizeClass(_ctx.$style.emptyText)
 | |
|                 }, [
 | |
|                   createBaseVNode("div", {
 | |
|                     class: normalizeClass(_ctx.$style.focusParameterWrapper)
 | |
|                   }, [
 | |
|                     createBaseVNode("div", {
 | |
|                       class: normalizeClass(_ctx.$style.iconWrapper)
 | |
|                     }, [
 | |
|                       createVNode(_component_N8nIcon, {
 | |
|                         class: normalizeClass(_ctx.$style.forceHover),
 | |
|                         icon: "panel-right",
 | |
|                         size: "medium"
 | |
|                       }, null, 8, ["class"]),
 | |
|                       createVNode(_component_N8nIcon, {
 | |
|                         class: normalizeClass(_ctx.$style.pointerIcon),
 | |
|                         icon: "mouse-pointer",
 | |
|                         color: "text-dark",
 | |
|                         size: "large"
 | |
|                       }, null, 8, ["class"])
 | |
|                     ], 2),
 | |
|                     createVNode(_component_N8nIcon, {
 | |
|                       icon: "ellipsis-vertical",
 | |
|                       size: "small",
 | |
|                       color: "text-base"
 | |
|                     }),
 | |
|                     createVNode(_component_N8nRadioButtons, {
 | |
|                       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),
 | |
|                   createVNode(unref(N8nText), {
 | |
|                     color: "text-base",
 | |
|                     size: "medium",
 | |
|                     bold: true
 | |
|                   }, {
 | |
|                     default: withCtx(() => [
 | |
|                       createTextVNode(toDisplayString(unref(locale).baseText("nodeView.focusPanel.noParameters.title")), 1)
 | |
|                     ]),
 | |
|                     _: 1
 | |
|                   }),
 | |
|                   createVNode(unref(N8nText), {
 | |
|                     color: "text-base",
 | |
|                     size: "small"
 | |
|                   }, {
 | |
|                     default: withCtx(() => [
 | |
|                       createTextVNode(toDisplayString(unref(locale).baseText("nodeView.focusPanel.noParameters.subtitle")), 1)
 | |
|                     ]),
 | |
|                     _: 1
 | |
|                   })
 | |
|                 ], 2)
 | |
|               ], 2))
 | |
|             ], 2)
 | |
|           ]),
 | |
|           _: 1
 | |
|         }, 8, ["width", "max-width", "style", "onResize"])
 | |
|       ], 34)) : createCommentVNode("", true);
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const wrapper$1 = "_wrapper_1yhze_123";
 | |
| const container = "_container_1yhze_135";
 | |
| const content = "_content_1yhze_141";
 | |
| const emptyContent = "_emptyContent_1yhze_147";
 | |
| const emptyText = "_emptyText_1yhze_152";
 | |
| const focusParameterWrapper = "_focusParameterWrapper_1yhze_158";
 | |
| const iconWrapper$1 = "_iconWrapper_1yhze_165";
 | |
| const pointerIcon = "_pointerIcon_1yhze_169";
 | |
| const tabHeader = "_tabHeader_1yhze_179";
 | |
| const tabHeaderText = "_tabHeaderText_1yhze_186";
 | |
| const buttonWrapper = "_buttonWrapper_1yhze_191";
 | |
| const parameterDetailsWrapper = "_parameterDetailsWrapper_1yhze_196";
 | |
| const parameterOptionsWrapper = "_parameterOptionsWrapper_1yhze_203";
 | |
| const noExecutionDataTip = "_noExecutionDataTip_1yhze_207";
 | |
| const editorContainer = "_editorContainer_1yhze_210";
 | |
| const editor = "_editor_1yhze_210";
 | |
| const delayedShow = "_delayedShow_1yhze_225";
 | |
| const triggerShow = "_triggerShow_1yhze_1";
 | |
| const closeButton = "_closeButton_1yhze_236";
 | |
| const heightFull = "_heightFull_1yhze_240";
 | |
| const forceHover = "_forceHover_1yhze_244";
 | |
| const style0$3 = {
 | |
|   wrapper: wrapper$1,
 | |
|   container,
 | |
|   content,
 | |
|   emptyContent,
 | |
|   emptyText,
 | |
|   focusParameterWrapper,
 | |
|   iconWrapper: iconWrapper$1,
 | |
|   pointerIcon,
 | |
|   tabHeader,
 | |
|   tabHeaderText,
 | |
|   buttonWrapper,
 | |
|   parameterDetailsWrapper,
 | |
|   parameterOptionsWrapper,
 | |
|   noExecutionDataTip,
 | |
|   editorContainer,
 | |
|   editor,
 | |
|   delayedShow,
 | |
|   triggerShow,
 | |
|   closeButton,
 | |
|   heightFull,
 | |
|   forceHover
 | |
| };
 | |
| const cssModules$3 = {
 | |
|   "$style": style0$3
 | |
| };
 | |
| const FocusPanel = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["__cssModules", cssModules$3]]);
 | |
| const _sfc_main$6 = /* @__PURE__ */ defineComponent({
 | |
|   __name: "CanvasRunWorkflowButton",
 | |
|   props: {
 | |
|     selectedTriggerNodeName: {},
 | |
|     triggerNodes: {},
 | |
|     waitingForWebhook: { type: Boolean },
 | |
|     executing: { type: Boolean },
 | |
|     disabled: { type: Boolean },
 | |
|     getNodeType: { type: Function }
 | |
|   },
 | |
|   emits: ["mouseenter", "mouseleave", "execute", "selectTriggerNode"],
 | |
|   setup(__props, { emit: __emit }) {
 | |
|     const emit = __emit;
 | |
|     const props = __props;
 | |
|     const i18n = useI18n();
 | |
|     const selectableTriggerNodes = computed(
 | |
|       () => props.triggerNodes.filter((node) => !node.disabled && !isChatNode(node))
 | |
|     );
 | |
|     const label = computed(() => {
 | |
|       if (!props.executing) {
 | |
|         return i18n.baseText("nodeView.runButtonText.executeWorkflow");
 | |
|       }
 | |
|       if (props.waitingForWebhook) {
 | |
|         return i18n.baseText("nodeView.runButtonText.waitingForTriggerEvent");
 | |
|       }
 | |
|       return i18n.baseText("nodeView.runButtonText.executingWorkflow");
 | |
|     });
 | |
|     const actions = computed(
 | |
|       () => props.triggerNodes.filter((node) => !isChatNode(node)).toSorted((a, b) => {
 | |
|         const [aX, aY] = a.position;
 | |
|         const [bX, bY] = b.position;
 | |
|         return aY === bY ? aX - bX : aY - bY;
 | |
|       }).map((node) => ({
 | |
|         label: truncateBeforeLast(node.name, 50),
 | |
|         disabled: !!node.disabled || props.executing,
 | |
|         id: node.name,
 | |
|         checked: props.selectedTriggerNodeName === node.name
 | |
|       }))
 | |
|     );
 | |
|     const isSplitButton = computed(
 | |
|       () => selectableTriggerNodes.value.length > 1 && props.selectedTriggerNodeName !== void 0
 | |
|     );
 | |
|     function getNodeTypeByName(name) {
 | |
|       const node = props.triggerNodes.find((trigger) => trigger.name === name);
 | |
|       if (!node) {
 | |
|         return null;
 | |
|       }
 | |
|       return props.getNodeType(node.type, node.typeVersion);
 | |
|     }
 | |
|     return (_ctx, _cache) => {
 | |
|       const _component_NodeIcon = NodeIcon;
 | |
|       return openBlock(), createElementBlock("div", {
 | |
|         class: normalizeClass([_ctx.$style.component, isSplitButton.value ? _ctx.$style.split : ""])
 | |
|       }, [
 | |
|         createVNode(KeyboardShortcutTooltip, {
 | |
|           label: label.value,
 | |
|           shortcut: { metaKey: true, keys: ["↵"] },
 | |
|           disabled: _ctx.executing
 | |
|         }, {
 | |
|           default: withCtx(() => [
 | |
|             createVNode(unref(N8nButton), {
 | |
|               class: normalizeClass(_ctx.$style.button),
 | |
|               loading: _ctx.executing,
 | |
|               disabled: _ctx.disabled,
 | |
|               size: "large",
 | |
|               icon: "flask-conical",
 | |
|               type: "primary",
 | |
|               "data-test-id": "execute-workflow-button",
 | |
|               onMouseenter: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("mouseenter", $event)),
 | |
|               onMouseleave: _cache[1] || (_cache[1] = ($event) => _ctx.$emit("mouseleave", $event)),
 | |
|               onClick: _cache[2] || (_cache[2] = ($event) => emit("execute"))
 | |
|             }, {
 | |
|               default: withCtx(() => [
 | |
|                 createBaseVNode("span", {
 | |
|                   class: normalizeClass(_ctx.$style.buttonContent)
 | |
|                 }, [
 | |
|                   createTextVNode(toDisplayString(label.value) + " ", 1),
 | |
|                   isSplitButton.value ? (openBlock(), createBlock(unref(N8nText), {
 | |
|                     key: 0,
 | |
|                     class: normalizeClass(_ctx.$style.subText),
 | |
|                     bold: false
 | |
|                   }, {
 | |
|                     default: withCtx(() => [
 | |
|                       createVNode(unref(I18nT), {
 | |
|                         keypath: "nodeView.runButtonText.from",
 | |
|                         scope: "global"
 | |
|                       }, {
 | |
|                         nodeName: withCtx(() => [
 | |
|                           createVNode(unref(N8nText), {
 | |
|                             bold: "",
 | |
|                             size: "mini"
 | |
|                           }, {
 | |
|                             default: withCtx(() => [
 | |
|                               createTextVNode(toDisplayString(unref(truncateBeforeLast)(props.selectedTriggerNodeName ?? "", 25)), 1)
 | |
|                             ]),
 | |
|                             _: 1
 | |
|                           })
 | |
|                         ]),
 | |
|                         _: 1
 | |
|                       })
 | |
|                     ]),
 | |
|                     _: 1
 | |
|                   }, 8, ["class"])) : createCommentVNode("", true)
 | |
|                 ], 2)
 | |
|               ]),
 | |
|               _: 1
 | |
|             }, 8, ["class", "loading", "disabled"])
 | |
|           ]),
 | |
|           _: 1
 | |
|         }, 8, ["label", "disabled"]),
 | |
|         isSplitButton.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
 | |
|           createBaseVNode("div", {
 | |
|             role: "presentation",
 | |
|             class: normalizeClass(_ctx.$style.divider)
 | |
|           }, null, 2),
 | |
|           createVNode(unref(N8nActionDropdown), {
 | |
|             class: normalizeClass(_ctx.$style.menu),
 | |
|             items: actions.value,
 | |
|             disabled: _ctx.disabled,
 | |
|             placement: "top",
 | |
|             "extra-popper-class": _ctx.$style.menuPopper,
 | |
|             onSelect: _cache[3] || (_cache[3] = ($event) => emit("selectTriggerNode", $event))
 | |
|           }, {
 | |
|             activator: withCtx(() => [
 | |
|               createVNode(unref(N8nButton), {
 | |
|                 type: "primary",
 | |
|                 "icon-size": "large",
 | |
|                 disabled: _ctx.disabled,
 | |
|                 class: normalizeClass(_ctx.$style.chevron),
 | |
|                 "aria-label": "Select trigger node",
 | |
|                 icon: "chevron-down"
 | |
|               }, null, 8, ["disabled", "class"])
 | |
|             ]),
 | |
|             menuItem: withCtx((item) => [
 | |
|               createBaseVNode("div", {
 | |
|                 class: normalizeClass([_ctx.$style.menuItem, item.disabled ? _ctx.$style.disabled : ""])
 | |
|               }, [
 | |
|                 createVNode(_component_NodeIcon, {
 | |
|                   class: normalizeClass(_ctx.$style.menuIcon),
 | |
|                   size: 16,
 | |
|                   "node-type": getNodeTypeByName(item.id)
 | |
|                 }, null, 8, ["class", "node-type"]),
 | |
|                 createBaseVNode("span", null, [
 | |
|                   createVNode(unref(I18nT), {
 | |
|                     keypath: "nodeView.runButtonText.from",
 | |
|                     scope: "global"
 | |
|                   }, {
 | |
|                     nodeName: withCtx(() => [
 | |
|                       createVNode(unref(N8nText), {
 | |
|                         bold: "",
 | |
|                         size: "small"
 | |
|                       }, {
 | |
|                         default: withCtx(() => [
 | |
|                           createTextVNode(toDisplayString(item.label), 1)
 | |
|                         ]),
 | |
|                         _: 2
 | |
|                       }, 1024)
 | |
|                     ]),
 | |
|                     _: 2
 | |
|                   }, 1024)
 | |
|                 ])
 | |
|               ], 2)
 | |
|             ]),
 | |
|             _: 1
 | |
|           }, 8, ["class", "items", "disabled", "extra-popper-class"])
 | |
|         ], 64)) : createCommentVNode("", true)
 | |
|       ], 2);
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const component = "_component_3izac_123";
 | |
| const split = "_split_3izac_129";
 | |
| const button = "_button_3izac_129";
 | |
| const divider = "_divider_3izac_137";
 | |
| const chevron = "_chevron_3izac_142";
 | |
| const menu = "_menu_3izac_148";
 | |
| const menuPopper = "_menuPopper_3izac_152";
 | |
| const menuItem = "_menuItem_3izac_156";
 | |
| const disabled = "_disabled_3izac_162";
 | |
| const menuIcon = "_menuIcon_3izac_162";
 | |
| const buttonContent = "_buttonContent_3izac_166";
 | |
| const subText = "_subText_3izac_173";
 | |
| const style0$2 = {
 | |
|   component,
 | |
|   split,
 | |
|   button,
 | |
|   divider,
 | |
|   chevron,
 | |
|   menu,
 | |
|   menuPopper,
 | |
|   menuItem,
 | |
|   disabled,
 | |
|   menuIcon,
 | |
|   buttonContent,
 | |
|   subText
 | |
| };
 | |
| const cssModules$2 = {
 | |
|   "$style": style0$2
 | |
| };
 | |
| const CanvasRunWorkflowButton = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["__cssModules", cssModules$2]]);
 | |
| const state = reactive({
 | |
|   customActions: {},
 | |
|   delegatedClickHandler: null
 | |
| });
 | |
| function useGlobalLinkActions() {
 | |
|   function registerCustomAction({ key, action }) {
 | |
|     state.customActions[key] = action;
 | |
|   }
 | |
|   function unregisterCustomAction(key) {
 | |
|     const { [key]: _, ...rest } = state.customActions;
 | |
|     state.customActions = rest;
 | |
|   }
 | |
|   function getElementAttributes(element) {
 | |
|     const attributesObject = {};
 | |
|     for (let i = 0; i < element.attributes.length; i++) {
 | |
|       const attr = element.attributes[i];
 | |
|       if (attr.name.startsWith("data-action-parameter-")) {
 | |
|         attributesObject[attr.name.replace("data-action-parameter-", "")] = attr.value;
 | |
|       }
 | |
|     }
 | |
|     return attributesObject;
 | |
|   }
 | |
|   function delegateClick(e) {
 | |
|     const clickedElement = e.target;
 | |
|     if (!(clickedElement instanceof Element) || clickedElement.tagName !== "A") return;
 | |
|     const actionAttribute = clickedElement.getAttribute("data-action");
 | |
|     if (actionAttribute && typeof availableActions.value[actionAttribute] === "function") {
 | |
|       e.preventDefault();
 | |
|       const elementAttributes = getElementAttributes(clickedElement);
 | |
|       availableActions.value[actionAttribute](elementAttributes);
 | |
|     }
 | |
|   }
 | |
|   function reload() {
 | |
|     if (window.top) {
 | |
|       window.top.location.reload();
 | |
|     } else {
 | |
|       window.location.reload();
 | |
|     }
 | |
|   }
 | |
|   const availableActions = computed(() => ({
 | |
|     reload,
 | |
|     ...state.customActions
 | |
|   }));
 | |
|   onMounted(() => {
 | |
|     if (state.delegatedClickHandler) return;
 | |
|     state.delegatedClickHandler = delegateClick;
 | |
|     window.addEventListener("click", delegateClick);
 | |
|     globalLinkActionsEventBus.on("registerGlobalLinkAction", registerCustomAction);
 | |
|   });
 | |
|   onUnmounted(() => {
 | |
|     window.removeEventListener("click", delegateClick);
 | |
|     state.delegatedClickHandler = null;
 | |
|     globalLinkActionsEventBus.off("registerGlobalLinkAction", registerCustomAction);
 | |
|   });
 | |
|   return {
 | |
|     registerCustomAction,
 | |
|     unregisterCustomAction
 | |
|   };
 | |
| }
 | |
| const _sfc_main$5 = /* @__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) => {
 | |
|       const _component_N8nIconButton = _sfc_main$c;
 | |
|       return openBlock(), createBlock(_component_N8nIconButton, {
 | |
|         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"]);
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const _sfc_main$4 = /* @__PURE__ */ defineComponent({
 | |
|   __name: "CanvasStopWaitingForWebhookButton",
 | |
|   setup(__props) {
 | |
|     const i18n = useI18n();
 | |
|     return (_ctx, _cache) => {
 | |
|       const _component_N8nIconButton = _sfc_main$c;
 | |
|       return openBlock(), createBlock(_component_N8nIconButton, {
 | |
|         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"]);
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const _sfc_main$3 = /* @__PURE__ */ defineComponent({
 | |
|   ...{
 | |
|     name: "CanvasThinkingPill"
 | |
|   },
 | |
|   __name: "CanvasThinkingPill",
 | |
|   props: {
 | |
|     showStop: { type: Boolean }
 | |
|   },
 | |
|   emits: ["stop"],
 | |
|   setup(__props, { emit: __emit }) {
 | |
|     const emit = __emit;
 | |
|     const { t } = useI18n$1();
 | |
|     const $style = useCssModule();
 | |
|     return (_ctx, _cache) => {
 | |
|       return openBlock(), createElementBlock("div", {
 | |
|         class: normalizeClass(unref($style).thinkingPill)
 | |
|       }, [
 | |
|         createBaseVNode("div", {
 | |
|           class: normalizeClass(unref($style).iconWrapper)
 | |
|         }, [
 | |
|           createVNode(_sfc_main$e, { theme: "blank" })
 | |
|         ], 2),
 | |
|         createBaseVNode("span", {
 | |
|           class: normalizeClass(unref($style).text)
 | |
|         }, [
 | |
|           createTextVNode(toDisplayString(unref(t)("aiAssistant.builder.canvas.thinking")) + " ", 1),
 | |
|           _ctx.showStop ? (openBlock(), createBlock(unref(N8nButton), {
 | |
|             key: 0,
 | |
|             class: normalizeClass(unref($style).stopButton),
 | |
|             label: "Stop",
 | |
|             type: "secondary",
 | |
|             size: "mini",
 | |
|             onClick: _cache[0] || (_cache[0] = ($event) => emit("stop"))
 | |
|           }, null, 8, ["class"])) : createCommentVNode("", true)
 | |
|         ], 2)
 | |
|       ], 2);
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const thinkingPill$1 = "_thinkingPill_nk220_123";
 | |
| const iconWrapper = "_iconWrapper_nk220_139";
 | |
| const stopButton = "_stopButton_nk220_149";
 | |
| const text = "_text_nk220_153";
 | |
| const style0$1 = {
 | |
|   thinkingPill: thinkingPill$1,
 | |
|   iconWrapper,
 | |
|   stopButton,
 | |
|   text
 | |
| };
 | |
| const cssModules$1 = {
 | |
|   "$style": style0$1
 | |
| };
 | |
| const CanvasThinkingPill = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__cssModules", cssModules$1]]);
 | |
| const _hoisted_1 = { "data-action": "reload" };
 | |
| const _hoisted_2 = {
 | |
|   href: "https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.wait/",
 | |
|   target: "_blank"
 | |
| };
 | |
| const _sfc_main$2 = /* @__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)
 | |
|       ]);
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const _sfc_main$1 = /* @__PURE__ */ defineComponent({
 | |
|   __name: "CanvasChatButton",
 | |
|   props: {
 | |
|     label: {},
 | |
|     type: {}
 | |
|   },
 | |
|   setup(__props) {
 | |
|     return (_ctx, _cache) => {
 | |
|       const _component_N8nButton = N8nButton;
 | |
|       return openBlock(), createBlock(_component_N8nButton, {
 | |
|         label: _ctx.label,
 | |
|         size: "large",
 | |
|         icon: "message-circle",
 | |
|         type: _ctx.type,
 | |
|         "data-test-id": "workflow-chat-button"
 | |
|       }, null, 8, ["label", "type"]);
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const _sfc_main = /* @__PURE__ */ defineComponent({
 | |
|   ...{
 | |
|     name: "NodeView"
 | |
|   },
 | |
|   __name: "NodeView",
 | |
|   setup(__props) {
 | |
|     const LazyNodeCreation = defineAsyncComponent(
 | |
|       async () => await __vitePreload(() => import("./NodeCreation-iNUuiza-.js"), true ? __vite__mapDeps([0,1,2,3]) : void 0)
 | |
|     );
 | |
|     const LazyNodeDetailsView = defineAsyncComponent(
 | |
|       async () => await __vitePreload(() => import("./NodeDetailsView-BKEGFeZ7.js"), true ? __vite__mapDeps([4,1,2,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]) : void 0)
 | |
|     );
 | |
|     const LazyNodeDetailsViewV2 = defineAsyncComponent(
 | |
|       async () => await __vitePreload(() => import("./NodeDetailsViewV2-XPdbzrLu.js"), true ? __vite__mapDeps([20,1,2,5,6,7,8,9,10,11,12,13,14,15,16,17,18,21]) : void 0)
 | |
|     );
 | |
|     const LazySetupWorkflowCredentialsButton = defineAsyncComponent(
 | |
|       async () => await __vitePreload(() => import("./SetupWorkflowCredentialsButton-DMIEMB5C.js"), true ? __vite__mapDeps([22,1,2]) : void 0)
 | |
|     );
 | |
|     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 workflowHelpers = useWorkflowHelpers();
 | |
|     const workflowSaving = useWorkflowSaving({ router });
 | |
|     const nodeHelpers = useNodeHelpers();
 | |
|     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 templatesStore = useTemplatesStore();
 | |
|     const builderStore = useBuilderStore();
 | |
|     const foldersStore = useFoldersStore();
 | |
|     const posthogStore = usePostHog();
 | |
|     const agentRequestStore = useAgentRequestStore();
 | |
|     const logsStore = useLogsStore();
 | |
|     const aiTemplatesStarterCollectionStore = useAITemplatesStarterCollectionStore();
 | |
|     const readyToRunWorkflowsStore = useReadyToRunWorkflowsStore();
 | |
|     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,
 | |
|       addNodes,
 | |
|       importTemplate,
 | |
|       revertAddNode,
 | |
|       createConnection,
 | |
|       revertCreateConnection,
 | |
|       deleteConnection,
 | |
|       revertDeleteConnection,
 | |
|       revalidateNodeInputConnections,
 | |
|       revalidateNodeOutputConnections,
 | |
|       setNodeActiveByName,
 | |
|       clearNodeActive,
 | |
|       addConnections,
 | |
|       tryToOpenSubworkflowInNewTab,
 | |
|       importWorkflowData,
 | |
|       fetchWorkflowDataFromUrl,
 | |
|       resetWorkspace,
 | |
|       initializeWorkspace,
 | |
|       openExecution,
 | |
|       editableWorkflow,
 | |
|       editableWorkflowObject,
 | |
|       lastClickPosition,
 | |
|       startChat
 | |
|     } = useCanvasOperations();
 | |
|     const { extractWorkflow } = useWorkflowExtraction();
 | |
|     const { applyExecutionData } = useExecutionDebugging();
 | |
|     useClipboard({ onPaste: onClipboardPaste });
 | |
|     useKeybindings({
 | |
|       ctrl_alt_o: () => uiStore.openModal(ABOUT_MODAL_KEY)
 | |
|     });
 | |
|     const isLoading = ref(true);
 | |
|     const isBlankRedirect = ref(false);
 | |
|     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 workflowIdParam = route.params.name;
 | |
|       return [PLACEHOLDER_EMPTY_WORKFLOW_ID, NEW_WORKFLOW_ID].includes(workflowIdParam) ? void 0 : workflowIdParam;
 | |
|     });
 | |
|     const routeNodeId = computed(() => route.params.nodeId);
 | |
|     const isNewWorkflowRoute = computed(() => route.name === VIEWS.NEW_WORKFLOW || !workflowId.value);
 | |
|     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(
 | |
|       () => posthogStore.isVariantEnabled(
 | |
|         NDV_UI_OVERHAUL_EXPERIMENT.name,
 | |
|         NDV_UI_OVERHAUL_EXPERIMENT.variant
 | |
|       )
 | |
|     );
 | |
|     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.fetchAllCredentials(),
 | |
|           credentialsStore.fetchCredentialTypes(true)
 | |
|         ];
 | |
|         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);
 | |
|         void 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 === "workflowSave") {
 | |
|         uiStore.stateIsDirty = false;
 | |
|         await router.replace({
 | |
|           query: { ...route.query, action: void 0 }
 | |
|         });
 | |
|         return;
 | |
|       }
 | |
|       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) {
 | |
|           void runEntireWorkflow("node", evaluationTriggerNode.value.name);
 | |
|         }
 | |
|       }
 | |
|       const isAlreadyInitialized = !force && initializedWorkflowId.value && [NEW_WORKFLOW_ID, workflowId.value].includes(initializedWorkflowId.value);
 | |
|       if (isBlankRedirect.value) {
 | |
|         isBlankRedirect.value = 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 openTemplateFromWorkflowJSON(workflow);
 | |
|         } else {
 | |
|           await openWorkflowTemplate(templateId.toString());
 | |
|         }
 | |
|       } else if (isWorkflowRoute.value) {
 | |
|         if (!isAlreadyInitialized) {
 | |
|           historyStore.reset();
 | |
|           if (!isDemoRoute.value) {
 | |
|             await loadCredentials();
 | |
|           }
 | |
|           if (isNewWorkflowRoute.value || !workflowId.value) {
 | |
|             if (route.meta?.nodeView === true) {
 | |
|               await initializeWorkspaceForNewWorkflow();
 | |
|             }
 | |
|             return;
 | |
|           }
 | |
|           await initializeWorkspaceForExistingWorkflow(workflowId.value);
 | |
|           void nextTick(() => {
 | |
|             updateNodesIssues();
 | |
|           });
 | |
|         }
 | |
|         if (route.name === VIEWS.EXECUTION_DEBUG) {
 | |
|           await initializeDebugMode();
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     async function initializeWorkspaceForNewWorkflow() {
 | |
|       resetWorkspace();
 | |
|       const parentFolderId = route.query.parentFolderId;
 | |
|       await workflowsStore.getNewWorkflowDataAndMakeShareable(
 | |
|         void 0,
 | |
|         projectsStore.currentProjectId,
 | |
|         parentFolderId
 | |
|       );
 | |
|       if (projectsStore.currentProjectId) {
 | |
|         await fetchAndSetProject(projectsStore.currentProjectId);
 | |
|       }
 | |
|       await fetchAndSetParentFolder(parentFolderId);
 | |
|       uiStore.nodeViewInitialized = true;
 | |
|       initializedWorkflowId.value = NEW_WORKFLOW_ID;
 | |
|     }
 | |
|     async function fetchAndSetParentFolder(folderId) {
 | |
|       if (folderId) {
 | |
|         let parentFolder = foldersStore.getCachedFolder(folderId);
 | |
|         if (!parentFolder && projectsStore.currentProjectId) {
 | |
|           await foldersStore.getFolderPath(projectsStore.currentProjectId, folderId);
 | |
|           parentFolder = foldersStore.getCachedFolder(folderId);
 | |
|         }
 | |
|         if (parentFolder) {
 | |
|           workflowsStore.setParentFolder({
 | |
|             ...parentFolder,
 | |
|             parentFolderId: parentFolder.parentFolder ?? null
 | |
|           });
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     async function fetchAndSetProject(projectId) {
 | |
|       if (!projectsStore.currentProject) {
 | |
|         const project = await projectsStore.fetchProject(projectId);
 | |
|         projectsStore.setCurrentProject(project);
 | |
|       }
 | |
|     }
 | |
|     async function initializeWorkspaceForExistingWorkflow(id) {
 | |
|       try {
 | |
|         const workflowData = await workflowsStore.fetchWorkflow(id);
 | |
|         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);
 | |
|       } 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"));
 | |
|         void router.push({
 | |
|           name: VIEWS.NEW_WORKFLOW
 | |
|         });
 | |
|       } finally {
 | |
|         uiStore.nodeViewInitialized = true;
 | |
|         initializedWorkflowId.value = workflowId.value;
 | |
|       }
 | |
|     }
 | |
|     function updateNodesIssues() {
 | |
|       nodeHelpers.updateNodesInputIssues();
 | |
|       nodeHelpers.updateNodesCredentialsIssues();
 | |
|       nodeHelpers.updateNodesParameterIssues();
 | |
|     }
 | |
|     function openWorkflow(data) {
 | |
|       resetWorkspace();
 | |
|       workflowHelpers.setDocumentTitle(data.name, "IDLE");
 | |
|       initializeWorkspace(data);
 | |
|       void 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
 | |
|         }
 | |
|       );
 | |
|     }
 | |
|     async function openTemplateFromWorkflowJSON(workflow) {
 | |
|       if (!workflow.nodes || !workflow.connections) {
 | |
|         toast.showError(
 | |
|           new Error(i18n.baseText("nodeView.couldntLoadWorkflow.invalidWorkflowObject")),
 | |
|           i18n.baseText("nodeView.couldntImportWorkflow")
 | |
|         );
 | |
|         await router.replace({ name: VIEWS.NEW_WORKFLOW });
 | |
|         return;
 | |
|       }
 | |
|       resetWorkspace();
 | |
|       canvasStore.startLoading();
 | |
|       canvasStore.setLoadingText(i18n.baseText("nodeView.loadingTemplate"));
 | |
|       workflowsStore.currentWorkflowExecutions = [];
 | |
|       executionsStore.activeExecution = null;
 | |
|       isBlankRedirect.value = true;
 | |
|       const templateId = workflow.meta.templateId;
 | |
|       const parentFolderId = route.query.parentFolderId;
 | |
|       await router.replace({
 | |
|         name: VIEWS.NEW_WORKFLOW,
 | |
|         query: { templateId, parentFolderId }
 | |
|       });
 | |
|       await importTemplate({
 | |
|         id: templateId,
 | |
|         name: workflow.name,
 | |
|         workflow
 | |
|       });
 | |
|       uiStore.stateIsDirty = true;
 | |
|       canvasStore.stopLoading();
 | |
|       fitView();
 | |
|     }
 | |
|     async function openWorkflowTemplate(templateId) {
 | |
|       resetWorkspace();
 | |
|       canvasStore.startLoading();
 | |
|       canvasStore.setLoadingText(i18n.baseText("nodeView.loadingTemplate"));
 | |
|       workflowsStore.currentWorkflowExecutions = [];
 | |
|       executionsStore.activeExecution = null;
 | |
|       let data;
 | |
|       try {
 | |
|         void externalHooks.run("template.requested", { templateId });
 | |
|         data = await templatesStore.getFixedWorkflowTemplate(templateId);
 | |
|         if (!data) {
 | |
|           throw new Error(
 | |
|             i18n.baseText("nodeView.workflowTemplateWithIdCouldNotBeFound", {
 | |
|               interpolate: { templateId }
 | |
|             })
 | |
|           );
 | |
|         }
 | |
|       } catch (error) {
 | |
|         toast.showError(error, i18n.baseText("nodeView.couldntImportWorkflow"));
 | |
|         await router.replace({ name: VIEWS.NEW_WORKFLOW });
 | |
|         return;
 | |
|       }
 | |
|       trackOpenWorkflowTemplate(templateId);
 | |
|       isBlankRedirect.value = true;
 | |
|       await router.replace({ name: VIEWS.NEW_WORKFLOW, query: { templateId } });
 | |
|       await importTemplate({ id: templateId, name: data.name, workflow: data.workflow });
 | |
|       uiStore.stateIsDirty = true;
 | |
|       canvasStore.stopLoading();
 | |
|       void externalHooks.run("template.open", {
 | |
|         templateId,
 | |
|         templateName: data.name,
 | |
|         workflow: data.workflow
 | |
|       });
 | |
|       fitView();
 | |
|     }
 | |
|     function trackOpenWorkflowTemplate(templateId) {
 | |
|       telemetry.track("User inserted workflow template", {
 | |
|         source: "workflow",
 | |
|         template_id: tryToParseNumber(templateId),
 | |
|         wf_template_repo_session_id: templatesStore.previousSessionId
 | |
|       });
 | |
|     }
 | |
|     const triggerNodes = computed(() => {
 | |
|       return editableWorkflow.value.nodes.filter(
 | |
|         (node) => node.type === START_NODE_TYPE || nodeTypesStore.isTriggerNode(node.type)
 | |
|       );
 | |
|     });
 | |
|     const containsTriggerNodes = computed(() => triggerNodes.value.length > 0);
 | |
|     const allTriggerNodesDisabled = computed(() => {
 | |
|       const disabledTriggerNodes = triggerNodes.value.filter((node) => node.disabled);
 | |
|       return disabledTriggerNodes.length === triggerNodes.value.length;
 | |
|     });
 | |
|     function onTidyUp(event) {
 | |
|       tidyUp(event);
 | |
|     }
 | |
|     function onExtractWorkflow(nodeIds) {
 | |
|       void 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) {
 | |
|         const didOpen = tryToOpenSubworkflowInNewTab(id);
 | |
|         if (didOpen) {
 | |
|           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)) {
 | |
|         const importConfirm = 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"
 | |
|             )
 | |
|           }
 | |
|         );
 | |
|         if (importConfirm !== MODAL_CONFIRM) {
 | |
|           return;
 | |
|         }
 | |
|         workflowData = await fetchWorkflowDataFromUrl(plainTextData);
 | |
|       } else {
 | |
|         workflowData = jsonParse(plainTextData, { fallbackValue: null });
 | |
|       }
 | |
|       if (!workflowData) {
 | |
|         return;
 | |
|       }
 | |
|       const result = await importWorkflowData(workflowData, "paste", {
 | |
|         importTags: false,
 | |
|         viewport: viewportBoundaries.value
 | |
|       });
 | |
|       selectNodes(result.nodes?.map((node) => node.id) ?? []);
 | |
|     }
 | |
|     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
 | |
|       });
 | |
|       selectNodes(newIds);
 | |
|     }
 | |
|     function onPinNodes(ids, source) {
 | |
|       if (!checkIfEditingIsAllowed()) {
 | |
|         return;
 | |
|       }
 | |
|       toggleNodesPinned(ids, source);
 | |
|     }
 | |
|     async function onSaveWorkflow() {
 | |
|       const workflowIsSaved = !uiStore.stateIsDirty && !workflowsStore.isNewWorkflow;
 | |
|       const workflowIsArchived = workflowsStore.workflow.isArchived;
 | |
|       if (workflowIsSaved || workflowIsArchived) {
 | |
|         return;
 | |
|       }
 | |
|       const saved = await workflowSaving.saveCurrentWorkflow();
 | |
|       if (saved) {
 | |
|         canvasEventBus.emit("saved:workflow");
 | |
|       }
 | |
|     }
 | |
|     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) {
 | |
|         void 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();
 | |
|         const promptResponse = await promptResponsePromise;
 | |
|         if (promptResponse.action === MODAL_CONFIRM) {
 | |
|           await renameNode(currentName, promptResponse.value, { trackHistory: true });
 | |
|         }
 | |
|       } 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) {
 | |
|         options = { workflowId: workflowId.value };
 | |
|       } else {
 | |
|         const queryParam = typeof route.query?.projectId === "string" ? route.query?.projectId : void 0;
 | |
|         const projectId = queryParam ?? 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) {
 | |
|       const preventDefault = (mouseEvent?.target).classList?.contains("clickable");
 | |
|       if (preventDefault) {
 | |
|         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();
 | |
|       initializeWorkspace({
 | |
|         ...workflowData,
 | |
|         nodes: getNodesWithNormalizedPosition(workflowData.nodes)
 | |
|       });
 | |
|       fitView();
 | |
|     }
 | |
|     async function onImportWorkflowDataEvent(data) {
 | |
|       const workflowData = data.data;
 | |
|       await importWorkflowData(workflowData, "file", {
 | |
|         viewport: viewportBoundaries.value,
 | |
|         regenerateIds: data.regenerateIds === true || data.regenerateIds === void 0
 | |
|       });
 | |
|       fitView();
 | |
|       selectNodes(workflowData.nodes?.map((node) => node.id) ?? []);
 | |
|       if (data.tidyUp) {
 | |
|         const nodesIdsToTidyUp = data.nodesIdsToTidyUp;
 | |
|         setTimeout(() => {
 | |
|           canvasEventBus.emit("tidyUp", {
 | |
|             source: "import-workflow-data",
 | |
|             nodeIdsFilter: nodesIdsToTidyUp
 | |
|           });
 | |
|         }, 0);
 | |
|       }
 | |
|     }
 | |
|     async function onImportWorkflowUrlEvent(data) {
 | |
|       const workflowData = await fetchWorkflowDataFromUrl(data.url);
 | |
|       if (!workflowData) {
 | |
|         return;
 | |
|       }
 | |
|       await importWorkflowData(workflowData, "url", {
 | |
|         viewport: viewportBoundaries.value
 | |
|       });
 | |
|       fitView();
 | |
|       selectNodes(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);
 | |
|     }
 | |
|     async function onAddNodesAndConnections({ nodes, connections }, dragAndDrop = false, position) {
 | |
|       if (!checkIfEditingIsAllowed()) {
 | |
|         return;
 | |
|       }
 | |
|       const addedNodes = await addNodes(nodes, {
 | |
|         dragAndDrop,
 | |
|         position,
 | |
|         viewport: viewportBoundaries.value,
 | |
|         trackHistory: true,
 | |
|         telemetry: true
 | |
|       });
 | |
|       const offsetIndex = editableWorkflow.value.nodes.length - nodes.length;
 | |
|       const mappedConnections = connections.map(({ from, to }) => {
 | |
|         const fromNode = editableWorkflow.value.nodes[offsetIndex + from.nodeIndex];
 | |
|         const toNode = editableWorkflow.value.nodes[offsetIndex + to.nodeIndex];
 | |
|         const type = from.type ?? to.type ?? NodeConnectionTypes.Main;
 | |
|         return {
 | |
|           source: fromNode.id,
 | |
|           sourceHandle: createCanvasConnectionHandleString({
 | |
|             mode: CanvasConnectionMode.Output,
 | |
|             type: isValidNodeConnectionType(type) ? type : NodeConnectionTypes.Main,
 | |
|             index: from.outputIndex ?? 0
 | |
|           }),
 | |
|           target: toNode.id,
 | |
|           targetHandle: createCanvasConnectionHandleString({
 | |
|             mode: CanvasConnectionMode.Input,
 | |
|             type: isValidNodeConnectionType(type) ? type : NodeConnectionTypes.Main,
 | |
|             index: to.inputIndex ?? 0
 | |
|           }),
 | |
|           data: {
 | |
|             source: {
 | |
|               index: from.outputIndex ?? 0,
 | |
|               type
 | |
|             },
 | |
|             target: {
 | |
|               index: to.inputIndex ?? 0,
 | |
|               type
 | |
|             }
 | |
|           }
 | |
|         };
 | |
|       });
 | |
|       await addConnections(mappedConnections);
 | |
|       uiStore.resetLastInteractedWith();
 | |
|       if (addedNodes.length > 0) {
 | |
|         selectNodes([addedNodes[addedNodes.length - 1].id]);
 | |
|       }
 | |
|     }
 | |
|     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 && !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() {
 | |
|       void onAddNodesAndConnections({ nodes: [{ type: STICKY_NODE_TYPE }], connections: [] });
 | |
|     }
 | |
|     function onClickConnectionAdd(connection) {
 | |
|       nodeCreatorStore.openNodeCreatorForConnectingNode({
 | |
|         connection,
 | |
|         eventSource: NODE_CREATOR_OPEN_SOURCES.NODE_CONNECTION_ACTION
 | |
|       });
 | |
|     }
 | |
|     const workflowPermissions = computed(() => {
 | |
|       return workflowId.value ? getResourcePermissions(workflowsStore.getWorkflowById(workflowId.value)?.scopes).workflow : {};
 | |
|     });
 | |
|     const projectPermissions = computed(() => {
 | |
|       const project = route.query?.projectId ? projectsStore.myProjects.find((p) => p.id === route.query.projectId) : projectsStore.currentProject ?? projectsStore.personalProject;
 | |
|       return getResourcePermissions(project?.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);
 | |
|         void runWorkflow({ destinationNode: node.name, source: "Node.executeNode" });
 | |
|       }
 | |
|     }
 | |
|     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);
 | |
|       void externalHooks.run("nodeView.onRunNode", telemetryPayload);
 | |
|     }
 | |
|     async function onOpenExecution(executionId, nodeId) {
 | |
|       canvasStore.startLoading();
 | |
|       resetWorkspace();
 | |
|       await initializeData();
 | |
|       const data = await openExecution(executionId, nodeId);
 | |
|       if (!data) {
 | |
|         return;
 | |
|       }
 | |
|       void nextTick(() => {
 | |
|         updateNodesIssues();
 | |
|       });
 | |
|       canvasStore.stopLoading();
 | |
|       fitView();
 | |
|       canvasEventBus.emit("open:execution", data);
 | |
|       void 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(_sfc_main$2),
 | |
|           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) => [MANUAL_CHAT_TRIGGER_NODE_TYPE, CHAT_TRIGGER_NODE_TYPE].includes(node.type) && node.disabled !== true
 | |
|       );
 | |
|     });
 | |
|     const isOnlyChatTriggerNodeActive = computed(() => {
 | |
|       return triggerNodes.value.every((node) => node.disabled || node.type === CHAT_TRIGGER_NODE_TYPE);
 | |
|     });
 | |
|     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()
 | |
|         ]);
 | |
|         if (workflowId.value && !uiStore.stateIsDirty) {
 | |
|           const workflowData = await workflowsStore.fetchWorkflow(workflowId.value);
 | |
|           if (workflowData) {
 | |
|             workflowHelpers.setDocumentTitle(workflowData.name, "IDLE");
 | |
|             openWorkflow(workflowData);
 | |
|           }
 | |
|         }
 | |
|       } catch (error) {
 | |
|         console.error(error);
 | |
|       }
 | |
|     }
 | |
|     function addSourceControlEventBindings() {
 | |
|       sourceControlEventBus.on("pull", onSourceControlPull);
 | |
|     }
 | |
|     function removeSourceControlEventBindings() {
 | |
|       sourceControlEventBus.off("pull", onSourceControlPull);
 | |
|     }
 | |
|     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 {
 | |
|             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 {
 | |
|             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 (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)) {
 | |
|         void nextTick(async () => {
 | |
|           resetWorkspace();
 | |
|           uiStore.stateIsDirty = false;
 | |
|           await router.replace({ name: VIEWS.HOMEPAGE });
 | |
|         });
 | |
|       }
 | |
|     }
 | |
|     async function initializeDebugMode() {
 | |
|       workflowHelpers.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 fitView() {
 | |
|       setTimeout(() => canvasEventBus.emit("fitView"));
 | |
|     }
 | |
|     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) {
 | |
|         const insertNodePosition = [position.x, position.y];
 | |
|         await onAddNodesAndConnections(dropData, true, insertNodePosition);
 | |
|         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();
 | |
|           void nextTick(() => {
 | |
|             void onOpenNodeCreatorForTriggerNodes(NODE_CREATOR_OPEN_SOURCES.TAB);
 | |
|           });
 | |
|         }
 | |
|       });
 | |
|     }
 | |
|     function unregisterCustomActions() {
 | |
|       unregisterCustomAction("openNodeDetail");
 | |
|       unregisterCustomAction("openSelectiveNodeCreator");
 | |
|       unregisterCustomAction("showNodeCreator");
 | |
|     }
 | |
|     function showAddFirstStepIfEnabled() {
 | |
|       if (uiStore.addFirstStepOnLoad) {
 | |
|         void 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"
 | |
|         });
 | |
|         void router.replace({
 | |
|           name: route.name,
 | |
|           params: { name: workflowId.value }
 | |
|         });
 | |
|       }
 | |
|     }
 | |
|     watch(
 | |
|       () => route.name,
 | |
|       async (newRouteName, oldRouteName) => {
 | |
|         const force = newRouteName === VIEWS.NEW_WORKFLOW && oldRouteName === VIEWS.WORKFLOW || newRouteName === VIEWS.WORKFLOW && oldRouteName === VIEWS.NEW_WORKFLOW;
 | |
|         await initializeRoute(force);
 | |
|       }
 | |
|     );
 | |
|     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 aiPromptItem = {
 | |
|           id: CanvasNodeRenderType.AIPrompt,
 | |
|           name: CanvasNodeRenderType.AIPrompt,
 | |
|           type: CanvasNodeRenderType.AIPrompt,
 | |
|           typeVersion: 1,
 | |
|           position: [-690, -15],
 | |
|           parameters: {},
 | |
|           draggable: false
 | |
|         };
 | |
|         fallbackNodes.value = builderStore.isAIBuilderEnabled && builderStore.isAssistantEnabled && builderStore.assistantMessages.length === 0 ? [aiPromptItem] : [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 }
 | |
|           });
 | |
|         }
 | |
|       }
 | |
|     );
 | |
|     onBeforeRouteLeave(async (to, from, next) => {
 | |
|       const toNodeViewTab = getNodeViewTab(to);
 | |
|       if (toNodeViewTab === MAIN_HEADER_TABS.EXECUTIONS || from.name === VIEWS.TEMPLATE_IMPORT || toNodeViewTab === MAIN_HEADER_TABS.WORKFLOW && from.name === VIEWS.EXECUTION_DEBUG || isReadOnlyEnvironment.value) {
 | |
|         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;
 | |
|           }
 | |
|           workflowsStore.setWorkflowId(PLACEHOLDER_EMPTY_WORKFLOW_ID);
 | |
|           return true;
 | |
|         }
 | |
|       });
 | |
|     });
 | |
|     onBeforeMount(() => {
 | |
|       if (!isDemoRoute.value) {
 | |
|         pushConnectionStore.pushConnect();
 | |
|       }
 | |
|       addPostMessageEventBindings();
 | |
|     });
 | |
|     onMounted(() => {
 | |
|       canvasStore.startLoading();
 | |
|       documentTitle.reset();
 | |
|       resetWorkspace();
 | |
|       void initializeData().then(() => {
 | |
|         void initializeRoute().then(() => {
 | |
|           toast.showNotificationForViews([VIEWS.WORKFLOW, VIEWS.NEW_WORKFLOW]);
 | |
|           if (route.query.settings) {
 | |
|             uiStore.openModal(WORKFLOW_SETTINGS_MODAL_KEY);
 | |
|             void router.replace({ query: { settings: void 0 } });
 | |
|           }
 | |
|         }).finally(() => {
 | |
|           isLoading.value = false;
 | |
|           canvasStore.stopLoading();
 | |
|           void externalHooks.run("nodeView.mount").catch(() => {
 | |
|           });
 | |
|           setTimeout(() => {
 | |
|             if (routeNodeId.value) {
 | |
|               updateNodeRoute(routeNodeId.value);
 | |
|             }
 | |
|           }, 500);
 | |
|           emitPostMessageReady();
 | |
|         });
 | |
|         void usersStore.showPersonalizationSurvey();
 | |
|         checkIfRouteIsAllowed();
 | |
|       });
 | |
|       addSourceControlEventBindings();
 | |
|       addWorkflowSavedEventBindings();
 | |
|       addBeforeUnloadEventBindings();
 | |
|       addImportEventBindings();
 | |
|       addExecutionOpenedEventBindings();
 | |
|       registerCustomActions();
 | |
|     });
 | |
|     onActivated(async () => {
 | |
|       addUndoRedoEventBindings();
 | |
|       showAddFirstStepIfEnabled();
 | |
|     });
 | |
|     onDeactivated(() => {
 | |
|       uiStore.closeModal(WORKFLOW_SETTINGS_MODAL_KEY);
 | |
|       removeUndoRedoEventBindings();
 | |
|     });
 | |
|     onBeforeUnmount(() => {
 | |
|       removeSourceControlEventBindings();
 | |
|       removePostMessageEventBindings();
 | |
|       removeWorkflowSavedEventBindings();
 | |
|       removeBeforeUnloadEventBindings();
 | |
|       removeImportEventBindings();
 | |
|       removeExecutionOpenedEventBindings();
 | |
|       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, {
 | |
|           key: 0,
 | |
|           id: unref(editableWorkflow).id,
 | |
|           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,
 | |
|           "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,
 | |
|           "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,
 | |
|           "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(() => [
 | |
|             (openBlock(), createBlock(Suspense, null, {
 | |
|               default: withCtx(() => [
 | |
|                 createVNode(unref(LazySetupWorkflowCredentialsButton), {
 | |
|                   class: normalizeClass(unref($style).setupCredentialsButtonWrapper)
 | |
|                 }, null, 8, ["class"])
 | |
|               ]),
 | |
|               _: 1
 | |
|             })),
 | |
|             !isCanvasReadOnly.value ? (openBlock(), createElementBlock("div", {
 | |
|               key: 0,
 | |
|               class: normalizeClass(unref($style).executionButtons)
 | |
|             }, [
 | |
|               isRunWorkflowButtonVisible.value ? (openBlock(), createBlock(CanvasRunWorkflowButton, {
 | |
|                 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(_sfc_main$1, {
 | |
|                   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, {
 | |
|                   key: 1,
 | |
|                   label: unref(i18n).baseText("chat.open"),
 | |
|                   shortcut: { keys: ["c"] }
 | |
|                 }, {
 | |
|                   default: withCtx(() => [
 | |
|                     createVNode(_sfc_main$1, {
 | |
|                       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(_sfc_main$5, {
 | |
|                 key: 2,
 | |
|                 stopping: isStoppingExecution.value,
 | |
|                 onClick: onStopExecution
 | |
|               }, null, 8, ["stopping"])) : createCommentVNode("", true),
 | |
|               isStopWaitingForWebhookButtonVisible.value ? (openBlock(), createBlock(_sfc_main$4, {
 | |
|                 key: 3,
 | |
|                 onClick: onStopWaitingForWebhook
 | |
|               })) : createCommentVNode("", true)
 | |
|             ], 2)) : createCommentVNode("", true),
 | |
|             isReadOnlyEnvironment.value ? (openBlock(), createBlock(unref(N8nCallout), {
 | |
|               key: 1,
 | |
|               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(CanvasThinkingPill, {
 | |
|               key: 2,
 | |
|               class: normalizeClass(unref($style).thinkingPill),
 | |
|               "show-stop": "",
 | |
|               onStop: unref(builderStore).stopStreaming
 | |
|             }, 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
 | |
|                 }, 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", "onUpdate:logs:inputOpen", "onUpdate:logs:outputOpen", "onUpdate:hasRangeSelection"])) : createCommentVNode("", true),
 | |
|         !isLoading.value ? (openBlock(), createBlock(FocusPanel, {
 | |
|           key: 1,
 | |
|           "is-canvas-read-only": isCanvasReadOnly.value,
 | |
|           onSaveKeyboardShortcut: onSaveWorkflow
 | |
|         }, null, 8, ["is-canvas-read-only"])) : createCommentVNode("", true)
 | |
|       ], 2);
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const wrapper = "_wrapper_16h3t_123";
 | |
| const executionButtons = "_executionButtons_16h3t_128";
 | |
| const chatButton = "_chatButton_16h3t_165";
 | |
| const setupCredentialsButtonWrapper = "_setupCredentialsButtonWrapper_16h3t_169";
 | |
| const readOnlyEnvironmentNotification = "_readOnlyEnvironmentNotification_16h3t_175";
 | |
| const thinkingPill = "_thinkingPill_16h3t_182";
 | |
| const style0 = {
 | |
|   wrapper,
 | |
|   executionButtons,
 | |
|   chatButton,
 | |
|   setupCredentialsButtonWrapper,
 | |
|   readOnlyEnvironmentNotification,
 | |
|   thinkingPill
 | |
| };
 | |
| const cssModules = {
 | |
|   "$style": style0
 | |
| };
 | |
| const NodeView = /* @__PURE__ */ _export_sfc(_sfc_main, [["__cssModules", cssModules]]);
 | |
| const NodeView$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
 | |
|   __proto__: null,
 | |
|   default: NodeView
 | |
| }, Symbol.toStringTag, { value: "Module" }));
 | |
| export {
 | |
|   NodeView$1 as N,
 | |
|   useExecutionData as u
 | |
| };
 |