n8n-editor-ui
Version:
Workflow Editor UI for n8n
1,077 lines (1,076 loc) • 45.2 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, Q as onUnmounted, T as createBlock, W as mergeProps, Z as onMounted, _ as Fragment, _t as watch, b as Teleport, bn as normalizeStyle, bt as withCtx, ct as resolveDynamicComponent, et as openBlock, it as renderList, j as createTextVNode, mt as useTemplateRef, q as onBeforeMount, vn as normalizeClass, w as createBaseVNode } from "./vue.runtime.esm-bundler-tP5dCd7J.js";
import { _t as I18nT, g as onClickOutside, gt as useI18n } from "./_MapCache-B159LOu5.js";
import { A as N8nNavigationDropdown_default, Hn as N8nButton_default, N as N8nLogo_default, Vn as N8nText_default, Wn as N8nIcon_default, i as N8nScrollArea_default, j as N8nMenuItem_default, mt as N8nTooltip_default, ut as N8nLink_default, w as N8nPopoverReka_default, xt as N8nIconButton_default, zn as N8nHeading_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 { v as useRoute, y as useRouter } from "./truncate-Dc5upPom.js";
import "./icon-MZ_3fB_h.js";
import "./empty-4-N75rxI.js";
import { Dn as useSourceControlStore, En as useProjectsStore, Fi as useUIStore, Ho as useSettingsStore, Ls as getBecomeCreatorCta, Vo as useStorage, nr as useUsersStore, o as useWorkflowsStore, oc as STORES, qn as hasPermission, t as useTelemetry } 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 { Do as getResourcePermissions, Ga as DateTime, Go as EXPERIMENT_TEMPLATE_RECO_V2_KEY, Io as VIEWS, Ko as EXPERIMENT_TEMPLATE_RECO_V3_KEY, Lo as ABOUT_MODAL_KEY, S as RELEASE_NOTES_URL, Wo as EXPERIMENT_TEMPLATES_DATA_QUALITY_KEY, cs as VERSIONS_MODAL_KEY, ls as WHATS_NEW_MODAL_KEY } from "./constants-CX1ozgFz.js";
import "./merge-BArJwbQo.js";
import { k as defineStore, r as useRootStore } from "./_baseOrderBy-DL6Sy5xK.js";
import "./dateformat-CMLc6OKJ.js";
import { t as useDebounce } from "./useDebounce-RgPaX171.js";
import { t as useExternalHooks } from "./useExternalHooks-CYMS6JpD.js";
import "./useStyles-DhM0cpS7.js";
import { t as useCloudPlanStore } from "./cloudPlan.store-nppjm48S.js";
import { a as useTemplatesDataQualityStore, i as trackTemplatesClick, n as TemplateClickSource, t as useTemplatesStore } from "./templates.store-CSx5YxpE.js";
import { _ as useCalloutHelpers } from "./nodeCreator.store-DfjyHcRR.js";
import "./nodeIcon-CdzjV7EE.js";
import { t as useVersionsStore } from "./versions.store-BYh7N-zv.js";
import { t as usePageRedirectionHelper } from "./usePageRedirectionHelper-DY-ECTME.js";
import { n as EXTERNAL_LINKS, r as useGlobalEntityCreation, t as useBugReporting } from "./useBugReporting-B_5-Tujg.js";
import "./sortByProperty-DeupcrDk.js";
import { l as CHAT_VIEW } from "./constants-D2fYduVh.js";
import { t as sourceControlEventBus } from "./sourceControl.eventBus-CqqWQrr5.js";
import { t as useKeybindings } from "./useKeybindings-CFy7jL6I.js";
import { n as usePersonalizedTemplatesV2Store, t as usePersonalizedTemplatesV3Store } from "./personalizedTemplatesV3.store-CrBjsVbu.js";
import { t as MainSidebarUserArea_default } from "./MainSidebarUserArea-BZJJYvAQ.js";
const isCustomMenuItem = (e) => "component" in e;
var LOCAL_STORAGE_KEY = "N8N_BECOME_TEMPLATE_CREATOR_CTA_DISMISSED_AT";
var RESHOW_DISMISSED_AFTER_DAYS = 30;
var POLL_INTERVAL_IN_MS = 900 * 1e3;
const useBecomeTemplateCreatorStore = defineStore(STORES.BECOME_TEMPLATE_CREATOR, () => {
const cloudPlanStore = useCloudPlanStore();
const rootStore = useRootStore();
const dismissedAt = useStorage(LOCAL_STORAGE_KEY);
const ctaMeetsCriteria = ref(false);
const monitorCtasTimer = ref(null);
const isDismissed = computed(() => {
return dismissedAt.value ? !hasEnoughTimePassedSinceDismissal(dismissedAt.value) : false;
});
const showBecomeCreatorCta = computed(() => {
return ctaMeetsCriteria.value && !cloudPlanStore.userIsTrialing && !isDismissed.value;
});
const dismissCta = () => {
dismissedAt.value = DateTime.now().toISO();
};
const fetchBecomeCreatorCta = async () => {
ctaMeetsCriteria.value = await getBecomeCreatorCta(rootStore.restApiContext);
};
const fetchUserCtasIfNeeded = async () => {
if (isDismissed.value || cloudPlanStore.userIsTrialing || ctaMeetsCriteria.value) return;
await fetchBecomeCreatorCta();
};
const startMonitoringCta = () => {
if (monitorCtasTimer.value) return;
setTimeout(fetchUserCtasIfNeeded, 1e3);
monitorCtasTimer.value = setInterval(fetchUserCtasIfNeeded, POLL_INTERVAL_IN_MS);
};
const stopMonitoringCta = () => {
if (!monitorCtasTimer.value) return;
clearInterval(monitorCtasTimer.value);
monitorCtasTimer.value = null;
};
return {
showBecomeCreatorCta,
dismissCta,
startMonitoringCta,
stopMonitoringCta
};
});
function hasEnoughTimePassedSinceDismissal(dismissedAt) {
return DateTime.fromISO(dismissedAt).plus({ days: RESHOW_DISMISSED_AFTER_DAYS }) <= DateTime.now();
}
var BecomeTemplateCreatorCta_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
__name: "BecomeTemplateCreatorCta",
setup(__props) {
const i18n = useI18n();
const store = useBecomeTemplateCreatorStore();
const telemetry = useTelemetry();
const onClick = () => {
telemetry.track("User clicked become creator CTA");
};
return (_ctx, _cache) => {
return unref(store).showBecomeCreatorCta ? (openBlock(), createElementBlock("div", {
key: 0,
class: normalizeClass(_ctx.$style.container),
"data-test-id": "become-template-creator-cta"
}, [createBaseVNode("div", { class: normalizeClass(_ctx.$style.textAndCloseButton) }, [createBaseVNode("p", { class: normalizeClass(_ctx.$style.text) }, toDisplayString(unref(i18n).baseText("becomeCreator.text")), 3), createBaseVNode("button", {
class: normalizeClass(_ctx.$style.closeButton),
"data-test-id": "close-become-template-creator-cta",
onClick: _cache[0] || (_cache[0] = ($event) => unref(store).dismissCta())
}, [createVNode(unref(N8nIcon_default), {
icon: "x",
size: "xsmall",
title: unref(i18n).baseText("generic.close")
}, null, 8, ["title"])], 2)], 2), createVNode(unref(N8nButton_default), {
class: normalizeClass(_ctx.$style.becomeCreatorButton),
label: unref(i18n).baseText("becomeCreator.buttonText"),
size: "xmini",
type: "secondary",
element: "a",
href: "https://creators.n8n.io/hub",
target: "_blank",
onClick
}, null, 8, ["class", "label"])], 2)) : createCommentVNode("", true);
};
}
});
var BecomeTemplateCreatorCta_vue_vue_type_style_index_0_lang_module_default = {
container: "_container_1ab4u_123",
textAndCloseButton: "_textAndCloseButton_1ab4u_131",
text: "_text_1ab4u_131",
closeButton: "_closeButton_1ab4u_144",
becomeCreatorButton: "_becomeCreatorButton_1ab4u_156"
};
var BecomeTemplateCreatorCta_default = /* @__PURE__ */ __plugin_vue_export_helper_default(BecomeTemplateCreatorCta_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": BecomeTemplateCreatorCta_vue_vue_type_style_index_0_lang_module_default }]]);
var VersionUpdateCTA_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
__name: "VersionUpdateCTA",
props: {
disabled: {
type: Boolean,
default: false
},
tooltipText: { default: void 0 }
},
setup(__props) {
const props = __props;
const i18n = useI18n();
const versionsStore = useVersionsStore();
const uiStore = useUIStore();
const pageRedirectionHelper = usePageRedirectionHelper();
const telemetry = useTelemetry();
const openUpdatesPanel = () => {
uiStore.openModal(VERSIONS_MODAL_KEY);
};
const onUpdateClick = async () => {
telemetry.track("User clicked on update button", { source: "main-sidebar" });
await pageRedirectionHelper.goToVersions();
};
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", { class: normalizeClass(_ctx.$style.container) }, [createVNode(unref(N8nLink_default), {
size: "small",
theme: "text",
"data-test-id": "version-update-next-versions-link",
onClick: openUpdatesPanel
}, {
default: withCtx(() => [createTextVNode(toDisplayString(unref(i18n).baseText("whatsNew.versionsBehind", { interpolate: { count: unref(versionsStore).nextVersions.length > 99 ? "99+" : unref(versionsStore).nextVersions.length } })), 1)]),
_: 1
}), createVNode(unref(N8nTooltip_default), {
disabled: !props.tooltipText,
content: props.tooltipText
}, {
default: withCtx(() => [createVNode(unref(N8nButton_default), {
class: normalizeClass(_ctx.$style.button),
label: unref(i18n).baseText("whatsNew.update"),
"data-test-id": "version-update-cta-button",
size: "mini",
disabled: props.disabled,
onClick: onUpdateClick
}, null, 8, [
"class",
"label",
"disabled"
])]),
_: 1
}, 8, ["disabled", "content"])], 2);
};
}
});
var VersionUpdateCTA_vue_vue_type_style_index_0_lang_module_default = {
container: "_container_5mg6c_123",
button: "_button_5mg6c_135"
};
var VersionUpdateCTA_default = /* @__PURE__ */ __plugin_vue_export_helper_default(VersionUpdateCTA_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": VersionUpdateCTA_vue_vue_type_style_index_0_lang_module_default }]]);
var TemplateTooltip_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
__name: "TemplateTooltip",
setup(__props) {
const personalizedTemplatesV3Store = usePersonalizedTemplatesV3Store();
const { markTemplateRecommendationInteraction, trackPersonalizationTooltipView, trackPersonalizationTooltipDismiss } = personalizedTemplatesV3Store;
const locale = useI18n();
const tooltipRef = ref();
const isVisible = ref(false);
const position = ref({
top: 0,
left: 0
});
const tooltipKey = ref(0);
const shouldShow = computed(() => personalizedTemplatesV3Store.shouldShowTemplateTooltip);
const calculatePosition = () => {
const templatesElement = document.querySelector("[data-test-id=\"menu-item\"][id=\"templates\"]");
if (!templatesElement) return;
const menuRect = templatesElement.getBoundingClientRect();
position.value = {
top: menuRect.top + menuRect.height / 2 - 5,
left: menuRect.right
};
tooltipKey.value++;
};
const showTooltip = async () => {
isVisible.value = true;
trackPersonalizationTooltipView();
await nextTick();
calculatePosition();
};
const hideTooltip = () => {
isVisible.value = false;
};
const handleDismiss = () => {
trackPersonalizationTooltipDismiss();
markTemplateRecommendationInteraction();
hideTooltip();
};
const handleResize = () => {
if (isVisible.value) calculatePosition();
};
const handleContentResize = () => {
if (isVisible.value) setTimeout(() => {
calculatePosition();
}, 500);
};
watch(shouldShow, async (newValue) => {
if (newValue) await showTooltip();
else hideTooltip();
}, { immediate: true });
let contentResizeObserver = null;
onMounted(() => {
window.addEventListener("resize", handleResize);
window.addEventListener("scroll", handleResize);
const contentElement = document.getElementById("content");
if (contentElement) {
contentResizeObserver = new ResizeObserver(handleContentResize);
contentResizeObserver.observe(contentElement);
}
});
onUnmounted(() => {
window.removeEventListener("resize", handleResize);
window.removeEventListener("scroll", handleResize);
if (contentResizeObserver) {
contentResizeObserver.disconnect();
contentResizeObserver = null;
}
});
return (_ctx, _cache) => {
return openBlock(), createBlock(Teleport, { to: "body" }, [isVisible.value && shouldShow.value ? (openBlock(), createElementBlock("div", {
ref_key: "tooltipRef",
ref: tooltipRef,
key: tooltipKey.value,
class: normalizeClass(_ctx.$style.triggerContainer),
style: normalizeStyle({
position: "fixed",
top: position.value.top + "px",
left: position.value.left + "px"
})
}, [createVNode(unref(N8nTooltip_default), {
visible: true,
placement: "right",
"show-arrow": true,
"popper-style": {
maxWidth: "260px",
minWidth: "240px"
}
}, {
content: withCtx(() => [createBaseVNode("div", { class: normalizeClass(_ctx.$style.tooltipContent) }, [createBaseVNode("span", { class: normalizeClass(_ctx.$style.text) }, toDisplayString(unref(locale).baseText("experiments.personalizedTemplatesV3.recommendationTooltip")), 3), createBaseVNode("button", {
class: normalizeClass(_ctx.$style.dismissButton),
type: "button",
onClick: handleDismiss,
"aria-label": "Dismiss tooltip"
}, [createVNode(unref(N8nIcon_default), {
icon: "x",
size: "small"
})], 2)], 2)]),
default: withCtx(() => [createBaseVNode("div", { class: normalizeClass(_ctx.$style.tooltipTrigger) }, null, 2)]),
_: 1
})], 6)) : createCommentVNode("", true)]);
};
}
});
var TemplateTooltip_vue_vue_type_style_index_0_lang_module_default = {
triggerContainer: "_triggerContainer_5kwt6_123",
tooltipTrigger: "_tooltipTrigger_5kwt6_128",
tooltipContent: "_tooltipContent_5kwt6_134",
text: "_text_5kwt6_140",
dismissButton: "_dismissButton_5kwt6_146"
};
var TemplateTooltip_default = /* @__PURE__ */ __plugin_vue_export_helper_default(TemplateTooltip_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": TemplateTooltip_vue_vue_type_style_index_0_lang_module_default }]]);
var _hoisted_1 = { class: "home" };
var ProjectNavigation_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
__name: "ProjectNavigation",
props: {
collapsed: { type: Boolean },
planName: {}
},
setup(__props) {
const props = __props;
const locale = useI18n();
const globalEntityCreation = useGlobalEntityCreation();
const projectsStore = useProjectsStore();
const settingsStore = useSettingsStore();
const usersStore = useUsersStore();
const isCreatingProject = computed(() => globalEntityCreation.isCreatingProject.value);
const displayProjects = computed(() => globalEntityCreation.displayProjects.value);
const isFoldersFeatureEnabled = computed(() => settingsStore.isFoldersFeatureEnabled);
const hasMultipleVerifiedUsers = computed(() => usersStore.allUsers.filter((user) => !user.isPendingUser).length > 1);
const home = computed(() => ({
id: "home",
label: locale.baseText("projects.menu.overview"),
icon: "house",
route: { to: { name: VIEWS.HOMEPAGE } }
}));
const shared = computed(() => ({
id: "shared",
label: locale.baseText("projects.menu.shared"),
icon: "share",
route: { to: { name: VIEWS.SHARED_WITH_ME } }
}));
const getProjectMenuItem = (project) => ({
id: project.id,
label: project.name ?? "",
icon: project.icon,
route: { to: {
name: VIEWS.PROJECTS_WORKFLOWS,
params: { projectId: project.id }
} }
});
const personalProject = computed(() => ({
id: projectsStore.personalProject?.id ?? "",
label: locale.baseText("projects.menu.personal"),
icon: "user",
route: { to: {
name: VIEWS.PROJECTS_WORKFLOWS,
params: { projectId: projectsStore.personalProject?.id }
} }
}));
const showAddFirstProject = computed(() => projectsStore.isTeamProjectFeatureEnabled && !displayProjects.value.length);
const activeTabId = computed(() => {
return (Array.isArray(projectsStore.projectNavActiveId) ? projectsStore.projectNavActiveId[0] : projectsStore.projectNavActiveId) ?? void 0;
});
async function onSourceControlPull() {
await projectsStore.getMyProjects();
}
onBeforeMount(async () => {
await usersStore.fetchUsers();
sourceControlEventBus.on("pull", onSourceControlPull);
});
onBeforeUnmount(() => {
sourceControlEventBus.off("pull", onSourceControlPull);
});
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", { class: normalizeClass(_ctx.$style.projects) }, [
createBaseVNode("div", _hoisted_1, [
createVNode(unref(N8nMenuItem_default), {
item: home.value,
compact: props.collapsed,
active: activeTabId.value === "home",
"data-test-id": "project-home-menu-item"
}, null, 8, [
"item",
"compact",
"active"
]),
unref(projectsStore).isTeamProjectFeatureEnabled || isFoldersFeatureEnabled.value ? (openBlock(), createBlock(unref(N8nMenuItem_default), {
key: 0,
item: personalProject.value,
compact: props.collapsed,
active: activeTabId.value === personalProject.value.id,
"data-test-id": "project-personal-menu-item"
}, null, 8, [
"item",
"compact",
"active"
])) : createCommentVNode("", true),
(unref(projectsStore).isTeamProjectFeatureEnabled || isFoldersFeatureEnabled.value) && hasMultipleVerifiedUsers.value ? (openBlock(), createBlock(unref(N8nMenuItem_default), {
key: 1,
item: shared.value,
compact: props.collapsed,
active: activeTabId.value === "shared",
"data-test-id": "project-shared-menu-item"
}, null, 8, [
"item",
"compact",
"active"
])) : createCommentVNode("", true)
]),
!props.collapsed && unref(projectsStore).isTeamProjectFeatureEnabled ? (openBlock(), createBlock(unref(N8nHeading_default), {
key: 0,
class: normalizeClass([_ctx.$style.projectsLabel]),
bold: "",
size: "small",
color: "text-light",
tag: "h3"
}, {
default: withCtx(() => [createBaseVNode("span", null, toDisplayString(unref(locale).baseText("projects.menu.title")), 1), unref(projectsStore).canCreateProjects ? (openBlock(), createBlock(unref(N8nTooltip_default), {
key: 0,
placement: "right",
disabled: unref(projectsStore).hasPermissionToCreateProjects,
content: unref(locale).baseText("projects.create.permissionDenied")
}, {
default: withCtx(() => [createVNode(unref(N8nButton_default), {
icon: "plus",
text: "",
"data-test-id": "project-plus-button",
disabled: isCreatingProject.value || !unref(projectsStore).hasPermissionToCreateProjects,
class: normalizeClass(_ctx.$style.plusBtn),
onClick: _cache[0] || (_cache[0] = ($event) => unref(globalEntityCreation).createProject("add_icon"))
}, null, 8, ["disabled", "class"])]),
_: 1
}, 8, ["disabled", "content"])) : createCommentVNode("", true)]),
_: 1
}, 8, ["class"])) : createCommentVNode("", true),
unref(projectsStore).isTeamProjectFeatureEnabled || isFoldersFeatureEnabled.value ? (openBlock(), createElementBlock("div", {
key: 1,
class: normalizeClass(_ctx.$style.projectItems)
}, [(openBlock(true), createElementBlock(Fragment, null, renderList(displayProjects.value, (project) => {
return openBlock(), createBlock(unref(N8nMenuItem_default), {
key: project.id,
class: normalizeClass({ [_ctx.$style.collapsed]: props.collapsed }),
item: getProjectMenuItem(project),
compact: props.collapsed,
active: activeTabId.value === project.id,
"data-test-id": "project-menu-item"
}, null, 8, [
"class",
"item",
"compact",
"active"
]);
}), 128))], 2)) : createCommentVNode("", true),
showAddFirstProject.value ? (openBlock(), createBlock(unref(N8nTooltip_default), {
key: 2,
placement: "right",
disabled: unref(projectsStore).hasPermissionToCreateProjects,
content: unref(locale).baseText("projects.create.permissionDenied")
}, {
default: withCtx(() => [createVNode(unref(N8nButton_default), {
class: normalizeClass([_ctx.$style.addFirstProjectBtn, { [_ctx.$style.collapsed]: props.collapsed }]),
disabled: isCreatingProject.value || !unref(projectsStore).hasPermissionToCreateProjects,
type: "secondary",
icon: "plus",
"data-test-id": "add-first-project-button",
onClick: _cache[1] || (_cache[1] = ($event) => unref(globalEntityCreation).createProject("add_first_project_button"))
}, {
default: withCtx(() => [createBaseVNode("span", null, toDisplayString(unref(locale).baseText("projects.menu.addFirstProject")), 1)]),
_: 1
}, 8, ["class", "disabled"])]),
_: 1
}, 8, ["disabled", "content"])) : createCommentVNode("", true)
], 2);
};
}
});
var ProjectNavigation_vue_vue_type_style_index_0_lang_module_default = {
projects: "_projects_81iv3_123",
plusBtn: "_plusBtn_81iv3_128",
projectItems: "_projectItems_81iv3_132",
upgradeLink: "_upgradeLink_81iv3_136",
projectsLabel: "_projectsLabel_81iv3_141",
collapsed: "_collapsed_81iv3_150",
addFirstProjectBtn: "_addFirstProjectBtn_81iv3_163"
};
var ProjectNavigation_default = /* @__PURE__ */ __plugin_vue_export_helper_default(ProjectNavigation_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": ProjectNavigation_vue_vue_type_style_index_0_lang_module_default }], ["__scopeId", "data-v-7bf5593b"]]);
var MainSidebarSourceControl_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
__name: "MainSidebarSourceControl",
props: { isCollapsed: { type: Boolean } },
setup(__props) {
const sourceControlStore = useSourceControlStore();
const projectStore = useProjectsStore();
const i18n = useI18n();
const route = useRoute();
const router = useRouter();
const tooltipOpenDelay = ref(300);
const currentBranch = computed(() => {
return sourceControlStore.preferences.branchName;
});
const hasPushPermission = computed(() => {
return hasPermission(["rbac"], { rbac: { scope: "sourceControl:push" } }) || projectStore.myProjects.some((project) => project.type === "team" && getResourcePermissions(project?.scopes)?.sourceControl?.push);
});
const hasPullPermission = computed(() => {
return hasPermission(["rbac"], { rbac: { scope: "sourceControl:pull" } });
});
const sourceControlAvailable = computed(() => sourceControlStore.isEnterpriseSourceControlEnabled && (hasPullPermission.value || hasPushPermission.value));
async function pushWorkfolder() {
router.push({ query: {
...route.query,
sourceControl: "push"
} });
}
function pullWorkfolder() {
router.push({ query: {
...route.query,
sourceControl: "pull"
} });
}
return (_ctx, _cache) => {
return sourceControlAvailable.value ? (openBlock(), createElementBlock("div", {
key: 0,
class: normalizeClass({
[_ctx.$style.sync]: true,
[_ctx.$style.collapsed]: _ctx.isCollapsed,
[_ctx.$style.isConnected]: unref(sourceControlStore).isEnterpriseSourceControlEnabled
}),
style: normalizeStyle({ borderLeftColor: unref(sourceControlStore).preferences.branchColor }),
"data-test-id": "main-sidebar-source-control"
}, [unref(sourceControlStore).preferences.connected && unref(sourceControlStore).preferences.branchName ? (openBlock(), createElementBlock("div", {
key: 0,
class: normalizeClass(_ctx.$style.connected),
"data-test-id": "main-sidebar-source-control-connected"
}, [createBaseVNode("span", { class: normalizeClass(_ctx.$style.branchName) }, [createVNode(unref(N8nIcon_default), { icon: "git-branch" }), createTextVNode(" " + toDisplayString(currentBranch.value), 1)], 2), createBaseVNode("div", { class: normalizeClass({ "pt-xs": !_ctx.isCollapsed }) }, [createVNode(unref(N8nTooltip_default), {
disabled: !_ctx.isCollapsed && hasPullPermission.value,
"show-after": tooltipOpenDelay.value,
placement: _ctx.isCollapsed ? "right" : "top"
}, {
content: withCtx(() => [createBaseVNode("div", null, toDisplayString(!hasPullPermission.value ? unref(i18n).baseText("settings.sourceControl.button.pull.forbidden") : unref(i18n).baseText("settings.sourceControl.button.pull")), 1)]),
default: withCtx(() => [createVNode(unref(N8nButton_default), {
class: normalizeClass({
"mr-2xs": !_ctx.isCollapsed,
"mb-2xs": _ctx.isCollapsed
}),
disabled: !hasPullPermission.value,
"data-test-id": "main-sidebar-source-control-pull",
icon: "arrow-down",
type: "tertiary",
size: "mini",
square: _ctx.isCollapsed,
label: _ctx.isCollapsed ? "" : unref(i18n).baseText("settings.sourceControl.button.pull"),
onClick: pullWorkfolder
}, null, 8, [
"class",
"disabled",
"square",
"label"
])]),
_: 1
}, 8, [
"disabled",
"show-after",
"placement"
]), createVNode(unref(N8nTooltip_default), {
disabled: !_ctx.isCollapsed && !unref(sourceControlStore).preferences.branchReadOnly && hasPushPermission.value,
"show-after": tooltipOpenDelay.value,
placement: _ctx.isCollapsed ? "right" : "top"
}, {
content: withCtx(() => [createBaseVNode("div", null, toDisplayString(unref(sourceControlStore).preferences.branchReadOnly || !hasPushPermission.value ? unref(i18n).baseText("settings.sourceControl.button.push.forbidden") : unref(i18n).baseText("settings.sourceControl.button.push")), 1)]),
default: withCtx(() => [createVNode(unref(N8nButton_default), {
square: _ctx.isCollapsed,
label: _ctx.isCollapsed ? "" : unref(i18n).baseText("settings.sourceControl.button.push"),
disabled: unref(sourceControlStore).preferences.branchReadOnly || !hasPushPermission.value,
"data-test-id": "main-sidebar-source-control-push",
icon: "arrow-up",
type: "tertiary",
size: "mini",
onClick: pushWorkfolder
}, null, 8, [
"square",
"label",
"disabled"
])]),
_: 1
}, 8, [
"disabled",
"show-after",
"placement"
])], 2)], 2)) : createCommentVNode("", true)], 6)) : createCommentVNode("", true);
};
}
});
var MainSidebarSourceControl_vue_vue_type_style_index_0_lang_module_default = {
sync: "_sync_1xb4i_123",
isConnected: "_isConnected_1xb4i_129",
collapsed: "_collapsed_1xb4i_133",
branchName: "_branchName_1xb4i_143",
connected: "_connected_1xb4i_153"
};
var MainSidebarSourceControl_default = /* @__PURE__ */ __plugin_vue_export_helper_default(MainSidebarSourceControl_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": MainSidebarSourceControl_vue_vue_type_style_index_0_lang_module_default }]]);
var MainSidebar_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
__name: "MainSidebar",
setup(__props) {
const becomeTemplateCreatorStore = useBecomeTemplateCreatorStore();
const cloudPlanStore = useCloudPlanStore();
const rootStore = useRootStore();
const settingsStore = useSettingsStore();
const templatesStore = useTemplatesStore();
const uiStore = useUIStore();
const usersStore = useUsersStore();
const versionsStore = useVersionsStore();
const workflowsStore = useWorkflowsStore();
const sourceControlStore = useSourceControlStore();
const personalizedTemplatesV2Store = usePersonalizedTemplatesV2Store();
const personalizedTemplatesV3Store = usePersonalizedTemplatesV3Store();
const templatesDataQualityStore = useTemplatesDataQualityStore();
const { callDebounced } = useDebounce();
const externalHooks = useExternalHooks();
const i18n = useI18n();
const telemetry = useTelemetry();
const pageRedirectionHelper = usePageRedirectionHelper();
const { getReportingURL } = useBugReporting();
const calloutHelpers = useCalloutHelpers();
useKeybindings({ ctrl_alt_o: () => handleSelect("about") });
const user = useTemplateRef("user");
const basePath = ref("");
const fullyExpanded = ref(false);
const showWhatsNewNotification = computed(() => versionsStore.hasVersionUpdates || versionsStore.whatsNewArticles.some((article) => !versionsStore.isWhatsNewArticleRead(article.id)));
const isTemplatesExperimentEnabled = computed(() => {
return personalizedTemplatesV2Store.isFeatureEnabled() || personalizedTemplatesV3Store.isFeatureEnabled() || templatesDataQualityStore.isFeatureEnabled();
});
const mainMenuItems = computed(() => [
{
id: "cloud-admin",
position: "bottom",
label: "Admin Panel",
icon: "cloud",
available: settingsStore.isCloudDeployment && hasPermission(["instanceOwner"])
},
{
id: "chat",
icon: "message-circle",
label: "Chat",
position: "bottom",
route: { to: { name: CHAT_VIEW } },
available: settingsStore.isChatFeatureEnabled && hasPermission(["rbac"], { rbac: { scope: "chatHub:message" } })
},
{
id: "templates",
icon: "package-open",
label: i18n.baseText("generic.templates"),
position: "bottom",
available: settingsStore.isTemplatesEnabled && calloutHelpers.isPreBuiltAgentsCalloutVisible.value && !isTemplatesExperimentEnabled.value,
route: { to: { name: VIEWS.PRE_BUILT_AGENT_TEMPLATES } }
},
{
id: "templates",
icon: "package-open",
label: i18n.baseText("generic.templates"),
position: "bottom",
available: settingsStore.isTemplatesEnabled && isTemplatesExperimentEnabled.value
},
{
id: "templates",
icon: "package-open",
label: i18n.baseText("generic.templates"),
position: "bottom",
available: settingsStore.isTemplatesEnabled && !calloutHelpers.isPreBuiltAgentsCalloutVisible.value && templatesStore.hasCustomTemplatesHost && !isTemplatesExperimentEnabled.value,
route: { to: { name: VIEWS.TEMPLATES } }
},
{
id: "templates",
icon: "package-open",
label: i18n.baseText("generic.templates"),
position: "bottom",
available: settingsStore.isTemplatesEnabled && !calloutHelpers.isPreBuiltAgentsCalloutVisible.value && !templatesStore.hasCustomTemplatesHost && !isTemplatesExperimentEnabled.value,
link: {
href: templatesStore.websiteTemplateRepositoryURL,
target: "_blank"
}
},
{
id: "insights",
icon: "chart-column-decreasing",
label: "Insights",
position: "bottom",
route: { to: { name: VIEWS.INSIGHTS } },
available: settingsStore.isModuleActive("insights") && hasPermission(["rbac"], { rbac: { scope: "insights:list" } })
},
{
id: "help",
icon: "circle-help",
label: i18n.baseText("mainSidebar.help"),
position: "bottom",
children: [
{
id: "quickstart",
icon: "video",
label: i18n.baseText("mainSidebar.helpMenuItems.quickstart"),
link: {
href: EXTERNAL_LINKS.QUICKSTART_VIDEO,
target: "_blank"
}
},
{
id: "docs",
icon: "book",
label: i18n.baseText("mainSidebar.helpMenuItems.documentation"),
link: {
href: EXTERNAL_LINKS.DOCUMENTATION,
target: "_blank"
}
},
{
id: "forum",
icon: "users",
label: i18n.baseText("mainSidebar.helpMenuItems.forum"),
link: {
href: EXTERNAL_LINKS.FORUM,
target: "_blank"
}
},
{
id: "examples",
icon: "graduation-cap",
label: i18n.baseText("mainSidebar.helpMenuItems.course"),
link: {
href: EXTERNAL_LINKS.COURSES,
target: "_blank"
}
},
{
id: "report-bug",
icon: "bug",
label: i18n.baseText("mainSidebar.helpMenuItems.reportBug"),
link: {
href: getReportingURL(),
target: "_blank"
}
},
{
id: "about",
icon: "info",
label: i18n.baseText("mainSidebar.aboutN8n"),
position: "bottom"
}
]
},
{
id: "whats-new",
icon: "bell",
notification: showWhatsNewNotification.value,
label: i18n.baseText("mainSidebar.whatsNew"),
position: "bottom",
available: versionsStore.hasVersionUpdates || versionsStore.whatsNewArticles.length > 0,
children: [
...versionsStore.whatsNewArticles.map((article) => ({
id: `whats-new-article-${article.id}`,
label: article.title,
size: "small",
customIconSize: "small",
icon: {
type: "emoji",
value: "•",
color: !versionsStore.isWhatsNewArticleRead(article.id) ? "primary" : "text-light"
}
})),
{
id: "full-changelog",
icon: "external-link",
label: i18n.baseText("mainSidebar.whatsNew.fullChangelog"),
link: {
href: RELEASE_NOTES_URL,
target: "_blank"
},
size: "small",
customIconSize: "small"
},
{
id: "version-upgrade-cta",
component: VersionUpdateCTA_default,
available: versionsStore.hasVersionUpdates,
props: {
disabled: !usersStore.canUserUpdateVersion,
tooltipText: !usersStore.canUserUpdateVersion ? i18n.baseText("whatsNew.updateNudgeTooltip") : void 0
}
}
]
}
]);
const visibleMenuItems = computed(() => mainMenuItems.value.filter((item) => item.available !== false));
const createBtn = ref();
const isCollapsed = computed(() => uiStore.sidebarMenuCollapsed);
const showUserArea = computed(() => hasPermission(["authenticated"]));
const userIsTrialing = computed(() => cloudPlanStore.userIsTrialing);
onMounted(async () => {
window.addEventListener("resize", onResize);
basePath.value = rootStore.baseUrl;
if (user.value?.$el) externalHooks.run("mainSidebar.mounted", { userRef: user.value.$el });
becomeTemplateCreatorStore.startMonitoringCta();
await nextTick(onResizeEnd);
});
onBeforeUnmount(() => {
becomeTemplateCreatorStore.stopMonitoringCta();
window.removeEventListener("resize", onResize);
});
const trackHelpItemClick = (itemType) => {
telemetry.track("User clicked help resource", {
type: itemType,
workflow_id: workflowsStore.workflowId
});
};
const toggleCollapse = () => {
uiStore.toggleSidebarMenuCollapse();
if (!isCollapsed.value) setTimeout(() => {
fullyExpanded.value = !isCollapsed.value;
}, 300);
else fullyExpanded.value = !isCollapsed.value;
};
const handleSelect = (key) => {
switch (key) {
case "templates":
if (templatesDataQualityStore.isFeatureEnabled()) {
uiStore.openModal(EXPERIMENT_TEMPLATES_DATA_QUALITY_KEY);
trackTemplatesClick(TemplateClickSource.sidebarButton);
} else if (personalizedTemplatesV3Store.isFeatureEnabled()) {
personalizedTemplatesV3Store.markTemplateRecommendationInteraction();
uiStore.openModalWithData({
name: EXPERIMENT_TEMPLATE_RECO_V3_KEY,
data: {}
});
trackTemplatesClick(TemplateClickSource.sidebarButton);
} else if (personalizedTemplatesV2Store.isFeatureEnabled()) {
uiStore.openModalWithData({
name: EXPERIMENT_TEMPLATE_RECO_V2_KEY,
data: {}
});
trackTemplatesClick(TemplateClickSource.sidebarButton);
} else if (settingsStore.isTemplatesEnabled && !templatesStore.hasCustomTemplatesHost) trackTemplatesClick(TemplateClickSource.sidebarButton);
break;
case "about":
trackHelpItemClick("about");
uiStore.openModal(ABOUT_MODAL_KEY);
break;
case "cloud-admin":
pageRedirectionHelper.goToDashboard();
break;
case "quickstart":
case "docs":
case "forum":
case "examples":
trackHelpItemClick(key);
break;
case "insights": telemetry.track("User clicked insights link from side menu");
default:
if (key.startsWith("whats-new-article-")) {
const articleId = Number(key.replace("whats-new-article-", ""));
telemetry.track("User clicked on what's new section", { article_id: articleId });
uiStore.openModalWithData({
name: WHATS_NEW_MODAL_KEY,
data: { articleId }
});
}
break;
}
};
function onResize() {
callDebounced(onResizeEnd, { debounceTime: 250 });
}
async function onResizeEnd() {
if (window.innerWidth < 900) uiStore.sidebarMenuCollapsed = true;
else uiStore.sidebarMenuCollapsed = uiStore.sidebarMenuCollapsedPreference;
nextTick(() => {
fullyExpanded.value = !isCollapsed.value;
});
}
const { menu, handleSelect: handleMenuSelect, createProjectAppendSlotName, createWorkflowsAppendSlotName, createCredentialsAppendSlotName, projectsLimitReachedMessage, upgradeLabel, hasPermissionToCreateProjects } = useGlobalEntityCreation();
onClickOutside(createBtn, () => {
createBtn.value?.close();
});
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", {
id: "side-menu",
class: normalizeClass({
["side-menu"]: true,
[_ctx.$style.sideMenu]: true,
[_ctx.$style.sideMenuCollapsed]: isCollapsed.value
})
}, [
createBaseVNode("div", {
id: "collapse-change-button",
class: normalizeClass(["clickable", _ctx.$style.sideMenuCollapseButton]),
onClick: toggleCollapse
}, [isCollapsed.value ? (openBlock(), createBlock(unref(N8nIcon_default), {
key: 0,
icon: "chevron-right",
size: "xsmall",
class: "ml-5xs"
})) : (openBlock(), createBlock(unref(N8nIcon_default), {
key: 1,
icon: "chevron-left",
size: "xsmall",
class: "mr-5xs"
}))], 2),
createBaseVNode("div", { class: normalizeClass(_ctx.$style.logo) }, [createVNode(unref(N8nLogo_default), {
size: "small",
collapsed: isCollapsed.value,
"release-channel": unref(settingsStore).settings.releaseChannel
}, {
default: withCtx(() => [unref(sourceControlStore).preferences.branchReadOnly && !isCollapsed.value ? (openBlock(), createBlock(unref(N8nTooltip_default), {
key: 0,
placement: "bottom"
}, {
content: withCtx(() => [createVNode(unref(I18nT), {
keypath: "readOnlyEnv.tooltip",
scope: "global"
}, {
link: withCtx(() => [createVNode(unref(N8nLink_default), {
to: "https://docs.n8n.io/source-control-environments/setup/#step-4-connect-n8n-and-configure-your-instance",
size: "small"
}, {
default: withCtx(() => [createTextVNode(toDisplayString(unref(i18n).baseText("readOnlyEnv.tooltip.link")), 1)]),
_: 1
})]),
_: 1
})]),
default: withCtx(() => [createVNode(unref(N8nIcon_default), {
"data-test-id": "read-only-env-icon",
icon: "lock",
size: "xsmall",
class: normalizeClass(_ctx.$style.readOnlyEnvironmentIcon)
}, null, 8, ["class"])]),
_: 1
})) : createCommentVNode("", true)]),
_: 1
}, 8, ["collapsed", "release-channel"]), createVNode(unref(N8nNavigationDropdown_default), {
ref_key: "createBtn",
ref: createBtn,
"data-test-id": "universal-add",
menu: unref(menu),
onSelect: unref(handleMenuSelect)
}, {
[unref(createWorkflowsAppendSlotName)]: withCtx(() => [unref(sourceControlStore).preferences.branchReadOnly ? (openBlock(), createBlock(unref(N8nTooltip_default), {
key: 0,
placement: "right",
content: unref(i18n).baseText("readOnlyEnv.cantAdd.workflow")
}, {
default: withCtx(() => [createVNode(unref(N8nIcon_default), {
style: {
"margin-left": "auto",
"margin-right": "5px"
},
icon: "lock",
size: "xsmall"
})]),
_: 1
}, 8, ["content"])) : createCommentVNode("", true)]),
[unref(createCredentialsAppendSlotName)]: withCtx(() => [unref(sourceControlStore).preferences.branchReadOnly ? (openBlock(), createBlock(unref(N8nTooltip_default), {
key: 0,
placement: "right",
content: unref(i18n).baseText("readOnlyEnv.cantAdd.credential")
}, {
default: withCtx(() => [createVNode(unref(N8nIcon_default), {
style: {
"margin-left": "auto",
"margin-right": "5px"
},
icon: "lock",
size: "xsmall"
})]),
_: 1
}, 8, ["content"])) : createCommentVNode("", true)]),
[unref(createProjectAppendSlotName)]: withCtx(({ item }) => [unref(sourceControlStore).preferences.branchReadOnly ? (openBlock(), createBlock(unref(N8nTooltip_default), {
key: 0,
placement: "right",
content: unref(i18n).baseText("readOnlyEnv.cantAdd.project")
}, {
default: withCtx(() => [createVNode(unref(N8nIcon_default), {
style: {
"margin-left": "auto",
"margin-right": "5px"
},
icon: "lock",
size: "xsmall"
})]),
_: 1
}, 8, ["content"])) : item.disabled ? (openBlock(), createBlock(unref(N8nTooltip_default), {
key: 1,
placement: "right",
content: unref(projectsLimitReachedMessage)
}, {
default: withCtx(() => [!unref(hasPermissionToCreateProjects) ? (openBlock(), createBlock(unref(N8nIcon_default), {
key: 0,
style: {
"margin-left": "auto",
"margin-right": "5px"
},
icon: "lock",
size: "xsmall"
})) : (openBlock(), createBlock(unref(N8nButton_default), {
key: 1,
size: "mini",
style: { "margin-left": "auto" },
type: "tertiary",
onClick: ($event) => unref(handleMenuSelect)(item.id)
}, {
default: withCtx(() => [createTextVNode(toDisplayString(unref(upgradeLabel)), 1)]),
_: 2
}, 1032, ["onClick"]))]),
_: 2
}, 1032, ["content"])) : createCommentVNode("", true)]),
default: withCtx(() => [createVNode(unref(N8nIconButton_default), {
icon: "plus",
type: "secondary",
outline: ""
})]),
_: 2
}, 1032, ["menu", "onSelect"])], 2),
createVNode(unref(N8nScrollArea_default), { "as-child": "" }, {
default: withCtx(() => [createBaseVNode("div", { class: normalizeClass(_ctx.$style.scrollArea) }, [createVNode(ProjectNavigation_default, {
collapsed: isCollapsed.value,
"plan-name": unref(cloudPlanStore).currentPlanData?.displayName
}, null, 8, ["collapsed", "plan-name"]), createBaseVNode("div", { class: normalizeClass(_ctx.$style.bottomMenu) }, [fullyExpanded.value && !userIsTrialing.value ? (openBlock(), createBlock(BecomeTemplateCreatorCta_default, { key: 0 })) : createCommentVNode("", true), createBaseVNode("div", { class: normalizeClass(_ctx.$style.bottomMenuItems) }, [(openBlock(true), createElementBlock(Fragment, null, renderList(visibleMenuItems.value, (item) => {
return openBlock(), createElementBlock(Fragment, { key: item.id }, [item.children ? (openBlock(), createBlock(unref(N8nPopoverReka_default), {
key: item.id,
side: "right",
align: "end",
"side-offset": 16
}, {
content: withCtx(() => [createBaseVNode("div", { class: normalizeClass(_ctx.$style.popover) }, [createVNode(unref(N8nText_default), {
class: normalizeClass(_ctx.$style.popoverTitle),
bold: "",
color: "foreground-xdark"
}, {
default: withCtx(() => [createTextVNode(toDisplayString(item.label), 1)]),
_: 2
}, 1032, ["class"]), (openBlock(true), createElementBlock(Fragment, null, renderList(item.children, (child) => {
return openBlock(), createElementBlock(Fragment, { key: child.id }, [unref(isCustomMenuItem)(child) ? (openBlock(), createBlock(resolveDynamicComponent(child.component), mergeProps({
key: 0,
ref_for: true
}, child.props), null, 16)) : (openBlock(), createBlock(unref(N8nMenuItem_default), {
key: 1,
item: child,
onClick: () => handleSelect(child.id)
}, null, 8, ["item", "onClick"]))], 64);
}), 128))], 2)]),
trigger: withCtx(() => [createVNode(unref(N8nMenuItem_default), {
item,
compact: isCollapsed.value,
onClick: () => handleSelect(item.id)
}, null, 8, [
"item",
"compact",
"onClick"
])]),
_: 2
}, 1024)) : (openBlock(), createBlock(unref(N8nMenuItem_default), {
key: 1,
item,
compact: isCollapsed.value,
onClick: () => handleSelect(item.id)
}, null, 8, [
"item",
"compact",
"onClick"
]))], 64);
}), 128))], 2)], 2)], 2)]),
_: 1
}),
createVNode(MainSidebarSourceControl_default, { "is-collapsed": isCollapsed.value }, null, 8, ["is-collapsed"]),
showUserArea.value ? (openBlock(), createBlock(MainSidebarUserArea_default, {
key: 0,
ref_key: "user",
ref: user,
"fully-expanded": fullyExpanded.value,
"is-collapsed": isCollapsed.value
}, null, 8, ["fully-expanded", "is-collapsed"])) : createCommentVNode("", true),
createVNode(TemplateTooltip_default)
], 2);
};
}
});
var MainSidebar_vue_vue_type_style_index_0_lang_module_default = {
sideMenu: "_sideMenu_1icmk_123",
logo: "_logo_1icmk_132",
sideMenuCollapsed: "_sideMenuCollapsed_1icmk_143",
scrollArea: "_scrollArea_1icmk_152",
sideMenuCollapseButton: "_sideMenuCollapseButton_1icmk_158",
bottomMenu: "_bottomMenu_1icmk_177",
bottomMenuItems: "_bottomMenuItems_1icmk_183",
popover: "_popover_1icmk_187",
popoverTitle: "_popoverTitle_1icmk_192",
readOnlyEnvironmentIcon: "_readOnlyEnvironmentIcon_1icmk_202"
};
var MainSidebar_default = /* @__PURE__ */ __plugin_vue_export_helper_default(MainSidebar_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": MainSidebar_vue_vue_type_style_index_0_lang_module_default }]]);
export { MainSidebar_default as default };