902 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			902 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
| import { ba as get, d as defineComponent, r as ref, x as computed, fQ as dateFormat, c as useI18n, o as onMounted, h as createElementBlock, g as openBlock, n as normalizeClass, X as renderSlot, j as createBaseVNode, i as createVNode, t as toDisplayString, w as withCtx, k as createTextVNode, a9 as Tooltip, e as createBlock, f as createCommentVNode, aK as N8nBadge, l as unref, B as withModifiers, e6 as N8nActionToggle, _ as _export_sfc, F as Fragment, A as renderList, dD as N8nLoading, ab as I18nT, q as N8nButton, N as N8nIcon, $ as defineStore, at as useRootStore, v as useSettingsStore, a1 as useWorkflowsStore, aQ as FileSaver_minExports, eJ as getNewWorkflow, a2 as useRoute, b as useRouter, a as useToast, aA as usePageRedirectionHelper, Q as useUIStore, V as VIEWS, aB as getResourcePermissions, b1 as onBeforeMount, fR as watchEffect, a8 as resolveComponent, m as N8nHeading, eX as telemetry, aW as h, fS as WORKFLOW_HISTORY_VERSION_RESTORE } from "./index-CeNA_ukL.js";
 | |
| import { W as WorkflowPreview } from "./WorkflowPreview-BZs8Di_n.js";
 | |
| var getWorkflowHistory = async (context, workflowId, queryParams) => {
 | |
|   const { data } = await get(
 | |
|     context.baseUrl,
 | |
|     `/workflow-history/workflow/${workflowId}`,
 | |
|     queryParams
 | |
|   );
 | |
|   return data;
 | |
| };
 | |
| var getWorkflowVersion = async (context, workflowId, versionId) => {
 | |
|   const { data } = await get(
 | |
|     context.baseUrl,
 | |
|     `/workflow-history/workflow/${workflowId}/version/${versionId}`
 | |
|   );
 | |
|   return data;
 | |
| };
 | |
| const _hoisted_1$3 = ["datetime"];
 | |
| const _hoisted_2$1 = ["value"];
 | |
| const _sfc_main$3 = /* @__PURE__ */ defineComponent({
 | |
|   __name: "WorkflowHistoryListItem",
 | |
|   props: {
 | |
|     item: {},
 | |
|     index: {},
 | |
|     actions: {},
 | |
|     isActive: { type: Boolean }
 | |
|   },
 | |
|   emits: ["action", "preview", "mounted"],
 | |
|   setup(__props, { emit: __emit }) {
 | |
|     const props = __props;
 | |
|     const emit = __emit;
 | |
|     const i18n = useI18n();
 | |
|     const actionsVisible2 = ref(false);
 | |
|     const itemElement = ref(null);
 | |
|     const authorElement = ref(null);
 | |
|     const isAuthorElementTruncated = ref(false);
 | |
|     const formattedCreatedAt = computed(() => {
 | |
|       const currentYear = (/* @__PURE__ */ new Date()).getFullYear().toString();
 | |
|       const [date, time] = dateFormat(
 | |
|         props.item.createdAt,
 | |
|         `${props.item.createdAt.startsWith(currentYear) ? "" : "yyyy "}mmm d"#"HH:MM:ss`
 | |
|       ).split("#");
 | |
|       return i18n.baseText("workflowHistory.item.createdAt", { interpolate: { date, time } });
 | |
|     });
 | |
|     const authors = computed(() => {
 | |
|       const allAuthors = props.item.authors.split(", ");
 | |
|       let label2 = allAuthors[0];
 | |
|       if (allAuthors.length > 1) {
 | |
|         label2 = `${label2} + ${allAuthors.length - 1}`;
 | |
|       }
 | |
|       return {
 | |
|         size: allAuthors.length,
 | |
|         label: label2
 | |
|       };
 | |
|     });
 | |
|     const idLabel = computed(
 | |
|       () => i18n.baseText("workflowHistory.item.id", { interpolate: { id: props.item.versionId } })
 | |
|     );
 | |
|     const onAction = (value) => {
 | |
|       const action = value;
 | |
|       emit("action", {
 | |
|         action,
 | |
|         id: props.item.versionId,
 | |
|         data: { formattedCreatedAt: formattedCreatedAt.value }
 | |
|       });
 | |
|     };
 | |
|     const onVisibleChange = (visible) => {
 | |
|       actionsVisible2.value = visible;
 | |
|     };
 | |
|     const onItemClick = (event) => {
 | |
|       emit("preview", { event, id: props.item.versionId });
 | |
|     };
 | |
|     onMounted(() => {
 | |
|       emit("mounted", {
 | |
|         index: props.index,
 | |
|         offsetTop: itemElement.value?.offsetTop ?? 0,
 | |
|         isActive: props.isActive
 | |
|       });
 | |
|       isAuthorElementTruncated.value = (authorElement.value?.scrollWidth ?? 0) > (authorElement.value?.clientWidth ?? 0);
 | |
|     });
 | |
|     return (_ctx, _cache) => {
 | |
|       const _component_n8n_tooltip = Tooltip;
 | |
|       const _component_n8n_badge = N8nBadge;
 | |
|       const _component_n8n_action_toggle = N8nActionToggle;
 | |
|       return openBlock(), createElementBlock("li", {
 | |
|         ref_key: "itemElement",
 | |
|         ref: itemElement,
 | |
|         "data-test-id": "workflow-history-list-item",
 | |
|         class: normalizeClass({
 | |
|           [_ctx.$style.item]: true,
 | |
|           [_ctx.$style.active]: props.isActive,
 | |
|           [_ctx.$style.actionsVisible]: actionsVisible2.value
 | |
|         })
 | |
|       }, [
 | |
|         renderSlot(_ctx.$slots, "default", { formattedCreatedAt: formattedCreatedAt.value }, () => [
 | |
|           createBaseVNode("p", { onClick: onItemClick }, [
 | |
|             createBaseVNode("time", {
 | |
|               datetime: _ctx.item.createdAt
 | |
|             }, toDisplayString(formattedCreatedAt.value), 9, _hoisted_1$3),
 | |
|             createVNode(_component_n8n_tooltip, {
 | |
|               placement: "right-end",
 | |
|               disabled: authors.value.size < 2 && !isAuthorElementTruncated.value
 | |
|             }, {
 | |
|               content: withCtx(() => [
 | |
|                 createTextVNode(toDisplayString(props.item.authors), 1)
 | |
|               ]),
 | |
|               default: withCtx(() => [
 | |
|                 createBaseVNode("span", {
 | |
|                   ref_key: "authorElement",
 | |
|                   ref: authorElement
 | |
|                 }, toDisplayString(authors.value.label), 513)
 | |
|               ]),
 | |
|               _: 1
 | |
|             }, 8, ["disabled"]),
 | |
|             createBaseVNode("data", {
 | |
|               value: _ctx.item.versionId
 | |
|             }, toDisplayString(idLabel.value), 9, _hoisted_2$1)
 | |
|           ])
 | |
|         ]),
 | |
|         createBaseVNode("div", {
 | |
|           class: normalizeClass(_ctx.$style.tail)
 | |
|         }, [
 | |
|           props.index === 0 ? (openBlock(), createBlock(_component_n8n_badge, { key: 0 }, {
 | |
|             default: withCtx(() => [
 | |
|               createTextVNode(toDisplayString(unref(i18n).baseText("workflowHistory.item.latest")), 1)
 | |
|             ]),
 | |
|             _: 1
 | |
|           })) : createCommentVNode("", true),
 | |
|           createVNode(_component_n8n_action_toggle, {
 | |
|             theme: "dark",
 | |
|             class: normalizeClass(_ctx.$style.actions),
 | |
|             actions: props.actions,
 | |
|             placement: "bottom-end",
 | |
|             onAction,
 | |
|             onClick: _cache[0] || (_cache[0] = withModifiers(() => {
 | |
|             }, ["stop"])),
 | |
|             onVisibleChange
 | |
|           }, {
 | |
|             default: withCtx(() => [
 | |
|               renderSlot(_ctx.$slots, "action-toggle-button")
 | |
|             ]),
 | |
|             _: 3
 | |
|           }, 8, ["class", "actions"])
 | |
|         ], 2)
 | |
|       ], 2);
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const item = "_item_1amfi_123";
 | |
| const tail = "_tail_1amfi_155";
 | |
| const active = "_active_1amfi_160";
 | |
| const actionsVisible = "_actionsVisible_1amfi_167";
 | |
| const actions = "_actions_1amfi_167";
 | |
| const style0$3 = {
 | |
|   item,
 | |
|   tail,
 | |
|   active,
 | |
|   actionsVisible,
 | |
|   actions
 | |
| };
 | |
| const cssModules$3 = {
 | |
|   "$style": style0$3
 | |
| };
 | |
| const WorkflowHistoryListItem = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__cssModules", cssModules$3]]);
 | |
| const _hoisted_1$2 = ["aria-label"];
 | |
| const _sfc_main$2 = /* @__PURE__ */ defineComponent({
 | |
|   __name: "WorkflowHistoryList",
 | |
|   props: {
 | |
|     items: {},
 | |
|     activeItem: {},
 | |
|     actions: {},
 | |
|     requestNumberOfItems: {},
 | |
|     lastReceivedItemsLength: {},
 | |
|     evaluatedPruneTime: {},
 | |
|     shouldUpgrade: { type: Boolean },
 | |
|     isListLoading: { type: Boolean }
 | |
|   },
 | |
|   emits: ["action", "preview", "loadMore", "upgrade"],
 | |
|   setup(__props, { emit: __emit }) {
 | |
|     const props = __props;
 | |
|     const emit = __emit;
 | |
|     const i18n = useI18n();
 | |
|     const listElement = ref(null);
 | |
|     const shouldAutoScroll = ref(true);
 | |
|     const observer = ref(null);
 | |
|     const getActions = (index) => index === 0 ? props.actions.filter((action) => action.value !== "restore") : props.actions;
 | |
|     const observeElement = (element) => {
 | |
|       observer.value = new IntersectionObserver(
 | |
|         ([entry]) => {
 | |
|           if (entry.isIntersecting) {
 | |
|             observer.value?.unobserve(element);
 | |
|             observer.value?.disconnect();
 | |
|             observer.value = null;
 | |
|             emit("loadMore", { take: props.requestNumberOfItems, skip: props.items.length });
 | |
|           }
 | |
|         },
 | |
|         {
 | |
|           root: listElement.value,
 | |
|           threshold: 0.01
 | |
|         }
 | |
|       );
 | |
|       observer.value.observe(element);
 | |
|     };
 | |
|     const onAction = ({
 | |
|       action,
 | |
|       id,
 | |
|       data
 | |
|     }) => {
 | |
|       shouldAutoScroll.value = false;
 | |
|       emit("action", { action, id, data });
 | |
|     };
 | |
|     const onPreview = ({ event, id }) => {
 | |
|       shouldAutoScroll.value = false;
 | |
|       emit("preview", { event, id });
 | |
|     };
 | |
|     const onItemMounted = ({
 | |
|       index,
 | |
|       offsetTop,
 | |
|       isActive
 | |
|     }) => {
 | |
|       if (isActive && shouldAutoScroll.value) {
 | |
|         shouldAutoScroll.value = false;
 | |
|         listElement.value?.scrollTo({ top: offsetTop, behavior: "smooth" });
 | |
|       }
 | |
|       if (index === props.items.length - 1 && props.lastReceivedItemsLength === props.requestNumberOfItems) {
 | |
|         observeElement(listElement.value?.children[index]);
 | |
|       }
 | |
|     };
 | |
|     return (_ctx, _cache) => {
 | |
|       const _component_n8n_loading = N8nLoading;
 | |
|       return openBlock(), createElementBlock("ul", {
 | |
|         ref_key: "listElement",
 | |
|         ref: listElement,
 | |
|         class: normalizeClass(_ctx.$style.list),
 | |
|         "data-test-id": "workflow-history-list"
 | |
|       }, [
 | |
|         (openBlock(true), createElementBlock(Fragment, null, renderList(props.items, (item2, index) => {
 | |
|           return openBlock(), createBlock(WorkflowHistoryListItem, {
 | |
|             key: item2.versionId,
 | |
|             index,
 | |
|             item: item2,
 | |
|             "is-active": item2.versionId === props.activeItem?.versionId,
 | |
|             actions: getActions(index),
 | |
|             onAction,
 | |
|             onPreview,
 | |
|             onMounted: onItemMounted
 | |
|           }, null, 8, ["index", "item", "is-active", "actions"]);
 | |
|         }), 128)),
 | |
|         !props.items.length && !props.isListLoading ? (openBlock(), createElementBlock("li", {
 | |
|           key: 0,
 | |
|           class: normalizeClass(_ctx.$style.empty)
 | |
|         }, [
 | |
|           createTextVNode(toDisplayString(unref(i18n).baseText("workflowHistory.empty")) + " ", 1),
 | |
|           _cache[1] || (_cache[1] = createBaseVNode("br", null, null, -1)),
 | |
|           createTextVNode(" " + toDisplayString(unref(i18n).baseText("workflowHistory.hint")), 1)
 | |
|         ], 2)) : createCommentVNode("", true),
 | |
|         props.isListLoading ? (openBlock(), createElementBlock("li", {
 | |
|           key: 1,
 | |
|           class: normalizeClass(_ctx.$style.loader),
 | |
|           role: "status",
 | |
|           "aria-live": "polite",
 | |
|           "aria-busy": "true",
 | |
|           "aria-label": unref(i18n).baseText("generic.loading")
 | |
|         }, [
 | |
|           createVNode(_component_n8n_loading, {
 | |
|             rows: 3,
 | |
|             class: "mb-xs"
 | |
|           }),
 | |
|           createVNode(_component_n8n_loading, {
 | |
|             rows: 3,
 | |
|             class: "mb-xs"
 | |
|           }),
 | |
|           createVNode(_component_n8n_loading, {
 | |
|             rows: 3,
 | |
|             class: "mb-xs"
 | |
|           })
 | |
|         ], 10, _hoisted_1$2)) : createCommentVNode("", true),
 | |
|         props.shouldUpgrade ? (openBlock(), createElementBlock("li", {
 | |
|           key: 2,
 | |
|           class: normalizeClass(_ctx.$style.retention)
 | |
|         }, [
 | |
|           createBaseVNode("span", null, toDisplayString(unref(i18n).baseText("workflowHistory.limit", {
 | |
|             interpolate: { evaluatedPruneTime: String(props.evaluatedPruneTime) }
 | |
|           })), 1),
 | |
|           createVNode(unref(I18nT), {
 | |
|             keypath: "workflowHistory.upgrade",
 | |
|             tag: "span",
 | |
|             scope: "global"
 | |
|           }, {
 | |
|             link: withCtx(() => [
 | |
|               createBaseVNode("a", {
 | |
|                 href: "#",
 | |
|                 onClick: _cache[0] || (_cache[0] = ($event) => emit("upgrade"))
 | |
|               }, toDisplayString(unref(i18n).baseText("workflowHistory.upgrade.link")), 1)
 | |
|             ]),
 | |
|             _: 1
 | |
|           })
 | |
|         ], 2)) : createCommentVNode("", true)
 | |
|       ], 2);
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const list = "_list_1rv1j_123";
 | |
| const empty = "_empty_1rv1j_132";
 | |
| const loader = "_loader_1rv1j_145";
 | |
| const retention = "_retention_1rv1j_149";
 | |
| const style0$2 = {
 | |
|   list,
 | |
|   empty,
 | |
|   loader,
 | |
|   retention
 | |
| };
 | |
| const cssModules$2 = {
 | |
|   "$style": style0$2
 | |
| };
 | |
| const WorkflowHistoryList = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__cssModules", cssModules$2]]);
 | |
| const _hoisted_1$1 = ["datetime"];
 | |
| const _hoisted_2 = ["value"];
 | |
| const _sfc_main$1 = /* @__PURE__ */ defineComponent({
 | |
|   __name: "WorkflowHistoryContent",
 | |
|   props: {
 | |
|     workflow: {},
 | |
|     workflowVersion: {},
 | |
|     actions: {},
 | |
|     isListLoading: { type: Boolean },
 | |
|     isFirstItemShown: { type: Boolean }
 | |
|   },
 | |
|   emits: ["action"],
 | |
|   setup(__props, { emit: __emit }) {
 | |
|     const i18n = useI18n();
 | |
|     const props = __props;
 | |
|     const emit = __emit;
 | |
|     const workflowVersionPreview = computed(() => {
 | |
|       if (!props.workflowVersion || !props.workflow) {
 | |
|         return;
 | |
|       }
 | |
|       const { pinData, ...workflow } = props.workflow;
 | |
|       return {
 | |
|         ...workflow,
 | |
|         nodes: props.workflowVersion.nodes,
 | |
|         connections: props.workflowVersion.connections
 | |
|       };
 | |
|     });
 | |
|     const actions2 = computed(
 | |
|       () => props.isFirstItemShown ? props.actions.filter((action) => action.value !== "restore") : props.actions
 | |
|     );
 | |
|     const onAction = ({
 | |
|       action,
 | |
|       id,
 | |
|       data
 | |
|     }) => {
 | |
|       emit("action", { action, id, data });
 | |
|     };
 | |
|     return (_ctx, _cache) => {
 | |
|       const _component_n8n_icon = N8nIcon;
 | |
|       const _component_n8n_button = N8nButton;
 | |
|       return openBlock(), createElementBlock("div", {
 | |
|         class: normalizeClass(_ctx.$style.content)
 | |
|       }, [
 | |
|         props.workflowVersion ? (openBlock(), createBlock(WorkflowPreview, {
 | |
|           key: 0,
 | |
|           workflow: workflowVersionPreview.value,
 | |
|           loading: props.isListLoading,
 | |
|           "loader-type": "spinner"
 | |
|         }, null, 8, ["workflow", "loading"])) : createCommentVNode("", true),
 | |
|         createBaseVNode("ul", {
 | |
|           class: normalizeClass(_ctx.$style.info)
 | |
|         }, [
 | |
|           props.workflowVersion ? (openBlock(), createBlock(WorkflowHistoryListItem, {
 | |
|             key: 0,
 | |
|             class: normalizeClass(_ctx.$style.card),
 | |
|             index: -1,
 | |
|             item: props.workflowVersion,
 | |
|             "is-active": false,
 | |
|             actions: actions2.value,
 | |
|             onAction
 | |
|           }, {
 | |
|             default: withCtx(({ formattedCreatedAt }) => [
 | |
|               createBaseVNode("section", {
 | |
|                 class: normalizeClass(_ctx.$style.text)
 | |
|               }, [
 | |
|                 createBaseVNode("p", null, [
 | |
|                   createBaseVNode("span", {
 | |
|                     class: normalizeClass(_ctx.$style.label)
 | |
|                   }, toDisplayString(unref(i18n).baseText("workflowHistory.content.title")) + ": ", 3),
 | |
|                   createBaseVNode("time", {
 | |
|                     datetime: props.workflowVersion.createdAt
 | |
|                   }, toDisplayString(formattedCreatedAt), 9, _hoisted_1$1)
 | |
|                 ]),
 | |
|                 createBaseVNode("p", null, [
 | |
|                   createBaseVNode("span", {
 | |
|                     class: normalizeClass(_ctx.$style.label)
 | |
|                   }, toDisplayString(unref(i18n).baseText("workflowHistory.content.editedBy")) + ": ", 3),
 | |
|                   createBaseVNode("span", null, toDisplayString(props.workflowVersion.authors), 1)
 | |
|                 ]),
 | |
|                 createBaseVNode("p", null, [
 | |
|                   createBaseVNode("span", {
 | |
|                     class: normalizeClass(_ctx.$style.label)
 | |
|                   }, toDisplayString(unref(i18n).baseText("workflowHistory.content.versionId")) + ": ", 3),
 | |
|                   createBaseVNode("data", {
 | |
|                     value: props.workflowVersion.versionId
 | |
|                   }, toDisplayString(props.workflowVersion.versionId), 9, _hoisted_2)
 | |
|                 ])
 | |
|               ], 2)
 | |
|             ]),
 | |
|             "action-toggle-button": withCtx(() => [
 | |
|               createVNode(_component_n8n_button, {
 | |
|                 type: "tertiary",
 | |
|                 size: "large",
 | |
|                 "data-test-id": "action-toggle-button"
 | |
|               }, {
 | |
|                 default: withCtx(() => [
 | |
|                   createTextVNode(toDisplayString(unref(i18n).baseText("workflowHistory.content.actions")) + " ", 1),
 | |
|                   createVNode(_component_n8n_icon, {
 | |
|                     class: "ml-3xs",
 | |
|                     icon: "chevron-down",
 | |
|                     size: "small"
 | |
|                   })
 | |
|                 ]),
 | |
|                 _: 1
 | |
|               })
 | |
|             ]),
 | |
|             _: 1
 | |
|           }, 8, ["class", "item", "actions"])) : createCommentVNode("", true)
 | |
|         ], 2)
 | |
|       ], 2);
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const content = "_content_ne8yf_123";
 | |
| const info = "_info_ne8yf_133";
 | |
| const card = "_card_ne8yf_141";
 | |
| const text = "_text_ne8yf_146";
 | |
| const label = "_label_ne8yf_171";
 | |
| const style0$1 = {
 | |
|   content,
 | |
|   info,
 | |
|   card,
 | |
|   text,
 | |
|   label
 | |
| };
 | |
| const cssModules$1 = {
 | |
|   "$style": style0$1
 | |
| };
 | |
| const WorkflowHistoryContent = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__cssModules", cssModules$1]]);
 | |
| const useWorkflowHistoryStore = defineStore("workflowHistory", () => {
 | |
|   const rootStore = useRootStore();
 | |
|   const settingsStore = useSettingsStore();
 | |
|   const workflowsStore = useWorkflowsStore();
 | |
|   const licensePruneTime = computed(() => settingsStore.settings.workflowHistory.licensePruneTime);
 | |
|   const pruneTime = computed(() => settingsStore.settings.workflowHistory.pruneTime);
 | |
|   const evaluatedPruneTime = computed(() => Math.min(pruneTime.value, licensePruneTime.value));
 | |
|   const shouldUpgrade = computed(
 | |
|     () => licensePruneTime.value !== -1 && licensePruneTime.value === pruneTime.value
 | |
|   );
 | |
|   const getWorkflowHistory$1 = async (workflowId, queryParams) => await getWorkflowHistory(rootStore.restApiContext, workflowId, queryParams);
 | |
|   const getWorkflowVersion$1 = async (workflowId, versionId) => await getWorkflowVersion(rootStore.restApiContext, workflowId, versionId);
 | |
|   const downloadVersion = async (workflowId, workflowVersionId, data) => {
 | |
|     const [workflow, workflowVersion] = await Promise.all([
 | |
|       workflowsStore.fetchWorkflow(workflowId),
 | |
|       getWorkflowVersion$1(workflowId, workflowVersionId)
 | |
|     ]);
 | |
|     const { connections, nodes } = workflowVersion;
 | |
|     const blob = new Blob([JSON.stringify({ ...workflow, nodes, connections }, null, 2)], {
 | |
|       type: "application/json;charset=utf-8"
 | |
|     });
 | |
|     FileSaver_minExports.saveAs(blob, `${workflow.name}(${data.formattedCreatedAt}).json`);
 | |
|   };
 | |
|   const cloneIntoNewWorkflow = async (workflowId, workflowVersionId, data) => {
 | |
|     const [workflow, workflowVersion] = await Promise.all([
 | |
|       workflowsStore.fetchWorkflow(workflowId),
 | |
|       getWorkflowVersion$1(workflowId, workflowVersionId)
 | |
|     ]);
 | |
|     const { connections, nodes } = workflowVersion;
 | |
|     const { name } = workflow;
 | |
|     const newWorkflow = await getNewWorkflow(rootStore.restApiContext, {
 | |
|       name: `${name} (${data.formattedCreatedAt})`
 | |
|     });
 | |
|     const newWorkflowData = {
 | |
|       nodes,
 | |
|       connections,
 | |
|       name: newWorkflow.name
 | |
|     };
 | |
|     return await workflowsStore.createNewWorkflow(newWorkflowData);
 | |
|   };
 | |
|   const restoreWorkflow = async (workflowId, workflowVersionId, shouldDeactivate) => {
 | |
|     const workflowVersion = await getWorkflowVersion$1(workflowId, workflowVersionId);
 | |
|     const { connections, nodes } = workflowVersion;
 | |
|     const updateData = { connections, nodes };
 | |
|     if (shouldDeactivate) {
 | |
|       updateData.active = false;
 | |
|     }
 | |
|     return await workflowsStore.updateWorkflow(workflowId, updateData, true).catch(async (error) => {
 | |
|       if (error.httpStatusCode === 400 && typeof error.message === "string" && error.message.includes("can not be activated")) {
 | |
|         return await workflowsStore.fetchWorkflow(workflowId);
 | |
|       } else {
 | |
|         throw new Error(error);
 | |
|       }
 | |
|     });
 | |
|   };
 | |
|   return {
 | |
|     getWorkflowHistory: getWorkflowHistory$1,
 | |
|     getWorkflowVersion: getWorkflowVersion$1,
 | |
|     downloadVersion,
 | |
|     cloneIntoNewWorkflow,
 | |
|     restoreWorkflow,
 | |
|     evaluatedPruneTime,
 | |
|     shouldUpgrade
 | |
|   };
 | |
| });
 | |
| const _hoisted_1 = { key: 0 };
 | |
| const _sfc_main = /* @__PURE__ */ defineComponent({
 | |
|   __name: "WorkflowHistory",
 | |
|   setup(__props) {
 | |
|     const workflowHistoryActionTypes = [
 | |
|       "restore",
 | |
|       "clone",
 | |
|       "open",
 | |
|       "download"
 | |
|     ];
 | |
|     const WORKFLOW_HISTORY_ACTIONS = workflowHistoryActionTypes.reduce(
 | |
|       (record, key) => ({ ...record, [key.toUpperCase()]: key }),
 | |
|       {}
 | |
|     );
 | |
|     const route = useRoute();
 | |
|     const router = useRouter();
 | |
|     const i18n = useI18n();
 | |
|     const toast = useToast();
 | |
|     const pageRedirectionHelper = usePageRedirectionHelper();
 | |
|     const workflowHistoryStore = useWorkflowHistoryStore();
 | |
|     const uiStore = useUIStore();
 | |
|     const workflowsStore = useWorkflowsStore();
 | |
|     const canRender = ref(true);
 | |
|     const isListLoading = ref(true);
 | |
|     const requestNumberOfItems = ref(20);
 | |
|     const lastReceivedItemsLength = ref(0);
 | |
|     const activeWorkflow = ref(null);
 | |
|     const workflowHistory = ref([]);
 | |
|     const activeWorkflowVersion = ref(null);
 | |
|     const workflowId = computed(() => normalizeSingleRouteParam("workflowId"));
 | |
|     const versionId = computed(() => normalizeSingleRouteParam("versionId"));
 | |
|     const editorRoute = computed(() => ({
 | |
|       name: VIEWS.WORKFLOW,
 | |
|       params: {
 | |
|         name: workflowId.value
 | |
|       }
 | |
|     }));
 | |
|     const workflowPermissions = computed(
 | |
|       () => getResourcePermissions(workflowsStore.getWorkflowById(workflowId.value)?.scopes).workflow
 | |
|     );
 | |
|     const actions2 = computed(
 | |
|       () => workflowHistoryActionTypes.map((value) => ({
 | |
|         label: i18n.baseText(`workflowHistory.item.actions.${value}`),
 | |
|         disabled: value === "clone" && !workflowPermissions.value.create || value === "restore" && !workflowPermissions.value.update,
 | |
|         value
 | |
|       }))
 | |
|     );
 | |
|     const isFirstItemShown = computed(() => workflowHistory.value[0]?.versionId === versionId.value);
 | |
|     const evaluatedPruneTime = computed(() => Math.floor(workflowHistoryStore.evaluatedPruneTime / 24));
 | |
|     const sendTelemetry = (event) => {
 | |
|       telemetry.track(event, {
 | |
|         instance_id: useRootStore().instanceId,
 | |
|         workflow_id: workflowId.value
 | |
|       });
 | |
|     };
 | |
|     const loadMore = async (queryParams) => {
 | |
|       const history = await workflowHistoryStore.getWorkflowHistory(workflowId.value, queryParams);
 | |
|       lastReceivedItemsLength.value = history.length;
 | |
|       workflowHistory.value = workflowHistory.value.concat(history);
 | |
|     };
 | |
|     onBeforeMount(async () => {
 | |
|       sendTelemetry("User opened workflow history");
 | |
|       try {
 | |
|         const [workflow] = await Promise.all([
 | |
|           workflowsStore.fetchWorkflow(workflowId.value),
 | |
|           loadMore({ take: requestNumberOfItems.value })
 | |
|         ]);
 | |
|         activeWorkflow.value = workflow;
 | |
|         isListLoading.value = false;
 | |
|         if (!versionId.value && workflowHistory.value.length) {
 | |
|           await router.replace({
 | |
|             name: VIEWS.WORKFLOW_HISTORY,
 | |
|             params: {
 | |
|               workflowId: workflowId.value,
 | |
|               versionId: workflowHistory.value[0].versionId
 | |
|             }
 | |
|           });
 | |
|         }
 | |
|       } catch (error) {
 | |
|         canRender.value = false;
 | |
|         toast.showError(error, i18n.baseText("workflowHistory.title"));
 | |
|       }
 | |
|     });
 | |
|     const normalizeSingleRouteParam = (name) => {
 | |
|       const param = route.params[name];
 | |
|       if (typeof param === "string") return param;
 | |
|       return param?.[0] ?? "";
 | |
|     };
 | |
|     const openInNewTab = (id) => {
 | |
|       const { href } = router.resolve({
 | |
|         name: VIEWS.WORKFLOW_HISTORY,
 | |
|         params: {
 | |
|           workflowId: workflowId.value,
 | |
|           versionId: id
 | |
|         }
 | |
|       });
 | |
|       window.open(href, "_blank");
 | |
|     };
 | |
|     const openRestorationModal = async (isWorkflowActivated, formattedCreatedAt) => {
 | |
|       return await new Promise((resolve, reject) => {
 | |
|         const buttons = [
 | |
|           {
 | |
|             text: i18n.baseText("workflowHistory.action.restore.modal.button.cancel"),
 | |
|             type: "tertiary",
 | |
|             action: () => {
 | |
|               resolve(
 | |
|                 "cancel"
 | |
|                 /* cancel */
 | |
|               );
 | |
|             }
 | |
|           }
 | |
|         ];
 | |
|         if (isWorkflowActivated) {
 | |
|           buttons.push({
 | |
|             text: i18n.baseText("workflowHistory.action.restore.modal.button.deactivateAndRestore"),
 | |
|             type: "tertiary",
 | |
|             action: () => {
 | |
|               resolve(
 | |
|                 "deactivateAndRestore"
 | |
|                 /* deactivateAndRestore */
 | |
|               );
 | |
|             }
 | |
|           });
 | |
|         }
 | |
|         buttons.push({
 | |
|           text: i18n.baseText("workflowHistory.action.restore.modal.button.restore"),
 | |
|           type: "primary",
 | |
|           action: () => {
 | |
|             resolve(
 | |
|               "restore"
 | |
|               /* restore */
 | |
|             );
 | |
|           }
 | |
|         });
 | |
|         try {
 | |
|           uiStore.openModalWithData({
 | |
|             name: WORKFLOW_HISTORY_VERSION_RESTORE,
 | |
|             data: {
 | |
|               beforeClose: () => {
 | |
|                 resolve(
 | |
|                   "cancel"
 | |
|                   /* cancel */
 | |
|                 );
 | |
|               },
 | |
|               isWorkflowActivated,
 | |
|               formattedCreatedAt,
 | |
|               buttons
 | |
|             }
 | |
|           });
 | |
|         } catch (error) {
 | |
|           reject(error);
 | |
|         }
 | |
|       });
 | |
|     };
 | |
|     const cloneWorkflowVersion = async (id, data) => {
 | |
|       const clonedWorkflow = await workflowHistoryStore.cloneIntoNewWorkflow(
 | |
|         workflowId.value,
 | |
|         id,
 | |
|         data
 | |
|       );
 | |
|       const { href } = router.resolve({
 | |
|         name: VIEWS.WORKFLOW,
 | |
|         params: {
 | |
|           name: clonedWorkflow.id
 | |
|         }
 | |
|       });
 | |
|       toast.showMessage({
 | |
|         title: i18n.baseText("workflowHistory.action.clone.success.title"),
 | |
|         message: h(
 | |
|           "a",
 | |
|           { href, target: "_blank" },
 | |
|           i18n.baseText("workflowHistory.action.clone.success.message")
 | |
|         ),
 | |
|         type: "success",
 | |
|         duration: 1e4
 | |
|       });
 | |
|     };
 | |
|     const restoreWorkflowVersion = async (id, data) => {
 | |
|       const workflow = await workflowsStore.fetchWorkflow(workflowId.value);
 | |
|       const modalAction = await openRestorationModal(workflow.active, data.formattedCreatedAt);
 | |
|       if (modalAction === "cancel") {
 | |
|         return;
 | |
|       }
 | |
|       activeWorkflow.value = await workflowHistoryStore.restoreWorkflow(
 | |
|         workflowId.value,
 | |
|         id,
 | |
|         modalAction === "deactivateAndRestore"
 | |
|         /* deactivateAndRestore */
 | |
|       );
 | |
|       const history = await workflowHistoryStore.getWorkflowHistory(workflowId.value, {
 | |
|         take: 1
 | |
|       });
 | |
|       workflowHistory.value = history.concat(workflowHistory.value);
 | |
|       toast.showMessage({
 | |
|         title: i18n.baseText("workflowHistory.action.restore.success.title"),
 | |
|         type: "success"
 | |
|       });
 | |
|     };
 | |
|     const onAction = async ({
 | |
|       action,
 | |
|       id,
 | |
|       data
 | |
|     }) => {
 | |
|       try {
 | |
|         switch (action) {
 | |
|           case WORKFLOW_HISTORY_ACTIONS.OPEN:
 | |
|             openInNewTab(id);
 | |
|             sendTelemetry("User opened version in new tab");
 | |
|             break;
 | |
|           case WORKFLOW_HISTORY_ACTIONS.DOWNLOAD:
 | |
|             await workflowHistoryStore.downloadVersion(workflowId.value, id, data);
 | |
|             sendTelemetry("User downloaded version");
 | |
|             break;
 | |
|           case WORKFLOW_HISTORY_ACTIONS.CLONE:
 | |
|             await cloneWorkflowVersion(id, data);
 | |
|             sendTelemetry("User cloned version");
 | |
|             break;
 | |
|           case WORKFLOW_HISTORY_ACTIONS.RESTORE:
 | |
|             await restoreWorkflowVersion(id, data);
 | |
|             sendTelemetry("User restored version");
 | |
|             break;
 | |
|         }
 | |
|       } catch (error) {
 | |
|         toast.showError(
 | |
|           error,
 | |
|           i18n.baseText("workflowHistory.action.error.title", {
 | |
|             interpolate: {
 | |
|               action: i18n.baseText(`workflowHistory.item.actions.${action}`).toLowerCase()
 | |
|             }
 | |
|           })
 | |
|         );
 | |
|       }
 | |
|     };
 | |
|     const onPreview = async ({ event, id }) => {
 | |
|       if (event.metaKey || event.ctrlKey) {
 | |
|         openInNewTab(id);
 | |
|         sendTelemetry("User opened version in new tab");
 | |
|       } else {
 | |
|         await router.push({
 | |
|           name: VIEWS.WORKFLOW_HISTORY,
 | |
|           params: {
 | |
|             workflowId: workflowId.value,
 | |
|             versionId: id
 | |
|           }
 | |
|         });
 | |
|       }
 | |
|     };
 | |
|     const onUpgrade = () => {
 | |
|       void pageRedirectionHelper.goToUpgrade("workflow-history", "upgrade-workflow-history");
 | |
|     };
 | |
|     watchEffect(async () => {
 | |
|       if (!versionId.value) {
 | |
|         return;
 | |
|       }
 | |
|       try {
 | |
|         activeWorkflowVersion.value = await workflowHistoryStore.getWorkflowVersion(
 | |
|           workflowId.value,
 | |
|           versionId.value
 | |
|         );
 | |
|         sendTelemetry("User selected version");
 | |
|       } catch (error) {
 | |
|         toast.showError(
 | |
|           new Error(`${error.message} "${versionId.value}" `),
 | |
|           i18n.baseText("workflowHistory.title")
 | |
|         );
 | |
|       }
 | |
|       try {
 | |
|         activeWorkflow.value = await workflowsStore.fetchWorkflow(workflowId.value);
 | |
|       } catch (error) {
 | |
|         canRender.value = false;
 | |
|         toast.showError(error, i18n.baseText("workflowHistory.title"));
 | |
|       }
 | |
|     });
 | |
|     return (_ctx, _cache) => {
 | |
|       const _component_n8n_heading = N8nHeading;
 | |
|       const _component_N8nBadge = N8nBadge;
 | |
|       const _component_n8n_button = N8nButton;
 | |
|       const _component_router_link = resolveComponent("router-link");
 | |
|       return openBlock(), createElementBlock("div", {
 | |
|         class: normalizeClass(_ctx.$style.view)
 | |
|       }, [
 | |
|         createBaseVNode("div", {
 | |
|           class: normalizeClass(_ctx.$style.header)
 | |
|         }, [
 | |
|           createVNode(_component_n8n_heading, {
 | |
|             tag: "h2",
 | |
|             size: "medium"
 | |
|           }, {
 | |
|             default: withCtx(() => [
 | |
|               createTextVNode(toDisplayString(activeWorkflow.value?.name), 1)
 | |
|             ]),
 | |
|             _: 1
 | |
|           }),
 | |
|           activeWorkflow.value?.isArchived ? (openBlock(), createElementBlock("span", _hoisted_1, [
 | |
|             createVNode(_component_N8nBadge, {
 | |
|               class: "ml-s",
 | |
|               theme: "tertiary",
 | |
|               bold: "",
 | |
|               "data-test-id": "workflow-archived-tag"
 | |
|             }, {
 | |
|               default: withCtx(() => [
 | |
|                 createTextVNode(toDisplayString(unref(i18n).baseText("workflows.item.archived")), 1)
 | |
|               ]),
 | |
|               _: 1
 | |
|             })
 | |
|           ])) : createCommentVNode("", true)
 | |
|         ], 2),
 | |
|         createBaseVNode("div", {
 | |
|           class: normalizeClass(_ctx.$style.corner)
 | |
|         }, [
 | |
|           createVNode(_component_n8n_heading, {
 | |
|             tag: "h2",
 | |
|             size: "medium",
 | |
|             bold: ""
 | |
|           }, {
 | |
|             default: withCtx(() => [
 | |
|               createTextVNode(toDisplayString(unref(i18n).baseText("workflowHistory.title")), 1)
 | |
|             ]),
 | |
|             _: 1
 | |
|           }),
 | |
|           createVNode(_component_router_link, {
 | |
|             to: editorRoute.value,
 | |
|             "data-test-id": "workflow-history-close-button"
 | |
|           }, {
 | |
|             default: withCtx(() => [
 | |
|               createVNode(_component_n8n_button, {
 | |
|                 type: "tertiary",
 | |
|                 icon: "x",
 | |
|                 size: "small",
 | |
|                 text: "",
 | |
|                 square: ""
 | |
|               })
 | |
|             ]),
 | |
|             _: 1
 | |
|           }, 8, ["to"])
 | |
|         ], 2),
 | |
|         createBaseVNode("div", {
 | |
|           class: normalizeClass(_ctx.$style.listComponentWrapper)
 | |
|         }, [
 | |
|           canRender.value ? (openBlock(), createBlock(WorkflowHistoryList, {
 | |
|             key: 0,
 | |
|             items: workflowHistory.value,
 | |
|             "last-received-items-length": lastReceivedItemsLength.value,
 | |
|             "active-item": activeWorkflowVersion.value,
 | |
|             actions: actions2.value,
 | |
|             "request-number-of-items": requestNumberOfItems.value,
 | |
|             "should-upgrade": unref(workflowHistoryStore).shouldUpgrade,
 | |
|             "evaluated-prune-time": evaluatedPruneTime.value,
 | |
|             "is-list-loading": isListLoading.value,
 | |
|             onAction,
 | |
|             onPreview,
 | |
|             onLoadMore: loadMore,
 | |
|             onUpgrade
 | |
|           }, null, 8, ["items", "last-received-items-length", "active-item", "actions", "request-number-of-items", "should-upgrade", "evaluated-prune-time", "is-list-loading"])) : createCommentVNode("", true)
 | |
|         ], 2),
 | |
|         createBaseVNode("div", {
 | |
|           class: normalizeClass(_ctx.$style.contentComponentWrapper)
 | |
|         }, [
 | |
|           canRender.value ? (openBlock(), createBlock(WorkflowHistoryContent, {
 | |
|             key: 0,
 | |
|             workflow: activeWorkflow.value,
 | |
|             "workflow-version": activeWorkflowVersion.value,
 | |
|             actions: actions2.value,
 | |
|             "is-list-loading": isListLoading.value,
 | |
|             "is-first-item-shown": isFirstItemShown.value,
 | |
|             onAction
 | |
|           }, null, 8, ["workflow", "workflow-version", "actions", "is-list-loading", "is-first-item-shown"])) : createCommentVNode("", true)
 | |
|         ], 2)
 | |
|       ], 2);
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const view = "_view_1m8fw_123";
 | |
| const header = "_header_1m8fw_133";
 | |
| const corner = "_corner_1m8fw_141";
 | |
| const contentComponentWrapper = "_contentComponentWrapper_1m8fw_152";
 | |
| const listComponentWrapper = "_listComponentWrapper_1m8fw_157";
 | |
| const style0 = {
 | |
|   view,
 | |
|   header,
 | |
|   corner,
 | |
|   contentComponentWrapper,
 | |
|   listComponentWrapper
 | |
| };
 | |
| const cssModules = {
 | |
|   "$style": style0
 | |
| };
 | |
| const WorkflowHistory = /* @__PURE__ */ _export_sfc(_sfc_main, [["__cssModules", cssModules]]);
 | |
| export {
 | |
|   WorkflowHistory as default
 | |
| };
 |