Files
lcbp3.np-dms.work/n8n-cache/n8n/public/assets/MainHeader-CTxGLJsC.js
2025-09-21 20:29:15 +07:00

2229 lines
84 KiB
JavaScript
Executable File

import { d as defineComponent, r as ref, x as computed, e as createBlock, f as createCommentVNode, g as openBlock, l as unref, y as N8nPopoverReka, w as withCtx, j as createBaseVNode, n as normalizeClass, i as createVNode, h as createElementBlock, m as N8nHeading, k as createTextVNode, t as toDisplayString, z as N8nCallout, F as Fragment, A as renderList, B as withModifiers, N as N8nIcon, p as N8nText, C as N8nLink, D as useI18n, _ as _export_sfc, E as ElDropdown, G as N8nAvatar, H as ElDropdownMenu, I as ElDropdownItem, J as N8nUserInfo, K as mergeProps, L as MAIN_HEADER_TABS, O as N8nRadioButtons, P as useDebounce, Q as useUIStore, R as BREAKPOINT_SM, S as BREAKPOINT_XL, T as BREAKPOINT_LG, U as BREAKPOINT_MD, o as onMounted, W as onBeforeUnmount, X as renderSlot, Y as nextTick, Z as getBannerRowHeight, $ as defineStore, a0 as usePushConnectionStore, a1 as useWorkflowsStore, u as useUsersStore, a2 as useRoute, a3 as PLACEHOLDER_EMPTY_WORKFLOW_ID, a4 as STORES, a5 as TIME, a6 as useDocumentVisibility, a7 as watch, V as VIEWS, a8 as resolveComponent, a9 as Tooltip, aa as _sfc_main$d, c as useI18n$1, ab as I18nT, b as useRouter, ac as useEvaluationStore, ad as useNodeTypesStore, ae as useWorkflowSettingsCache, af as useSourceControlStore, ag as WORKFLOW_ACTIVE_MODAL_KEY, ah as ERROR_WORKFLOW_DOCS_URL, ai as EVALUATIONS_DOCS_URL, aj as TIME_SAVED_DOCS_URL, ak as WORKFLOW_SETTINGS_MODAL_KEY, al as useTelemetry, am as useMessage, an as MODAL_CONFIRM, ao as debounce, ap as normalizeStyle, aq as createEventBus, ar as useTagsStore, as as useCssModule, at as useRootStore, v as useSettingsStore, au as useProjectsStore, av as useFoldersStore, aw as useNpsSurveyStore, a as useToast, ax as useDocumentTitle, ay as useWorkflowSaving, az as useWorkflowHelpers, aA as usePageRedirectionHelper, aB as getResourcePermissions, aC as WORKFLOW_MENU_ACTIONS, aD as hasPermission, aE as EnterpriseEditionFeature, aF as ProjectTypes, aG as useTemplateRef, aH as InlineRename, aI as MAX_WORKFLOW_NAME_LENGTH, aJ as _sfc_main$e, aK as N8nBadge, q as N8nButton, aL as SaveButton, aM as N8nActionDropdown, aN as WORKFLOW_SHARE_MODAL_KEY, aO as nodeViewEventBus, aP as IMPORT_WORKFLOW_URL_MODAL_KEY, aQ as FileSaver_minExports, aR as DUPLICATE_MODAL_KEY, aS as ResourceType, aT as PROJECT_MOVE_RESOURCE_MODAL, aU as __vitePreload, aV as hyphenate, aW as h, aX as hasOwn, aY as useNDVStore, aZ as useExecutionsStore, a_ as useLocalStorage, a$ as LOCAL_STORAGE_HIDE_GITHUB_STAR_BUTTON, b0 as STICKY_NODE_TYPE, b1 as onBeforeMount, b2 as withDirectives, b3 as vShow, b4 as N8N_MAIN_GITHUB_REPO_URL } from "./index--OJ5nhDf.js";
import { _ as __unplugin_components_0, W as WorkflowActivator } from "./WorkflowActivator-DZIgVvgL.js";
import { u as useBeforeUnload } from "./useBeforeUnload-ZtUpNFCu.js";
import { _ as _sfc_main$f } from "./PushConnectionTracker.vue_vue_type_script_setup_true_lang-zVio8c2n.js";
import { T as Tag } from "./Tag-BQAJRKFE.js";
import { u as usePushConnection } from "./usePushConnection-Db77V5LR.js";
import "./ProjectBreadcrumb-BxMwihEP.js";
import "./useWorkflowActivate-7Rw9KyzM.js";
import "./global-link-actions--TiC75iP.js";
import "./readyToRunWorkflows.store-Dhb8bhvk.js";
const _hoisted_1$4 = ["data-action-id", "onClick"];
const _hoisted_2$3 = { key: 0 };
const _sfc_main$c = /* @__PURE__ */ defineComponent({
...{ name: "N8nSuggestedActions" },
__name: "SuggestedActions",
props: {
title: {},
actions: {},
open: { type: Boolean },
ignoreAllLabel: { default: void 0 },
popoverAlignment: { default: void 0 },
notice: { default: void 0 }
},
emits: ["action-click", "ignore-click", "ignore-all", "update:open"],
setup(__props, { emit: __emit }) {
const props = __props;
const emit = __emit;
const { t } = useI18n();
const ignoringActions = ref(/* @__PURE__ */ new Set());
const completedCount = computed(() => props.actions.filter((action) => action.completed).length);
const handleActionClick = (action) => {
if (!action.completed) {
emit("action-click", action.id);
}
};
const handleIgnoreClick = (actionId) => {
ignoringActions.value.add(actionId);
setTimeout(() => {
emit("ignore-click", actionId);
ignoringActions.value.delete(actionId);
}, 500);
};
return (_ctx, _cache) => {
return completedCount.value !== _ctx.actions.length ? (openBlock(), createBlock(unref(N8nPopoverReka), {
key: 0,
open: _ctx.open,
width: "360px",
"max-height": "500px",
align: _ctx.popoverAlignment,
"onUpdate:open": _cache[2] || (_cache[2] = ($event) => _ctx.$emit("update:open", $event))
}, {
trigger: withCtx(() => [
createBaseVNode("div", {
class: normalizeClass([_ctx.$style.triggerContainer, _ctx.open ? _ctx.$style.activeTrigger : ""]),
"data-test-id": "suggested-action-count"
}, [
createVNode(unref(Tag), {
text: `${completedCount.value} / ${_ctx.actions.length}`
}, null, 8, ["text"])
], 2)
]),
content: withCtx(() => [
createBaseVNode("div", {
class: normalizeClass(_ctx.$style.popoverContent)
}, [
createVNode(unref(N8nHeading), { tag: "h4" }, {
default: withCtx(() => [
createTextVNode(toDisplayString(_ctx.title), 1)
]),
_: 1
}),
_ctx.notice ? (openBlock(), createBlock(unref(N8nCallout), {
key: 0,
theme: "warning"
}, {
default: withCtx(() => [
createTextVNode(toDisplayString(_ctx.notice), 1)
]),
_: 1
})) : createCommentVNode("", true),
(openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.actions, (action) => {
return openBlock(), createElementBlock("div", {
key: action.id,
class: normalizeClass([
{
[_ctx.$style.actionItem]: true,
[_ctx.$style.ignoring]: ignoringActions.value.has(action.id),
[_ctx.$style.actionable]: !action.completed
}
]),
"data-test-id": "suggested-action-item",
"data-action-id": action.id,
onClick: withModifiers(() => handleActionClick(action), ["prevent", "stop"])
}, [
createBaseVNode("div", {
class: normalizeClass(_ctx.$style.checkboxContainer)
}, [
action.completed ? (openBlock(), createBlock(unref(N8nIcon), {
key: 0,
icon: "circle-check",
color: "success"
})) : (openBlock(), createBlock(unref(N8nIcon), {
key: 1,
icon: "circle",
color: "foreground-dark"
}))
], 2),
createBaseVNode("div", {
class: normalizeClass(_ctx.$style.actionItemBody)
}, [
createBaseVNode("div", {
class: normalizeClass([action.completed ? "" : "mb-3xs", _ctx.$style.actionHeader])
}, [
createVNode(unref(N8nText), {
size: "medium",
bold: true
}, {
default: withCtx(() => [
createTextVNode(toDisplayString(action.title), 1)
]),
_: 2
}, 1024)
], 2),
!action.completed ? (openBlock(), createElementBlock("div", _hoisted_2$3, [
createVNode(unref(N8nText), {
size: "small",
color: "text-base"
}, {
default: withCtx(() => [
createTextVNode(toDisplayString(action.description) + " ", 1),
action.moreInfoLink ? (openBlock(), createBlock(unref(N8nLink), {
key: 0,
to: action.moreInfoLink,
size: "small",
theme: "text",
"new-window": "",
underline: "",
onClick: _cache[0] || (_cache[0] = withModifiers(() => {
}, ["stop"]))
}, {
default: withCtx(() => [
createTextVNode(toDisplayString(unref(t)("generic.moreInfo")), 1)
]),
_: 2
}, 1032, ["to"])) : createCommentVNode("", true)
]),
_: 2
}, 1024)
])) : createCommentVNode("", true)
], 2),
createVNode(unref(N8nLink), {
theme: "text",
title: unref(t)("generic.ignore"),
"data-test-id": "suggested-action-ignore",
onClick: withModifiers(($event) => handleIgnoreClick(action.id), ["prevent", "stop"])
}, {
default: withCtx(() => [
!action.completed ? (openBlock(), createBlock(unref(N8nIcon), {
key: 0,
icon: "x",
size: "large"
})) : createCommentVNode("", true)
]),
_: 2
}, 1032, ["title", "onClick"])
], 10, _hoisted_1$4);
}), 128)),
createBaseVNode("div", {
class: normalizeClass(_ctx.$style.ignoreAllContainer)
}, [
createVNode(unref(N8nLink), {
theme: "text",
size: "small",
underline: "",
"data-test-id": "suggested-action-ignore-all",
onClick: _cache[1] || (_cache[1] = withModifiers(($event) => emit("ignore-all"), ["prevent", "stop"]))
}, {
default: withCtx(() => [
createTextVNode(toDisplayString(_ctx.ignoreAllLabel ?? unref(t)("generic.ignoreAll")), 1)
]),
_: 1
})
], 2)
], 2)
]),
_: 1
}, 8, ["open", "align"])) : createCommentVNode("", true);
};
}
});
const triggerContainer = "_triggerContainer_1gki6_123";
const activeTrigger = "_activeTrigger_1gki6_129";
const popoverContent = "_popoverContent_1gki6_134";
const actionItem = "_actionItem_1gki6_141";
const ignoring = "_ignoring_1gki6_147";
const actionable = "_actionable_1gki6_154";
const actionHeader = "_actionHeader_1gki6_157";
const actionItemBody = "_actionItemBody_1gki6_164";
const checkboxContainer = "_checkboxContainer_1gki6_171";
const ignoreAllContainer = "_ignoreAllContainer_1gki6_176";
const style0$4 = {
triggerContainer,
activeTrigger,
popoverContent,
actionItem,
ignoring,
actionable,
actionHeader,
actionItemBody,
checkboxContainer,
ignoreAllContainer
};
const cssModules$5 = {
"$style": style0$4
};
const N8nSuggestedActions = /* @__PURE__ */ _export_sfc(_sfc_main$c, [["__cssModules", cssModules$5]]);
const _hoisted_1$3 = {
class: "user-stack",
"data-test-id": "user-stack-container"
};
const _sfc_main$b = /* @__PURE__ */ defineComponent({
__name: "UserStack",
props: {
users: {},
currentUserEmail: { default: "" },
maxAvatars: { default: 2 },
dropdownTrigger: { default: "hover" }
},
setup(__props) {
const props = __props;
const nonEmptyGroups = computed(() => {
const users = {};
for (const groupName2 in props.users) {
if (props.users[groupName2].length > 0) {
users[groupName2] = props.users[groupName2];
}
}
return users;
});
const groupCount = computed(() => {
return Object.keys(nonEmptyGroups.value).length;
});
const flatUserList = computed(() => {
const users = [];
for (const groupName2 in props.users) {
users.push(...props.users[groupName2]);
}
return users;
});
const visibleAvatarCount = computed(() => {
return flatUserList.value.length >= props.maxAvatars ? props.maxAvatars : flatUserList.value.length;
});
const hiddenUsersCount = computed(() => {
return flatUserList.value.length - visibleAvatarCount.value;
});
const menuHeight = computed(() => {
return groupCount.value > 1 ? 220 : 190;
});
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", _hoisted_1$3, [
createVNode(unref(ElDropdown), {
trigger: _ctx.$props.dropdownTrigger,
"max-height": menuHeight.value,
"popper-class": "user-stack-popper"
}, {
dropdown: withCtx(() => [
createVNode(unref(ElDropdownMenu), {
class: "user-stack-list",
"data-test-id": "user-stack-list"
}, {
default: withCtx(() => [
(openBlock(true), createElementBlock(Fragment, null, renderList(nonEmptyGroups.value, (groupUsers2, index) => {
return openBlock(), createElementBlock("div", { key: index }, [
createBaseVNode("div", {
class: normalizeClass(_ctx.$style.groupContainer)
}, [
createVNode(unref(ElDropdownItem), null, {
default: withCtx(() => [
groupCount.value > 1 ? (openBlock(), createElementBlock("header", {
key: 0,
class: normalizeClass(_ctx.$style.groupName)
}, toDisplayString(index), 3)) : createCommentVNode("", true)
]),
_: 2
}, 1024),
createBaseVNode("div", {
class: normalizeClass(_ctx.$style.groupUsers)
}, [
(openBlock(true), createElementBlock(Fragment, null, renderList(groupUsers2, (user) => {
return openBlock(), createBlock(unref(ElDropdownItem), {
key: user.id,
"data-test-id": `user-stack-info-${user.id}`,
class: normalizeClass(_ctx.$style.userInfoContainer)
}, {
default: withCtx(() => [
createVNode(unref(N8nUserInfo), mergeProps({ ref_for: true }, user, {
"is-current-user": user.email === props.currentUserEmail
}), null, 16, ["is-current-user"])
]),
_: 2
}, 1032, ["data-test-id", "class"]);
}), 128))
], 2)
], 2)
]);
}), 128))
]),
_: 1
})
]),
default: withCtx(() => [
createBaseVNode("div", {
class: normalizeClass(_ctx.$style.avatars),
"data-test-id": "user-stack-avatars"
}, [
(openBlock(true), createElementBlock(Fragment, null, renderList(flatUserList.value.slice(0, visibleAvatarCount.value), (user) => {
return openBlock(), createBlock(unref(N8nAvatar), {
key: user.id,
"first-name": user.firstName,
"last-name": user.lastName,
class: normalizeClass(_ctx.$style.avatar),
"data-test-id": `user-stack-avatar-${user.id}`,
size: "small"
}, null, 8, ["first-name", "last-name", "class", "data-test-id"]);
}), 128)),
hiddenUsersCount.value > 0 ? (openBlock(), createElementBlock("div", {
key: 0,
class: normalizeClass(_ctx.$style.hiddenBadge)
}, "+" + toDisplayString(hiddenUsersCount.value), 3)) : createCommentVNode("", true)
], 2)
]),
_: 1
}, 8, ["trigger", "max-height"])
]);
};
}
});
const avatars = "_avatars_1u5zw_123";
const avatar = "_avatar_1u5zw_123";
const hiddenBadge = "_hiddenBadge_1u5zw_133";
const groupContainer = "_groupContainer_1u5zw_148";
const groupName = "_groupName_1u5zw_156";
const groupUsers = "_groupUsers_1u5zw_164";
const userInfoContainer = "_userInfoContainer_1u5zw_170";
const style0$3 = {
avatars,
avatar,
hiddenBadge,
groupContainer,
groupName,
groupUsers,
userInfoContainer
};
const cssModules$4 = {
"$style": style0$3
};
const N8nUserStack = /* @__PURE__ */ _export_sfc(_sfc_main$b, [["__cssModules", cssModules$4]]);
const _sfc_main$a = /* @__PURE__ */ defineComponent({
__name: "TabBar",
props: {
items: {},
modelValue: { default: MAIN_HEADER_TABS.WORKFLOW }
},
emits: ["update:modelValue"],
setup(__props, { emit: __emit }) {
const emit = __emit;
function onUpdateModelValue(tab, event) {
emit("update:modelValue", tab, event);
}
return (_ctx, _cache) => {
const _component_N8nRadioButtons = N8nRadioButtons;
return _ctx.items ? (openBlock(), createElementBlock("div", {
key: 0,
class: normalizeClass({
[_ctx.$style.container]: true,
["tab-bar-container"]: true
})
}, [
createVNode(_component_N8nRadioButtons, {
"model-value": _ctx.modelValue,
options: _ctx.items,
"onUpdate:modelValue": onUpdateModelValue
}, null, 8, ["model-value", "options"])
], 2)) : createCommentVNode("", true);
};
}
});
const container$3 = "_container_j6ct2_123";
const style0$2 = {
container: container$3
};
const cssModules$3 = {
"$style": style0$2
};
const TabBar = /* @__PURE__ */ _export_sfc(_sfc_main$a, [["__cssModules", cssModules$3]]);
const _sfc_main$9 = /* @__PURE__ */ defineComponent({
__name: "BreakpointsObserver",
props: {
valueXS: {},
valueXL: {},
valueLG: {},
valueMD: {},
valueSM: {},
valueDefault: {}
},
setup(__props) {
const props = __props;
const { callDebounced } = useDebounce();
const uiStore = useUIStore();
const width = ref(window.innerWidth);
const bp = computed(() => {
if (width.value < BREAKPOINT_SM) {
return "XS";
}
if (width.value >= BREAKPOINT_XL) {
return "XL";
}
if (width.value >= BREAKPOINT_LG) {
return "LG";
}
if (width.value >= BREAKPOINT_MD) {
return "MD";
}
return "SM";
});
const value = computed(() => {
if (props.valueXS && width.value < BREAKPOINT_SM) {
return props.valueXS;
}
if (props.valueXL && width.value >= BREAKPOINT_XL) {
return props.valueXL;
}
if (props.valueLG && width.value >= BREAKPOINT_LG) {
return props.valueLG;
}
if (props.valueMD && width.value >= BREAKPOINT_MD) {
return props.valueMD;
}
if (props.valueSM) {
return props.valueSM;
}
return props.valueDefault;
});
const onResize = () => {
void callDebounced(onResizeEnd, { debounceTime: 50 });
};
const onResizeEnd = async () => {
width.value = window.innerWidth;
await nextTick();
const bannerHeight = await getBannerRowHeight();
uiStore.updateBannersHeight(bannerHeight);
};
onMounted(() => {
window.addEventListener("resize", onResize);
});
onBeforeUnmount(() => {
window.removeEventListener("resize", onResize);
});
return (_ctx, _cache) => {
return openBlock(), createElementBlock("span", null, [
renderSlot(_ctx.$slots, "default", {
bp: bp.value,
value: value.value
})
]);
};
}
});
const HEARTBEAT_INTERVAL = 5 * TIME.MINUTE;
const useCollaborationStore = defineStore(STORES.COLLABORATION, () => {
const pushStore = usePushConnectionStore();
const workflowsStore = useWorkflowsStore();
const usersStore = useUsersStore();
const uiStore = useUIStore();
const route = useRoute();
const { addBeforeUnloadEventBindings, removeBeforeUnloadEventBindings, addBeforeUnloadHandler } = useBeforeUnload({ route });
const unloadTimeout = ref(null);
addBeforeUnloadHandler(() => {
notifyWorkflowClosed();
if (uiStore.stateIsDirty) {
unloadTimeout.value = setTimeout(() => notifyWorkflowOpened, 5 * TIME.SECOND);
}
});
const collaborators = ref([]);
const heartbeatTimer = ref(null);
const startHeartbeat = () => {
stopHeartbeat();
heartbeatTimer.value = window.setInterval(notifyWorkflowOpened, HEARTBEAT_INTERVAL);
};
const stopHeartbeat = () => {
if (heartbeatTimer.value !== null) {
clearInterval(heartbeatTimer.value);
heartbeatTimer.value = null;
}
};
const pushStoreEventListenerRemovalFn = ref(null);
function initialize() {
if (pushStoreEventListenerRemovalFn.value) {
return;
}
pushStoreEventListenerRemovalFn.value = pushStore.addEventListener((event) => {
if (event.type === "collaboratorsChanged" && event.data.workflowId === workflowsStore.workflowId) {
collaborators.value = event.data.collaborators;
}
});
addBeforeUnloadEventBindings();
notifyWorkflowOpened();
startHeartbeat();
}
function terminate() {
if (typeof pushStoreEventListenerRemovalFn.value === "function") {
pushStoreEventListenerRemovalFn.value();
pushStoreEventListenerRemovalFn.value = null;
}
notifyWorkflowClosed();
stopHeartbeat();
pushStore.clearQueue();
removeBeforeUnloadEventBindings();
if (unloadTimeout.value) {
clearTimeout(unloadTimeout.value);
}
}
function notifyWorkflowOpened() {
const { workflowId } = workflowsStore;
if (workflowId === PLACEHOLDER_EMPTY_WORKFLOW_ID) return;
pushStore.send({ type: "workflowOpened", workflowId });
}
function notifyWorkflowClosed() {
const { workflowId } = workflowsStore;
if (workflowId === PLACEHOLDER_EMPTY_WORKFLOW_ID) return;
pushStore.send({ type: "workflowClosed", workflowId });
collaborators.value = collaborators.value.filter(
({ user }) => user.id !== usersStore.currentUserId
);
}
return {
collaborators,
initialize,
terminate,
startHeartbeat,
stopHeartbeat
};
});
const _sfc_main$8 = /* @__PURE__ */ defineComponent({
__name: "CollaborationPane",
setup(__props) {
const collaborationStore = useCollaborationStore();
const usersStore = useUsersStore();
const visibility = useDocumentVisibility();
watch(visibility, (visibilityState) => {
if (visibilityState === "hidden") {
collaborationStore.stopHeartbeat();
} else {
collaborationStore.startHeartbeat();
}
});
const showUserStack = computed(() => collaborationStore.collaborators.length > 1);
const collaboratorsSorted = computed(() => {
const users = collaborationStore.collaborators.map(({ user }) => user);
const index = users.findIndex((user) => user.id === usersStore.currentUser?.id);
if (index < 1) return { defaultGroup: users };
const [currentUser] = users.splice(index, 1);
return { defaultGroup: [currentUser, ...users] };
});
const currentUserEmail = computed(() => usersStore.currentUser?.email);
onMounted(() => {
collaborationStore.initialize();
});
onBeforeUnmount(() => {
collaborationStore.terminate();
});
return (_ctx, _cache) => {
const _component_n8n_user_stack = N8nUserStack;
return openBlock(), createElementBlock("div", {
class: normalizeClass(`collaboration-pane-container ${_ctx.$style.container}`),
"data-test-id": "collaboration-pane"
}, [
showUserStack.value ? (openBlock(), createBlock(_component_n8n_user_stack, {
key: 0,
users: collaboratorsSorted.value,
"current-user-email": currentUserEmail.value
}, null, 8, ["users", "current-user-email"])) : createCommentVNode("", true)
], 2);
};
}
});
const container$2 = "_container_ame1i_123";
const style0$1 = {
container: container$2
};
const cssModules$2 = {
"$style": style0$1
};
const CollaborationPane = /* @__PURE__ */ _export_sfc(_sfc_main$8, [["__cssModules", cssModules$2]]);
const _hoisted_1$2 = { key: 0 };
const _hoisted_2$2 = { key: 1 };
const _sfc_main$7 = /* @__PURE__ */ defineComponent({
__name: "WorkflowHistoryButton",
props: {
workflowId: {},
isNewWorkflow: { type: Boolean },
isFeatureEnabled: { type: Boolean }
},
emits: ["upgrade"],
setup(__props, { emit: __emit }) {
const locale = useI18n$1();
const props = __props;
const emit = __emit;
const workflowHistoryRoute = computed(() => ({
name: VIEWS.WORKFLOW_HISTORY,
params: {
workflowId: props.workflowId
}
}));
return (_ctx, _cache) => {
const _component_N8nIconButton = _sfc_main$d;
const _component_RouterLink = resolveComponent("RouterLink");
const _component_N8nLink = N8nLink;
const _component_N8nTooltip = Tooltip;
return openBlock(), createBlock(_component_N8nTooltip, { placement: "bottom" }, {
content: withCtx(() => [
_ctx.isFeatureEnabled && _ctx.isNewWorkflow ? (openBlock(), createElementBlock("span", _hoisted_1$2, toDisplayString(unref(locale).baseText("workflowHistory.button.tooltip.empty")), 1)) : _ctx.isFeatureEnabled ? (openBlock(), createElementBlock("span", _hoisted_2$2, toDisplayString(unref(locale).baseText("workflowHistory.button.tooltip.enabled")), 1)) : (openBlock(), createBlock(unref(I18nT), {
key: 2,
keypath: "workflowHistory.button.tooltip.disabled",
scope: "global"
}, {
link: withCtx(() => [
createVNode(_component_N8nLink, {
size: "small",
onClick: _cache[0] || (_cache[0] = ($event) => emit("upgrade"))
}, {
default: withCtx(() => [
createTextVNode(toDisplayString(unref(locale).baseText("workflowHistory.button.tooltip.disabled.link")), 1)
]),
_: 1
})
]),
_: 1
}))
]),
default: withCtx(() => [
createVNode(_component_RouterLink, { to: workflowHistoryRoute.value }, {
default: withCtx(() => [
createVNode(_component_N8nIconButton, {
disabled: _ctx.isNewWorkflow || !_ctx.isFeatureEnabled,
"data-test-id": "workflow-history-button",
type: "highlight",
icon: "history",
size: "medium"
}, null, 8, ["disabled"])
]),
_: 1
}, 8, ["to"])
]),
_: 1
});
};
}
});
const _sfc_main$6 = /* @__PURE__ */ defineComponent({
__name: "WorkflowProductionChecklist",
props: {
workflow: {}
},
setup(__props) {
const props = __props;
const i18n = useI18n$1();
const router = useRouter();
const evaluationStore = useEvaluationStore();
const nodeTypesStore = useNodeTypesStore();
const workflowsCache = useWorkflowSettingsCache();
const uiStore = useUIStore();
const message = useMessage();
const telemetry = useTelemetry();
const sourceControlStore = useSourceControlStore();
const isPopoverOpen = ref(false);
const cachedSettings = ref(null);
const hasAINode = computed(() => {
const nodes = props.workflow.nodes;
return nodes.some((node) => {
const nodeType = nodeTypesStore.getNodeType(node.type, node.typeVersion);
return nodeType?.codex?.categories?.includes("AI");
});
});
const hasEvaluationSetOutputsNode = computed(() => {
return evaluationStore.evaluationSetOutputsNodeExist;
});
const hasErrorWorkflow = computed(() => {
return !!props.workflow.settings?.errorWorkflow;
});
const hasTimeSaved = computed(() => {
return props.workflow.settings?.timeSavedPerExecution !== void 0;
});
const isActivationModalOpen = computed(() => {
return uiStore.isModalActiveById[WORKFLOW_ACTIVE_MODAL_KEY];
});
const isProtectedEnvironment = computed(() => {
return sourceControlStore.preferences.branchReadOnly;
});
const availableActions = computed(() => {
if (!props.workflow.active || workflowsCache.isCacheLoading.value) {
return [];
}
const actions = [];
const suggestedActionSettings = cachedSettings.value?.suggestedActions ?? {};
if (!suggestedActionSettings.errorWorkflow?.ignored) {
actions.push({
id: "errorWorkflow",
title: i18n.baseText("workflowProductionChecklist.errorWorkflow.title"),
description: i18n.baseText("workflowProductionChecklist.errorWorkflow.description"),
moreInfoLink: ERROR_WORKFLOW_DOCS_URL,
completed: hasErrorWorkflow.value
});
}
if (hasAINode.value && evaluationStore.isEvaluationEnabled && !suggestedActionSettings.evaluations?.ignored) {
actions.push({
id: "evaluations",
title: i18n.baseText("workflowProductionChecklist.evaluations.title"),
description: i18n.baseText("workflowProductionChecklist.evaluations.description"),
moreInfoLink: EVALUATIONS_DOCS_URL,
completed: hasEvaluationSetOutputsNode.value
});
}
if (!suggestedActionSettings.timeSaved?.ignored) {
actions.push({
id: "timeSaved",
title: i18n.baseText("workflowProductionChecklist.timeSaved.title"),
description: i18n.baseText("workflowProductionChecklist.timeSaved.description"),
moreInfoLink: TIME_SAVED_DOCS_URL,
completed: hasTimeSaved.value
});
}
return actions;
});
async function loadWorkflowSettings() {
if (props.workflow.id) {
cachedSettings.value = await workflowsCache.getMergedWorkflowSettings(props.workflow.id);
}
}
async function handleActionClick(actionId) {
if (actionId === "evaluations") {
await router.push({
name: VIEWS.EVALUATION_EDIT,
params: { name: props.workflow.id }
});
} else if (actionId === "errorWorkflow" || actionId === "timeSaved") {
uiStore.openModal(WORKFLOW_SETTINGS_MODAL_KEY);
}
isPopoverOpen.value = false;
}
function isValidAction(action) {
return ["evaluations", "errorWorkflow", "timeSaved"].includes(action);
}
async function handleIgnoreClick(actionId) {
if (!isValidAction(actionId)) {
return;
}
await workflowsCache.ignoreSuggestedAction(props.workflow.id, actionId);
await loadWorkflowSettings();
telemetry.track("user clicked ignore suggested action", {
actionId
});
}
async function handleIgnoreAll() {
const ignoreAllConfirmed = await message.confirm(
i18n.baseText("workflowProductionChecklist.ignoreAllConfirmation.description"),
i18n.baseText("workflowProductionChecklist.ignoreAllConfirmation.title"),
{
confirmButtonText: i18n.baseText("workflowProductionChecklist.ignoreAllConfirmation.confirm")
}
);
if (ignoreAllConfirmed === MODAL_CONFIRM) {
await workflowsCache.ignoreAllSuggestedActionsForAllWorkflows(
availableActions.value.map((action) => action.id)
);
await loadWorkflowSettings();
telemetry.track("user clicked ignore suggested actions for all workflows");
}
}
function openSuggestedActions() {
isPopoverOpen.value = true;
}
function onPopoverOpened() {
telemetry.track("user opened suggested actions checklist");
}
function handlePopoverOpenChange(open) {
if (open) {
isPopoverOpen.value = true;
onPopoverOpened();
} else if (!isActivationModalOpen.value) {
isPopoverOpen.value = false;
}
}
watch(
() => props.workflow.active,
async (isActive, wasActive) => {
if (isActive && !wasActive) {
if (!cachedSettings.value?.firstActivatedAt) {
setTimeout(() => {
openSuggestedActions();
}, 0);
}
await workflowsCache.updateFirstActivatedAt(props.workflow.id);
}
}
);
onMounted(async () => {
await loadWorkflowSettings();
});
return (_ctx, _cache) => {
return availableActions.value.length > 0 ? (openBlock(), createBlock(unref(N8nSuggestedActions), {
key: 0,
open: isPopoverOpen.value,
title: unref(i18n).baseText("workflowProductionChecklist.title"),
actions: availableActions.value,
"ignore-all-label": unref(i18n).baseText("workflowProductionChecklist.turnOffWorkflowSuggestions"),
notice: isProtectedEnvironment.value ? unref(i18n).baseText("workflowProductionChecklist.readOnlyNotice") : "",
"popover-alignment": "end",
onActionClick: handleActionClick,
onIgnoreClick: handleIgnoreClick,
onIgnoreAll: handleIgnoreAll,
"onUpdate:open": handlePopoverOpenChange
}, null, 8, ["open", "title", "actions", "ignore-all-label", "notice"])) : createCommentVNode("", true);
};
}
});
const _sfc_main$5 = /* @__PURE__ */ defineComponent({
__name: "IntersectionObserver",
props: {
threshold: { default: 0 },
enabled: { type: Boolean, default: false },
eventBus: {}
},
emits: ["observed"],
setup(__props, { emit: __emit }) {
const props = __props;
const emit = __emit;
const observer = ref(null);
const root = ref(null);
onBeforeUnmount(() => {
if (props.enabled && observer.value) {
observer.value.disconnect();
}
});
onMounted(() => {
if (!props.enabled) {
return;
}
const options = {
root: root.value,
rootMargin: "0px",
threshold: props.threshold
};
const intersectionObserver = new IntersectionObserver((entries) => {
entries.forEach(({ target, isIntersecting }) => {
emit("observed", {
el: target,
isIntersecting
});
});
}, options);
observer.value = intersectionObserver;
props.eventBus.on("observe", (observed) => {
if (observed) {
intersectionObserver.observe(observed);
}
});
props.eventBus.on("unobserve", (observed) => {
intersectionObserver.unobserve(observed);
});
});
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", {
ref_key: "root",
ref: root
}, [
renderSlot(_ctx.$slots, "default")
], 512);
};
}
});
const _sfc_main$4 = /* @__PURE__ */ defineComponent({
__name: "IntersectionObserved",
props: {
enabled: { type: Boolean, default: false },
eventBus: {}
},
setup(__props) {
const props = __props;
const observed = ref(null);
onMounted(async () => {
if (!props.enabled) {
return;
}
await nextTick();
props.eventBus.emit("observe", observed.value);
});
onBeforeUnmount(() => {
if (props.enabled) {
props.eventBus.emit("unobserve", observed.value);
}
});
return (_ctx, _cache) => {
return openBlock(), createElementBlock("span", {
ref_key: "observed",
ref: observed
}, [
renderSlot(_ctx.$slots, "default")
], 512);
};
}
});
const _hoisted_1$1 = { class: "tags" };
const _hoisted_2$1 = ["onClick"];
const _sfc_main$3 = /* @__PURE__ */ defineComponent({
__name: "TagsContainer",
props: {
tagIds: {},
tagsById: {},
limit: { default: 20 },
clickable: { type: Boolean, default: false },
responsive: { type: Boolean, default: false },
hoverable: { type: Boolean, default: false }
},
emits: ["click"],
setup(__props, { emit: __emit }) {
const props = __props;
const emit = __emit;
const maxWidth = ref(320);
const intersectionEventBus = createEventBus();
const visibility = ref({});
const tagsContainer = ref();
const style = computed(() => ({
"max-width": `${maxWidth.value}px`
}));
const tags = computed(() => {
const allTags = props.tagIds.map((tagId) => props.tagsById[tagId]).filter(Boolean);
let toDisplay = props.limit ? allTags.slice(0, props.limit) : allTags;
toDisplay = toDisplay.map((tag) => ({
...tag,
hidden: props.responsive && !visibility.value[tag.id]
}));
let visibleCount = toDisplay.length;
if (props.responsive) {
visibleCount = Object.values(visibility.value).reduce(
(accu, val) => val ? accu + 1 : accu,
0
);
}
if (visibleCount < allTags.length) {
const hidden = allTags.slice(visibleCount);
const hiddenTitle = hidden.reduce(
(accu, tag) => accu ? `${accu}, ${tag.name}` : tag.name,
""
);
const countTag = {
id: "count",
name: `+${hidden.length}`,
title: hiddenTitle,
isCount: true
};
toDisplay.splice(visibleCount, 0, countTag);
}
return toDisplay;
});
const setMaxWidth = () => {
const container2 = tagsContainer.value?.$el;
const parent = container2?.parentNode;
if (parent) {
maxWidth.value = 0;
void nextTick(() => {
maxWidth.value = parent.clientWidth;
});
}
};
const debouncedSetMaxWidth = debounce(setMaxWidth, 100);
const onObserved = ({ el, isIntersecting }) => {
if (el.dataset.id) {
visibility.value = { ...visibility.value, [el.dataset.id]: isIntersecting };
}
};
const onClick = (e, tag) => {
if (props.clickable) {
e.stopPropagation();
}
if (!tag.hidden) {
emit("click", tag.id);
}
};
onMounted(() => {
setMaxWidth();
window.addEventListener("resize", debouncedSetMaxWidth);
});
onBeforeUnmount(() => {
window.removeEventListener("resize", debouncedSetMaxWidth);
});
return (_ctx, _cache) => {
const _component_el_tag = resolveComponent("el-tag");
return openBlock(), createBlock(_sfc_main$5, {
ref_key: "tagsContainer",
ref: tagsContainer,
threshold: 1,
class: "tags-container",
style: normalizeStyle(style.value),
enabled: _ctx.responsive,
"event-bus": unref(intersectionEventBus),
onObserved
}, {
default: withCtx(() => [
createBaseVNode("span", _hoisted_1$1, [
(openBlock(true), createElementBlock(Fragment, null, renderList(tags.value, (tag) => {
return openBlock(), createElementBlock("span", {
key: tag.id,
class: normalizeClass({ clickable: !tag.hidden }),
onClick: (e) => onClick(e, tag)
}, [
tag.isCount ? (openBlock(), createBlock(_component_el_tag, {
key: 0,
title: tag.title,
type: "info",
size: "small",
class: "count-container",
"disable-transitions": true
}, {
default: withCtx(() => [
createTextVNode(toDisplayString(tag.name), 1)
]),
_: 2
}, 1032, ["title"])) : (openBlock(), createBlock(_sfc_main$4, {
key: 1,
class: normalizeClass({ hideTag: tag.hidden }),
"data-id": tag.id,
enabled: _ctx.responsive,
"event-bus": unref(intersectionEventBus)
}, {
default: withCtx(() => [
createVNode(_component_el_tag, {
title: tag.name,
type: "info",
size: "mini",
class: normalizeClass({ hoverable: _ctx.hoverable }),
"disable-transitions": true
}, {
default: withCtx(() => [
createTextVNode(toDisplayString(tag.name), 1)
]),
_: 2
}, 1032, ["title", "class"])
]),
_: 2
}, 1032, ["class", "data-id", "enabled", "event-bus"]))
], 10, _hoisted_2$1);
}), 128))
])
]),
_: 1
}, 8, ["style", "enabled", "event-bus"]);
};
}
});
const TagsContainer = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__scopeId", "data-v-6bab2764"]]);
const _sfc_main$2 = /* @__PURE__ */ defineComponent({
__name: "WorkflowTagsContainer",
props: {
tagIds: {},
limit: {},
clickable: { type: Boolean },
responsive: { type: Boolean },
hoverable: { type: Boolean }
},
emits: ["click"],
setup(__props, { emit: __emit }) {
const emit = __emit;
const annotationTagsStore = useTagsStore();
const tagsById = computed(() => annotationTagsStore.tagsById);
function onClick(tagId) {
emit("click", tagId);
}
return (_ctx, _cache) => {
return openBlock(), createBlock(TagsContainer, {
"tag-ids": _ctx.tagIds,
"tags-by-id": tagsById.value,
limit: _ctx.limit,
clickable: _ctx.clickable,
responsive: _ctx.responsive,
hoverable: _ctx.hoverable,
onClick
}, null, 8, ["tag-ids", "tags-by-id", "limit", "clickable", "responsive", "hoverable"]);
};
}
});
const INVALID_CHARS_REGEX = /[<>:"/\\|?*\u0000-\u001F\u007F-\u009F]/g;
const ZERO_WIDTH_CHARS_REGEX = /[\u200B-\u200D\u2060\uFEFF]/g;
const UNICODE_SPACES_REGEX = /[\u00A0\u2000-\u200A]/g;
const LEADING_TRAILING_DOTS_SPACES_REGEX = /^[\s.]+|[\s.]+$/g;
const WINDOWS_RESERVED_NAMES = /* @__PURE__ */ new Set([
"CON",
"PRN",
"AUX",
"NUL",
"COM1",
"COM2",
"COM3",
"COM4",
"COM5",
"COM6",
"COM7",
"COM8",
"COM9",
"LPT1",
"LPT2",
"LPT3",
"LPT4",
"LPT5",
"LPT6",
"LPT7",
"LPT8",
"LPT9"
]);
const DEFAULT_FALLBACK_NAME = "untitled";
const MAX_FILENAME_LENGTH = 200;
const sanitizeFilename = (filename, maxLength = MAX_FILENAME_LENGTH) => {
if (!filename) {
return DEFAULT_FALLBACK_NAME;
}
let baseName = filename.trim().replace(INVALID_CHARS_REGEX, "_").replace(ZERO_WIDTH_CHARS_REGEX, "").replace(UNICODE_SPACES_REGEX, " ").replace(LEADING_TRAILING_DOTS_SPACES_REGEX, "");
if (!baseName) {
baseName = DEFAULT_FALLBACK_NAME;
}
if (WINDOWS_RESERVED_NAMES.has(baseName.toUpperCase())) {
baseName = `_${baseName}`;
}
if (baseName.length > maxLength) {
baseName = baseName.slice(0, maxLength);
}
return baseName;
};
const _hoisted_1 = {
class: "tags",
"data-test-id": "workflow-tags-container"
};
const _hoisted_2 = { key: 1 };
const _hoisted_3 = { class: "archived" };
const _sfc_main$1 = /* @__PURE__ */ defineComponent({
__name: "WorkflowDetails",
props: {
readOnly: { type: Boolean },
id: {},
tags: {},
name: {},
meta: {},
scopes: {},
active: { type: Boolean },
currentFolder: {},
isArchived: { type: Boolean }
},
setup(__props) {
const WORKFLOW_NAME_BP_TO_WIDTH = {
XS: 150,
SM: 200,
MD: 250,
LG: 500,
XL: 1e3
};
const props = __props;
const $style = useCssModule();
const rootStore = useRootStore();
const settingsStore = useSettingsStore();
const sourceControlStore = useSourceControlStore();
const tagsStore = useTagsStore();
const uiStore = useUIStore();
const usersStore = useUsersStore();
const workflowsStore = useWorkflowsStore();
const projectsStore = useProjectsStore();
const foldersStore = useFoldersStore();
const npsSurveyStore = useNpsSurveyStore();
const i18n = useI18n$1();
const router = useRouter();
const route = useRoute();
const locale = useI18n$1();
const telemetry = useTelemetry();
const message = useMessage();
const toast = useToast();
const documentTitle = useDocumentTitle();
const workflowSaving = useWorkflowSaving({ router });
const workflowHelpers = useWorkflowHelpers();
const pageRedirectionHelper = usePageRedirectionHelper();
const isTagsEditEnabled = ref(false);
const appliedTagIds = ref([]);
const tagsSaving = ref(false);
const importFileRef = ref();
const tagsEventBus = createEventBus();
const changeOwnerEventBus = createEventBus();
const hasChanged = (prev, curr) => {
if (prev.length !== curr.length) {
return true;
}
const set = new Set(prev);
return curr.reduce((acc, val) => acc || !set.has(val), false);
};
const isNewWorkflow = computed(() => {
return !props.id || props.id === PLACEHOLDER_EMPTY_WORKFLOW_ID || props.id === "new";
});
const isWorkflowSaving = computed(() => {
return uiStore.isActionActive.workflowSaving;
});
const onWorkflowPage = computed(() => {
return route.meta && (route.meta.nodeView || route.meta.keepWorkflowAlive === true);
});
const onExecutionsTab = computed(() => {
return [
VIEWS.EXECUTION_HOME.toString(),
VIEWS.WORKFLOW_EXECUTIONS.toString(),
VIEWS.EXECUTION_PREVIEW
].includes(route.name || "");
});
const workflowPermissions = computed(() => getResourcePermissions(props.scopes).workflow);
const workflowMenuItems = computed(() => {
const actions = [
{
id: WORKFLOW_MENU_ACTIONS.DOWNLOAD,
label: locale.baseText("menuActions.download"),
disabled: !onWorkflowPage.value
}
];
if (workflowPermissions.value.move && projectsStore.isTeamProjectFeatureEnabled) {
actions.push({
id: WORKFLOW_MENU_ACTIONS.CHANGE_OWNER,
label: locale.baseText("workflows.item.changeOwner"),
disabled: isNewWorkflow.value
});
}
if (!props.readOnly && !props.isArchived) {
actions.push({
id: WORKFLOW_MENU_ACTIONS.RENAME,
label: locale.baseText("generic.rename"),
disabled: !onWorkflowPage.value || workflowPermissions.value.update !== true
});
}
if (workflowPermissions.value.delete === true && !props.readOnly && !props.isArchived || isNewWorkflow.value) {
actions.unshift({
id: WORKFLOW_MENU_ACTIONS.DUPLICATE,
label: locale.baseText("menuActions.duplicate"),
disabled: !onWorkflowPage.value || !props.id
});
actions.push(
{
id: WORKFLOW_MENU_ACTIONS.IMPORT_FROM_URL,
label: locale.baseText("menuActions.importFromUrl"),
disabled: !onWorkflowPage.value || onExecutionsTab.value
},
{
id: WORKFLOW_MENU_ACTIONS.IMPORT_FROM_FILE,
label: locale.baseText("menuActions.importFromFile"),
disabled: !onWorkflowPage.value || onExecutionsTab.value
}
);
}
if (hasPermission(["rbac"], { rbac: { scope: "sourceControl:push" } })) {
actions.push({
id: WORKFLOW_MENU_ACTIONS.PUSH,
label: locale.baseText("menuActions.push"),
disabled: !sourceControlStore.isEnterpriseSourceControlEnabled || !onWorkflowPage.value || onExecutionsTab.value || sourceControlStore.preferences.branchReadOnly
});
}
actions.push({
id: WORKFLOW_MENU_ACTIONS.SETTINGS,
label: locale.baseText("generic.settings"),
disabled: !onWorkflowPage.value || isNewWorkflow.value
});
if (workflowPermissions.value.delete === true && !props.readOnly || isNewWorkflow.value) {
if (props.isArchived) {
actions.push({
id: WORKFLOW_MENU_ACTIONS.UNARCHIVE,
label: locale.baseText("menuActions.unarchive"),
disabled: !onWorkflowPage.value || isNewWorkflow.value
});
actions.push({
id: WORKFLOW_MENU_ACTIONS.DELETE,
label: locale.baseText("menuActions.delete"),
disabled: !onWorkflowPage.value || isNewWorkflow.value,
customClass: $style.deleteItem,
divided: true
});
} else {
actions.push({
id: WORKFLOW_MENU_ACTIONS.ARCHIVE,
label: locale.baseText("menuActions.archive"),
disabled: !onWorkflowPage.value || isNewWorkflow.value,
customClass: $style.deleteItem,
divided: true
});
}
}
return actions;
});
const isWorkflowHistoryFeatureEnabled = computed(() => {
return settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.WorkflowHistory];
});
const workflowTagIds = computed(() => {
return (props.tags ?? []).map((tag) => typeof tag === "string" ? tag : tag.id);
});
const currentProjectName = computed(() => {
if (projectsStore.currentProject?.type === ProjectTypes.Personal) {
return locale.baseText("projects.menu.personal");
}
return projectsStore.currentProject?.name;
});
const currentFolderForBreadcrumbs = computed(() => {
if (!isNewWorkflow.value && props.currentFolder) {
return props.currentFolder;
}
const folderId = route.query.parentFolderId;
if (folderId) {
return foldersStore.getCachedFolder(folderId);
}
return null;
});
watch(
() => props.id,
() => {
isTagsEditEnabled.value = false;
renameInput.value?.forceCancel();
}
);
function getWorkflowId() {
let id = void 0;
if (props.id !== PLACEHOLDER_EMPTY_WORKFLOW_ID) {
id = props.id;
} else if (route.params.name && route.params.name !== "new") {
id = route.params.name;
}
return id;
}
async function onSaveButtonClick() {
if (isWorkflowSaving.value) {
return;
}
const id = getWorkflowId();
const name = props.name;
const tags = props.tags;
const saved = await workflowSaving.saveCurrentWorkflow({
id,
name,
tags
});
if (saved) {
showCreateWorkflowSuccessToast(id);
await npsSurveyStore.fetchPromptsData();
if (route.name === VIEWS.EXECUTION_DEBUG) {
await router.replace({
name: VIEWS.WORKFLOW,
params: { name: props.id }
});
}
}
}
function onShareButtonClick() {
uiStore.openModalWithData({
name: WORKFLOW_SHARE_MODAL_KEY,
data: { id: props.id }
});
telemetry.track("User opened sharing modal", {
workflow_id: props.id,
user_id_sharer: usersStore.currentUser?.id,
sub_view: route.name === VIEWS.WORKFLOWS ? "Workflows listing" : "Workflow editor"
});
}
function onTagsEditEnable() {
appliedTagIds.value = props.tags ?? [];
isTagsEditEnabled.value = true;
setTimeout(() => {
renameInput.value?.forceCancel();
tagsEventBus.emit("focus");
}, 0);
}
async function onTagsBlur() {
const current = props.tags ?? [];
const tags = appliedTagIds.value;
if (!hasChanged(current, tags)) {
isTagsEditEnabled.value = false;
return;
}
if (tagsSaving.value) {
return;
}
tagsSaving.value = true;
const saved = await workflowSaving.saveCurrentWorkflow({ tags });
telemetry.track("User edited workflow tags", {
workflow_id: props.id,
new_tag_count: tags.length
});
tagsSaving.value = false;
if (saved) {
isTagsEditEnabled.value = false;
}
}
function onTagsEditEsc() {
isTagsEditEnabled.value = false;
}
const renameInput = useTemplateRef("renameInput");
function onNameToggle() {
if (renameInput.value?.forceFocus) {
renameInput.value.forceFocus();
}
}
async function onNameSubmit(name) {
const newName = name.trim();
if (!newName) {
toast.showMessage({
title: locale.baseText("renameAction.emptyName.title"),
message: locale.baseText("renameAction.emptyName.message"),
type: "error"
});
renameInput.value?.forceCancel();
return;
}
if (newName === props.name) {
renameInput.value?.forceCancel();
return;
}
uiStore.addActiveAction("workflowSaving");
const id = getWorkflowId();
const saved = await workflowSaving.saveCurrentWorkflow({ name });
if (saved) {
showCreateWorkflowSuccessToast(id);
workflowHelpers.setDocumentTitle(newName, "IDLE");
}
uiStore.removeActiveAction("workflowSaving");
renameInput.value?.forceCancel();
}
async function handleFileImport() {
const inputRef = importFileRef.value;
if (inputRef?.files && inputRef.files.length !== 0) {
const reader = new FileReader();
reader.onload = () => {
let workflowData;
try {
workflowData = JSON.parse(reader.result);
} catch (error) {
toast.showMessage({
title: locale.baseText("mainSidebar.showMessage.handleFileImport.title"),
message: locale.baseText("mainSidebar.showMessage.handleFileImport.message"),
type: "error"
});
return;
} finally {
reader.onload = null;
inputRef.value = "";
}
nodeViewEventBus.emit("importWorkflowData", { data: workflowData });
};
reader.readAsText(inputRef.files[0]);
}
}
async function onWorkflowMenuSelect(value) {
const action = value;
switch (action) {
case WORKFLOW_MENU_ACTIONS.DUPLICATE: {
uiStore.openModalWithData({
name: DUPLICATE_MODAL_KEY,
data: {
id: props.id,
name: props.name,
tags: props.tags,
parentFolderId: props.currentFolder?.id
}
});
break;
}
case WORKFLOW_MENU_ACTIONS.RENAME: {
onNameToggle();
break;
}
case WORKFLOW_MENU_ACTIONS.DOWNLOAD: {
const workflowData = await workflowHelpers.getWorkflowDataToSave();
const { tags, ...data } = workflowData;
const exportData = {
...data,
meta: {
...props.meta,
instanceId: rootStore.instanceId
},
tags: (tags ?? []).map((tagId) => {
const { usageCount, ...tag } = tagsStore.tagsById[tagId];
return tag;
})
};
const blob = new Blob([JSON.stringify(exportData, null, 2)], {
type: "application/json;charset=utf-8"
});
let name = props.name || "unsaved_workflow";
name = sanitizeFilename(name);
telemetry.track("User exported workflow", { workflow_id: workflowData.id });
FileSaver_minExports.saveAs(blob, name + ".json");
break;
}
case WORKFLOW_MENU_ACTIONS.IMPORT_FROM_URL: {
uiStore.openModal(IMPORT_WORKFLOW_URL_MODAL_KEY);
break;
}
case WORKFLOW_MENU_ACTIONS.IMPORT_FROM_FILE: {
importFileRef.value?.click();
break;
}
case WORKFLOW_MENU_ACTIONS.PUSH: {
try {
await onSaveButtonClick();
void router.push({
query: {
...route.query,
sourceControl: "push"
}
});
} catch (error) {
switch (error.message) {
case "source_control_not_connected":
toast.showError(
{ ...error, message: "" },
locale.baseText("settings.sourceControl.error.not.connected.title"),
locale.baseText("settings.sourceControl.error.not.connected.message")
);
break;
default:
toast.showError(error, locale.baseText("error"));
}
}
break;
}
case WORKFLOW_MENU_ACTIONS.SETTINGS: {
uiStore.openModal(WORKFLOW_SETTINGS_MODAL_KEY);
break;
}
case WORKFLOW_MENU_ACTIONS.ARCHIVE: {
if (props.active) {
const archiveConfirmed = await message.confirm(
locale.baseText("mainSidebar.confirmMessage.workflowArchive.message", {
interpolate: { workflowName: props.name }
}),
locale.baseText("mainSidebar.confirmMessage.workflowArchive.headline"),
{
type: "warning",
confirmButtonText: locale.baseText(
"mainSidebar.confirmMessage.workflowArchive.confirmButtonText"
),
cancelButtonText: locale.baseText(
"mainSidebar.confirmMessage.workflowArchive.cancelButtonText"
)
}
);
if (archiveConfirmed !== MODAL_CONFIRM) {
return;
}
}
try {
await workflowsStore.archiveWorkflow(props.id);
} catch (error) {
toast.showError(error, locale.baseText("generic.archiveWorkflowError"));
return;
}
uiStore.stateIsDirty = false;
toast.showMessage({
title: locale.baseText("mainSidebar.showMessage.handleArchive.title", {
interpolate: { workflowName: props.name }
}),
type: "success"
});
await router.push({ name: VIEWS.WORKFLOWS });
break;
}
case WORKFLOW_MENU_ACTIONS.UNARCHIVE: {
await workflowsStore.unarchiveWorkflow(props.id);
toast.showMessage({
title: locale.baseText("mainSidebar.showMessage.handleUnarchive.title", {
interpolate: { workflowName: props.name }
}),
type: "success"
});
break;
}
case WORKFLOW_MENU_ACTIONS.DELETE: {
const deleteConfirmed = await message.confirm(
locale.baseText("mainSidebar.confirmMessage.workflowDelete.message", {
interpolate: { workflowName: props.name }
}),
locale.baseText("mainSidebar.confirmMessage.workflowDelete.headline"),
{
type: "warning",
confirmButtonText: locale.baseText(
"mainSidebar.confirmMessage.workflowDelete.confirmButtonText"
),
cancelButtonText: locale.baseText(
"mainSidebar.confirmMessage.workflowDelete.cancelButtonText"
)
}
);
if (deleteConfirmed !== MODAL_CONFIRM) {
return;
}
try {
await workflowsStore.deleteWorkflow(props.id);
} catch (error) {
toast.showError(error, locale.baseText("generic.deleteWorkflowError"));
return;
}
uiStore.stateIsDirty = false;
documentTitle.reset();
toast.showMessage({
title: locale.baseText("mainSidebar.showMessage.handleSelect1.title", {
interpolate: { workflowName: props.name }
}),
type: "success"
});
await router.push({ name: VIEWS.WORKFLOWS });
break;
}
case WORKFLOW_MENU_ACTIONS.CHANGE_OWNER: {
const workflowId = getWorkflowId();
if (!workflowId) {
return;
}
changeOwnerEventBus.once(
"resource-moved",
async () => await router.push({ name: VIEWS.WORKFLOWS })
);
uiStore.openModalWithData({
name: PROJECT_MOVE_RESOURCE_MODAL,
data: {
resource: workflowsStore.workflowsById[workflowId],
resourceType: ResourceType.Workflow,
resourceTypeLabel: locale.baseText("generic.workflow").toLowerCase(),
eventBus: changeOwnerEventBus
}
});
break;
}
}
}
function goToUpgrade() {
void pageRedirectionHelper.goToUpgrade("workflow_sharing", "upgrade-workflow-sharing");
}
function goToWorkflowHistoryUpgrade() {
void pageRedirectionHelper.goToUpgrade("workflow-history", "upgrade-workflow-history");
}
function getPersonalProjectToastContent() {
const title = locale.baseText("workflows.create.personal.toast.title");
if (!props.currentFolder) {
return { title };
}
const toastMessage = locale.baseText("workflows.create.folder.toast.title", {
interpolate: {
projectName: "Personal",
folderName: props.currentFolder.name
}
});
return { title, toastMessage };
}
function getToastContent() {
const currentProject = projectsStore.currentProject;
const isPersonalProject = !projectsStore.currentProject || currentProject?.id === projectsStore.personalProject?.id;
const projectName = currentProjectName.value ?? "";
if (isPersonalProject) {
return getPersonalProjectToastContent();
}
const titleKey = props.currentFolder ? "workflows.create.folder.toast.title" : "workflows.create.project.toast.title";
const interpolateData = props.currentFolder ? { projectName, folderName: props.currentFolder.name ?? "" } : { projectName };
const title = locale.baseText(titleKey, { interpolate: interpolateData });
const toastMessage = locale.baseText("workflows.create.project.toast.text", {
interpolate: { projectName }
});
return { title, toastMessage };
}
function showCreateWorkflowSuccessToast(id) {
const shouldShowToast = !id || ["new", PLACEHOLDER_EMPTY_WORKFLOW_ID].includes(id);
if (!shouldShowToast) return;
const { title, toastMessage } = getToastContent();
toast.showMessage({
title,
message: toastMessage,
type: "success"
});
}
const onBreadcrumbsItemSelected = (item) => {
if (item.href) {
void router.push(item.href).catch((error) => {
toast.showError(error, i18n.baseText("folders.open.error.title"));
});
}
};
return (_ctx, _cache) => {
const _component_FolderBreadcrumbs = __unplugin_components_0;
const _component_N8nBadge = N8nBadge;
const _component_N8nButton = N8nButton;
const _component_N8nTooltip = Tooltip;
const _component_EnterpriseEdition = resolveComponent("EnterpriseEdition");
const _component_N8nActionDropdown = N8nActionDropdown;
return openBlock(), createElementBlock("div", {
class: normalizeClass(unref($style).container)
}, [
createVNode(_sfc_main$9, {
"value-x-s": 15,
"value-s-m": 25,
"value-m-d": 50,
class: "name-container",
"data-test-id": "canvas-breadcrumbs"
}, {
default: withCtx(({ bp }) => [
createVNode(_component_FolderBreadcrumbs, {
"current-folder": currentFolderForBreadcrumbs.value,
"current-folder-as-link": true,
onItemSelected: onBreadcrumbsItemSelected
}, {
append: withCtx(() => [
unref(projectsStore).currentProject ?? unref(projectsStore).personalProject ? (openBlock(), createElementBlock("span", {
key: 0,
class: normalizeClass(unref($style)["path-separator"])
}, "/", 2)) : createCommentVNode("", true),
(openBlock(), createBlock(unref(InlineRename), {
ref_key: "renameInput",
ref: renameInput,
key: _ctx.id,
placeholder: "Workflow name",
"data-test-id": "workflow-name-input",
class: "name",
"model-value": _ctx.name,
"max-length": unref(MAX_WORKFLOW_NAME_LENGTH),
"max-width": WORKFLOW_NAME_BP_TO_WIDTH[bp],
"read-only": _ctx.readOnly || _ctx.isArchived || !isNewWorkflow.value && !workflowPermissions.value.update,
disabled: _ctx.readOnly || _ctx.isArchived || !isNewWorkflow.value && !workflowPermissions.value.update,
"onUpdate:modelValue": onNameSubmit
}, null, 8, ["model-value", "max-length", "max-width", "read-only", "disabled"]))
]),
_: 2
}, 1032, ["current-folder"])
]),
_: 1
}),
createBaseVNode("span", _hoisted_1, [
unref(settingsStore).areTagsEnabled ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
isTagsEditEnabled.value && !(_ctx.readOnly || _ctx.isArchived) && (isNewWorkflow.value || workflowPermissions.value.update) ? (openBlock(), createBlock(_sfc_main$e, {
key: 0,
ref: "dropdown",
modelValue: appliedTagIds.value,
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => appliedTagIds.value = $event),
"event-bus": unref(tagsEventBus),
placeholder: unref(i18n).baseText("workflowDetails.chooseOrCreateATag"),
class: "tags-edit",
"data-test-id": "workflow-tags-dropdown",
onBlur: onTagsBlur,
onEsc: onTagsEditEsc
}, null, 8, ["modelValue", "event-bus", "placeholder"])) : (_ctx.tags ?? []).length === 0 && !(_ctx.readOnly || _ctx.isArchived) && (isNewWorkflow.value || workflowPermissions.value.update) ? (openBlock(), createElementBlock("div", _hoisted_2, [
createBaseVNode("span", {
class: "add-tag clickable",
"data-test-id": "new-tag-link",
onClick: onTagsEditEnable
}, " + " + toDisplayString(unref(i18n).baseText("workflowDetails.addTag")), 1)
])) : (openBlock(), createBlock(_sfc_main$2, {
key: _ctx.id,
"tag-ids": workflowTagIds.value,
clickable: true,
responsive: true,
"data-test-id": "workflow-tags",
onClick: onTagsEditEnable
}, null, 8, ["tag-ids"]))
], 64)) : createCommentVNode("", true),
createBaseVNode("span", _hoisted_3, [
_ctx.isArchived ? (openBlock(), createBlock(_component_N8nBadge, {
key: 0,
class: "ml-3xs",
theme: "tertiary",
bold: "",
"data-test-id": "workflow-archived-tag"
}, {
default: withCtx(() => [
createTextVNode(toDisplayString(unref(locale).baseText("workflows.item.archived")), 1)
]),
_: 1
})) : createCommentVNode("", true)
])
]),
createVNode(_sfc_main$f, { class: "actions" }, {
default: withCtx(() => [
!isNewWorkflow.value ? (openBlock(), createBlock(_sfc_main$6, {
key: 0,
workflow: unref(workflowsStore).workflow
}, null, 8, ["workflow"])) : createCommentVNode("", true),
createBaseVNode("span", {
class: normalizeClass(`activator ${unref($style).group}`)
}, [
createVNode(WorkflowActivator, {
"is-archived": _ctx.isArchived,
"workflow-active": _ctx.active,
"workflow-id": _ctx.id,
"workflow-permissions": workflowPermissions.value
}, null, 8, ["is-archived", "workflow-active", "workflow-id", "workflow-permissions"])
], 2),
createVNode(_component_EnterpriseEdition, {
features: [unref(EnterpriseEditionFeature).Sharing]
}, {
fallback: withCtx(() => [
createVNode(_component_N8nTooltip, null, {
content: withCtx(() => [
createVNode(unref(I18nT), {
keypath: unref(uiStore).contextBasedTranslationKeys.workflows.sharing.unavailable.description.tooltip,
tag: "span",
scope: "global"
}, {
action: withCtx(() => [
createBaseVNode("a", { onClick: goToUpgrade }, toDisplayString(unref(i18n).baseText(
unref(uiStore).contextBasedTranslationKeys.workflows.sharing.unavailable.button
)), 1)
]),
_: 1
}, 8, ["keypath"])
]),
default: withCtx(() => [
createVNode(_component_N8nButton, {
type: "secondary",
class: normalizeClass(["mr-2xs", unref($style).disabledShareButton])
}, {
default: withCtx(() => [
createTextVNode(toDisplayString(unref(i18n).baseText("workflowDetails.share")), 1)
]),
_: 1
}, 8, ["class"])
]),
_: 1
})
]),
default: withCtx(() => [
createBaseVNode("div", {
class: normalizeClass(unref($style).group)
}, [
!isNewWorkflow.value ? (openBlock(), createBlock(CollaborationPane, { key: 0 })) : createCommentVNode("", true),
createVNode(_component_N8nButton, {
type: "secondary",
"data-test-id": "workflow-share-button",
onClick: onShareButtonClick
}, {
default: withCtx(() => [
createTextVNode(toDisplayString(unref(i18n).baseText("workflowDetails.share")), 1)
]),
_: 1
})
], 2)
]),
_: 1
}, 8, ["features"]),
createBaseVNode("div", {
class: normalizeClass(unref($style).group)
}, [
createVNode(SaveButton, {
type: "primary",
saved: !unref(uiStore).stateIsDirty && !isNewWorkflow.value,
disabled: isWorkflowSaving.value || _ctx.readOnly || _ctx.isArchived || !isNewWorkflow.value && !workflowPermissions.value.update,
"is-saving": isWorkflowSaving.value,
"with-shortcut": !_ctx.readOnly && !_ctx.isArchived && workflowPermissions.value.update,
"shortcut-tooltip": unref(i18n).baseText("saveWorkflowButton.hint"),
"data-test-id": "workflow-save-button",
onClick: onSaveButtonClick
}, null, 8, ["saved", "disabled", "is-saving", "with-shortcut", "shortcut-tooltip"]),
createVNode(_sfc_main$7, {
"workflow-id": props.id,
"is-feature-enabled": isWorkflowHistoryFeatureEnabled.value,
"is-new-workflow": isNewWorkflow.value,
onUpgrade: goToWorkflowHistoryUpgrade
}, null, 8, ["workflow-id", "is-feature-enabled", "is-new-workflow"])
], 2),
createBaseVNode("div", {
class: normalizeClass([unref($style).workflowMenuContainer, unref($style).group])
}, [
createBaseVNode("input", {
ref_key: "importFileRef",
ref: importFileRef,
class: normalizeClass(unref($style).hiddenInput),
type: "file",
"data-test-id": "workflow-import-input",
onChange: _cache[1] || (_cache[1] = ($event) => handleFileImport())
}, null, 34),
createVNode(_component_N8nActionDropdown, {
items: workflowMenuItems.value,
"data-test-id": "workflow-menu",
onSelect: onWorkflowMenuSelect
}, null, 8, ["items"])
], 2)
]),
_: 1
})
], 2);
};
}
});
const container$1 = "_container_14b3x_123";
const group = "_group_14b3x_138";
const hiddenInput = "_hiddenInput_14b3x_143";
const deleteItem = "_deleteItem_14b3x_147";
const disabledShareButton = "_disabledShareButton_14b3x_151";
const closeNodeViewDiscovery = "_closeNodeViewDiscovery_14b3x_155";
const style1 = {
container: container$1,
"path-separator": "_path-separator_14b3x_132",
group,
hiddenInput,
deleteItem,
disabledShareButton,
closeNodeViewDiscovery
};
const cssModules$1 = {
"$style": style1
};
const WorkflowDetails = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__cssModules", cssModules$1], ["__scopeId", "data-v-1f7160d5"]]);
const GithubButton = defineComponent({
name: "github-button",
props: {
href: String,
ariaLabel: String,
title: String,
dataIcon: String,
dataColorScheme: String,
dataSize: String,
dataShowCount: String,
dataText: String
},
render: function() {
const props = { ref: "_" };
for (const key in this.$props) {
props[hyphenate(key)] = this.$props[key];
}
return h("span", [
hasOwn(this.$slots, "default") ? h("a", props, this.$slots.default()) : h("a", props)
]);
},
mounted: function() {
this.paint();
},
beforeUpdate: function() {
this.reset();
},
updated: function() {
this.paint();
},
beforeUnmount: function() {
this.reset();
},
methods: {
paint: function() {
if (this.$el.lastChild !== this.$refs._) {
return;
}
const _ = this.$el.appendChild(document.createElement("span"));
const _this = this;
__vitePreload(() => import(
/* webpackMode: "eager" */
"./buttons.esm-BOkmSohe.js"
), true ? [] : void 0).then(function(module) {
if (_this.$el.lastChild !== _) {
return;
}
module.render(_.appendChild(_this.$refs._), function(el) {
if (_this.$el.lastChild !== _) {
return;
}
_.parentNode.replaceChild(el, _);
});
});
},
reset: function() {
if (this.$refs._ == null) {
return;
}
this.$el.replaceChild(
/** @type {HTMLAnchorElement} */
this.$refs._,
this.$el.lastChild
);
}
}
});
const _sfc_main = /* @__PURE__ */ defineComponent({
__name: "MainHeader",
setup(__props) {
const router = useRouter();
const route = useRoute();
const locale = useI18n$1();
const pushConnection = usePushConnection({ router });
const ndvStore = useNDVStore();
const uiStore = useUIStore();
const sourceControlStore = useSourceControlStore();
const workflowsStore = useWorkflowsStore();
const executionsStore = useExecutionsStore();
const settingsStore = useSettingsStore();
const activeHeaderTab = ref(MAIN_HEADER_TABS.WORKFLOW);
const workflowToReturnTo = ref("");
const executionToReturnTo = ref("");
const dirtyState = ref(false);
const githubButtonHidden = useLocalStorage(LOCAL_STORAGE_HIDE_GITHUB_STAR_BUTTON, false);
const evaluationRoutes = [VIEWS.EVALUATION_EDIT, VIEWS.EVALUATION_RUNS_DETAIL];
const workflowRoutes = [VIEWS.WORKFLOW, VIEWS.NEW_WORKFLOW, VIEWS.EXECUTION_DEBUG];
const executionRoutes = [
VIEWS.EXECUTION_HOME,
VIEWS.WORKFLOW_EXECUTIONS,
VIEWS.EXECUTION_PREVIEW
];
const tabBarItems = computed(() => {
return [
{ value: MAIN_HEADER_TABS.WORKFLOW, label: locale.baseText("generic.editor") },
{ value: MAIN_HEADER_TABS.EXECUTIONS, label: locale.baseText("generic.executions") },
{ value: MAIN_HEADER_TABS.EVALUATION, label: locale.baseText("generic.tests") }
];
});
const activeNode = computed(() => ndvStore.activeNode);
const hideMenuBar = computed(
() => Boolean(activeNode.value && activeNode.value.type !== STICKY_NODE_TYPE)
);
const workflow = computed(() => workflowsStore.workflow);
const workflowId = computed(
() => String(router.currentRoute.value.params.name || workflowsStore.workflowId)
);
const onWorkflowPage = computed(() => !!(route.meta.nodeView || route.meta.keepWorkflowAlive));
const readOnly = computed(() => sourceControlStore.preferences.branchReadOnly);
const isEnterprise = computed(
() => settingsStore.isQueueModeEnabled && settingsStore.isWorkerViewAvailable
);
const isTelemetryEnabled = computed(() => {
return settingsStore.isTelemetryEnabled;
});
const showGitHubButton = computed(
() => !isEnterprise.value && !settingsStore.settings.inE2ETests && !githubButtonHidden.value && isTelemetryEnabled.value
);
const parentFolderForBreadcrumbs = computed(() => {
if (!workflow.value.parentFolder) {
return void 0;
}
return {
id: workflow.value.parentFolder.id,
name: workflow.value.parentFolder.name,
parentFolder: workflow.value.parentFolder.parentFolderId ?? void 0
};
});
watch(route, (to, from) => {
syncTabsWithRoute(to, from);
});
onBeforeMount(() => {
pushConnection.initialize();
});
onBeforeUnmount(() => {
pushConnection.terminate();
});
onMounted(async () => {
dirtyState.value = uiStore.stateIsDirty;
syncTabsWithRoute(route);
});
function isViewRoute(name) {
return typeof name === "string" && [evaluationRoutes, workflowRoutes, executionRoutes].flat().includes(name);
}
function syncTabsWithRoute(to, from) {
const routeTabMapping = [
{ routes: evaluationRoutes, tab: MAIN_HEADER_TABS.EVALUATION },
{ routes: executionRoutes, tab: MAIN_HEADER_TABS.EXECUTIONS },
{ routes: workflowRoutes, tab: MAIN_HEADER_TABS.WORKFLOW }
];
if (to.name && isViewRoute(to.name)) {
const matchingTab = routeTabMapping.find(({ routes }) => routes.includes(to.name));
if (matchingTab) {
activeHeaderTab.value = matchingTab.tab;
}
}
if (to.params.name !== "new" && typeof to.params.name === "string") {
workflowToReturnTo.value = to.params.name;
}
if (from?.name === VIEWS.EXECUTION_PREVIEW && to.params.name === from.params.name && typeof from.params.executionId === "string") {
executionToReturnTo.value = from.params.executionId;
}
}
function onTabSelected(tab, event) {
const openInNewTab = event.ctrlKey || event.metaKey;
switch (tab) {
case MAIN_HEADER_TABS.WORKFLOW:
void navigateToWorkflowView(openInNewTab);
break;
case MAIN_HEADER_TABS.EXECUTIONS:
void navigateToExecutionsView(openInNewTab);
break;
case MAIN_HEADER_TABS.EVALUATION:
void navigateToEvaluationsView(openInNewTab);
break;
}
}
async function navigateToWorkflowView(openInNewTab) {
let routeToNavigateTo;
if (!["", "new", PLACEHOLDER_EMPTY_WORKFLOW_ID].includes(workflowToReturnTo.value)) {
routeToNavigateTo = {
name: VIEWS.WORKFLOW,
params: { name: workflowToReturnTo.value }
};
} else {
routeToNavigateTo = { name: VIEWS.NEW_WORKFLOW };
}
if (openInNewTab) {
const { href } = router.resolve(routeToNavigateTo);
window.open(href, "_blank");
} else if (route.name !== routeToNavigateTo.name) {
if (route.name === VIEWS.NEW_WORKFLOW) {
uiStore.stateIsDirty = dirtyState.value;
}
activeHeaderTab.value = MAIN_HEADER_TABS.WORKFLOW;
await router.push(routeToNavigateTo);
}
}
async function navigateToExecutionsView(openInNewTab) {
const routeWorkflowId = workflowId.value === PLACEHOLDER_EMPTY_WORKFLOW_ID ? "new" : workflowId.value;
const executionToReturnToValue = executionsStore.activeExecution?.id || executionToReturnTo.value;
const routeToNavigateTo = executionToReturnToValue ? {
name: VIEWS.EXECUTION_PREVIEW,
params: { name: routeWorkflowId, executionId: executionToReturnToValue }
} : {
name: VIEWS.EXECUTION_HOME,
params: { name: routeWorkflowId }
};
if (openInNewTab) {
const { href } = router.resolve(routeToNavigateTo);
window.open(href, "_blank");
} else if (route.name !== routeToNavigateTo.name) {
dirtyState.value = uiStore.stateIsDirty;
workflowToReturnTo.value = workflowId.value;
activeHeaderTab.value = MAIN_HEADER_TABS.EXECUTIONS;
await router.push(routeToNavigateTo);
}
}
async function navigateToEvaluationsView(openInNewTab) {
const routeWorkflowId = workflowId.value === PLACEHOLDER_EMPTY_WORKFLOW_ID ? "new" : workflowId.value;
const routeToNavigateTo = {
name: VIEWS.EVALUATION_EDIT,
params: { name: routeWorkflowId }
};
if (openInNewTab) {
const { href } = router.resolve(routeToNavigateTo);
window.open(href, "_blank");
} else if (route.name !== routeToNavigateTo.name) {
dirtyState.value = uiStore.stateIsDirty;
workflowToReturnTo.value = workflowId.value;
activeHeaderTab.value = MAIN_HEADER_TABS.EXECUTIONS;
await router.push(routeToNavigateTo);
}
}
function hideGithubButton() {
githubButtonHidden.value = true;
}
return (_ctx, _cache) => {
const _component_N8nIcon = N8nIcon;
return openBlock(), createElementBlock("div", {
class: normalizeClass(_ctx.$style.container)
}, [
createBaseVNode("div", {
class: normalizeClass({ [_ctx.$style["main-header"]]: true, [_ctx.$style.expanded]: !unref(uiStore).sidebarMenuCollapsed })
}, [
withDirectives(createBaseVNode("div", {
class: normalizeClass(_ctx.$style["top-menu"])
}, [
workflow.value?.name ? (openBlock(), createBlock(WorkflowDetails, {
key: 0,
id: workflow.value.id,
tags: workflow.value.tags,
name: workflow.value.name,
meta: workflow.value.meta,
scopes: workflow.value.scopes,
active: workflow.value.active,
"read-only": readOnly.value,
"current-folder": parentFolderForBreadcrumbs.value,
"is-archived": workflow.value.isArchived
}, null, 8, ["id", "tags", "name", "meta", "scopes", "active", "read-only", "current-folder", "is-archived"])) : createCommentVNode("", true),
showGitHubButton.value ? (openBlock(), createElementBlock("div", {
key: 1,
class: normalizeClass([_ctx.$style["github-button"], "hidden-sm-and-down"])
}, [
createBaseVNode("div", {
class: normalizeClass(_ctx.$style["github-button-container"])
}, [
createVNode(unref(GithubButton), {
href: unref(N8N_MAIN_GITHUB_REPO_URL),
"data-color-scheme": unref(uiStore).appliedTheme,
"data-size": "large",
"data-show-count": "true",
"aria-label": unref(locale).baseText("editor.mainHeader.githubButton.label")
}, {
default: withCtx(() => [
createTextVNode(toDisplayString(unref(locale).baseText("generic.star")), 1)
]),
_: 1
}, 8, ["href", "data-color-scheme", "aria-label"]),
createVNode(_component_N8nIcon, {
class: normalizeClass(_ctx.$style["close-github-button"]),
icon: "circle-x",
size: "medium",
onClick: hideGithubButton
}, null, 8, ["class"])
], 2)
], 2)) : createCommentVNode("", true)
], 2), [
[vShow, !hideMenuBar.value]
]),
onWorkflowPage.value ? (openBlock(), createBlock(TabBar, {
key: 0,
items: tabBarItems.value,
"model-value": activeHeaderTab.value,
"onUpdate:modelValue": onTabSelected
}, null, 8, ["items", "model-value"])) : createCommentVNode("", true)
], 2)
], 2);
};
}
});
const container = "_container_gg3to_123";
const style0 = {
container,
"main-header": "_main-header_gg3to_130",
"top-menu": "_top-menu_gg3to_138",
"github-button": "_github-button_gg3to_149",
"close-github-button": "_close-github-button_gg3to_158",
"github-button-container": "_github-button-container_gg3to_173"
};
const cssModules = {
"$style": style0
};
const MainHeader = /* @__PURE__ */ _export_sfc(_sfc_main, [["__cssModules", cssModules]]);
export {
MainHeader as default
};