UNPKG

n8n-editor-ui

Version:

Workflow Editor UI for n8n

988 lines (987 loc) 39.7 kB
import { C as computed, Cn as toDisplayString, D as createElementBlock, E as createCommentVNode, Gt as unref, It as ref, J as onBeforeUnmount, M as createVNode, P as defineComponent, T as createBlock, Ut as toValue, Vt as toRef, W as mergeProps, Z as onMounted, _t as watch, b as Teleport, bn as normalizeStyle, bt as withCtx, et as openBlock, j as createTextVNode, mt as useTemplateRef, vn as normalizeClass, w as createBaseVNode } from "./vue.runtime.esm-bundler-tP5dCd7J.js"; import { E as useElementSize, gt as useI18n } from "./_MapCache-B159LOu5.js"; import { Vn as N8nText_default, Wn as N8nIcon_default, a as N8nInlineTextEdit_default, b as N8nResizeWrapper_default, it as useDeviceSupport, mt as N8nTooltip_default, ut as N8nLink_default, xt as N8nIconButton_default } from "./src-BW7zuOU1.js"; import "./en-b3uD8cvU.js"; import "./preload-helper-CR0ecmWK.js"; import { t as __plugin_vue_export_helper_default } from "./_plugin-vue_export-helper-BwBpWJRZ.js"; import { x as createEventBus } from "./truncate-Dc5upPom.js"; import "./icon-MZ_3fB_h.js"; import "./date-picker-DHibgWOB.js"; import "./overlay-CftFqN-S.js"; import { c as InputPanel_default } from "./ParameterInputList-Bsq4jEFq.js"; import "./empty-4-N75rxI.js"; import { t as useMessage } from "./useMessage-C1bozAQq.js"; import "./col-BYqH0g4Y.js"; import "./dialog-DlumiPST.js"; import { Bo as LOCAL_STORAGE_NDV_PANEL_WIDTH, Fi as useUIStore, Mi as dataPinningEventBus, a as useNDVStore, at as useNodeTypesStore, o as useWorkflowsStore, t as useTelemetry, xn as useNodeHelpers } from "./useTelemetry-C797TaYa.js"; import "./useToast-ZaUhbG9w.js"; import "./sanitize-html-CgpOSgtK.js"; import "./CalendarDate-DxkU3CHY.js"; import "./path-browserify-B5h_dP_u.js"; import { Aa as jsonParse, D as APP_MODALS_ELEMENT_ID, Ka as NodeConnectionTypes, in as EXECUTABLE_TRIGGER_NODE_TYPES, lr as START_NODE_TYPE, na as getNodeOutputs, ts as MODAL_CONFIRM, ur as STICKY_NODE_TYPE } from "./constants-CX1ozgFz.js"; import "./merge-BArJwbQo.js"; import "./assistant.store-CES0bOwj.js"; import { A as storeToRefs } from "./_baseOrderBy-DL6Sy5xK.js"; import "./dateformat-CMLc6OKJ.js"; import "./useDebounce-RgPaX171.js"; import { t as useExternalHooks } from "./useExternalHooks-CYMS6JpD.js"; import { t as useStyles } from "./useStyles-DhM0cpS7.js"; import "./chatPanel.store-DxVV7Zn2.js"; import "./npsSurvey.store-BuKohzKX.js"; import "./cloudPlan.store-nppjm48S.js"; import "./templates.store-CSx5YxpE.js"; import "./focusPanel.store-Dys3muoU.js"; import "./useWorkflowSaving-D0h-y5mZ.js"; import "./retry-CalJieID.js"; import "./executions.store-Cu3L65gQ.js"; import "./useRunWorkflow-B0MrxSlI.js"; import { t as usePinnedData } from "./usePinnedData-BPdJqXOY.js"; import "./nodeCreator.store-DfjyHcRR.js"; import { t as getNodeIconSource } from "./nodeIcon-CdzjV7EE.js"; import "./useClipboard-B4OWL4sL.js"; import "./useCanvasOperations-B_GKebCJ.js"; import "./folders.store-zKqujIOj.js"; import { t as NodeIcon_default } from "./NodeIcon-DywH900v.js"; import "./dataTable.store-DbXbbBi8.js"; import "./CopyInput-B-PxgATn.js"; import "./isEmpty-DE57Hvb_.js"; import "./NDVEmptyState-D6DVufbQ.js"; import "./exports-0lA49Fnw.js"; import "./externalSecrets.ee.store-BwtOvUyU.js"; import "./uniqBy-BAsCSiRe.js"; import "./semver-CSrR6yZm.js"; import "./CommunityNodeUpdateInfo-DRQanjaS.js"; import "./RunDataHtml-QefKJgzk.js"; import "./VueMarkdown-DxrTzpPH.js"; import { t as Draggable_default } from "./Draggable-sZwW_gr6.js"; import "./VirtualSchema-CXi2cQ39.js"; import "./TextWithHighlights-bwDYVgOs.js"; import { t as useTelemetryContext } from "./useTelemetryContext-CHWzGKT9.js"; import "./schemaPreview.store-Ck-1EjtJ.js"; import "./nodeTransforms-0T6NES_R.js"; import "./FileSaver.min-BZ3jw69B.js"; import "./vue-json-pretty-DsYkKELy.js"; import "./dateFormatter-BKQyEZlN.js"; import "./useExecutionHelpers-BqOSbeyu.js"; import { n as useNodeDocsUrl, t as NodeSettings_default } from "./NodeSettings-DUdVI_8H.js"; import "./useActions-Bc_58LkU.js"; import "./vue-CLRzcfGh.js"; import { t as useKeybindings } from "./useKeybindings-CFy7jL6I.js"; import { t as useWorkflowActivate } from "./useWorkflowActivate-Bjltj_L5.js"; import "./core-B834MECE.js"; import "./useExecutionData-eh3o7g7B.js"; import "./AnimatedSpinner-BKvs0-tV.js"; import "./useLogsTreeExpand-Dm3JA5_m.js"; import "./core-DNyEixOf.js"; import "./RunDataParsedAiContent-CyVIO66n.js"; import { n as OutputPanel_default, r as NDVFloatingNodes_default, t as TriggerPanel_default } from "./TriggerPanel-CyMv5s6g.js"; var NDVHeader_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({ __name: "NDVHeader", props: { nodeName: {}, nodeTypeName: {}, docsUrl: {}, icon: {}, readOnly: { type: Boolean } }, emits: ["close", "rename"], setup(__props, { emit: __emit }) { const props = __props; const i18n = useI18n(); const emit = __emit; function onRename(newNodeName) { emit("rename", newNodeName || props.nodeTypeName); } return (_ctx, _cache) => { return openBlock(), createElementBlock("header", { class: normalizeClass(_ctx.$style.ndvHeader) }, [createBaseVNode("div", { class: normalizeClass(_ctx.$style.content) }, [_ctx.icon ? (openBlock(), createBlock(NodeIcon_default, { key: 0, class: normalizeClass(_ctx.$style.icon), size: 20, "icon-source": _ctx.icon, "node-name": props.nodeTypeName, "show-tooltip": true }, null, 8, [ "class", "icon-source", "node-name" ])) : createCommentVNode("", true), createBaseVNode("div", { class: normalizeClass(_ctx.$style.title) }, [createVNode(unref(N8nInlineTextEdit_default), { "model-value": _ctx.nodeName, "min-width": 0, "max-width": 500, placeholder: unref(i18n).baseText("ndv.title.rename.placeholder"), "read-only": _ctx.readOnly, "onUpdate:modelValue": onRename }, null, 8, [ "model-value", "placeholder", "read-only" ])], 2)], 2), createBaseVNode("div", { class: normalizeClass(_ctx.$style.actions) }, [_ctx.docsUrl ? (openBlock(), createBlock(unref(N8nLink_default), { key: 0, theme: "text", target: "_blank", href: _ctx.docsUrl }, { default: withCtx(() => [createBaseVNode("span", { class: normalizeClass(_ctx.$style.docsLabel) }, [createVNode(unref(N8nText_default), { size: "small", bold: "" }, { default: withCtx(() => [createTextVNode(toDisplayString(unref(i18n).baseText("nodeSettings.docs")), 1)]), _: 1 }), createVNode(unref(N8nIcon_default), { icon: "external-link" })], 2)]), _: 1 }, 8, ["href"])) : createCommentVNode("", true), createVNode(unref(N8nTooltip_default), null, { content: withCtx(() => [createTextVNode(toDisplayString(unref(i18n).baseText("ndv.close.tooltip")), 1)]), default: withCtx(() => [createVNode(unref(N8nIconButton_default), { icon: "x", type: "tertiary", text: "", "data-test-id": "ndv-close-button", onClick: _cache[0] || (_cache[0] = ($event) => emit("close")) })]), _: 1 })], 2)], 2); }; } }); var NDVHeader_vue_vue_type_style_index_0_lang_module_default = { ndvHeader: "_ndvHeader_1e58b_2", content: "_content_1e58b_12", actions: "_actions_1e58b_19", title: "_title_1e58b_34", docsLabel: "_docsLabel_1e58b_39", icon: "_icon_1e58b_44" }; var NDVHeader_default = /* @__PURE__ */ __plugin_vue_export_helper_default(NDVHeader_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": NDVHeader_vue_vue_type_style_index_0_lang_module_default }]]); function useNdvLayout(options) { const MIN_MAIN_PANEL_WIDTH_PX = 368; const MIN_PANEL_WIDTH_PX = 120; const DEFAULT_INPUTLESS_MAIN_WIDTH_PX = 480; const DEFAULT_WIDE_MAIN_WIDTH_PX = 640; const DEFAULT_REGULAR_MAIN_WIDTH_PX = 420; const panelWidthPercentage = ref({ left: 40, main: 20, right: 40 }); const localStorageKey = computed(() => `${LOCAL_STORAGE_NDV_PANEL_WIDTH}_${toValue(options.paneType).toUpperCase()}`); const containerSize = useElementSize(options.container); const containerWidth = computed(() => containerSize.width.value); const percentageToPixels = (percentage) => { return percentage / 100 * containerWidth.value; }; const pixelsToPercentage = (pixels) => { return pixels / containerWidth.value * 100; }; const minMainPanelWidthPercentage = computed(() => pixelsToPercentage(MIN_MAIN_PANEL_WIDTH_PX)); const panelWidthPixels = computed(() => ({ left: percentageToPixels(panelWidthPercentage.value.left), main: percentageToPixels(panelWidthPercentage.value.main), right: percentageToPixels(panelWidthPercentage.value.right) })); const minPanelWidthPercentage = computed(() => pixelsToPercentage(MIN_PANEL_WIDTH_PX)); const defaultPanelSize = computed(() => { switch (toValue(options.paneType)) { case "inputless": { const main$1 = pixelsToPercentage(DEFAULT_INPUTLESS_MAIN_WIDTH_PX); return { left: 0, main: main$1, right: 100 - main$1 }; } case "wide": { const main$1 = pixelsToPercentage(DEFAULT_WIDE_MAIN_WIDTH_PX); const panels = (100 - main$1) / 2; return { left: panels, main: main$1, right: panels }; } case "dragless": case "unknown": case "regular": default: { const main$1 = pixelsToPercentage(DEFAULT_REGULAR_MAIN_WIDTH_PX); const panels = (100 - main$1) / 2; return { left: panels, main: main$1, right: panels }; } } }); const safePanelWidth = ({ left, main: main$1, right }) => { const minLeft = toValue(options.hasInputPanel) ? minPanelWidthPercentage.value : 0; const minRight = minPanelWidthPercentage.value; const minMain = minMainPanelWidthPercentage.value; const newPanelWidth = { left: Math.max(minLeft, left), main: Math.max(minMain, main$1), right: Math.max(minRight, right) }; const total = newPanelWidth.left + newPanelWidth.main + newPanelWidth.right; if (total > 100) { const overflow = total - 100; const trimLeft = newPanelWidth.left / (newPanelWidth.left + newPanelWidth.right) * overflow; const trimRight = overflow - trimLeft; newPanelWidth.left = Math.max(minLeft, newPanelWidth.left - trimLeft); newPanelWidth.right = Math.max(minRight, newPanelWidth.right - trimRight); } return newPanelWidth; }; const persistPanelSize = () => { localStorage.setItem(localStorageKey.value, JSON.stringify(panelWidthPercentage.value)); }; const loadPanelSize = () => { const storedPanelSizeString = localStorage.getItem(localStorageKey.value); const defaultSize = defaultPanelSize.value; if (storedPanelSizeString) panelWidthPercentage.value = safePanelWidth(jsonParse(storedPanelSizeString, { fallbackValue: defaultSize }) ?? defaultSize); else panelWidthPercentage.value = safePanelWidth(defaultSize); }; const onResizeEnd = () => { persistPanelSize(); }; const onResize = (event) => { const newMain = Math.max(minMainPanelWidthPercentage.value, pixelsToPercentage(event.width)); const initialLeft = panelWidthPercentage.value.left; const initialMain = panelWidthPercentage.value.main; const initialRight = panelWidthPercentage.value.right; const diffMain = newMain - initialMain; if (event.direction === "left") { const potentialLeft = initialLeft - diffMain; if (potentialLeft < minPanelWidthPercentage.value) return; panelWidthPercentage.value = safePanelWidth({ left: Math.max(minPanelWidthPercentage.value, potentialLeft), main: newMain, right: initialRight }); } else if (event.direction === "right") { const potentialRight = initialRight - diffMain; if (potentialRight < minPanelWidthPercentage.value) return; panelWidthPercentage.value = safePanelWidth({ left: initialLeft, main: newMain, right: Math.max(minPanelWidthPercentage.value, potentialRight) }); } }; const onDrag = (position) => { const newLeft = Math.max(minPanelWidthPercentage.value, pixelsToPercentage(position[0]) - panelWidthPercentage.value.main / 2); const newRight = Math.max(minPanelWidthPercentage.value, 100 - newLeft - panelWidthPercentage.value.main); if (newLeft + panelWidthPercentage.value.main + newRight > 100) return; panelWidthPercentage.value.left = newLeft; panelWidthPercentage.value.right = newRight; }; watch(containerWidth, (newWidth, oldWidth) => { if (!newWidth) return; if (!oldWidth) loadPanelSize(); else panelWidthPercentage.value = safePanelWidth(panelWidthPercentage.value); }); watch(toRef(options.paneType), () => { loadPanelSize(); }, { immediate: true }); return { containerWidth, panelWidthPercentage, panelWidthPixels, onResize, onDrag, onResizeEnd }; } var PanelDragButtonV2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({ __name: "PanelDragButtonV2", props: { canMoveRight: { type: Boolean }, canMoveLeft: { type: Boolean } }, emits: [ "drag", "dragstart", "dragend" ], setup(__props, { emit: __emit }) { const emit = __emit; const onDrag = (e) => { emit("drag", e); }; const onDragEnd = () => { emit("dragend"); }; const onDragStart = () => { emit("dragstart"); }; return (_ctx, _cache) => { return openBlock(), createBlock(Draggable_default, { class: normalizeClass(_ctx.$style.dragContainer), type: "panel-resize", cursor: "ew-resize", "data-test-id": "panel-drag-button", onDrag, onDragstart: onDragStart, onDragend: onDragEnd }, { default: withCtx(({ isDragging }) => [createBaseVNode("button", { class: normalizeClass([_ctx.$style.dragButton, { [_ctx.$style.dragging]: isDragging }]) }, [ _ctx.canMoveLeft ? (openBlock(), createBlock(unref(N8nIcon_default), { key: 0, class: normalizeClass(_ctx.$style.arrow), icon: "arrow-left" }, null, 8, ["class"])) : createCommentVNode("", true), createVNode(unref(N8nIcon_default), { class: normalizeClass(_ctx.$style.handle), icon: "menu" }, null, 8, ["class"]), _ctx.canMoveRight ? (openBlock(), createBlock(unref(N8nIcon_default), { key: 1, class: normalizeClass(_ctx.$style.arrow), icon: "arrow-right" }, null, 8, ["class"])) : createCommentVNode("", true) ], 2)]), _: 1 }, 8, ["class"]); }; } }); var PanelDragButtonV2_vue_vue_type_style_index_0_lang_module_default = { dragButton: "_dragButton_16ffn_123", arrow: "_arrow_16ffn_138", handle: "_handle_16ffn_142", dragging: "_dragging_16ffn_146" }; var PanelDragButtonV2_default = /* @__PURE__ */ __plugin_vue_export_helper_default(PanelDragButtonV2_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": PanelDragButtonV2_vue_vue_type_style_index_0_lang_module_default }]]); var NodeDetailsViewV2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({ __name: "NodeDetailsViewV2", props: { workflowObject: {}, readOnly: { type: Boolean, default: false }, isProductionExecutionPreview: { type: Boolean, default: false } }, emits: [ "saveKeyboardShortcut", "valueChanged", "switchSelectedNode", "openConnectionNodeCreator", "renameNode", "stopExecution" ], setup(__props, { emit: __emit }) { const emit = __emit; const props = __props; const ndvStore = useNDVStore(); const externalHooks = useExternalHooks(); const nodeHelpers = useNodeHelpers(); const { activeNode } = storeToRefs(ndvStore); const pinnedData = usePinnedData(activeNode); const workflowActivate = useWorkflowActivate(); const nodeTypesStore = useNodeTypesStore(); const uiStore = useUIStore(); const workflowsStore = useWorkflowsStore(); const deviceSupport = useDeviceSupport(); const telemetry = useTelemetry(); const telemetryContext = useTelemetryContext({ view_shown: "ndv" }); const i18n = useI18n(); const message = useMessage(); const { APP_Z_INDEXES } = useStyles(); const settingsEventBus = createEventBus(); const runInputIndex = ref(-1); const runOutputIndex = ref(-1); const isLinkingEnabled = ref(true); const selectedInput = ref(); const triggerWaitingWarningEnabled = ref(false); const isDragging = ref(false); const mainPanelPosition = ref(0); const pinDataDiscoveryTooltipVisible = ref(false); const avgInputRowHeight = ref(0); const avgOutputRowHeight = ref(0); const isInputPaneActive = ref(false); const isOutputPaneActive = ref(false); const isPairedItemHoveringEnabled = ref(true); const dialogRef = ref(); const containerRef = useTemplateRef("containerRef"); const mainPanelRef = useTemplateRef("mainPanelRef"); const pushRef = computed(() => ndvStore.pushRef); const activeNodeType = computed(() => { if (activeNode.value) return nodeTypesStore.getNodeType(activeNode.value.type, activeNode.value.typeVersion); return null; }); const { docsUrl } = useNodeDocsUrl({ nodeType: activeNodeType }); const workflowRunning = computed(() => uiStore.isActionActive.workflowRunning); const workflowRunData = computed(() => { if (workflowExecution.value === null) return null; const executionData = workflowExecution.value.data; if (executionData?.resultData) return executionData.resultData.runData; return null; }); const parentNodes = computed(() => { if (activeNode.value) return props.workflowObject.getParentNodesByDepth(activeNode.value.name, 1).map(({ name }) => name) || []; else return []; }); const parentNode = computed(() => { for (const parentNodeName of parentNodes.value) { if (workflowsStore?.pinnedWorkflowData?.[parentNodeName]) return parentNodeName; if (workflowRunData.value?.[parentNodeName]) return parentNodeName; } return parentNodes.value[0]; }); const inputNodeName = computed(() => { if ((activeNode.value && activeNodeType.value ? getNodeOutputs(props.workflowObject, activeNode.value, activeNodeType.value) : []).filter((output$1) => { if (typeof output$1 === "string") return output$1 !== NodeConnectionTypes.Main; return output$1.type !== NodeConnectionTypes.Main; }).length > 0 && activeNode.value) return props.workflowObject.getChildNodes(activeNode.value.name, "ALL_NON_MAIN")?.[0]; return selectedInput.value || parentNode.value; }); const inputNode = computed(() => { if (inputNodeName.value) return workflowsStore.getNodeByName(inputNodeName.value); return null; }); const inputSize = computed(() => ndvStore.ndvInputDataWithPinnedData.length); const isTriggerNode = computed(() => !!activeNodeType.value && (activeNodeType.value.group.includes("trigger") || activeNodeType.value.name === "n8n-nodes-base.start")); const showTriggerPanel = computed(() => { const override = !!activeNodeType.value?.triggerPanel; if (typeof activeNodeType.value?.triggerPanel === "boolean") return override; const isWebhookBasedNode = !!activeNodeType.value?.webhooks?.length; const isPollingNode = activeNodeType.value?.polling; return !props.readOnly && isTriggerNode.value && (isWebhookBasedNode || isPollingNode || override); }); const isExecutableTriggerNode = computed(() => { if (!activeNodeType.value) return false; return EXECUTABLE_TRIGGER_NODE_TYPES.includes(activeNodeType.value.name); }); const isActiveStickyNode = computed(() => !!ndvStore.activeNode && ndvStore.activeNode.type === "n8n-nodes-base.stickyNote"); const workflowExecution = computed(() => workflowsStore.getWorkflowExecution); const maxOutputRun = computed(() => { if (activeNode.value === null) return 0; const runData = workflowRunData.value; if (!runData?.[activeNode.value.name]) return 0; if (runData[activeNode.value.name].length) return runData[activeNode.value.name].length - 1; return 0; }); const outputRun = computed(() => runOutputIndex.value === -1 ? maxOutputRun.value : Math.min(runOutputIndex.value, maxOutputRun.value)); const maxInputRun = computed(() => { if (inputNode.value === null || activeNode.value === null) return 0; const workflowNode = props.workflowObject.getNode(activeNode.value.name); if (!workflowNode || !activeNodeType.value) return 0; const outputs = getNodeOutputs(props.workflowObject, workflowNode, activeNodeType.value); let node = inputNode.value; const runData = workflowRunData.value; if (outputs.some((output$1) => output$1 !== NodeConnectionTypes.Main)) node = activeNode.value; if (!node || !runData?.hasOwnProperty(node.name)) return 0; if (runData[node.name].length) return runData[node.name].length - 1; return 0; }); const inputRun = computed(() => { if (isLinkingEnabled.value && maxOutputRun.value === maxInputRun.value) return outputRun.value; if (runInputIndex.value === -1) return maxInputRun.value; return Math.min(runInputIndex.value, maxInputRun.value); }); const canLinkRuns = computed(() => maxOutputRun.value > 0 && maxOutputRun.value === maxInputRun.value); const linked = computed(() => isLinkingEnabled.value && canLinkRuns.value); const outputPanelEditMode = computed(() => ndvStore.outputPanelEditMode); const isWorkflowRunning = computed(() => uiStore.isActionActive.workflowRunning); const isExecutionWaitingForWebhook = computed(() => workflowsStore.executionWaitingForWebhook); const blockUi = computed(() => isWorkflowRunning.value || isExecutionWaitingForWebhook.value); const foreignCredentials = computed(() => nodeHelpers.getForeignCredentialsIfSharingEnabled(activeNode.value?.credentials)); const hasForeignCredential = computed(() => foreignCredentials.value.length > 0); const inputPanelDisplayMode = computed(() => ndvStore.inputPanelDisplayMode); const outputPanelDisplayMode = computed(() => ndvStore.outputPanelDisplayMode); const hasInputPanel = computed(() => !isTriggerNode.value || showTriggerPanel.value); const supportedResizeDirections = computed(() => hasInputPanel.value ? ["left", "right"] : ["right"]); const nodeSettingsProps = computed(() => ({ eventBus: settingsEventBus, dragging: isDragging.value, pushRef: pushRef.value, nodeType: activeNodeType.value, foreignCredentials: foreignCredentials.value, readOnly: props.readOnly, blockUI: blockUi.value && showTriggerPanel.value, executable: !props.readOnly, inputSize: inputSize.value, isNdvV2: true })); const { containerWidth, onDrag, onResize, onResizeEnd, panelWidthPercentage, panelWidthPixels } = useNdvLayout({ container: containerRef, hasInputPanel, paneType: computed(() => { if (!hasInputPanel.value) return "inputless"; return activeNodeType.value?.parameterPane ?? "regular"; }) }); const setIsTooltipVisible = ({ isTooltipVisible }) => { pinDataDiscoveryTooltipVisible.value = isTooltipVisible; }; const onKeyDown = (e) => { if (e.key === "s" && deviceSupport.isCtrlKeyPressed(e)) onSaveWorkflow(e); }; const onSaveWorkflow = (e) => { e.stopPropagation(); e.preventDefault(); if (props.readOnly) return; emit("saveKeyboardShortcut", e); }; const onInputItemHover = (e) => { if (e === null || !inputNodeName.value || !isPairedItemHoveringEnabled.value) { ndvStore.setHoveringItem(null); return; } const item = { nodeName: inputNodeName.value, runIndex: inputRun.value, outputIndex: e.outputIndex, itemIndex: e.itemIndex }; ndvStore.setHoveringItem(item); }; const onInputTableMounted = (e) => { avgInputRowHeight.value = e.avgRowHeight; }; const onWorkflowActivate = () => { ndvStore.unsetActiveNodeName(); setTimeout(() => { workflowActivate.activateCurrentWorkflow("ndv"); }, 1e3); }; const onOutputItemHover = (e) => { if (e === null || !activeNode.value || !isPairedItemHoveringEnabled.value) { ndvStore.setHoveringItem(null); return; } const item = { nodeName: activeNode.value?.name, runIndex: outputRun.value, outputIndex: e.outputIndex, itemIndex: e.itemIndex }; ndvStore.setHoveringItem(item); }; const onDragEnd = () => { onResizeEnd(); isDragging.value = false; telemetry.track("User moved parameters pane", { window_width: containerWidth.value, start_position: mainPanelPosition.value, node_type: activeNodeType.value ? activeNodeType.value.name : "", push_ref: pushRef.value, workflow_id: workflowsStore.workflowId }); }; const onDragStart = () => { isDragging.value = true; }; const onLinkRunToOutput = () => { isLinkingEnabled.value = true; trackLinking("output"); }; const onUnlinkRun = (pane) => { runInputIndex.value = runOutputIndex.value; isLinkingEnabled.value = false; trackLinking(pane); }; const onNodeExecute = () => { setTimeout(() => { if (!activeNode.value || !workflowRunning.value) return; triggerWaitingWarningEnabled.value = true; }, 1e3); }; const openSettings = () => { settingsEventBus.emit("openSettings"); }; const trackLinking = (pane) => { telemetry.track("User changed ndv run linking", { node_type: activeNodeType.value ? activeNodeType.value.name : "", push_ref: pushRef.value, linked: linked.value, pane }); }; const onLinkRunToInput = () => { runOutputIndex.value = runInputIndex.value; isLinkingEnabled.value = true; trackLinking("input"); }; const onSwitchSelectedNode = (nodeTypeName) => { emit("switchSelectedNode", nodeTypeName); }; const onOpenConnectionNodeCreator = (nodeTypeName, connectionType) => { emit("openConnectionNodeCreator", nodeTypeName, connectionType); }; const close = async () => { if (isDragging.value) return; if (outputPanelEditMode.value.enabled && activeNode.value) { if (await message.confirm("", i18n.baseText("ndv.pinData.beforeClosing.title"), { confirmButtonText: i18n.baseText("ndv.pinData.beforeClosing.confirm"), cancelButtonText: i18n.baseText("ndv.pinData.beforeClosing.cancel") }) === "confirm") { const { value } = outputPanelEditMode.value; try { pinnedData.setData(jsonParse(value), "on-ndv-close-modal"); } catch (error) { console.error(error); } } ndvStore.setOutputPanelEditModeEnabled(false); } await externalHooks.run("dataDisplay.nodeEditingFinished"); telemetry.track("User closed node modal", { node_type: activeNodeType.value ? activeNodeType.value?.name : "", push_ref: pushRef.value, workflow_id: workflowsStore.workflowId }); triggerWaitingWarningEnabled.value = false; ndvStore.unsetActiveNodeName(); ndvStore.resetNDVPushRef(); }; useKeybindings({ Escape: close }); const trackRunChange = (run, pane) => { telemetry.track("User changed ndv run dropdown", { push_ref: pushRef.value, run_index: run, node_type: activeNodeType.value ? activeNodeType.value?.name : "", pane }); }; const onRunOutputIndexChange = (run) => { runOutputIndex.value = run; trackRunChange(run, "output"); }; const onRunInputIndexChange = (run) => { runInputIndex.value = run; if (linked.value) runOutputIndex.value = run; trackRunChange(run, "input"); }; const onOutputTableMounted = (e) => { avgOutputRowHeight.value = e.avgRowHeight; }; const onInputNodeChange = (value, index) => { runInputIndex.value = -1; isLinkingEnabled.value = true; selectedInput.value = value; telemetry.track("User changed ndv input dropdown", { node_type: activeNode.value ? activeNode.value.type : "", push_ref: pushRef.value, workflow_id: workflowsStore.workflowId, selection_value: index, input_node_type: inputNode.value ? inputNode.value.type : "" }); }; const onStopExecution = () => { emit("stopExecution"); }; const activateInputPane = () => { isInputPaneActive.value = true; isOutputPaneActive.value = false; }; const activateOutputPane = () => { isInputPaneActive.value = false; isOutputPaneActive.value = true; }; const onSearch = (search) => { isPairedItemHoveringEnabled.value = !search; }; const registerKeyboardListener = () => { document.addEventListener("keydown", onKeyDown, true); }; const unregisterKeyboardListener = () => { document.removeEventListener("keydown", onKeyDown, true); }; const onRename = (name) => { emit("renameNode", name); }; const handleChangeDisplayMode = (pane, mode) => { ndvStore.setPanelDisplayMode({ pane, mode }); }; watch(activeNode, (node, oldNode) => { if (node && !oldNode) { registerKeyboardListener(); dialogRef.value?.show(); } else if (!node) unregisterKeyboardListener(); if (node && node.name !== oldNode?.name && !isActiveStickyNode.value) { runInputIndex.value = -1; runOutputIndex.value = -1; isLinkingEnabled.value = true; selectedInput.value = void 0; triggerWaitingWarningEnabled.value = false; avgOutputRowHeight.value = 0; avgInputRowHeight.value = 0; setTimeout(() => ndvStore.setNDVPushRef(), 0); if (!activeNodeType.value) return; externalHooks.run("dataDisplay.nodeTypeChanged", { nodeSubtitle: nodeHelpers.getNodeSubtitle(node, activeNodeType.value, props.workflowObject) }); setTimeout(() => { if (activeNode.value) { const outgoingConnections = workflowsStore.outgoingConnectionsByNodeName(activeNode.value?.name); telemetry.track("User opened node modal", { node_id: activeNode.value?.id, node_type: activeNodeType.value ? activeNodeType.value?.name : "", workflow_id: workflowsStore.workflowId, push_ref: pushRef.value, is_editable: !hasForeignCredential.value, parameters_pane_position: mainPanelPosition.value, input_first_connector_runs: maxInputRun.value, output_first_connector_runs: maxOutputRun.value, selected_view_inputs: isTriggerNode.value ? "trigger" : ndvStore.inputPanelDisplayMode, selected_view_outputs: ndvStore.outputPanelDisplayMode, input_connectors: parentNodes.value.length, output_connectors: outgoingConnections?.main?.length, input_displayed_run_index: inputRun.value, output_displayed_run_index: outputRun.value, data_pinning_tooltip_presented: pinDataDiscoveryTooltipVisible.value, input_displayed_row_height_avg: avgInputRowHeight.value, output_displayed_row_height_avg: avgOutputRowHeight.value, source: telemetryContext.ndv_source?.value ?? "other" }); } }, 2e3); } if (window.top && !isActiveStickyNode.value) window.top.postMessage(JSON.stringify({ command: node ? "openNDV" : "closeNDV" }), "*"); }, { immediate: true }); watch(maxOutputRun, () => { runOutputIndex.value = -1; }); watch(maxInputRun, () => { runInputIndex.value = -1; }); watch(inputNodeName, (nodeName) => { setTimeout(() => { ndvStore.setInputNodeName(nodeName); }, 0); }); watch(inputRun, (run) => { setTimeout(() => { ndvStore.setInputRunIndex(run); }, 0); }); watch(mainPanelRef, (mainPanel) => { if (!mainPanel) return; function getTabbableCandidates(element) { const nodes = []; const walker = document.createTreeWalker(element, NodeFilter.SHOW_ELEMENT, { acceptNode: (node) => { const isHiddenInput = node.tagName === "INPUT" && node.type === "hidden"; if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP; return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP; } }); while (walker.nextNode()) nodes.push(walker.currentNode); return nodes; } const firstFocusableElement = getTabbableCandidates(mainPanel)[0]; if (firstFocusableElement) firstFocusableElement.focus(); }); onMounted(() => { dialogRef.value?.show(); dataPinningEventBus.on("data-pinning-discovery", setIsTooltipVisible); }); onBeforeUnmount(() => { dataPinningEventBus.off("data-pinning-discovery", setIsTooltipVisible); unregisterKeyboardListener(); }); return (_ctx, _cache) => { return unref(activeNode) && !isActiveStickyNode.value ? (openBlock(), createBlock(Teleport, { key: 0, to: `#${unref(APP_MODALS_ELEMENT_ID)}` }, [createBaseVNode("div", { "data-test-id": "ndv-backdrop", class: normalizeClass(_ctx.$style.backdrop), style: normalizeStyle({ zIndex: unref(APP_Z_INDEXES).NDV }), onClick: close }, null, 6), createBaseVNode("dialog", { ref_key: "dialogRef", ref: dialogRef, open: "", "aria-modal": "true", "data-test-id": "ndv", class: normalizeClass(_ctx.$style.dialog), style: normalizeStyle({ zIndex: unref(APP_Z_INDEXES).NDV }) }, [createVNode(NDVFloatingNodes_default, { "root-node": unref(activeNode), onSwitchSelectedNode }, null, 8, ["root-node"]), createBaseVNode("div", { ref_key: "containerRef", ref: containerRef, class: normalizeClass({ [_ctx.$style.container]: true, [_ctx.$style.webhookWaiting]: isExecutionWaitingForWebhook.value }) }, [createVNode(NDVHeader_default, { class: normalizeClass(_ctx.$style.header), "node-name": unref(activeNode).name, "node-type-name": activeNodeType.value?.defaults.name ?? activeNodeType.value?.displayName ?? unref(activeNode).name, icon: unref(getNodeIconSource)(activeNodeType.value ?? unref(activeNode).type, unref(activeNode)), "docs-url": unref(docsUrl), onClose: close, onRename }, null, 8, [ "class", "node-name", "node-type-name", "icon", "docs-url" ]), createBaseVNode("main", { class: normalizeClass(_ctx.$style.main) }, [ hasInputPanel.value ? (openBlock(), createElementBlock("div", { key: 0, class: normalizeClass([_ctx.$style.column, _ctx.$style.dataColumn]), style: normalizeStyle({ width: `${unref(panelWidthPercentage).left}%` }) }, [showTriggerPanel.value ? (openBlock(), createBlock(TriggerPanel_default, { key: 0, "node-name": unref(activeNode).name, "push-ref": pushRef.value, class: normalizeClass(_ctx.$style.input), onExecute: onNodeExecute, onActivate: onWorkflowActivate }, null, 8, [ "node-name", "push-ref", "class" ])) : !isTriggerNode.value ? (openBlock(), createBlock(InputPanel_default, { key: 1, "workflow-object": _ctx.workflowObject, "can-link-runs": canLinkRuns.value, "run-index": inputRun.value, "linked-runs": linked.value, "active-node-name": unref(activeNode).name, "current-node-name": inputNodeName.value, "push-ref": pushRef.value, "read-only": _ctx.readOnly || hasForeignCredential.value, "is-production-execution-preview": _ctx.isProductionExecutionPreview, "search-shortcut": isInputPaneActive.value ? "/" : void 0, "display-mode": inputPanelDisplayMode.value, class: normalizeClass(_ctx.$style.input), "is-mapping-onboarded": unref(ndvStore).isMappingOnboarded, "focused-mappable-input": unref(ndvStore).focusedMappableInput, onActivatePane: activateInputPane, onLinkRun: onLinkRunToInput, onUnlinkRun: _cache[0] || (_cache[0] = () => onUnlinkRun("input")), onRunChange: onRunInputIndexChange, onOpenSettings: openSettings, onChangeInputNode: onInputNodeChange, onExecute: onNodeExecute, onTableMounted: onInputTableMounted, onItemHover: onInputItemHover, onSearch, onDisplayModeChange: _cache[1] || (_cache[1] = ($event) => handleChangeDisplayMode("input", $event)) }, null, 8, [ "workflow-object", "can-link-runs", "run-index", "linked-runs", "active-node-name", "current-node-name", "push-ref", "read-only", "is-production-execution-preview", "search-shortcut", "display-mode", "class", "is-mapping-onboarded", "focused-mappable-input" ])) : createCommentVNode("", true)], 6)) : createCommentVNode("", true), createVNode(unref(N8nResizeWrapper_default), { width: unref(panelWidthPixels).main, "min-width": 260, "supported-directions": supportedResizeDirections.value, "grid-size": 8, class: normalizeClass({ [_ctx.$style.column]: !isExecutionWaitingForWebhook.value, [_ctx.$style.webhookWaiting]: isExecutionWaitingForWebhook.value }), style: normalizeStyle({ width: `${unref(panelWidthPercentage).main}%` }), outset: "", onResize: unref(onResize), onResizestart: onDragStart, onResizeend: onDragEnd }, { default: withCtx(() => [createBaseVNode("div", { ref_key: "mainPanelRef", ref: mainPanelRef, class: normalizeClass(_ctx.$style.main) }, [hasInputPanel.value ? (openBlock(), createBlock(PanelDragButtonV2_default, { key: 0, class: normalizeClass(_ctx.$style.draggable), "can-move-left": true, "can-move-right": true, onDrag: unref(onDrag), onDragstart: onDragStart, onDragend: onDragEnd }, null, 8, ["class", "onDrag"])) : createCommentVNode("", true), createVNode(NodeSettings_default, mergeProps(nodeSettingsProps.value, { class: _ctx.$style.settings, onExecute: onNodeExecute, onStopExecution, onActivate: onWorkflowActivate, onSwitchSelectedNode, onOpenConnectionNodeCreator }), null, 16, ["class"])], 2)]), _: 1 }, 8, [ "width", "supported-directions", "class", "style", "onResize" ]), createBaseVNode("div", { class: normalizeClass([_ctx.$style.column, _ctx.$style.dataColumn]), style: normalizeStyle({ width: `${unref(panelWidthPercentage).right}%` }) }, [createVNode(OutputPanel_default, { "data-test-id": "output-panel", "workflow-object": _ctx.workflowObject, "can-link-runs": canLinkRuns.value, "run-index": outputRun.value, "linked-runs": linked.value, "push-ref": pushRef.value, "is-read-only": _ctx.readOnly || hasForeignCredential.value, "block-u-i": blockUi.value && isTriggerNode.value && !isExecutableTriggerNode.value, "is-production-execution-preview": _ctx.isProductionExecutionPreview, "is-pane-active": isOutputPaneActive.value, "display-mode": outputPanelDisplayMode.value, class: normalizeClass(_ctx.$style.output), onActivatePane: activateOutputPane, onLinkRun: onLinkRunToOutput, onUnlinkRun: _cache[2] || (_cache[2] = () => onUnlinkRun("output")), onRunChange: onRunOutputIndexChange, onOpenSettings: openSettings, onTableMounted: onOutputTableMounted, onItemHover: onOutputItemHover, onSearch, onExecute: onNodeExecute, onDisplayModeChange: _cache[3] || (_cache[3] = ($event) => handleChangeDisplayMode("output", $event)) }, null, 8, [ "workflow-object", "can-link-runs", "run-index", "linked-runs", "push-ref", "is-read-only", "block-u-i", "is-production-execution-preview", "is-pane-active", "display-mode", "class" ])], 6) ], 2)], 2)], 6)], 8, ["to"])) : createCommentVNode("", true); }; } }); var NodeDetailsViewV2_vue_vue_type_style_index_0_lang_module_default = { backdrop: "_backdrop_m8tra_123", dialog: "_dialog_m8tra_133", container: "_container_m8tra_148", main: "_main_m8tra_159", column: "_column_m8tra_169", input: "_input_m8tra_182", output: "_output_m8tra_183", dataColumn: "_dataColumn_m8tra_187", header: "_header_m8tra_191", settings: "_settings_m8tra_198", draggable: "_draggable_m8tra_203", webhookWaiting: "_webhookWaiting_m8tra_212" }; var NodeDetailsViewV2_default = /* @__PURE__ */ __plugin_vue_export_helper_default(NodeDetailsViewV2_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": NodeDetailsViewV2_vue_vue_type_style_index_0_lang_module_default }]]); export { NodeDetailsViewV2_default as default };