UNPKG

n8n-editor-ui

Version:

Workflow Editor UI for n8n

2,151 lines 83.7 kB
import { o as __toESM } from "./chunk-6z4oVpB-.js";
import { $t as hasOwn, C as computed, Cn as toDisplayString, D as createElementBlock, E as createCommentVNode, G as nextTick, Gt as unref, It as ref, J as onBeforeUnmount, L as h, M as createVNode, P as defineComponent, T as createBlock, Z as onMounted, _ as Fragment, _t as watch, at as renderSlot, bn as normalizeStyle, bt as withCtx, c as useCssModule, en as hyphenate, et as openBlock, it as renderList, j as createTextVNode, mt as useTemplateRef, ot as resolveComponent, p as vShow, q as onBeforeMount, tn as init_shared_esm_bundler, vn as normalizeClass, w as createBaseVNode, xt as withDirectives } from "./vue.runtime.esm-bundler-tP5dCd7J.js";
import { M as useLocalStorage, _t as useI18n, vt as I18nT, w as useDocumentVisibility } from "./_MapCache-ficiegRb.js";
import { Sn as N8nButton_default, T as N8nRadioButtons_default, b as SuggestedActions_default, c as N8nInlineTextEdit_default, h as N8nUserStack_default, ht as N8nTooltip_default, lt as N8nBadge_default, ot as N8nActionDropdown_default, wn as N8nIcon_default, x as N8nTag_default, xt as N8nIconButton_default } from "./src-DgvumQTi.js";
import "./en-CF30SCh2.js";
import { t as __vitePreload } from "./preload-helper-CR0ecmWK.js";
import { t as __plugin_vue_export_helper_default } from "./_plugin-vue_export-helper-BwBpWJRZ.js";
import { T as createEventBus, v as useRoute, y as useRouter } from "./truncate-B1HVeveJ.js";
import { $i as nodeViewEventBus, A as telemetry, Dr as useUsersStore, Ec as STORES, Ft as useEvaluationStore, M as useNDVStore, N as useWorkflowsStore, Nt as useNodeTypesStore, O as useTelemetry, Qn as ProjectTypes, Rn as useWorkflowHelpers, S as getBannerRowHeight, Vn as useTagsStore, Xn as useProjectsStore, Yn as useDocumentTitle, Zn as useSourceControlStore, _ as require_FileSaver_min, _a as PROJECT_MOVE_RESOURCE_MODAL, gs as useSettingsStore, h as useNpsSurveyStore, hi as getActivatableTriggerNodes, li as ResourceType, m as useMessage, n as useWorkflowSaving, oa as useUIStore, v as useToast, vr as hasPermission } from "./builder.store-sBTWwxRU.js";
import "./empty-BuGRxzl4.js";
import "./sanitize-html-Cc45ZKm8.js";
import "./CalendarDate-zWqgZMlk.js";
import "./path-browserify-BtCDmZ3_.js";
import { Cs as WORKFLOW_SHARE_MODAL_KEY, Go as DUPLICATE_MODAL_KEY, Lo as MAIN_HEADER_TABS, Ms as LOCAL_STORAGE_HIDE_GITHUB_STAR_BUTTON, Oc as TIME, Oo as getResourcePermissions, Qo as IMPORT_WORKFLOW_URL_MODAL_KEY, Ro as VIEWS, Ss as WORKFLOW_SETTINGS_MODAL_KEY, Uc as WORKFLOW_MENU_ACTIONS, a as IS_DRAFT_PUBLISH_ENABLED, bc as EnterpriseEditionFeature, bs as WORKFLOW_HISTORY_VERSION_UNPUBLISH, fr as TIME_SAVED_NODE_TYPE, g as EVALUATIONS_DOCS_URL, h as ERROR_WORKFLOW_DOCS_URL, hs as WORKFLOW_DESCRIPTION_MODAL_KEY, ms as WORKFLOW_ACTIVE_MODAL_KEY, o as MAX_WORKFLOW_NAME_LENGTH, rs as MODAL_CONFIRM, sr as STICKY_NODE_TYPE, v as N8N_MAIN_GITHUB_REPO_URL, w as TIME_SAVED_DOCS_URL, xs as WORKFLOW_PUBLISH_MODAL_KEY } from "./constants-BbpucWL4.js";
import "./merge-k8vSyyXH.js";
import { k as defineStore, r as useRootStore } from "./_baseOrderBy-B_6CV8x6.js";
import "./dateformat-CM9k0--B.js";
import { n as require_debounce, t as useDebounce } from "./useDebounce-Bnb8W2LR.js";
import "./assistant.store-bS9AHOoo.js";
import "./retry-dP46utx2.js";
import { t as useExecutionsStore } from "./executions.store-CXjGPxs0.js";
import { i as usePushConnectionStore } from "./useRunWorkflow-BQJbxiOd.js";
import "./usePinnedData-CL2qWhwp.js";
import "./nodeCreator.store-FJrC_Pu6.js";
import "./nodeIcon-DI2Acud1.js";
import "./useCanvasOperations-CAHezq7d.js";
import { t as useFoldersStore } from "./folders.store-BjAwtSH4.js";
import "./NodeIcon-BVhrZNYI.js";
import "./KeyboardShortcutTooltip-B4E72qs1.js";
import "./versions.store-BwdT833-.js";
import { t as usePageRedirectionHelper } from "./usePageRedirectionHelper-fGNB6ZKK.js";
import { t as useBannersStore } from "./banners.store-C9sgKjcT.js";
import "./dataTable.store-B4A4ieSD.js";
import "./ProjectIcon-A2WPT9dM.js";
import "./schemaPreview.store-BFprwUEe.js";
import { t as EnterpriseEdition_ee_default } from "./EnterpriseEdition.ee-UkQT-fFo.js";
import { t as TimeAgo_default } from "./TimeAgo-CWvYoS88.js";
import "./roles.store-DcLW4g80.js";
import { t as SaveButton_default } from "./SaveButton-DJxU0D7G.js";
import { t as router_default } from "./router-BuH0cEsQ.js";
import "./TagsDropdown-LwHy1RX4.js";
import { t as WorkflowTagsDropdown_default } from "./WorkflowTagsDropdown-DEysJMrX.js";
import "./sso.store-Ba2eVE3K.js";
import "./insights.store-BBo4cRMD.js";
import "./insights.constants-C8GITe6H.js";
import "./insights.utils-B7OXsqrQ.js";
import { a as MCP_DOCS_PAGE_URL, s as MCP_SETTINGS_VIEW } from "./mcp.constants-DQPD3Ntp.js";
import "./constants-DLTaaipl.js";
import "./useRecentResources-BAGmp8Wq.js";
import { t as useMcp } from "./useMcp-DzTrtFvb.js";
import { t as useWorkflowActivate } from "./useWorkflowActivate-BhSS_xpK.js";
import "./WorkflowActivationErrorMessage-v37Lr_Ej.js";
import { i as getLastPublishedVersion, r as generateVersionName } from "./utils-C2GPI2gK.js";
import "./ProjectBreadcrumb-C7tWU5jd.js";
import { n as FolderBreadcrumbs_default, t as WorkflowActivator_default } from "./WorkflowActivator-D3SAdw0t.js";
import { t as PushConnectionTracker_default } from "./PushConnectionTracker-TnOaTBdr.js";
import { t as useWorkflowSettingsCache } from "./useWorkflowsCache-K84an3SQ.js";
import { t as useBeforeUnload } from "./useBeforeUnload-Dmmheunz.js";
import { t as usePushConnection } from "./usePushConnection-DTJahVkB.js";
import "./aiTemplatesStarterCollection.store-DkHa_nSs.js";
import "./readyToRun.store-CsvyRJzn.js";
var TabBar_vue_vue_type_script_setup_true_lang_default = /* @__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) => {
			return _ctx.items ? (openBlock(), createElementBlock("div", {
				key: 0,
				class: normalizeClass({
					[_ctx.$style.container]: true,
					["tab-bar-container"]: true
				})
			}, [createVNode(unref(N8nRadioButtons_default), {
				"model-value": _ctx.modelValue,
				options: _ctx.items,
				"onUpdate:modelValue": onUpdateModelValue
			}, null, 8, ["model-value", "options"])], 2)) : createCommentVNode("", true);
		};
	}
});
var TabBar_vue_vue_type_style_index_0_lang_module_default = { container: "_container_cznfu_123" };
var TabBar_default = /* @__PURE__ */ __plugin_vue_export_helper_default(TabBar_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": TabBar_vue_vue_type_style_index_0_lang_module_default }]]);
var BreakpointsObserver_default = /* @__PURE__ */ defineComponent({
	__name: "BreakpointsObserver",
	props: {
		valueXS: {},
		valueXL: {},
		valueLG: {},
		valueMD: {},
		valueSM: {},
		valueDefault: {}
	},
	setup(__props) {
		const props = __props;
		const { callDebounced } = useDebounce();
		const bannersStore = useBannersStore();
		const width = ref(window.innerWidth);
		const bp = computed(() => {
			if (width.value < 768) return "XS";
			if (width.value >= 1920) return "XL";
			if (width.value >= 1200) return "LG";
			if (width.value >= 992) return "MD";
			return "SM";
		});
		const value = computed(() => {
			if (props.valueXS && width.value < 768) return props.valueXS;
			if (props.valueXL && width.value >= 1920) return props.valueXL;
			if (props.valueLG && width.value >= 1200) return props.valueLG;
			if (props.valueMD && width.value >= 992) return props.valueMD;
			if (props.valueSM) return props.valueSM;
			return props.valueDefault;
		});
		const onResize = () => {
			callDebounced(onResizeEnd, { debounceTime: 50 });
		};
		const onResizeEnd = async () => {
			width.value = window.innerWidth;
			await nextTick();
			const bannerHeight = await getBannerRowHeight();
			bannersStore.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
			})]);
		};
	}
});
var WorkflowProductionChecklist_default = /* @__PURE__ */ defineComponent({
	__name: "WorkflowProductionChecklist",
	props: { workflow: {} },
	setup(__props) {
		const props = __props;
		const i18n = useI18n();
		const router = useRouter();
		const evaluationStore = useEvaluationStore();
		const nodeTypesStore = useNodeTypesStore();
		const workflowsCache = useWorkflowSettingsCache();
		const uiStore = useUIStore();
		const message = useMessage();
		const telemetry$1 = useTelemetry();
		const sourceControlStore = useSourceControlStore();
		const settingsStore = useSettingsStore();
		const { isEligibleForMcpAccess } = useMcp();
		const usersStore = useUsersStore();
		const isPopoverOpen = ref(false);
		const cachedSettings = ref(null);
		const hasAINode = computed(() => {
			return props.workflow.nodes.some((node) => {
				return nodeTypesStore.getNodeType(node.type, node.typeVersion)?.codex?.categories?.includes("AI");
			});
		});
		const hasEvaluationSetOutputsNode = computed(() => {
			return evaluationStore.evaluationSetOutputsNodeExist;
		});
		const hasErrorWorkflow = computed(() => {
			return !!props.workflow.settings?.errorWorkflow;
		});
		const hasSavedTimeNodes = computed(() => {
			if (!props.workflow?.nodes) return false;
			return props.workflow.nodes.some((node) => node.type === "n8n-nodes-base.timeSaved" && node.disabled !== true);
		});
		const hasTimeSaved = computed(() => {
			return props.workflow.settings?.timeSavedPerExecution !== void 0 || hasSavedTimeNodes.value;
		});
		const isActivationModalOpen = computed(() => {
			return uiStore.isModalActiveById[WORKFLOW_ACTIVE_MODAL_KEY];
		});
		const isProtectedEnvironment = computed(() => {
			return sourceControlStore.preferences.branchReadOnly;
		});
		const isOwner = computed(() => usersStore.isInstanceOwner);
		const isAdmin = computed(() => usersStore.isAdmin);
		const isMcpModuleEnabled = computed(() => {
			return settingsStore.isModuleActive("mcp");
		});
		const isMcpAccessEnabled = computed(() => {
			return settingsStore.moduleSettings.mcp?.mcpAccessEnabled ?? false;
		});
		const isWorkflowEligibleForMcpAccess = computed(() => {
			return isEligibleForMcpAccess(props.workflow);
		});
		const canToggleInstanceMCPAccess = computed(() => isOwner.value || isAdmin.value);
		const availableActions = computed(() => {
			if (props.workflow.activeVersionId === null || 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
			});
			const mcpAction = getMcpAction();
			if (mcpAction) actions.push(mcpAction);
			return actions;
			function getMcpAction() {
				if (!isMcpModuleEnabled.value || !isWorkflowEligibleForMcpAccess.value) return null;
				const baseAction = {
					title: i18n.baseText("mcp.productionChecklist.title"),
					moreInfoLink: MCP_DOCS_PAGE_URL
				};
				if (!isMcpAccessEnabled.value) {
					if (!canToggleInstanceMCPAccess.value || suggestedActionSettings["instance-mcp-access"]?.ignored) return null;
					return {
						...baseAction,
						id: "instance-mcp-access",
						description: i18n.baseText("mcp.productionChecklist.instance.description"),
						completed: false
					};
				}
				if (suggestedActionSettings["workflow-mcp-access"]?.ignored) return null;
				return {
					...baseAction,
					id: "workflow-mcp-access",
					description: i18n.baseText("mcp.productionChecklist.workflow.description"),
					completed: props.workflow.settings?.availableInMCP ?? false
				};
			}
		});
		async function loadWorkflowSettings() {
			if (props.workflow.id) cachedSettings.value = await workflowsCache.getMergedWorkflowSettings(props.workflow.id);
		}
		async function handleActionClick(actionId) {
			switch (actionId) {
				case "evaluations":
					await router.push({
						name: VIEWS.EVALUATION_EDIT,
						params: { name: props.workflow.id }
					});
					break;
				case "errorWorkflow":
				case "timeSaved":
				case "workflow-mcp-access":
					uiStore.openModal(WORKFLOW_SETTINGS_MODAL_KEY);
					break;
				case "instance-mcp-access":
					await router.push({ name: MCP_SETTINGS_VIEW });
					break;
				default: break;
			}
			isPopoverOpen.value = false;
		}
		function isValidAction(action) {
			return [
				"evaluations",
				"errorWorkflow",
				"timeSaved",
				"workflow-mcp-access",
				"instance-mcp-access"
			].includes(action);
		}
		async function handleIgnoreClick(actionId) {
			if (!isValidAction(actionId)) return;
			await workflowsCache.ignoreSuggestedAction(props.workflow.id, actionId);
			await loadWorkflowSettings();
			telemetry$1.track("user clicked ignore suggested action", { actionId });
		}
		async function handleIgnoreAll() {
			if (await message.confirm(i18n.baseText("workflowProductionChecklist.ignoreAllConfirmation.description"), i18n.baseText("workflowProductionChecklist.ignoreAllConfirmation.title"), { confirmButtonText: i18n.baseText("workflowProductionChecklist.ignoreAllConfirmation.confirm") }) === "confirm") {
				await workflowsCache.ignoreAllSuggestedActionsForAllWorkflows(availableActions.value.map((action) => action.id));
				await loadWorkflowSettings();
				telemetry$1.track("user clicked ignore suggested actions for all workflows");
			}
		}
		function openSuggestedActions() {
			isPopoverOpen.value = true;
		}
		function onPopoverOpened() {
			telemetry$1.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.activeVersionId, 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(SuggestedActions_default), {
				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);
		};
	}
});
var IntersectionObserver_default = /* @__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);
		};
	}
});
var IntersectionObserved_default = /* @__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);
		};
	}
});
var import_debounce = /* @__PURE__ */ __toESM(require_debounce());
var _hoisted_1$2 = { class: "tags" };
var _hoisted_2$2 = ["onClick"];
var TagsContainer_default = /* @__PURE__ */ __plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
	__name: "TagsContainer",
	props: {
		tagIds: {},
		tagsById: {},
		limit: { default: 20 },
		clickable: {
			type: Boolean,
			default: false
		},
		responsive: {
			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 parent = (tagsContainer.value?.$el)?.parentNode;
			if (parent) {
				maxWidth.value = 0;
				nextTick(() => {
					maxWidth.value = parent.clientWidth;
				});
			}
		};
		const debouncedSetMaxWidth = (0, import_debounce.default)(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) => {
			return openBlock(), createBlock(IntersectionObserver_default, {
				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$2, [(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(unref(N8nTag_default), {
						key: 0,
						title: tag.title,
						text: tag.name,
						clickable: false,
						class: "count-container"
					}, null, 8, ["title", "text"])) : (openBlock(), createBlock(IntersectionObserved_default, {
						key: 1,
						class: normalizeClass({ hideTag: tag.hidden }),
						"data-id": tag.id,
						enabled: _ctx.responsive,
						"event-bus": unref(intersectionEventBus)
					}, {
						default: withCtx(() => [createVNode(unref(N8nTag_default), {
							title: tag.name,
							text: tag.name,
							clickable: _ctx.clickable
						}, null, 8, [
							"title",
							"text",
							"clickable"
						])]),
						_: 2
					}, 1032, [
						"class",
						"data-id",
						"enabled",
						"event-bus"
					]))], 10, _hoisted_2$2);
				}), 128))])]),
				_: 1
			}, 8, [
				"style",
				"enabled",
				"event-bus"
			]);
		};
	}
}), [["__scopeId", "data-v-2e7ba899"]]);
var WorkflowTagsContainer_default = /* @__PURE__ */ defineComponent({
	__name: "WorkflowTagsContainer",
	props: {
		tagIds: {},
		limit: {},
		clickable: { type: Boolean },
		responsive: { 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_default, {
				"tag-ids": _ctx.tagIds,
				"tags-by-id": tagsById.value,
				limit: _ctx.limit,
				clickable: _ctx.clickable,
				responsive: _ctx.responsive,
				onClick
			}, null, 8, [
				"tag-ids",
				"tags-by-id",
				"limit",
				"clickable",
				"responsive"
			]);
		};
	}
});
var HEARTBEAT_INTERVAL = 5 * TIME.MINUTE;
const useCollaborationStore = defineStore(STORES.COLLABORATION, () => {
	const pushStore = usePushConnectionStore();
	const workflowsStore = useWorkflowsStore();
	const usersStore = useUsersStore();
	const uiStore = useUIStore();
	const { addBeforeUnloadEventBindings, removeBeforeUnloadEventBindings, addBeforeUnloadHandler } = useBeforeUnload({ route: useRoute() });
	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() {
		if (!workflowsStore.isWorkflowSaved[workflowsStore.workflowId]) return;
		pushStore.send({
			type: "workflowOpened",
			workflowId: workflowsStore.workflowId
		});
	}
	function notifyWorkflowClosed() {
		if (!workflowsStore.isWorkflowSaved[workflowsStore.workflowId]) return;
		pushStore.send({
			type: "workflowClosed",
			workflowId: workflowsStore.workflowId
		});
		collaborators.value = collaborators.value.filter(({ user }) => user.id !== usersStore.currentUserId);
	}
	return {
		collaborators,
		initialize,
		terminate,
		startHeartbeat,
		stopHeartbeat
	};
});
var CollaborationPane_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
	__name: "CollaborationPane",
	setup(__props) {
		const collaborationStore = useCollaborationStore();
		const usersStore = useUsersStore();
		watch(useDocumentVisibility(), (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) => {
			return showUserStack.value ? (openBlock(), createElementBlock("div", {
				key: 0,
				class: normalizeClass(`collaboration-pane-container ${_ctx.$style.container}`),
				"data-test-id": "collaboration-pane"
			}, [createVNode(unref(N8nUserStack_default), {
				users: collaboratorsSorted.value,
				"current-user-email": currentUserEmail.value
			}, null, 8, ["users", "current-user-email"])], 2)) : createCommentVNode("", true);
		};
	}
});
var CollaborationPane_vue_vue_type_style_index_0_lang_module_default = { container: "_container_dsr9f_123" };
var CollaborationPane_default = /* @__PURE__ */ __plugin_vue_export_helper_default(CollaborationPane_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": CollaborationPane_vue_vue_type_style_index_0_lang_module_default }]]);
var _hoisted_1$1 = { key: 0 };
var _hoisted_2$1 = { key: 1 };
var WorkflowHistoryButton_default = /* @__PURE__ */ defineComponent({
	__name: "WorkflowHistoryButton",
	props: {
		workflowId: {},
		isNewWorkflow: { type: Boolean }
	},
	setup(__props) {
		const locale = useI18n();
		const props = __props;
		const workflowHistoryRoute = computed(() => ({
			name: VIEWS.WORKFLOW_HISTORY,
			params: { workflowId: props.workflowId }
		}));
		return (_ctx, _cache) => {
			const _component_RouterLink = resolveComponent("RouterLink");
			return _ctx.workflowId ? (openBlock(), createBlock(unref(N8nTooltip_default), {
				key: 0,
				placement: "bottom"
			}, {
				content: withCtx(() => [_ctx.isNewWorkflow ? (openBlock(), createElementBlock("span", _hoisted_1$1, toDisplayString(unref(locale).baseText("workflowHistory.button.tooltip.empty")), 1)) : (openBlock(), createElementBlock("span", _hoisted_2$1, toDisplayString(unref(locale).baseText("workflowHistory.button.tooltip")), 1))]),
				default: withCtx(() => [createVNode(_component_RouterLink, { to: workflowHistoryRoute.value }, {
					default: withCtx(() => [createVNode(unref(N8nIconButton_default), {
						disabled: _ctx.isNewWorkflow,
						"data-test-id": "workflow-history-button",
						type: "highlight",
						icon: "history",
						size: "medium"
					}, null, 8, ["disabled"])]),
					_: 1
				}, 8, ["to"])]),
				_: 1
			})) : createCommentVNode("", true);
		};
	}
});
var INVALID_CHARS_REGEX = /[<>:"/\\|?*\u0000-\u001F\u007F-\u009F]/g;
var ZERO_WIDTH_CHARS_REGEX = /[\u200B-\u200D\u2060\uFEFF]/g;
var UNICODE_SPACES_REGEX = /[\u00A0\u2000-\u200A]/g;
var LEADING_TRAILING_DOTS_SPACES_REGEX = /^[\s.]+|[\s.]+$/g;
var WINDOWS_RESERVED_NAMES = new Set([
	"CON",
	"PRN",
	"AUX",
	"NUL",
	"COM1",
	"COM2",
	"COM3",
	"COM4",
	"COM5",
	"COM6",
	"COM7",
	"COM8",
	"COM9",
	"LPT1",
	"LPT2",
	"LPT3",
	"LPT4",
	"LPT5",
	"LPT6",
	"LPT7",
	"LPT8",
	"LPT9"
]);
var DEFAULT_FALLBACK_NAME = "untitled";
var MAX_FILENAME_LENGTH = 200;
var 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;
};
var import_FileSaver_min = /* @__PURE__ */ __toESM(require_FileSaver_min());
const getWorkflowId = (propId, routeName) => {
	return propId ?? (typeof routeName === "string" ? routeName : void 0);
};
var ActionsDropdownMenu_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
	__name: "ActionsDropdownMenu",
	props: {
		workflowPermissions: {},
		isNewWorkflow: { type: Boolean },
		readOnly: { type: Boolean },
		isArchived: { type: Boolean },
		id: {},
		name: {},
		tags: {},
		currentFolder: {},
		meta: {}
	},
	emits: ["workflow:saved"],
	setup(__props, { expose: __expose, emit: __emit }) {
		const props = __props;
		const emit = __emit;
		const importFileRef = ref();
		const toast = useToast();
		const locale = useI18n();
		const route = useRoute();
		const projectsStore = useProjectsStore();
		const sourceControlStore = useSourceControlStore();
		const workflowsStore = useWorkflowsStore();
		const uiStore = useUIStore();
		const $style = useCssModule();
		const rootStore = useRootStore();
		const tagsStore = useTagsStore();
		const settingsStore = useSettingsStore();
		const usersStore = useUsersStore();
		const workflowHelpers = useWorkflowHelpers();
		const workflowActivate = useWorkflowActivate();
		const changeOwnerEventBus = createEventBus();
		const workflowTelemetry = useTelemetry();
		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 activeVersion = computed(() => workflowsStore.workflow.activeVersion);
		const isSharingEnabled = computed(() => settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Sharing]);
		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]);
			}
		}
		const workflowMenuItems = computed(() => {
			const actions = [{
				id: WORKFLOW_MENU_ACTIONS.DOWNLOAD,
				label: locale.baseText("menuActions.download"),
				disabled: !onWorkflowPage.value
			}];
			if (isSharingEnabled.value) actions.push({
				id: WORKFLOW_MENU_ACTIONS.SHARE,
				label: locale.baseText("workflowDetails.share"),
				disabled: !onWorkflowPage.value
			});
			if (props.workflowPermissions.move && projectsStore.isTeamProjectFeatureEnabled) actions.push({
				id: WORKFLOW_MENU_ACTIONS.CHANGE_OWNER,
				label: locale.baseText("workflows.item.changeOwner"),
				disabled: props.isNewWorkflow
			});
			if (!props.readOnly && !props.isArchived) actions.push({
				id: WORKFLOW_MENU_ACTIONS.RENAME,
				label: locale.baseText("generic.rename"),
				disabled: !onWorkflowPage.value || props.workflowPermissions.update !== true
			});
			if (props.workflowPermissions.update === true && !props.readOnly && !props.isArchived || props.isNewWorkflow) {
				actions.unshift({
					id: WORKFLOW_MENU_ACTIONS.DUPLICATE,
					label: locale.baseText("menuActions.duplicate"),
					disabled: !onWorkflowPage.value || !props.id
				});
				actions.unshift({
					id: WORKFLOW_MENU_ACTIONS.EDIT_DESCRIPTION,
					label: locale.baseText("menuActions.editDescription"),
					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 || props.isNewWorkflow
			});
			if (activeVersion.value && props.workflowPermissions.publish && !props.readOnly) actions.push({
				id: WORKFLOW_MENU_ACTIONS.UNPUBLISH,
				label: locale.baseText("menuActions.unpublish"),
				disabled: !onWorkflowPage.value
			});
			if (props.workflowPermissions.delete === true && !props.readOnly || props.isNewWorkflow) if (props.isArchived) {
				actions.push({
					id: WORKFLOW_MENU_ACTIONS.UNARCHIVE,
					label: locale.baseText("menuActions.unarchive"),
					disabled: !onWorkflowPage.value || props.isNewWorkflow
				});
				actions.push({
					id: WORKFLOW_MENU_ACTIONS.DELETE,
					label: locale.baseText("menuActions.delete"),
					disabled: !onWorkflowPage.value || props.isNewWorkflow,
					customClass: $style.deleteItem,
					divided: true
				});
			} else actions.push({
				id: WORKFLOW_MENU_ACTIONS.ARCHIVE,
				label: locale.baseText("menuActions.archive"),
				disabled: !onWorkflowPage.value || props.isNewWorkflow,
				customClass: $style.deleteItem,
				divided: true
			});
			return actions;
		});
		function onUnpublishWorkflow() {
			const workflowId = getWorkflowId(props.id, route.params.name);
			if (!workflowId || !activeVersion.value) {
				toast.showMessage({
					title: locale.baseText("workflowHistory.action.unpublish.notAvailable"),
					type: "warning"
				});
				return;
			}
			const unpublishEventBus = createEventBus();
			unpublishEventBus.once("unpublish", async () => {
				const success = await workflowActivate.unpublishWorkflowFromHistory(workflowId);
				uiStore.closeModal(WORKFLOW_HISTORY_VERSION_UNPUBLISH);
				if (success) toast.showMessage({
					title: locale.baseText("workflowHistory.action.unpublish.success.title"),
					type: "success"
				});
			});
			uiStore.openModalWithData({
				name: WORKFLOW_HISTORY_VERSION_UNPUBLISH,
				data: {
					versionName: activeVersion.value.name,
					eventBus: unpublishEventBus
				}
			});
		}
		async function onWorkflowMenuSelect(action) {
			switch (action) {
				case WORKFLOW_MENU_ACTIONS.EDIT_DESCRIPTION: {
					const workflowId = getWorkflowId(props.id, route.params.name);
					if (!workflowId) return;
					const workflowDescription = workflowsStore.getWorkflowById(workflowId).description;
					uiStore.openModalWithData({
						name: WORKFLOW_DESCRIPTION_MODAL_KEY,
						data: {
							workflowId,
							workflowDescription
						}
					});
					break;
				}
				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:
					nodeViewEventBus.emit("renameWorkflow");
					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 });
					(0, import_FileSaver_min.default)(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:
					nodeViewEventBus.emit("importWorkflowFromFile");
					break;
				case WORKFLOW_MENU_ACTIONS.PUSH:
					try {
						emit("workflow:saved");
						router_default.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.SHARE:
					uiStore.openModalWithData({
						name: WORKFLOW_SHARE_MODAL_KEY,
						data: { id: props.id }
					});
					workflowTelemetry.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"
					});
					break;
				case WORKFLOW_MENU_ACTIONS.ARCHIVE:
					nodeViewEventBus.emit("archiveWorkflow");
					break;
				case WORKFLOW_MENU_ACTIONS.UNARCHIVE:
					nodeViewEventBus.emit("unarchiveWorkflow");
					break;
				case WORKFLOW_MENU_ACTIONS.DELETE:
					nodeViewEventBus.emit("deleteWorkflow");
					break;
				case WORKFLOW_MENU_ACTIONS.CHANGE_OWNER: {
					const workflowId = getWorkflowId(props.id, route.params.name);
					if (!workflowId) return;
					changeOwnerEventBus.once("resource-moved", async () => await router_default.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;
				}
				case WORKFLOW_MENU_ACTIONS.UNPUBLISH:
					onUnpublishWorkflow();
					break;
				default: break;
			}
		}
		onMounted(() => {
			nodeViewEventBus.on("unpublishWorkflow", onUnpublishWorkflow);
		});
		onBeforeUnmount(() => {
			nodeViewEventBus.off("unpublishWorkflow", onUnpublishWorkflow);
		});
		__expose({ importFileRef });
		return (_ctx, _cache) => {
			return openBlock(), createElementBlock("div", { class: normalizeClass([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[0] || (_cache[0] = ($event) => handleFileImport())
			}, null, 34), createVNode(unref(N8nActionDropdown_default), {
				items: workflowMenuItems.value,
				"data-test-id": "workflow-menu",
				onSelect: onWorkflowMenuSelect
			}, null, 8, ["items"])], 2);
		};
	}
});
var ActionsDropdownMenu_vue_vue_type_style_index_0_lang_module_default = {
	deleteItem: "_deleteItem_ntqfl_123",
	group: "_group_ntqfl_127",
	hiddenInput: "_hiddenInput_ntqfl_132"
};
var ActionsDropdownMenu_default = /* @__PURE__ */ __plugin_vue_export_helper_default(ActionsDropdownMenu_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": ActionsDropdownMenu_vue_vue_type_style_index_0_lang_module_default }]]);
var WorkflowHeaderActions_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
	__name: "WorkflowHeaderActions",
	props: {
		readOnly: { type: Boolean },
		id: {},
		tags: {},
		name: {},
		meta: {},
		active: { type: Boolean },
		currentFolder: {},
		isArchived: { type: Boolean },
		isNewWorkflow: { type: Boolean },
		workflowPermissions: {}
	},
	emits: ["workflow:deactivated", "workflow:saved"],
	setup(__props, { expose: __expose, emit: __emit }) {
		const i18n = useI18n();
		const uiStore = useUIStore();
		const telemetry$1 = useTelemetry();
		const usersStore = useUsersStore();
		const route = useRoute();
		const pageRedirectionHelper = usePageRedirectionHelper();
		const $style = useCssModule();
		const props = __props;
		const emit = __emit;
		const isWorkflowSaving = computed(() => {
			return uiStore.isActionActive.workflowSaving;
		});
		const actionsMenuRef = useTemplateRef("actionsMenu");
		const importFileRef = computed(() => actionsMenuRef.value?.importFileRef);
		const onWorkflowActiveToggle = async (value) => {
			if (!value.active) emit("workflow:deactivated");
		};
		function onShareButtonClick() {
			uiStore.openModalWithData({
				name: WORKFLOW_SHARE_MODAL_KEY,
				data: { id: props.id }
			});
			telemetry$1.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 goToUpgrade() {
			pageRedirectionHelper.goToUpgrade("workflow_sharing", "upgrade-workflow-sharing");
		}
		__expose({ importFileRef });
		return (_ctx, _cache) => {
			return openBlock(), createElementBlock("div", { class: normalizeClass(unref($style).container) }, [
				createBaseVNode("span", { class: normalizeClass([unref($style).activator, unref($style).group]) }, [createVNode(WorkflowActivator_default, {
					"is-archived": _ctx.isArchived,
					"workflow-active": _ctx.active,
					"workflow-id": _ctx.id,
					"workflow-permissions": _ctx.workflowPermissions,
					"onUpdate:workflowActive": onWorkflowActiveToggle
				}, null, 8, [
					"is-archived",
					"workflow-active",
					"workflow-id",
					"workflow-permissions"
				])], 2),
				createVNode(EnterpriseEdition_ee_default, { features: [unref(EnterpriseEditionFeature).Sharing] }, {
					fallback: withCtx(() => [createVNode(unref(N8nTooltip_default), 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(unref(N8nButton_default), {
							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) }, [!_ctx.isNewWorkflow ? (openBlock(), createBlock(CollaborationPane_default, { key: 0 })) : createCommentVNode("", true), createVNode(unref(N8nButton_default), {
						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_default, {
						type: "primary",
						saved: !unref(uiStore).stateIsDirty && !_ctx.isNewWorkflow,
						disabled: isWorkflowSaving.value || _ctx.readOnly || _ctx.isArchived || !_ctx.isNewWorkflow && !_ctx.workflowPermissions.update,
						"is-saving": isWorkflowSaving.value,
						"with-shortcut": !_ctx.readOnly && !_ctx.isArchived && _ctx.workflowPermissions.update,
						"shortcut-tooltip": unref(i18n).baseText("saveWorkflowButton.hint"),
						"data-test-id": "workflow-save-button",
						onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("workflow:saved"))
					}, null, 8, [
						"saved",
						"disabled",
						"is-saving",
						"with-shortcut",
						"shortcut-tooltip"
					]),
					createVNode(WorkflowHistoryButton_default, {
						"workflow-id": props.id,
						"is-new-workflow": _ctx.isNewWorkflow
					}, null, 8, ["workflow-id", "is-new-workflow"]),
					createVNode(ActionsDropdownMenu_default, {
						id: _ctx.id,
						ref: "actionsMenu",
						"workflow-permissions": _ctx.workflowPermissions,
						"is-new-workflow": _ctx.isNewWorkflow,
						"read-only": _ctx.readOnly,
						"is-archived": _ctx.isArchived,
						name: _ctx.name,
						tags: _ctx.tags,
						"current-folder": _ctx.currentFolder,
						meta: _ctx.meta,
						"onWorkflow:saved": _cache[1] || (_cache[1] = ($event) => _ctx.$emit("workflow:saved"))
					}, null, 8, [
						"id",
						"workflow-permissions",
						"is-new-workflow",
						"read-only",
						"is-archived",
						"name",
						"tags",
						"current-folder",
						"meta"
					])
				], 2)
			], 2);
		};
	}
});
var WorkflowHeaderActions_vue_vue_type_style_index_0_lang_module_default = {
	container: "_container_uqc1z_123",
	activator: "_activator_uqc1z_127",
	group: "_group_uqc1z_138",
	disabledShareButton: "_disabledShareButton_uqc1z_143"
};
var WorkflowHeaderActions_default = /* @__PURE__ */ __plugin_vue_export_helper_default(WorkflowHeaderActions_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": WorkflowHeaderActions_vue_vue_type_style_index_0_lang_module_default }]]);
var WorkflowHeaderDraftPublishActions_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
	__name: "WorkflowHeaderDraftPublishActions",
	props: {
		readOnly: { type: Boolean },
		id: {},
		tags: {},
		name: {},
		meta: {},
		currentFolder: {},
		isArchived: { type: Boolean },
		isNewWorkflow: { type: Boolean },
		workflowPermissions: {}
	},
	emits: ["workflow:saved"],
	setup(__props, { expose: __expose }) {
		const props = __props;
		const actionsMenuRef = useTemplateRef("actionsMenu");
		const locale = useI18n();
		const uiStore = useUIStore();
		const workflowsStore = useWorkflowsStore();
		const i18n = useI18n();
		const { saveCurrentWorkflow } = useWorkflowSaving({ router: useRouter() });
		const autoSaveForPublish = ref(false);
		const isWorkflowSaving = computed(() => {
			return uiStore.isActionActive.workflowSaving && !autoSaveForPublish.value;
		});
		const importFileRef = computed(() => actionsMenuRef.value?.importFileRef);
		const onPublishButtonClick = async () => {
			if (uiStore.stateIsDirty || props.isNewWorkflow) {
				autoSaveForPublish.value = true;
				const saved = await saveCurrentWorkflow({}, true);
				autoSaveForPublish.value = false;
				if (!saved) return;
			}
			uiStore.openModalWithData({
				name: WORKFLOW_PUBLISH_MODAL_KEY,
				data: {}
			});
		};
		const foundTriggers = computed(() => getActivatableTriggerNodes(workflowsStore.workflowTriggerNodes));
		const containsTrigger = computed(() => {
			return foundTriggers.value.length > 0;
		});
		const isWorkflowSaved = computed(() => {
			return !uiStore.stateIsDirty && !props.isNewWorkflow;
		});
		const publishButtonEnabled = computed(() => {
			if (!props.workflowPermissions.publish) return false;
			if (!containsTrigger.value) return false;
			if (workflowsStore.nodesIssuesExist) return false;
			return workflowsStore.workflow.versionId && workflowsStore.workflow.versionId !== workflowsStore.workflow.activeVersion?.versionId || uiStore.stateIsDirty;
		});
		const publishTooltipText = computed(() => {
			if (!props.workflowPermissions.publish) return i18n.baseText("workflows.publish.permissionDenied");
			const wfHasAnyChanges = workflowsStore.workflow.versionId !== workflowsStore.workflow.activeVersion?.versionId;
			if (!containsTrigger.value) return i18n.baseText("workflows.publishModal.noTriggerMessage");
			if (workflowsStore.nodesIssuesExist) return i18n.baseText("workflowActivator.showMessage.activeChangedNodesIssuesExistTrue.title", {
				interpolate: { count: workflowsStore.nodesWithIssues.length },
				adjustToNumber: workflowsStore.nodesWithIssues.length
			});
			if (!wfHasAnyChanges && !uiStore.stateIsDirty) return i18n.baseText("workflows.publishModal.noChanges");
			return "";
		});
		const activeVersion = computed(() => workflowsStore.workflow.activeVersion);
		const activeVersionName = computed(() => {
			if (!activeVersion.value) return "";
			return activeVersion.value.name || generateVersionName(activeVersion.value.versionId);
		});
		const latestPublishDate = computed(() => {
			return getLastPublishedVersion(activeVersion.value?.workflowPublishHistory ?? [])?.createdAt;
		});
		onMounted(() => {
			nodeViewEventBus.on("publishWorkflow", onPublishButtonClick);
		});
		onBeforeUnmount(() => {
			nodeViewEventBus.off("publishWorkflow", onPublishButtonClick);
		});
		__expose({ importFileRef });
		return (_ctx, _cache) => {
			return openBlock(), createElementBlock("div", { class: normalizeClass(_ctx.$style.container) }, [
				!_ctx.isNewWorkflow ? (openBlock(), createBlock(CollaborationPane_default, { key: 0 })) : createCommentVNode("", true),
				activeVersion.value ? (openBlock(), createElementBlock("div", {
					key: 1,
					class: normalizeClass(_ctx.$style.activeVersionIndicator),
					"data-test-id": "workflow-active-version-indicator"
				}, [createVNode(unref(N8nTooltip_default), null, {
					content: withCtx(() => [
						createTextVNode(toDisplayString(activeVersionName.value), 1),
						_cache[2] || (_cache[2] = createBaseVNode("br", null, null, -1)),
						createTextVNode(toDisplayString(unref(i18n).baseText("workflowHistory.item.active")) + " ", 1),
						latestPublishDate.value ? (openBlock(), createBlock(TimeAgo_default, {
							key: 0,
							date: latestPublishDate.value
						}, null, 8, ["date"])) : createCommentVNode("", true)
					]),
					default: withCtx(() => [createVNode(unref(N8nIcon_default), {
						icon: "circle-check",
						color: "success",
						size: "xlarge",
						class: normalizeClass(_ctx.$style.icon)
					}, null, 8, ["class"])]),
					_: 1
				})], 2)) : createCommentVNode("", true),
				!_ctx.isArchived && (_ctx.workflowPermissions.update || _ctx.workflowPermissions.publish) ? (openBlock(), createElementBlock("div", {
					key: 2,
					class: normalizeClass(_ctx.$style.publishButtonWrapper)
				}, [createVNode(unref(N8nTooltip_default), { disabled: !publishTooltipText.value }, {
					content: withCtx(() => [createTextVNode(toDisplayString(publishTooltipText.value), 1)]),
					default: withCtx(() => [createVNode(unref(N8nButton_default), {
						loading: autoSaveForPublish.value,
						disabled: !publishButtonEnabled.value || isWorkflowSaving.value,
						type: "secondary",
						"data-test-id": "workflow-open-publish-modal-button",
						onClick: onPublishButtonClick
					}, {
						default: withCtx(() => [createTextVNode(toDisplayString(unref(locale).baseText("workflows.publish")), 1)]),
						_: 1
					}, 8, ["loading", "disabled"])]),
					_: 1
				}, 8, ["disabled"])], 2)) : createCommentVNode("", true),
				createVNode(SaveButton_default, {
					type: "primary",
					saved: isWorkflowSaved.value,
					disabled: isWorkflowSaving.value || _ctx.readOnly || _ctx.isArchived || !_ctx.isNewWorkflow && !_ctx.workflowPermissions.update,
					"is-saving": isWorkflowSaving.value,
					"with-shortcut": !_ctx.readOnly && !_ctx.isArchived && _ctx.workflowPermissions.update,
					"shortcut-tooltip": unref(i18n).baseText("saveWorkflowButton.hint"),
					"data-test-id": "workflow-save-button",
					onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("workflow:saved"))
				}, null, 8, [
					"saved",
					"disabled",
					"is-saving",
					"with-shortcut",
					"shortcut-tooltip"
				]),
				createVNode(WorkflowHistoryButton_default, {
					"workflow-id": props.id,
					"is-new-workflow": _ctx.isNewWorkflow
				}, null, 8, ["workflow-id", "is-new-workflow"]),
				createVNode(ActionsDropdownMenu_default, {
					id: _ctx.id,
					ref: "actionsMenu",
					"workflow-permissions": _ctx.workflowPermissions,
					"is-new-workflow": _ctx.isNewWorkflow,
					"read-only": _ctx.readOnly,
					"is-archived": _ctx.isArchived,
					name: _ctx.name,
					tags: _ctx.tags,
					"current-folder": _ctx.currentFolder,
					meta: _ctx.meta,
					"onWorkflow:saved": _cache[1] || (_cache[1] = ($event) => _ctx.$emit("workflow:saved"))
				}, null, 8, [
					"id",
					"workflow-permissions",
					"is-new-workflow",
					"read-only",
					"is-archived",
					"name",
					"tags",
					"current-folder",
					"meta"
				])
			], 2);
		};
	}
});
var WorkflowHeaderDraftPublishActions_vue_vue_type_style_index_0_lang_module_default = {
	container: "_container_p6bf9_123",
	activeVersionIndicator: "_activeVersionIndicator_p6bf9_127",
	icon: "_icon_p6bf9_131",
	publishButtonWrapper: "_publishButtonWrapper_p6bf9_135"
};
var WorkflowHeaderDraftPublishActions_default = /* @__PURE__ */ __plugin_vue_export_helper_default(WorkflowHeaderDraftPublishActions_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": WorkflowHeaderDraftPublishActions_vue_vue_type_style_index_0_lang_module_default }]]);
var _hoisted_1 = {
	class: "tags",
	"data-test-id": "workflow-tags-container"
};
var _hoisted_2 = { key: 1 };
var WorkflowDetails_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
	__name: "WorkflowDetails",
	props: {
		readOnly: { type: Boolean },
		id: {},
		tags: {},
		name: {},
		meta: {},
		scopes: {},
		active: { type: Boolean },
		currentFolder: {},
		isArchived: { type: Boolean },
		description: {}
	},
	emits: ["workflow:deactivated"],
	setup(__props, { emit: __emit }) {
		const WORKFLOW_NAME_BP_TO_WIDTH = {
			XS: 150,
			SM: 200,
			MD: 250,
			LG: 500,
			XL: 1e3
		};
		const props = __props;
		const emit = __emit;
		const $style = useCssModule();
		const settingsStore = useSettingsStore();
		const uiStore = useUIStore();
		const workflowsStore = useWorkflowsStore();
		const projectsStore = useProjectsStore();
		const foldersStore = useFoldersStore();
		const npsSurveyStore = useNpsSurveyStore();
		const i18n = useI18n();
		const router = useRouter();
		const route = useRoute();
		const locale = useI18n();
		const telemetry$1 = useTelemetry();
		const message = useMessage();
		const toast = useToast();
		const documentTitle = useDocumentTitle();
		const workflowSaving = useWorkflowSaving({ router });
		const isTagsEditEnabled = ref(false);
		const appliedTagIds = ref([]);
		const tagsSaving = ref(false);
		const workflowHeaderActionsRef = useTemplateRef("workflowHeaderActions");
		const tagsEventBus = 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 !workflowsStore.isWorkflowSaved[props.id];
		});
		const isWorkflowSaving = computed(() => {
			return uiStore.isActionActive.workflowSaving;
		});
		const workflowPermissions = computed(() => getResourcePermissions(props.scopes).workflow);
		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();
		});
		async function onSaveButtonClick() {
			if (isWorkflowSaving.value) return;
			const id = getWorkflowId(props.id, route.params.name);
			const name = props.name;
			const tags = props.tags;
			const wasNewWorkflow = !workflowsStore.isWorkflowSaved[props.id];
			if (await workflowSaving.saveCurrentWorkflow({
				id,
				name,
				tags
			})) {
				showCreateWorkflowSuccessToast(id, wasNewWorkflow);
				await npsSurveyStore.fetchPromptsData();
				if (route.name === VIEWS.EXECUTION_DEBUG) await router.replace({
					name: VIEWS.WORKFLOW,
					params: { name: props.id }
				});
			}
		}
		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$1.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(props.id, route.params.name);
			const wasNewWorkflow = !workflowsStore.isWorkflowSaved[props.id];
			if (await workflowSaving.saveCurrentWorkflow({ name })) {
				showCreateWorkflowSuccessToast(id, wasNewWorkflow);
				documentTitle.setDocumentTitle(newName, "IDLE");
			}
			uiStore.removeActiveAction("workflowSaving");
			renameInput.value?.forceCancel();
		}
		async function handleArchiveWorkflow() {
			if (props.active) {
				if (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")
				}) !== "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"
			});
			const workflow = workflowsStore.getWorkflowById(props.id);
			if (workflow?.homeProject?.type === ProjectTypes.Team) await router.push({
				name: VIEWS.PROJECTS_WORKFLOWS,
				params: { projectId: workflow.homeProject.id }
			});
			else await router.push({ name: VIEWS.WORKFLOWS });
		}
		async function handleUnarchiveWorkflow() {
			await workflowsStore.unarchiveWorkflow(props.id);
			toast.showMessage({
				title: locale.baseText("mainSidebar.showMessage.handleUnarchive.title", { interpolate: { workflowName: props.name } }),
				type: "success"
			});
		}
		async function handleDeleteWorkflow() {
			if (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")
			}) !== "confirm") return;
			const workflow = workflowsStore.getWorkflowById(props.id);
			const isTeamProject = workflow?.homeProject?.type === ProjectTypes.Team;
			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"
			});
			if (isTeamProject && workflow?.homeProject) await router.push({
				name: VIEWS.PROJECTS_WORKFLOWS,
				params: { projectId: workflow.homeProject.id }
			});
			else await router.push({ name: VIEWS.WORKFLOWS });
		}
		function getPersonalProjectToastContent() {
			const title = locale.baseText("workflows.create.personal.toast.title");
			if (!props.currentFolder) return { title };
			return {
				title,
				toastMessage: locale.baseText("workflows.create.folder.toast.title", { interpolate: {
					projectName: "Personal",
					folderName: props.currentFolder.name
				} })
			};
		}
		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 };
			return {
				title: locale.baseText(titleKey, { interpolate: interpolateData }),
				toastMessage: locale.baseText("workflows.create.project.toast.text", { interpolate: { projectName } })
			};
		}
		function showCreateWorkflowSuccessToast(id, wasNewWorkflow) {
			if (!id) return;
			if (!(wasNewWorkflow ?? false)) return;
			const { title, toastMessage } = getToastContent();
			toast.showMessage({
				title,
				message: toastMessage,
				type: "success"
			});
		}
		const onBreadcrumbsItemSelected = (item) => {
			if (item.href) router.push(item.href).catch((error) => {
				toast.showError(error, i18n.baseText("folders.open.error.title"));
			});
		};
		const handleImportWorkflowFromFile = () => {
			if (workflowHeaderActionsRef.value?.importFileRef) workflowHeaderActionsRef.value.importFileRef.click();
		};
		onMounted(() => {
			nodeViewEventBus.on("importWorkflowFromFile", handleImportWorkflowFromFile);
			nodeViewEventBus.on("archiveWorkflow", handleArchiveWorkflow);
			nodeViewEventBus.on("unarchiveWorkflow", handleUnarchiveWorkflow);
			nodeViewEventBus.on("deleteWorkflow", handleDeleteWorkflow);
			nodeViewEventBus.on("renameWorkflow", onNameToggle);
			nodeViewEventBus.on("addTag", onTagsEditEnable);
		});
		onBeforeUnmount(() => {
			nodeViewEventBus.off("importWorkflowFromFile", handleImportWorkflowFromFile);
			nodeViewEventBus.off("archiveWorkflow", handleArchiveWorkflow);
			nodeViewEventBus.off("unarchiveWorkflow", handleUnarchiveWorkflow);
			nodeViewEventBus.off("deleteWorkflow", handleDeleteWorkflow);
			nodeViewEventBus.off("renameWorkflow", onNameToggle);
			nodeViewEventBus.off("addTag", onTagsEditEnable);
		});
		return (_ctx, _cache) => {
			return openBlock(), createElementBlock("div", { class: normalizeClass(unref($style).container) }, [
				createVNode(BreakpointsObserver_default, {
					"value-x-s": 15,
					"value-s-m": 25,
					"value-m-d": 50,
					class: "name-container",
					"data-test-id": "canvas-breadcrumbs"
				}, {
					default: withCtx(({ bp }) => [createVNode(FolderBreadcrumbs_default, {
						"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(N8nInlineTextEdit_default), {
							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(128),
							"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(WorkflowTagsDropdown_default, {
					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(WorkflowTagsContainer_default, {
					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", { class: normalizeClass(unref($style)["header-controls"]) }, [_ctx.isArchived ? (openBlock(), createBlock(unref(N8nBadge_default), {
					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)], 2)]),
				createVNode(PushConnectionTracker_default, { class: "actions" }, {
					default: withCtx(() => [!isNewWorkflow.value ? (openBlock(), createBlock(WorkflowProductionChecklist_default, {
						key: 0,
						workflow: unref(workflowsStore).workflow
					}, null, 8, ["workflow"])) : createCommentVNode("", true), unref(true) ? (openBlock(), createBlock(WorkflowHeaderDraftPublishActions_default, {
						key: 1,
						id: _ctx.id,
						ref: "workflowHeaderActions",
						tags: _ctx.tags,
						name: _ctx.name,
						meta: _ctx.meta,
						"read-only": _ctx.readOnly,
						"is-archived": _ctx.isArchived,
						"is-new-workflow": isNewWorkflow.value,
						"workflow-permissions": workflowPermissions.value,
						"onWorkflow:saved": onSaveButtonClick
					}, null, 8, [
						"id",
						"tags",
						"name",
						"meta",
						"read-only",
						"is-archived",
						"is-new-workflow",
						"workflow-permissions"
					])) : (openBlock(), createBlock(WorkflowHeaderActions_default, {
						key: 2,
						id: _ctx.id,
						ref: "workflowHeaderActions",
						name: _ctx.name,
						tags: _ctx.tags,
						"current-folder": _ctx.currentFolder,
						meta: _ctx.meta,
						"read-only": _ctx.readOnly,
						"is-archived": _ctx.isArchived,
						active: _ctx.active,
						"is-new-workflow": isNewWorkflow.value,
						"workflow-permissions": workflowPermissions.value,
						"onWorkflow:saved": onSaveButtonClick,
						"onWorkflow:deactivated": _cache[1] || (_cache[1] = ($event) => emit("workflow:deactivated"))
					}, null, 8, [
						"id",
						"name",
						"tags",
						"current-folder",
						"meta",
						"read-only",
						"is-archived",
						"active",
						"is-new-workflow",
						"workflow-permissions"
					]))]),
					_: 1
				})
			], 2);
		};
	}
});
const container$1 = "_container_7bao3_123";
const closeNodeViewDiscovery = "_closeNodeViewDiscovery_7bao3_138";
var WorkflowDetails_vue_vue_type_style_index_1_lang_module_default = {
	container: container$1,
	"path-separator": "_path-separator_7bao3_132",
	closeNodeViewDiscovery,
	"header-controls": "_header-controls_7bao3_145"
};
var WorkflowDetails_default = /* @__PURE__ */ __plugin_vue_export_helper_default(WorkflowDetails_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": WorkflowDetails_vue_vue_type_style_index_1_lang_module_default }], ["__scopeId", "data-v-22fed76c"]]);
init_shared_esm_bundler();
var vue_github_button_default = 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-CT4flsfB.js"
), []).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(this.$refs._, this.$el.lastChild);
		}
	}
});
var MainHeader_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
	__name: "MainHeader",
	setup(__props) {
		const router = useRouter();
		const route = useRoute();
		const locale = useI18n();
		const pushConnection = usePushConnection({ router });
		const toast = useToast();
		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 !== "n8n-nodes-base.stickyNote"));
		const workflow = computed(() => workflowsStore.workflow);
		const workflowId = computed(() => String(route.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;
			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 (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:
					navigateToWorkflowView(openInNewTab);
					break;
				case MAIN_HEADER_TABS.EXECUTIONS:
					navigateToExecutionsView(openInNewTab);
					break;
				case MAIN_HEADER_TABS.EVALUATION:
					navigateToEvaluationsView(openInNewTab);
					break;
				default: break;
			}
		}
		async function navigateToWorkflowView(openInNewTab) {
			let routeToNavigateTo;
			if (workflowToReturnTo.value && workflowToReturnTo.value !== "") routeToNavigateTo = {
				name: VIEWS.WORKFLOW,
				params: { name: workflowToReturnTo.value },
				query: route.query
			};
			else routeToNavigateTo = {
				name: VIEWS.NEW_WORKFLOW,
				query: route.query
			};
			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 executionToReturnToValue = executionsStore.activeExecution?.id || executionToReturnTo.value;
			const routeToNavigateTo = executionToReturnToValue ? {
				name: VIEWS.EXECUTION_PREVIEW,
				params: {
					name: workflowId.value,
					executionId: executionToReturnToValue
				},
				query: route.query
			} : {
				name: VIEWS.EXECUTION_HOME,
				params: { name: workflowId.value },
				query: route.query
			};
			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 routeToNavigateTo = {
				name: VIEWS.EVALUATION_EDIT,
				params: { name: workflowId.value },
				query: route.query
			};
			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;
		}
		async function onWorkflowDeactivated() {
			if (settingsStore.isModuleActive("mcp") && workflow.value.settings?.availableInMCP) try {
				const updatedWorkflow = await workflowsStore.fetchWorkflow(workflow.value.id);
				workflowsStore.setWorkflow(updatedWorkflow);
				toast.showToast({
					title: locale.baseText("mcp.workflowDeactivated.title"),
					message: locale.baseText("mcp.workflowDeactivated.message"),
					type: "info"
				});
			} catch (error) {
				toast.showError(error, locale.baseText("workflowSettings.showError.fetchSettings.title"));
			}
		}
		return (_ctx, _cache) => {
			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_default, {
				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,
				description: workflow.value.description,
				"onWorkflow:deactivated": onWorkflowDeactivated
			}, null, 8, [
				"id",
				"tags",
				"name",
				"meta",
				"scopes",
				"active",
				"read-only",
				"current-folder",
				"is-archived",
				"description"
			])) : 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(vue_github_button_default), {
				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(unref(N8nIcon_default), {
				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_default, {
				key: 0,
				items: tabBarItems.value,
				"model-value": activeHeaderTab.value,
				"onUpdate:modelValue": onTabSelected
			}, null, 8, ["items", "model-value"])) : createCommentVNode("", true)], 2)], 2);
		};
	}
});
var MainHeader_vue_vue_type_style_index_0_lang_module_default = {
	container: "_container_4ekmy_123",
	"main-header": "_main-header_4ekmy_130",
	"top-menu": "_top-menu_4ekmy_138",
	"github-button": "_github-button_4ekmy_149",
	"close-github-button": "_close-github-button_4ekmy_158",
	"github-button-container": "_github-button-container_4ekmy_173"
};
var MainHeader_default = /* @__PURE__ */ __plugin_vue_export_helper_default(MainHeader_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": MainHeader_vue_vue_type_style_index_0_lang_module_default }]]);
export { MainHeader_default as default };