n8n-editor-ui
Version:
Workflow Editor UI for n8n
1,074 lines (1,073 loc) • 43.8 kB
JavaScript
import { C as computed, Cn as toDisplayString, D as createElementBlock, E as createCommentVNode, G as nextTick, Gt as unref, It as ref, J as onBeforeUnmount, M as createVNode, P as defineComponent, T as createBlock, Z as onMounted, _t as watch, at as renderSlot, bn as normalizeStyle, bt as withCtx, et as openBlock, j as createTextVNode, k as createSlots, pt as useSlots, vn as normalizeClass, w as createBaseVNode } from "./vue.runtime.esm-bundler-tP5dCd7J.js";
import { _t as useI18n, at as useThrottleFn } from "./_MapCache-ficiegRb.js";
import { C as N8nResizeWrapper_default, ct as useDeviceSupport, ht as N8nTooltip_default, wn as N8nIcon_default, xn as N8nText_default } from "./src-DgvumQTi.js";
import "./en-CF30SCh2.js";
import "./preload-helper-CR0ecmWK.js";
import { t as __plugin_vue_export_helper_default } from "./_plugin-vue_export-helper-BwBpWJRZ.js";
import { T as createEventBus } from "./truncate-B1HVeveJ.js";
import "./date-picker-B6nJ4qMb.js";
import { $i as nodeViewEventBus, Gn as useNodeHelpers, M as useNDVStore, N as useWorkflowsStore, Nt as useNodeTypesStore, O as useTelemetry, b as useExternalHooks, hs as useStorage, m as useMessage, oa as useUIStore, ra as dataPinningEventBus, y as useStyles } from "./builder.store-sBTWwxRU.js";
import { c as InputPanel_default } from "./ParameterInputList-B4xJHjua.js";
import "./empty-BuGRxzl4.js";
import "./col-Cd5kWzv_.js";
import { t as ElDialog } from "./dialog-D5O6wJX0.js";
import "./sanitize-html-Cc45ZKm8.js";
import "./CalendarDate-zWqgZMlk.js";
import "./path-browserify-BtCDmZ3_.js";
import { Da as jsonParse, E as APP_MODALS_ELEMENT_ID, G as MAIN_NODE_PANEL_WIDTH, Ls as LOCAL_STORAGE_MAIN_PANEL_RELATIVE_WIDTH, Qi as getNodeOutputs, Ua as NodeConnectionTypes, rn as EXECUTABLE_TRIGGER_NODE_TYPES, rs as MODAL_CONFIRM, s as BASE_NODE_SURVEY_URL, sr as STICKY_NODE_TYPE } from "./constants-BbpucWL4.js";
import "./merge-k8vSyyXH.js";
import { A as storeToRefs } from "./_baseOrderBy-B_6CV8x6.js";
import "./dateformat-CM9k0--B.js";
import "./useDebounce-Bnb8W2LR.js";
import { n as ndvEventBus } from "./assistant.store-bS9AHOoo.js";
import "./chatPanel.store-4qGv1TCZ.js";
import "./retry-dP46utx2.js";
import "./executions.store-CXjGPxs0.js";
import "./useRunWorkflow-BQJbxiOd.js";
import { t as usePinnedData } from "./usePinnedData-CL2qWhwp.js";
import "./nodeCreator.store-FJrC_Pu6.js";
import "./nodeIcon-DI2Acud1.js";
import "./useCanvasOperations-CAHezq7d.js";
import "./folders.store-BjAwtSH4.js";
import "./NodeIcon-BVhrZNYI.js";
import "./dataTable.store-B4A4ieSD.js";
import "./useClipboard-CyG-SBdG.js";
import "./CopyInput-DKOPkUXT.js";
import "./RunData-B4jIonVZ.js";
import "./NDVEmptyState-CpUQ-969.js";
import "./exports-hpMZaOPT.js";
import "./externalSecrets.ee.store-D27nc9Y2.js";
import "./uniqBy-BwIeMDu6.js";
import "./semver-CVsBQkSJ.js";
import "./CommunityNodeUpdateInfo-Cd_-b5Xu.js";
import "./RunDataHtml-CkjC7YuF.js";
import "./VueMarkdown-D9lDzMKr.js";
import { t as Draggable_default } from "./Draggable-04Tfmp_H.js";
import "./VirtualSchema-D2LnRq9K.js";
import "./TextWithHighlights-DjzuDrgO.js";
import { t as useTelemetryContext } from "./useTelemetryContext-5Wb7vBCv.js";
import "./schemaPreview.store-BFprwUEe.js";
import "./nodeTransforms-Lk_uXh7p.js";
import "./vue-json-pretty-DGKuDe33.js";
import "./dateFormatter-DDfPHI9I.js";
import "./useExecutionHelpers-BhJEW8lu.js";
import { t as NodeSettings_default } from "./NodeSettings-iHP6f-9G.js";
import "./useActions-O8-gYbRP.js";
import "./vue-Dg_43WEg.js";
import "./core-6W4wWNc1.js";
import "./useExecutionData-4UjwITsD.js";
import "./AnimatedSpinner-wiGFgffA.js";
import "./useLogsTreeExpand-WR32ACA6.js";
import "./core-BbiIkN91.js";
import "./RunDataParsedAiContent-Dl9d2Tx7.js";
import { n as OutputPanel_default, r as NDVFloatingNodes_default, t as TriggerPanel_default } from "./TriggerPanel-BJOFVjKr.js";
var PanelDragButton_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
__name: "PanelDragButton",
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, {
type: "panel-resize",
class: normalizeClass(_ctx.$style.dragContainer),
onDrag,
onDragstart: onDragStart,
onDragend: onDragEnd
}, {
default: withCtx(({ isDragging }) => [createBaseVNode("div", {
class: normalizeClass({ [_ctx.$style.dragButton]: true }),
"data-test-id": "panel-drag-button"
}, [
_ctx.canMoveLeft ? (openBlock(), createElementBlock("span", {
key: 0,
class: normalizeClass({
[_ctx.$style.leftArrow]: true,
[_ctx.$style.visible]: isDragging
})
}, [createVNode(unref(N8nIcon_default), { icon: "arrow-left" })], 2)) : createCommentVNode("", true),
_ctx.canMoveRight ? (openBlock(), createElementBlock("span", {
key: 1,
class: normalizeClass({
[_ctx.$style.rightArrow]: true,
[_ctx.$style.visible]: isDragging
})
}, [createVNode(unref(N8nIcon_default), { icon: "arrow-right" })], 2)) : createCommentVNode("", true),
createBaseVNode("div", { class: normalizeClass(_ctx.$style.grid) }, _cache[0] || (_cache[0] = [createBaseVNode("div", null, [
createBaseVNode("div"),
createBaseVNode("div"),
createBaseVNode("div"),
createBaseVNode("div"),
createBaseVNode("div")
], -1), createBaseVNode("div", null, [
createBaseVNode("div"),
createBaseVNode("div"),
createBaseVNode("div"),
createBaseVNode("div"),
createBaseVNode("div")
], -1)]), 2)
], 2)]),
_: 1
}, 8, ["class"]);
};
}
});
var PanelDragButton_vue_vue_type_style_index_0_lang_module_default = {
dragContainer: "_dragContainer_1i6l1_123",
dragButton: "_dragButton_1i6l1_127",
leftArrow: "_leftArrow_1i6l1_141 _arrow_1i6l1_150",
rightArrow: "_rightArrow_1i6l1_142 _arrow_1i6l1_150",
visible: "_visible_1i6l1_146",
arrow: "_arrow_1i6l1_150",
grid: "_grid_1i6l1_168"
};
var PanelDragButton_default = /* @__PURE__ */ __plugin_vue_export_helper_default(PanelDragButton_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": PanelDragButton_vue_vue_type_style_index_0_lang_module_default }]]);
var SIDE_MARGIN = 24;
var SIDE_PANELS_MARGIN = 80;
var MIN_PANEL_WIDTH = 310;
var PANEL_WIDTH = 350;
var PANEL_WIDTH_LARGE = 420;
var NDVDraggablePanels_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
__name: "NDVDraggablePanels",
props: {
isDraggable: { type: Boolean },
hideInputAndOutput: { type: Boolean },
nodeType: {}
},
emits: [
"init",
"dragstart",
"dragend",
"switchSelectedNode",
"close"
],
setup(__props, { emit: __emit }) {
const MIN_WINDOW_WIDTH = 2 * (SIDE_MARGIN + SIDE_PANELS_MARGIN) + MIN_PANEL_WIDTH;
const initialMainPanelWidth = {
regular: 390,
dragless: 390,
unknown: 390,
inputless: 390,
wide: 390 * 2
};
const throttledOnResize = useThrottleFn(onResize, 100);
const ndvStore = useNDVStore();
const uiStore = useUIStore();
const props = __props;
const isDragging = ref(false);
const initialized = ref(false);
const containerWidth = ref(uiStore.appGridDimensions.width);
const emit = __emit;
const slots = useSlots();
onMounted(() => {
if (mainPanelDimensions.value.relativeLeft === 1 && mainPanelDimensions.value.relativeRight === 1) {
setMainPanelWidth();
setPositions(getInitialLeftPosition(mainPanelDimensions.value.relativeWidth));
restorePositionData();
}
emit("init", { position: mainPanelDimensions.value.relativeLeft });
setTimeout(() => {
initialized.value = true;
}, 0);
ndvEventBus.on("setPositionByName", setPositionByName);
});
onBeforeUnmount(() => {
ndvEventBus.off("setPositionByName", setPositionByName);
});
watch(() => uiStore.appGridDimensions, async (dimensions) => {
const ndv = document.getElementById("ndv");
if (ndv) {
await nextTick();
const { width: ndvWidth } = ndv.getBoundingClientRect();
containerWidth.value = ndvWidth;
} else containerWidth.value = dimensions.width;
const minRelativeWidth = pxToRelativeWidth(MIN_PANEL_WIDTH);
if (mainPanelDimensions.value.relativeWidth < minRelativeWidth) setMainPanelWidth(minRelativeWidth);
const isBelowMinLeft = minimumLeftPosition.value > mainPanelDimensions.value.relativeLeft;
const isMaxRight = maximumRightPosition.value > mainPanelDimensions.value.relativeRight;
if (dimensions.width > MIN_WINDOW_WIDTH && isBelowMinLeft && isMaxRight) {
setMainPanelWidth(minRelativeWidth);
setPositions(getInitialLeftPosition(mainPanelDimensions.value.relativeWidth));
}
setPositions(mainPanelDimensions.value.relativeLeft);
});
const currentNodePaneType = computed(() => {
if (!hasInputSlot.value) return "inputless";
if (!props.isDraggable) return "dragless";
if (props.nodeType === null) return "unknown";
return props.nodeType.parameterPane ?? "regular";
});
const mainPanelDimensions = computed(() => {
return ndvStore.mainPanelDimensions[currentNodePaneType.value];
});
const calculatedPositions = computed(() => {
const hasInput = slots.input !== void 0;
const outputPanelRelativeLeft = mainPanelDimensions.value.relativeLeft + mainPanelDimensions.value.relativeWidth;
return {
inputPanelRelativeRight: hasInput ? 1 - outputPanelRelativeLeft + mainPanelDimensions.value.relativeWidth : 1 - pxToRelativeWidth(SIDE_MARGIN),
outputPanelRelativeLeft
};
});
const outputPanelRelativeTranslate = computed(() => {
const panelMinLeft = 1 - pxToRelativeWidth(MIN_PANEL_WIDTH + SIDE_MARGIN);
const currentRelativeLeftDelta = calculatedPositions.value.outputPanelRelativeLeft - panelMinLeft;
return currentRelativeLeftDelta > 0 ? currentRelativeLeftDelta : 0;
});
const supportedResizeDirections = computed(() => {
const supportedDirections = ["right"];
if (props.isDraggable) supportedDirections.push("left");
return supportedDirections;
});
const hasInputSlot = computed(() => {
return slots.input !== void 0;
});
const inputPanelMargin = computed(() => pxToRelativeWidth(SIDE_PANELS_MARGIN));
const minimumLeftPosition = computed(() => {
if (containerWidth.value < MIN_WINDOW_WIDTH) return pxToRelativeWidth(1);
if (!hasInputSlot.value) return pxToRelativeWidth(SIDE_MARGIN);
return pxToRelativeWidth(SIDE_MARGIN + 20) + inputPanelMargin.value;
});
const maximumRightPosition = computed(() => {
if (containerWidth.value < MIN_WINDOW_WIDTH) return pxToRelativeWidth(1);
return pxToRelativeWidth(SIDE_MARGIN + 20) + inputPanelMargin.value;
});
const canMoveLeft = computed(() => {
return mainPanelDimensions.value.relativeLeft > minimumLeftPosition.value;
});
const canMoveRight = computed(() => {
return mainPanelDimensions.value.relativeRight > maximumRightPosition.value;
});
const mainPanelStyles = computed(() => {
return {
left: `${relativeWidthToPx(mainPanelDimensions.value.relativeLeft)}px`,
right: `${relativeWidthToPx(mainPanelDimensions.value.relativeRight)}px`
};
});
const inputPanelStyles = computed(() => {
return { right: `${relativeWidthToPx(calculatedPositions.value.inputPanelRelativeRight)}px` };
});
const outputPanelStyles = computed(() => {
return {
left: `${relativeWidthToPx(calculatedPositions.value.outputPanelRelativeLeft)}px`,
transform: `translateX(-${relativeWidthToPx(outputPanelRelativeTranslate.value)}px)`
};
});
const hasDoubleWidth = computed(() => {
return props.nodeType?.parameterPane === "wide";
});
const fixedPanelWidth = computed(() => {
const multiplier = hasDoubleWidth.value ? 2 : 1;
if (containerWidth.value > 1700) return PANEL_WIDTH_LARGE * multiplier;
return PANEL_WIDTH * multiplier;
});
const onSwitchSelectedNode = (node) => emit("switchSelectedNode", node);
function getInitialLeftPosition(width) {
if (currentNodePaneType.value === "dragless") return pxToRelativeWidth(SIDE_MARGIN + 1 + fixedPanelWidth.value);
return hasInputSlot.value ? .5 - width / 2 : minimumLeftPosition.value;
}
function setMainPanelWidth(relativeWidth) {
const mainPanelRelativeWidth = relativeWidth || pxToRelativeWidth(initialMainPanelWidth[currentNodePaneType.value]);
ndvStore.setMainPanelDimensions({
panelType: currentNodePaneType.value,
dimensions: { relativeWidth: mainPanelRelativeWidth }
});
}
function setPositions(relativeLeft) {
const mainPanelRelativeLeft = relativeLeft || 1 - calculatedPositions.value.inputPanelRelativeRight;
const mainPanelRelativeRight = 1 - mainPanelRelativeLeft - mainPanelDimensions.value.relativeWidth;
const isMaxRight = maximumRightPosition.value > mainPanelRelativeRight;
const isMinLeft = minimumLeftPosition.value > mainPanelRelativeLeft;
const isInputless = currentNodePaneType.value === "inputless";
if (isMinLeft) {
ndvStore.setMainPanelDimensions({
panelType: currentNodePaneType.value,
dimensions: {
relativeLeft: minimumLeftPosition.value,
relativeRight: 1 - mainPanelDimensions.value.relativeWidth - minimumLeftPosition.value
}
});
return;
}
if (isMaxRight) {
ndvStore.setMainPanelDimensions({
panelType: currentNodePaneType.value,
dimensions: {
relativeLeft: 1 - mainPanelDimensions.value.relativeWidth - maximumRightPosition.value,
relativeRight: maximumRightPosition.value
}
});
return;
}
ndvStore.setMainPanelDimensions({
panelType: currentNodePaneType.value,
dimensions: {
relativeLeft: isInputless ? minimumLeftPosition.value : mainPanelRelativeLeft,
relativeRight: mainPanelRelativeRight
}
});
}
function setPositionByName(position) {
setPositions({
minLeft: minimumLeftPosition.value,
maxRight: maximumRightPosition.value,
initial: getInitialLeftPosition(mainPanelDimensions.value.relativeWidth)
}[position]);
}
function pxToRelativeWidth(px) {
return px / containerWidth.value;
}
function relativeWidthToPx(relativeWidth) {
return relativeWidth * containerWidth.value;
}
function onResizeEnd() {
storePositionData();
}
function onResizeThrottle(data) {
if (initialized.value) throttledOnResize(data);
}
function onResize({ direction, x, width }) {
const relativeDistance = pxToRelativeWidth(x);
const relativeWidth = pxToRelativeWidth(width);
if (direction === "left" && relativeDistance <= minimumLeftPosition.value) return;
if (direction === "right" && 1 - relativeDistance <= maximumRightPosition.value) return;
if (width <= MIN_PANEL_WIDTH) return;
setMainPanelWidth(relativeWidth);
setPositions(direction === "left" ? relativeDistance : mainPanelDimensions.value.relativeLeft);
}
function restorePositionData() {
const storedPanelWidthData = useStorage(`${LOCAL_STORAGE_MAIN_PANEL_RELATIVE_WIDTH}_${currentNodePaneType.value}`).value;
if (storedPanelWidthData) {
const parsedWidth = parseFloat(storedPanelWidthData);
setMainPanelWidth(parsedWidth);
setPositions(getInitialLeftPosition(parsedWidth));
return true;
}
return false;
}
function storePositionData() {
useStorage(`${LOCAL_STORAGE_MAIN_PANEL_RELATIVE_WIDTH}_${currentNodePaneType.value}`).value = mainPanelDimensions.value.relativeWidth.toString();
}
function onDragStart() {
isDragging.value = true;
emit("dragstart", { position: mainPanelDimensions.value.relativeLeft });
}
function onDrag(position) {
setPositions(pxToRelativeWidth(position[0]) - mainPanelDimensions.value.relativeWidth / 2);
}
function onDragEnd() {
setTimeout(() => {
isDragging.value = false;
emit("dragend", {
windowWidth: containerWidth.value,
position: mainPanelDimensions.value.relativeLeft
});
}, 0);
storePositionData();
}
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", null, [
unref(ndvStore).activeNode ? (openBlock(), createBlock(NDVFloatingNodes_default, {
key: 0,
"root-node": unref(ndvStore).activeNode,
onSwitchSelectedNode
}, null, 8, ["root-node"])) : createCommentVNode("", true),
!_ctx.hideInputAndOutput ? (openBlock(), createElementBlock("div", {
key: 1,
class: normalizeClass(_ctx.$style.inputPanel),
style: normalizeStyle(inputPanelStyles.value)
}, [renderSlot(_ctx.$slots, "input")], 6)) : createCommentVNode("", true),
!_ctx.hideInputAndOutput ? (openBlock(), createElementBlock("div", {
key: 2,
class: normalizeClass(_ctx.$style.outputPanel),
style: normalizeStyle(outputPanelStyles.value)
}, [renderSlot(_ctx.$slots, "output")], 6)) : createCommentVNode("", true),
createBaseVNode("div", {
class: normalizeClass(_ctx.$style.mainPanel),
style: normalizeStyle(mainPanelStyles.value)
}, [createVNode(unref(N8nResizeWrapper_default), {
"is-resizing-enabled": currentNodePaneType.value !== "unknown",
width: relativeWidthToPx(mainPanelDimensions.value.relativeWidth),
"min-width": MIN_PANEL_WIDTH,
"grid-size": 20,
"supported-directions": supportedResizeDirections.value,
outset: "",
onResize: onResizeThrottle,
onResizeend: onResizeEnd
}, {
default: withCtx(() => [createBaseVNode("div", { class: normalizeClass(_ctx.$style.dragButtonContainer) }, [!_ctx.hideInputAndOutput && _ctx.isDraggable ? (openBlock(), createBlock(PanelDragButton_default, {
key: 0,
class: normalizeClass({
[_ctx.$style.draggable]: true,
[_ctx.$style.visible]: isDragging.value
}),
"can-move-left": canMoveLeft.value,
"can-move-right": canMoveRight.value,
onDragstart: onDragStart,
onDrag,
onDragend: onDragEnd
}, null, 8, [
"class",
"can-move-left",
"can-move-right"
])) : createCommentVNode("", true)], 2), createBaseVNode("div", { class: normalizeClass({
[_ctx.$style.mainPanelInner]: true,
[_ctx.$style.dragging]: isDragging.value
}) }, [renderSlot(_ctx.$slots, "main")], 2)]),
_: 3
}, 8, [
"is-resizing-enabled",
"width",
"supported-directions"
])], 6)
]);
};
}
});
const dataPanel = "_dataPanel_1xgxx_123";
const inputPanel = "_inputPanel_1xgxx_132 _dataPanel_1xgxx_123";
const outputPanel = "_outputPanel_1xgxx_140 _dataPanel_1xgxx_123";
const mainPanel = "_mainPanel_1xgxx_148";
const draggable = "_draggable_1xgxx_152";
const mainPanelInner = "_mainPanelInner_1xgxx_156";
const dragging = "_dragging_1xgxx_163";
const dragButtonContainer = "_dragButtonContainer_1xgxx_176";
const visible = "_visible_1xgxx_192";
var NDVDraggablePanels_vue_vue_type_style_index_0_lang_module_default = {
dataPanel,
inputPanel,
outputPanel,
mainPanel,
draggable,
mainPanelInner,
dragging,
"double-width": "_double-width_1xgxx_172",
dragButtonContainer,
visible
};
var NDVDraggablePanels_default = /* @__PURE__ */ __plugin_vue_export_helper_default(NDVDraggablePanels_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": NDVDraggablePanels_vue_vue_type_style_index_0_lang_module_default }]]);
var _hoisted_1 = {
key: 0,
ref: "container",
class: "data-display",
"data-test-id": "ndv-modal",
tabindex: "0"
};
var NodeDetailsView_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
__name: "NodeDetailsView",
props: {
workflowObject: {},
readOnly: {
type: Boolean,
default: false
},
renaming: { type: Boolean },
isProductionExecutionPreview: {
type: Boolean,
default: false
}
},
emits: [
"saveKeyboardShortcut",
"valueChanged",
"switchSelectedNode",
"openConnectionNodeCreator",
"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 nodeTypesStore = useNodeTypesStore();
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 = computed(() => ndvStore.output.run ?? -1);
const selectedInput = ref();
const isLinkingEnabled = ref(true);
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 pushRef = computed(() => ndvStore.pushRef);
const activeNodeType = computed(() => {
if (activeNode.value) return nodeTypesStore.getNodeType(activeNode.value.type, activeNode.value.typeVersion);
return null;
});
const showTriggerWaitingWarning = computed(() => triggerWaitingWarningEnabled.value && !!activeNodeType.value && !activeNodeType.value.group.includes("trigger") && workflowsStore.isWorkflowRunning && workflowsStore.executionWaitingForWebhook);
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);
return [];
});
const parentNode = computed(() => {
for (const parent of parentNodes.value) {
if (workflowsStore?.pinnedWorkflowData?.[parent.name]) return parent;
if (workflowRunData.value?.[parent.name]) return parent;
}
return parentNodes.value[0];
});
const inputNodeName = computed(() => {
if ((activeNode.value && activeNodeType.value ? getNodeOutputs(props.workflowObject, activeNode.value, activeNodeType.value) : []).filter((output) => {
if (typeof output === "string") return output !== NodeConnectionTypes.Main;
return output.type !== NodeConnectionTypes.Main;
}).length > 0 && activeNode.value) return props.workflowObject.getChildNodes(activeNode.value.name, "ALL_NON_MAIN")?.[0];
return selectedInput.value ?? parentNode.value?.name;
});
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"));
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) => output !== 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 connectedCurrentNodeOutputs = computed(() => {
return parentNodes.value.find(({ name }) => name === inputNodeName.value)?.indicies;
});
const inputRun = computed(() => {
if (isLinkingEnabled.value && maxOutputRun.value === maxInputRun.value) return outputRun.value;
const currentInputNodeName = inputNodeName.value;
if (runInputIndex.value === -1 && currentInputNodeName) return connectedCurrentNodeOutputs.value?.map((outputIndex) => nodeHelpers.getLastRunIndexWithData(currentInputNodeName, outputIndex)).find((runIndex) => runIndex !== -1) ?? 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 featureRequestUrl = computed(() => {
if (!activeNodeType.value) return "";
return `${BASE_NODE_SURVEY_URL}${activeNodeType.value.name}`;
});
const outputPanelEditMode = computed(() => ndvStore.outputPanelEditMode);
const isExecutionWaitingForWebhook = computed(() => workflowsStore.executionWaitingForWebhook);
const blockUi = computed(() => workflowsStore.isWorkflowRunning || 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 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();
nodeViewEventBus.emit("publishWorkflow");
};
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 onFeatureRequestClick = () => {
window.open(featureRequestUrl.value, "_blank");
if (activeNode.value) telemetry.track("User clicked ndv link", {
node_type: activeNode.value.type,
workflow_id: workflowsStore.workflowId,
push_ref: pushRef.value,
pane: NodeConnectionTypes.Main,
type: "i-wish-this-node-would"
});
};
const onDragEnd = (e) => {
isDragging.value = false;
telemetry.track("User moved parameters pane", {
window_width: e.windowWidth,
start_position: mainPanelPosition.value,
end_position: e.position,
node_type: activeNodeType.value ? activeNodeType.value.name : "",
push_ref: pushRef.value,
workflow_id: workflowsStore.workflowId
});
mainPanelPosition.value = e.position;
};
const onDragStart = (e) => {
isDragging.value = true;
mainPanelPosition.value = e.position;
};
const onPanelsInit = (e) => {
mainPanelPosition.value = e.position;
};
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 || !workflowsStore.isWorkflowRunning) 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 = () => {
ndvStore.setOutputRunIndex(runInputIndex.value);
isLinkingEnabled.value = true;
trackLinking("input");
};
const valueChanged = (parameterData) => {
emit("valueChanged", parameterData);
};
const onSwitchSelectedNode = (nodeTypeName) => {
emit("switchSelectedNode", nodeTypeName);
};
const onOpenConnectionNodeCreator = (nodeTypeName, connectionType, connectionIndex = 0) => {
emit("openConnectionNodeCreator", nodeTypeName, connectionType, connectionIndex);
};
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();
};
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) => {
ndvStore.setOutputRunIndex(run);
trackRunChange(run, "output");
};
const onRunInputIndexChange = (run) => {
runInputIndex.value = run;
if (linked.value) ndvStore.setOutputRunIndex(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 setSelectedInput = (value) => {
selectedInput.value = value;
};
const handleChangeDisplayMode = (pane, mode) => {
ndvStore.setPanelDisplayMode({
pane,
mode
});
};
watch(activeNode, (node, oldNode) => {
if (node && !oldNode) registerKeyboardListener();
else if (!node) unregisterKeyboardListener();
if (node && node.name !== oldNode?.name && !isActiveStickyNode.value) {
runInputIndex.value = -1;
ndvStore.setOutputRunIndex(-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" : inputPanelDisplayMode.value,
selected_view_outputs: outputPanelDisplayMode.value,
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, () => {
ndvStore.setOutputRunIndex(-1);
});
watch(maxInputRun, () => {
runInputIndex.value = -1;
});
watch(inputNodeName, (nodeName) => {
setTimeout(() => {
ndvStore.setInputNodeName(nodeName);
}, 0);
});
watch(inputRun, (inputRun$1) => {
setTimeout(() => {
ndvStore.setInputRunIndex(inputRun$1);
}, 0);
});
onMounted(() => {
dataPinningEventBus.on("data-pinning-discovery", setIsTooltipVisible);
ndvEventBus.on("updateInputNodeName", setSelectedInput);
});
onBeforeUnmount(() => {
dataPinningEventBus.off("data-pinning-discovery", setIsTooltipVisible);
ndvEventBus.off("updateInputNodeName", setSelectedInput);
unregisterKeyboardListener();
});
return (_ctx, _cache) => {
return openBlock(), createBlock(unref(ElDialog), {
id: "ndv",
"model-value": (!!unref(activeNode) || _ctx.renaming) && !isActiveStickyNode.value,
"before-close": close,
"show-close": false,
class: "data-display-wrapper ndv-wrapper",
"overlay-class": "data-display-overlay",
width: "auto",
"append-to": `#${unref(APP_MODALS_ELEMENT_ID)}`,
"data-test-id": "ndv",
"z-index": unref(APP_Z_INDEXES).NDV
}, {
default: withCtx(() => [createVNode(unref(N8nTooltip_default), {
placement: "bottom-start",
visible: showTriggerWaitingWarning.value,
disabled: !showTriggerWaitingWarning.value
}, {
content: withCtx(() => [createBaseVNode("div", { class: normalizeClass(_ctx.$style.triggerWarning) }, toDisplayString(unref(i18n).baseText("ndv.backToCanvas.waitingForTriggerWarning")), 3)]),
default: withCtx(() => [createBaseVNode("div", {
class: normalizeClass(_ctx.$style.backToCanvas),
"data-test-id": "back-to-canvas",
onClick: close
}, [createVNode(unref(N8nIcon_default), {
icon: "arrow-left",
color: "text-xlight",
size: "medium"
}), createVNode(unref(N8nText_default), {
color: "text-xlight",
size: "medium",
bold: true
}, {
default: withCtx(() => [createTextVNode(toDisplayString(unref(i18n).baseText("ndv.backToCanvas")), 1)]),
_: 1
})], 2)]),
_: 1
}, 8, ["visible", "disabled"]), unref(activeNode) ? (openBlock(), createElementBlock("div", _hoisted_1, [createBaseVNode("div", {
class: normalizeClass(_ctx.$style.modalBackground),
onClick: close
}, null, 2), (openBlock(), createBlock(NDVDraggablePanels_default, {
key: unref(activeNode).name,
"is-trigger-node": isTriggerNode.value,
"hide-input-and-output": activeNodeType.value === null,
position: isTriggerNode.value && !showTriggerPanel.value ? 0 : void 0,
"is-draggable": !isTriggerNode.value,
"has-double-width": activeNodeType.value?.parameterPane === "wide",
"node-type": activeNodeType.value,
onSwitchSelectedNode,
onOpenConnectionNodeCreator,
onClose: close,
onInit: onPanelsInit,
onDragstart: onDragStart,
onDragend: onDragEnd
}, createSlots({
output: withCtx(() => [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,
onActivatePane: activateOutputPane,
onLinkRun: onLinkRunToOutput,
onUnlinkRun: _cache[2] || (_cache[2] = () => onUnlinkRun("output")),
onRunChange: onRunOutputIndexChange,
onOpenSettings: openSettings,
onTableMounted: onOutputTableMounted,
onItemHover: onOutputItemHover,
onSearch,
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"
])]),
main: withCtx(() => [createVNode(NodeSettings_default, {
"event-bus": unref(settingsEventBus),
dragging: isDragging.value,
"push-ref": pushRef.value,
"foreign-credentials": foreignCredentials.value,
"read-only": _ctx.readOnly,
"block-u-i": blockUi.value && showTriggerPanel.value,
executable: !_ctx.readOnly,
"input-size": inputSize.value,
onValueChanged: valueChanged,
onExecute: onNodeExecute,
onStopExecution,
onActivate: onWorkflowActivate,
onSwitchSelectedNode,
onOpenConnectionNodeCreator
}, null, 8, [
"event-bus",
"dragging",
"push-ref",
"foreign-credentials",
"read-only",
"block-u-i",
"executable",
"input-size"
]), featureRequestUrl.value ? (openBlock(), createElementBlock("a", {
key: 0,
class: normalizeClass(_ctx.$style.featureRequest),
target: "_blank",
onClick: onFeatureRequestClick
}, [createVNode(unref(N8nIcon_default), { icon: "lightbulb" }), createTextVNode(" " + toDisplayString(unref(i18n).baseText("ndv.featureRequest")), 1)], 2)) : createCommentVNode("", true)]),
_: 2
}, [showTriggerPanel.value || !isTriggerNode.value ? {
name: "input",
fn: withCtx(() => [showTriggerPanel.value ? (openBlock(), createBlock(TriggerPanel_default, {
key: 0,
"node-name": unref(activeNode).name,
"push-ref": pushRef.value,
onExecute: onNodeExecute,
onActivate: onWorkflowActivate
}, null, 8, ["node-name", "push-ref"])) : !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,
"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",
"is-mapping-onboarded",
"focused-mappable-input"
])) : createCommentVNode("", true)]),
key: "0"
} : void 0]), 1032, [
"is-trigger-node",
"hide-input-and-output",
"position",
"is-draggable",
"has-double-width",
"node-type"
]))], 512)) : createCommentVNode("", true)]),
_: 1
}, 8, [
"model-value",
"append-to",
"z-index"
]);
};
}
});
var NodeDetailsView_vue_vue_type_style_index_1_lang_module_default = {
modalBackground: "_modalBackground_1qkc8_123",
triggerWarning: "_triggerWarning_1qkc8_128",
backToCanvas: "_backToCanvas_1qkc8_132",
featureRequest: "_featureRequest_1qkc8_153"
};
var NodeDetailsView_default = /* @__PURE__ */ __plugin_vue_export_helper_default(NodeDetailsView_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": NodeDetailsView_vue_vue_type_style_index_1_lang_module_default }]]);
export { NodeDetailsView_default as default };