n8n-editor-ui
Version:
Workflow Editor UI for n8n
551 lines (550 loc) • 22.7 kB
JavaScript
import { C as computed, Cn as toDisplayString, D as createElementBlock, E as createCommentVNode, Gt as unref, It as ref, M as createVNode, P as defineComponent, T as createBlock, W as mergeProps, _ as Fragment, bt as withCtx, ct as resolveDynamicComponent, et as openBlock, it as renderList, j as createTextVNode, vn as normalizeClass, w as createBaseVNode } from "./vue.runtime.esm-bundler-tP5dCd7J.js";
import { M as useLocalStorage, _t as useI18n, g as onClickOutside, vt as I18nT } from "./_MapCache-ficiegRb.js";
import { D as N8nPopover_default, I as N8nLogo_default, M as N8nNavigationDropdown_default, N as N8nMenuItem_default, P as BetaTag_default, Sn as N8nButton_default, ht as N8nTooltip_default, mt as N8nLink_default, wn as N8nIcon_default, xn as N8nText_default, xt as N8nIconButton_default } from "./src-DgvumQTi.js";
import { t as __plugin_vue_export_helper_default } from "./_plugin-vue_export-helper-BwBpWJRZ.js";
import { f as RouterLink } from "./truncate-B1HVeveJ.js";
import { Dr as useUsersStore, Ec as STORES, O as useTelemetry, Zn as useSourceControlStore, gs as useSettingsStore, hs as useStorage, oa as useUIStore, p as useCloudPlanStore, sc as getBecomeCreatorCta } from "./builder.store-sBTWwxRU.js";
import { Ha as DateTime, Hs as LOCAL_STORAGE_SIDEBAR_WIDTH, Ro as VIEWS, x as RELEASE_NOTES_URL } from "./constants-BbpucWL4.js";
import { k as defineStore, r as useRootStore } from "./_baseOrderBy-B_6CV8x6.js";
import { t as KeyboardShortcutTooltip_default } from "./KeyboardShortcutTooltip-B4E72qs1.js";
import { t as useVersionsStore } from "./versions.store-BwdT833-.js";
import { t as usePageRedirectionHelper } from "./usePageRedirectionHelper-fGNB6ZKK.js";
import { i as useGlobalEntityCreation, t as useCommandBar } from "./useCommandBar-DX5Sf1tf.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();
}
function useSidebarLayout() {
const uiStore = useUIStore();
const isCollapsed = computed(() => uiStore.sidebarMenuCollapsed);
const sidebarWidth = useLocalStorage(LOCAL_STORAGE_SIDEBAR_WIDTH, isCollapsed.value ? 42 : 300);
const toggleCollapse = () => {
uiStore.toggleSidebarMenuCollapse();
if (!isCollapsed.value) sidebarWidth.value = 200;
else sidebarWidth.value = 42;
};
const isResizing = ref(false);
function onResizeStart() {
isResizing.value = true;
}
function onResize(event) {
if (isCollapsed.value && event.x > 100) {
toggleCollapse();
return;
}
if (isCollapsed.value) return;
if (event.x < 100 && !isCollapsed.value) {
toggleCollapse();
return;
}
sidebarWidth.value = event.width;
}
function onResizeEnd() {
isResizing.value = false;
}
return {
isCollapsed,
toggleCollapse,
sidebarWidth,
isResizing,
onResizeStart,
onResize,
onResizeEnd
};
}
var MainSidebarHeader_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
__name: "MainSidebarHeader",
props: {
isCollapsed: { type: Boolean },
isBeta: { type: Boolean },
hideCreate: { type: Boolean }
},
emits: ["collapse", "openCommandBar"],
setup(__props, { emit: __emit }) {
const emit = __emit;
const { isEnabled: isCommandBarEnabled } = useCommandBar();
const i18n = useI18n();
const sourceControlStore = useSourceControlStore();
const settingsStore = useSettingsStore();
const createBtn = ref();
onClickOutside(createBtn, () => {
createBtn.value?.close();
});
function toggleCollapse() {
emit("collapse");
}
function openCommandBar(event) {
emit("openCommandBar", event);
}
const { menu, handleSelect: handleMenuSelect, createProjectAppendSlotName, createWorkflowsAppendSlotName, createCredentialsAppendSlotName, projectsLimitReachedMessage, upgradeLabel, hasPermissionToCreateProjects } = useGlobalEntityCreation();
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", { class: normalizeClass({
[_ctx.$style.header]: true,
[_ctx.$style.collapsed]: _ctx.isCollapsed
}) }, [
!_ctx.isCollapsed ? (openBlock(), createBlock(unref(RouterLink), {
key: 0,
to: { name: unref(VIEWS).HOMEPAGE },
class: normalizeClass(_ctx.$style.logo)
}, {
default: withCtx(() => [createVNode(unref(N8nLogo_default), {
size: "small",
collapsed: _ctx.isCollapsed,
"release-channel": unref(settingsStore).settings.releaseChannel
}, {
default: withCtx(() => [_ctx.isBeta ? (openBlock(), createBlock(BetaTag_default, {
key: 0,
class: normalizeClass(_ctx.$style.beta),
"data-test-id": "beta-icon"
}, null, 8, ["class"])) : createCommentVNode("", true), unref(sourceControlStore).preferences.branchReadOnly && !_ctx.isCollapsed ? (openBlock(), createBlock(unref(N8nTooltip_default), {
key: 1,
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",
class: normalizeClass(_ctx.$style.readOnlyEnvironmentIcon)
}, null, 8, ["class"])]),
_: 1
})) : createCommentVNode("", true)]),
_: 1
}, 8, ["collapsed", "release-channel"])]),
_: 1
}, 8, ["to", "class"])) : createCommentVNode("", true),
!_ctx.hideCreate ? (openBlock(), createBlock(unref(N8nNavigationDropdown_default), {
key: 1,
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), {
class: normalizeClass(_ctx.$style.iconButton),
icon: "lock",
size: "xsmall"
}, null, 8, ["class"])]),
_: 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), {
class: normalizeClass(_ctx.$style.iconButton),
icon: "lock",
size: "xsmall"
}, null, 8, ["class"])]),
_: 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), {
class: normalizeClass(_ctx.$style.iconButton),
icon: "lock",
size: "xsmall"
}, null, 8, ["class"])]),
_: 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,
class: normalizeClass(_ctx.$style.iconButton),
icon: "lock",
size: "xsmall"
}, null, 8, ["class"])) : (openBlock(), createBlock(unref(N8nButton_default), {
key: 1,
size: "mini",
class: normalizeClass(_ctx.$style.upgradeButton),
type: "tertiary",
onClick: ($event) => unref(handleMenuSelect)(item.id)
}, {
default: withCtx(() => [createTextVNode(toDisplayString(unref(upgradeLabel)), 1)]),
_: 2
}, 1032, ["class", "onClick"]))]),
_: 2
}, 1032, ["content"])) : createCommentVNode("", true)]),
default: withCtx(() => [createVNode(unref(N8nIconButton_default), {
size: "small",
type: "highlight",
icon: "plus",
"icon-size": "large",
"aria-label": "Add new item"
})]),
_: 2
}, 1032, ["menu", "onSelect"])) : createCommentVNode("", true),
unref(isCommandBarEnabled) ? (openBlock(), createBlock(KeyboardShortcutTooltip_default, {
key: 2,
placement: _ctx.isCollapsed ? "right" : "bottom",
"show-after": 500,
label: unref(i18n).baseText("nodeView.openCommandBar"),
shortcut: {
keys: ["k"],
metaKey: true
}
}, {
default: withCtx(() => [createVNode(unref(N8nIconButton_default), {
size: "small",
type: "highlight",
icon: "search",
"icon-size": "large",
"aria-label": "Open command palette",
onClick: openCommandBar
})]),
_: 1
}, 8, ["placement", "label"])) : createCommentVNode("", true),
createVNode(KeyboardShortcutTooltip_default, {
placement: _ctx.isCollapsed ? "right" : "bottom",
label: _ctx.isCollapsed ? unref(i18n).baseText("mainSidebar.state.expand") : unref(i18n).baseText("mainSidebar.state.collapse"),
"show-after": 500,
shortcut: { keys: ["["] }
}, {
default: withCtx(() => [createVNode(unref(N8nIconButton_default), {
id: "toggle-sidebar-button",
size: "small",
type: "highlight",
icon: "panel-left",
"icon-size": "large",
"aria-label": "Toggle sidebar",
onClick: toggleCollapse
})]),
_: 1
}, 8, ["placement", "label"])
], 2);
};
}
});
var MainSidebarHeader_vue_vue_type_style_index_0_lang_module_default = {
header: "_header_voqst_123",
collapsed: "_collapsed_voqst_137",
logo: "_logo_voqst_142",
beta: "_beta_voqst_146",
readOnlyEnvironmentIcon: "_readOnlyEnvironmentIcon_voqst_151",
iconButton: "_iconButton_voqst_161",
upgradeButton: "_upgradeButton_voqst_166"
};
var MainSidebarHeader_default = /* @__PURE__ */ __plugin_vue_export_helper_default(MainSidebarHeader_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": MainSidebarHeader_vue_vue_type_style_index_0_lang_module_default }]]);
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) }, [createVNode(unref(N8nText_default), { size: "small" }, {
default: withCtx(() => [createTextVNode(toDisplayString(unref(i18n).baseText("becomeCreator.text")), 1)]),
_: 1
}), 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",
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"),
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_1yloq_123",
textAndCloseButton: "_textAndCloseButton_1yloq_132",
text: "_text_1yloq_132",
closeButton: "_closeButton_1yloq_145",
becomeCreatorButton: "_becomeCreatorButton_1yloq_157"
};
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_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 pageRedirectionHelper = usePageRedirectionHelper();
const telemetry = useTelemetry();
const onUpdateClick = async () => {
telemetry.track("User clicked on update button", { source: "main-sidebar" });
await pageRedirectionHelper.goToVersions();
};
return (_ctx, _cache) => {
return openBlock(), createBlock(unref(N8nMenuItem_default), {
"data-test-id": "version-update-cta-button",
item: {
id: "version-update-cta",
icon: {
value: "status-warning",
type: "icon",
color: "primary"
},
disabled: props.disabled,
disabledReason: props.tooltipText,
label: unref(i18n).baseText("whatsNew.versionsBehind", { interpolate: { count: unref(versionsStore).nextVersions.length > 99 ? "99+" : unref(versionsStore).nextVersions.length } })
},
onClick: onUpdateClick
}, null, 8, ["item"]);
};
}
});
var BottomMenu_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
__name: "BottomMenu",
props: {
items: {},
isCollapsed: { type: Boolean }
},
emits: ["select", "logout"],
setup(__props, { emit: __emit }) {
const emit = __emit;
const cloudPlanStore = useCloudPlanStore();
const versionsStore = useVersionsStore();
const usersStore = useUsersStore();
const i18n = useI18n();
const whatsNewItems = computed(() => ({
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"
},
...versionsStore.hasVersionUpdates ? [{
id: "version-upgrade-cta",
component: VersionUpdateCTA_default,
props: {
tooltipText: !usersStore.canUserUpdateVersion ? i18n.baseText("whatsNew.updateNudgeTooltip") : void 0,
disabled: !usersStore.canUserUpdateVersion
}
}] : []
]
}));
const userIsTrialing = computed(() => cloudPlanStore.userIsTrialing);
function handleSelect(key) {
emit("select", key);
}
function onLogout() {
emit("logout");
}
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", { class: normalizeClass({
[_ctx.$style.bottomMenu]: true,
[_ctx.$style.collapsed]: _ctx.isCollapsed
}) }, [createBaseVNode("div", { class: normalizeClass(_ctx.$style.bottomMenuItems) }, [(openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.items, (item) => {
return openBlock(), createElementBlock(Fragment, { key: item.id }, [item.children && item.id === "help" ? (openBlock(), createBlock(unref(N8nPopover_default), {
key: "help",
side: "right",
align: "end",
"side-offset": 12
}, {
content: withCtx(() => [createBaseVNode("div", { class: normalizeClass(_ctx.$style.popover) }, [
!_ctx.isCollapsed && !userIsTrialing.value ? (openBlock(), createBlock(BecomeTemplateCreatorCta_default, { key: 0 })) : createCommentVNode("", true),
(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)),
whatsNewItems.value.available ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [createVNode(unref(N8nText_default), {
bold: "",
size: "small",
class: normalizeClass(_ctx.$style.popoverTitle),
color: "text-light"
}, {
default: withCtx(() => _cache[0] || (_cache[0] = [createTextVNode("What's new")])),
_: 1
}, 8, ["class"]), (openBlock(true), createElementBlock(Fragment, null, renderList(whatsNewItems.value.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))], 64)) : createCommentVNode("", true)
], 2)]),
trigger: withCtx(() => [createVNode(unref(N8nMenuItem_default), {
"data-test-id": `main-sidebar-${item.id}`,
item,
compact: _ctx.isCollapsed,
onClick: () => handleSelect(item.id)
}, null, 8, [
"data-test-id",
"item",
"compact",
"onClick"
])]),
_: 2
}, 1024)) : item.children && item.id === "settings" ? (openBlock(), createBlock(unref(N8nPopover_default), {
key: "settings",
side: "right",
align: "end",
"side-offset": 12
}, {
content: withCtx(() => [createBaseVNode("div", { class: normalizeClass(_ctx.$style.popover) }, [
(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)),
createBaseVNode("span", { class: normalizeClass(_ctx.$style.divider) }, null, 2),
createVNode(unref(N8nMenuItem_default), {
"data-test-id": "main-sidebar-log-out",
item: {
id: "sign-out",
label: "Sign out",
icon: "door-open"
},
onClick: onLogout
})
], 2)]),
trigger: withCtx(() => [createVNode(unref(N8nMenuItem_default), {
"data-test-id": `main-sidebar-${item.id}`,
item,
compact: _ctx.isCollapsed,
onClick: () => handleSelect(item.id)
}, null, 8, [
"data-test-id",
"item",
"compact",
"onClick"
])]),
_: 2
}, 1024)) : (openBlock(), createBlock(unref(N8nMenuItem_default), {
key: 2,
"data-test-id": `main-sidebar-${item.id}`,
item,
compact: _ctx.isCollapsed,
onClick: () => handleSelect(item.id)
}, null, 8, [
"data-test-id",
"item",
"compact",
"onClick"
]))], 64);
}), 128))], 2)], 2);
};
}
});
var BottomMenu_vue_vue_type_style_index_0_lang_module_default = {
bottomMenu: "_bottomMenu_17gn9_123",
collapsed: "_collapsed_17gn9_128",
bottomMenuItems: "_bottomMenuItems_17gn9_132",
popover: "_popover_17gn9_136",
popoverTitle: "_popoverTitle_17gn9_143",
divider: "_divider_17gn9_150"
};
var BottomMenu_default = /* @__PURE__ */ __plugin_vue_export_helper_default(BottomMenu_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": BottomMenu_vue_vue_type_style_index_0_lang_module_default }]]);
export { useBecomeTemplateCreatorStore as i, MainSidebarHeader_default as n, useSidebarLayout as r, BottomMenu_default as t };