n8n-editor-ui
Version:
Workflow Editor UI for n8n
301 lines (300 loc) • 11.5 kB
JavaScript
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, U as mergeModels, Z as onMounted, _ as Fragment, bt as withCtx, et as openBlock, ft as useModel, it as renderList, j as createTextVNode, m as withKeys, vn as normalizeClass, w as createBaseVNode } from "./vue.runtime.esm-bundler-tP5dCd7J.js";
import { _t as useI18n } from "./_MapCache-ficiegRb.js";
import { J as N8nSelect_default, Sn as N8nButton_default, Y as N8nOption_default, k as N8nNotice_default, wn as N8nIcon_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 { O as useTelemetry, v as useToast } from "./builder.store-sBTWwxRU.js";
import "./empty-BuGRxzl4.js";
import "./dialog-D5O6wJX0.js";
import "./sanitize-html-Cc45ZKm8.js";
import "./CalendarDate-zWqgZMlk.js";
import "./path-browserify-BtCDmZ3_.js";
import "./constants-BbpucWL4.js";
import "./merge-k8vSyyXH.js";
import "./_baseOrderBy-B_6CV8x6.js";
import "./dateformat-CM9k0--B.js";
import "./useDebounce-Bnb8W2LR.js";
import "./executions.store-CXjGPxs0.js";
import "./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 "./versions.store-BwdT833-.js";
import "./banners.store-C9sgKjcT.js";
import "./dataTable.store-B4A4ieSD.js";
import { t as Modal_default } from "./Modal-CaRDt4OG.js";
import "./roles.store-DcLW4g80.js";
import "./router-BuH0cEsQ.js";
import "./sso.store-Ba2eVE3K.js";
import "./insights.store-BBo4cRMD.js";
import "./insights.constants-C8GITe6H.js";
import "./insights.utils-B7OXsqrQ.js";
import { a as MCP_DOCS_PAGE_URL, i as MCP_CONNECT_WORKFLOWS_MODAL_KEY, n as LOADING_INDICATOR_TIMEOUT, t as ELIGIBLE_WORKFLOWS_DOCS_SECTION } from "./mcp.constants-DQPD3Ntp.js";
import "./constants-DLTaaipl.js";
import "./useRecentResources-BAGmp8Wq.js";
import { t as useMCPStore } from "./mcp.store-Da5JCu0N.js";
import { t as WorkflowLocation_default } from "./WorkflowLocation-BSRxq9Yd.js";
var MCPWorkflowsSelect_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
__name: "MCPWorkflowsSelect",
props: /* @__PURE__ */ mergeModels({
placeholder: {},
disabled: { type: Boolean }
}, {
"modelValue": {},
"modelModifiers": {}
}),
emits: /* @__PURE__ */ mergeModels(["ready", "confirm"], ["update:modelValue"]),
setup(__props, { expose: __expose, emit: __emit }) {
const i18n = useI18n();
const toast = useToast();
const modelValue = useModel(__props, "modelValue");
const emit = __emit;
const mcpStore = useMCPStore();
const isLoading = ref(false);
const hasFetched = ref(false);
const isDropdownVisible = ref(false);
const selectRef = ref();
const workflowOptions = ref([]);
let loadingTimeoutId = null;
const showEmptyState = computed(() => {
return !isLoading.value && hasFetched.value && workflowOptions.value.length === 0;
});
async function searchWorkflows(query) {
if (loadingTimeoutId) {
clearTimeout(loadingTimeoutId);
loadingTimeoutId = null;
}
isLoading.value = true;
hasFetched.value = false;
try {
workflowOptions.value = (await mcpStore.getMcpEligibleWorkflows({
take: 10,
query: query ?? void 0
}))?.data ?? [];
} catch (e) {
toast.showError(e, i18n.baseText("settings.mcp.connectWorkflows.error"));
} finally {
await waitFor(200);
isLoading.value = false;
hasFetched.value = true;
}
}
async function waitFor(timeout) {
await new Promise((resolve) => {
setTimeout(() => {
resolve();
}, timeout);
});
}
function focusOnInput() {
selectRef.value?.focusOnInput();
}
function removeOption(value) {
workflowOptions.value = workflowOptions.value.filter((option) => option.id !== value);
}
function onVisibleChange(visible) {
isDropdownVisible.value = visible;
}
function onKeydownCapture(event) {
if (event.key === "Enter" && !isDropdownVisible.value && modelValue.value) {
event.preventDefault();
event.stopPropagation();
emit("confirm");
}
}
onMounted(async () => {
await searchWorkflows();
emit("ready");
});
__expose({
focusOnInput,
removeOption
});
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", { onKeydownCapture: withKeys(onKeydownCapture, ["enter"]) }, [createVNode(unref(N8nSelect_default), {
ref_key: "selectRef",
ref: selectRef,
modelValue: modelValue.value,
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => modelValue.value = $event),
"data-test-id": "mcp-workflows-select",
placeholder: _ctx.placeholder,
disabled: _ctx.disabled,
loading: isLoading.value,
filterable: true,
remote: true,
"remote-method": searchWorkflows,
"popper-class": {
[_ctx.$style["mcp-workflows-select-loading"]]: isLoading.value,
[_ctx.$style["mcp-workflows-select-empty"]]: showEmptyState.value
},
onVisibleChange
}, {
prefix: withCtx(() => [createVNode(unref(N8nIcon_default), {
class: normalizeClass(_ctx.$style["search-icon"]),
icon: "search",
size: "large"
}, null, 8, ["class"])]),
default: withCtx(() => [showEmptyState.value ? (openBlock(), createBlock(unref(N8nOption_default), {
key: 0,
value: "",
disabled: "",
class: normalizeClass(_ctx.$style["empty-option"])
}, {
default: withCtx(() => [createTextVNode(toDisplayString(unref(i18n).baseText("settings.mcp.connectWorkflows.emptyState")), 1)]),
_: 1
}, 8, ["class"])) : createCommentVNode("", true), (openBlock(true), createElementBlock(Fragment, null, renderList(workflowOptions.value, (workflow) => {
return openBlock(), createBlock(unref(N8nOption_default), {
key: workflow.id,
value: workflow.id,
label: workflow.name
}, {
default: withCtx(() => [createVNode(WorkflowLocation_default, {
"workflow-id": workflow.id,
"workflow-name": workflow.name,
"home-project": workflow.homeProject,
"parent-folder": workflow.parentFolder
}, null, 8, [
"workflow-id",
"workflow-name",
"home-project",
"parent-folder"
])]),
_: 2
}, 1032, ["value", "label"]);
}), 128))]),
_: 1
}, 8, [
"modelValue",
"placeholder",
"disabled",
"loading",
"popper-class"
])], 32);
};
}
});
var MCPWorkflowsSelect_vue_vue_type_style_index_0_lang_module_default = {
"mcp-workflows-select-loading": "_mcp-workflows-select-loading_w21ij_123",
"mcp-workflows-select-empty": "_mcp-workflows-select-empty_w21ij_124",
"empty-option": "_empty-option_w21ij_131"
};
var MCPWorkflowsSelect_default = /* @__PURE__ */ __plugin_vue_export_helper_default(MCPWorkflowsSelect_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": MCPWorkflowsSelect_vue_vue_type_style_index_0_lang_module_default }]]);
var MCPConnectWorkflowsModal_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
__name: "MCPConnectWorkflowsModal",
props: { data: {} },
setup(__props) {
const props = __props;
const i18n = useI18n();
const telemetry = useTelemetry();
const isSaving = ref(false);
const selectedWorkflowId = ref();
const selectRef = ref(null);
const modalBus = createEventBus();
const closedByAction = ref(false);
const docsLink = `${MCP_DOCS_PAGE_URL}#${ELIGIBLE_WORKFLOWS_DOCS_SECTION}`;
const canSave = computed(() => !!selectedWorkflowId.value);
const cancel = (close) => {
closedByAction.value = true;
telemetry.track("User dismissed mcp workflows dialog");
close();
};
async function save(close) {
if (!selectedWorkflowId.value) return;
isSaving.value = true;
try {
await props.data.onEnableMcpAccess(selectedWorkflowId.value);
closedByAction.value = true;
telemetry.track("User selected workflow from list", { workflowId: selectedWorkflowId.value });
close();
} finally {
isSaving.value = false;
}
}
function onModalClosed() {
if (!closedByAction.value) telemetry.track("User dismissed mcp workflows dialog");
}
function onSelectReady() {
selectRef.value?.focusOnInput();
}
function onConfirm() {
if (!isSaving.value) save(() => modalBus.emit("close"));
}
onMounted(() => {
modalBus.on("closed", onModalClosed);
});
onBeforeUnmount(() => {
modalBus.off("closed", onModalClosed);
});
return (_ctx, _cache) => {
return openBlock(), createBlock(Modal_default, {
name: unref(MCP_CONNECT_WORKFLOWS_MODAL_KEY),
title: unref(i18n).baseText("settings.mcp.connectWorkflows.modalTitle"),
width: "600px",
class: normalizeClass(_ctx.$style.container),
"event-bus": unref(modalBus)
}, {
content: withCtx(() => [createBaseVNode("div", { class: normalizeClass(_ctx.$style.content) }, [createVNode(unref(N8nNotice_default), {
"data-test-id": "mcp-connect-workflows-info-notice",
theme: "info",
content: unref(i18n).baseText("settings.mcp.connectWorkflows.notice", { interpolate: { docsLink } }),
class: normalizeClass(_ctx.$style.notice)
}, null, 8, ["content", "class"]), createVNode(MCPWorkflowsSelect_default, {
ref_key: "selectRef",
ref: selectRef,
modelValue: selectedWorkflowId.value,
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => selectedWorkflowId.value = $event),
placeholder: unref(i18n).baseText("settings.mcp.connectWorkflows.input.placeholder"),
disabled: isSaving.value,
onReady: onSelectReady,
onConfirm
}, null, 8, [
"modelValue",
"placeholder",
"disabled"
])], 2)]),
footer: withCtx(({ close }) => [createBaseVNode("div", { class: normalizeClass(_ctx.$style.footer) }, [createVNode(unref(N8nButton_default), {
label: unref(i18n).baseText("generic.cancel"),
size: "small",
disabled: isSaving.value,
type: "tertiary",
"data-test-id": "mcp-connect-workflows-cancel-button",
onClick: ($event) => cancel(close)
}, null, 8, [
"label",
"disabled",
"onClick"
]), createVNode(unref(N8nButton_default), {
label: unref(i18n).baseText("settings.mcp.connectWorkflows.confirm.label"),
loading: isSaving.value,
disabled: !canSave.value || isSaving.value,
type: "primary",
"data-test-id": "mcp-connect-workflows-save-button",
onClick: ($event) => save(close)
}, null, 8, [
"label",
"loading",
"disabled",
"onClick"
])], 2)]),
_: 1
}, 8, [
"name",
"title",
"class",
"event-bus"
]);
};
}
});
var MCPConnectWorkflowsModal_vue_vue_type_style_index_0_lang_module_default = {
container: "_container_1omke_123",
content: "_content_1omke_128",
notice: "_notice_1omke_133",
footer: "_footer_1omke_140"
};
var MCPConnectWorkflowsModal_default = /* @__PURE__ */ __plugin_vue_export_helper_default(MCPConnectWorkflowsModal_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": MCPConnectWorkflowsModal_vue_vue_type_style_index_0_lang_module_default }]]);
export { MCPConnectWorkflowsModal_default as default };