1563 lines
		
	
	
		
			51 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1563 lines
		
	
	
		
			51 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
| import { d as defineComponent, e as createBlock, g as openBlock, s as N8nCard, K as mergeProps, br as createSlots, w as withCtx, j as createBaseVNode, t as toDisplayString, n as normalizeClass, X as renderSlot, i as createVNode, dK as N8nLoading, _ as _export_sfc, ap as normalizeStyle, b2 as withDirectives, p as N8nText, k as createTextVNode, l as unref, c as useI18n, b3 as vShow, eS as orderBy, eT as requireDebounce, eU as requireIsObject, bS as getDefaultExportFromCjs, h as createElementBlock, f as createCommentVNode, F as Fragment, A as renderList, r as ref, a7 as watch, o as onMounted, Y as nextTick, b1 as onBeforeMount, N as N8nIcon, x as computed, a8 as resolveComponent, P as useDebounce, a as useToast, ax as useDocumentTitle, v as useSettingsStore, bk as useTemplatesStore, u as useUsersStore, a2 as useRoute, b as useRouter, dn as onBeforeRouteLeave, cc as resolveDirective, cZ as N8nInput, m as N8nHeading, q as N8nButton, eV as CREATOR_HUB_URL, V as VIEWS, al as useTelemetry } from "./index--OJ5nhDf.js";
 | |
| import { N as NodeList, T as TemplateList } from "./TemplateList-CV9csLUI.js";
 | |
| import { T as TemplatesView } from "./TemplatesView-CXSlz1M1.js";
 | |
| const _hoisted_1$3 = ["textContent"];
 | |
| const _sfc_main$5 = /* @__PURE__ */ defineComponent({
 | |
|   __name: "CollectionWorkflowCard",
 | |
|   props: {
 | |
|     loading: { type: Boolean },
 | |
|     title: {}
 | |
|   },
 | |
|   setup(__props) {
 | |
|     return (_ctx, _cache) => {
 | |
|       const _component_n8n_loading = N8nLoading;
 | |
|       const _component_n8n_card = N8nCard;
 | |
|       return openBlock(), createBlock(_component_n8n_card, mergeProps({
 | |
|         class: _ctx.$style.card
 | |
|       }, _ctx.$attrs), createSlots({
 | |
|         default: withCtx(() => [
 | |
|           createVNode(_component_n8n_loading, {
 | |
|             loading: _ctx.loading,
 | |
|             rows: 3,
 | |
|             variant: "p"
 | |
|           }, null, 8, ["loading"])
 | |
|         ]),
 | |
|         _: 2
 | |
|       }, [
 | |
|         !_ctx.loading && _ctx.title ? {
 | |
|           name: "header",
 | |
|           fn: withCtx(() => [
 | |
|             createBaseVNode("span", {
 | |
|               class: normalizeClass(_ctx.$style.title),
 | |
|               textContent: toDisplayString(_ctx.title)
 | |
|             }, null, 10, _hoisted_1$3)
 | |
|           ]),
 | |
|           key: "0"
 | |
|         } : void 0,
 | |
|         !_ctx.loading ? {
 | |
|           name: "footer",
 | |
|           fn: withCtx(() => [
 | |
|             renderSlot(_ctx.$slots, "footer")
 | |
|           ]),
 | |
|           key: "1"
 | |
|         } : void 0
 | |
|       ]), 1040, ["class"]);
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const card = "_card_p9uhf_123";
 | |
| const title$1 = "_title_p9uhf_139";
 | |
| const style0$3 = {
 | |
|   card,
 | |
|   title: title$1
 | |
| };
 | |
| const cssModules$3 = {
 | |
|   "$style": style0$3
 | |
| };
 | |
| const Card = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__cssModules", cssModules$3]]);
 | |
| const _sfc_main$4 = /* @__PURE__ */ defineComponent({
 | |
|   __name: "TemplatesInfoCard",
 | |
|   props: {
 | |
|     collection: {},
 | |
|     loading: { type: Boolean, default: false },
 | |
|     showItemCount: { type: Boolean, default: true },
 | |
|     width: {}
 | |
|   },
 | |
|   setup(__props) {
 | |
|     const i18n = useI18n();
 | |
|     return (_ctx, _cache) => {
 | |
|       const _component_n8n_text = N8nText;
 | |
|       return openBlock(), createBlock(Card, {
 | |
|         loading: _ctx.loading,
 | |
|         title: _ctx.collection.name,
 | |
|         style: normalizeStyle({ width: _ctx.width })
 | |
|       }, {
 | |
|         footer: withCtx(() => [
 | |
|           createBaseVNode("span", null, [
 | |
|             withDirectives(createVNode(_component_n8n_text, {
 | |
|               size: "small",
 | |
|               color: "text-light"
 | |
|             }, {
 | |
|               default: withCtx(() => [
 | |
|                 createTextVNode(toDisplayString(_ctx.collection.workflows.length) + " " + toDisplayString(unref(i18n).baseText("templates.workflows")), 1)
 | |
|               ]),
 | |
|               _: 1
 | |
|             }, 512), [
 | |
|               [vShow, _ctx.showItemCount]
 | |
|             ])
 | |
|           ]),
 | |
|           createVNode(NodeList, {
 | |
|             nodes: _ctx.collection.nodes,
 | |
|             "show-more": false
 | |
|           }, null, 8, ["nodes"])
 | |
|         ]),
 | |
|         _: 1
 | |
|       }, 8, ["loading", "title", "style"]);
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const mixin$6 = {
 | |
|   methods: {
 | |
|     handleMouseDown(e) {
 | |
|       this.isMouseDown = true;
 | |
|       if (e.type.indexOf("touch") !== -1) {
 | |
|         this.dragStartX = e.touches[0].clientX;
 | |
|         this.dragStartY = e.touches[0].clientY;
 | |
|       }
 | |
|       if (e.type.indexOf("mouse") !== -1) {
 | |
|         this.dragStartX = e.clientX;
 | |
|         this.dragStartY = e.clientY;
 | |
|       }
 | |
|     },
 | |
|     handleMouseMove(e) {
 | |
|       let positionX;
 | |
|       let positionY;
 | |
|       if (e.type.indexOf("touch") !== -1) {
 | |
|         positionX = e.touches[0].clientX;
 | |
|         positionY = e.touches[0].clientY;
 | |
|       }
 | |
|       if (e.type.indexOf("mouse") !== -1) {
 | |
|         positionX = e.clientX;
 | |
|         positionY = e.clientY;
 | |
|       }
 | |
|       const dragDistanceX = Math.abs(positionX - this.dragStartX);
 | |
|       const dragDistanceY = Math.abs(positionY - this.dragStartY);
 | |
|       if (dragDistanceX > 3 * dragDistanceY) {
 | |
|         this.disableScroll();
 | |
|         this.dragDistance = positionX - this.dragStartX;
 | |
|       }
 | |
|     },
 | |
|     handleMouseUp() {
 | |
|       this.isMouseDown = false;
 | |
|       this.enableScroll();
 | |
|     },
 | |
|     handleMouseOver(element) {
 | |
|       if (this.settings.autoplay) {
 | |
|         if (element === "dot" && this.settings.pauseOnDotsHover || element === "track" && this.settings.pauseOnHover) {
 | |
|           this.isAutoplayPaused = true;
 | |
|         }
 | |
|       }
 | |
|     },
 | |
|     handleMouseOut(element) {
 | |
|       if (this.settings.autoplay) {
 | |
|         if (element === "dot" && this.settings.pauseOnDotsHover || element === "track" && this.settings.pauseOnHover) {
 | |
|           this.isAutoplayPaused = false;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| };
 | |
| const mixin$5 = {
 | |
|   methods: {
 | |
|     /**
 | |
|      * Set window & container width
 | |
|      */
 | |
|     getWidth() {
 | |
|       if (this.isSSR) {
 | |
|         return false;
 | |
|       }
 | |
|       this.widthWindow = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
 | |
|       this.widthContainer = this.$refs.list.clientWidth;
 | |
|     },
 | |
|     /**
 | |
|      * Convert HTML Collection to JS Array
 | |
|      */
 | |
|     htmlCollectionToArray(collection) {
 | |
|       return Array.prototype.slice.call(collection, 0);
 | |
|     }
 | |
|   }
 | |
| };
 | |
| const mixin$4 = {
 | |
|   methods: {
 | |
|     clearAutoPlayPause() {
 | |
|       clearTimeout(this.autoplayTimeout);
 | |
|       this.autoplayRemaining = null;
 | |
|     },
 | |
|     disableAutoPlay() {
 | |
|       clearInterval(this.autoplayInterval);
 | |
|       this.autoplayInterval = null;
 | |
|     },
 | |
|     disableScroll() {
 | |
|       document.ontouchmove = (e) => e.preventDefault();
 | |
|     },
 | |
|     enableScroll() {
 | |
|       document.ontouchmove = () => true;
 | |
|     },
 | |
|     restartAutoPlay() {
 | |
|       this.disableAutoPlay();
 | |
|       this.toggleAutoPlay();
 | |
|     },
 | |
|     toggleAutoPlay() {
 | |
|       const enabled = !this.settings.unagile && this.settings.autoplay;
 | |
|       if (!this.autoplayInterval && enabled) {
 | |
|         this.autoplayInterval = setInterval(() => {
 | |
|           if (!document.hidden) {
 | |
|             if (!this.canGoToNext) {
 | |
|               this.disableAutoPlay();
 | |
|             } else {
 | |
|               this.goToNext();
 | |
|             }
 | |
|           }
 | |
|         }, this.settings.autoplaySpeed);
 | |
|       } else {
 | |
|         this.disableAutoPlay();
 | |
|       }
 | |
|     },
 | |
|     toggleFade() {
 | |
|       const enabled = !this.settings.unagile && this.settings.fade;
 | |
|       for (let i = 0; i < this.countSlides; i++) {
 | |
|         this.slides[i].style.transition = enabled ? "opacity " + this.settings.timing + " " + this.settings.speed + "ms" : "none";
 | |
|         this.slides[i].style.transform = enabled ? `translate(-${i * this.widthSlide}px)` : "none";
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| };
 | |
| const mixin$3 = {
 | |
|   methods: {
 | |
|     /**
 | |
|      * Prepare slides classes and styles
 | |
|      */
 | |
|     prepareSlides() {
 | |
|       this.slides = this.htmlCollectionToArray(this.$refs.slides.children);
 | |
|       if (this.slidesCloned) {
 | |
|         this.slidesClonedBefore = this.htmlCollectionToArray(this.$refs.slidesClonedBefore.children);
 | |
|         this.slidesClonedAfter = this.htmlCollectionToArray(this.$refs.slidesClonedAfter.children);
 | |
|       }
 | |
|       for (const slide of this.slidesAll) {
 | |
|         slide.classList.add("agile__slide");
 | |
|       }
 | |
|     },
 | |
|     /**
 | |
|      *  Prepare slides active/current classes
 | |
|      */
 | |
|     prepareSlidesClasses() {
 | |
|       if (this.currentSlide === null) {
 | |
|         return false;
 | |
|       }
 | |
|       for (let i = 0; i < this.countSlides; i++) {
 | |
|         this.slides[i].classList.remove("agile__slide--active");
 | |
|         this.slides[i].classList.remove("agile__slide--current");
 | |
|       }
 | |
|       setTimeout(() => this.slides[this.currentSlide].classList.add("agile__slide--active"), this.changeDelay);
 | |
|       let start = this.slidesCloned ? this.countSlides + this.currentSlide : this.currentSlide;
 | |
|       if (this.centerMode) {
 | |
|         start -= Math.floor(this.settings.slidesToShow / 2) - +(this.settings.slidesToShow % 2 === 0);
 | |
|       }
 | |
|       for (let i = Math.max(start, 0); i < Math.min(start + this.settings.slidesToShow, this.countSlides); i++) {
 | |
|         this.slidesAll[i].classList.add("agile__slide--current");
 | |
|       }
 | |
|     },
 | |
|     /**
 | |
|      * Prepare carousel styles
 | |
|      */
 | |
|     prepareCarousel() {
 | |
|       if (this.settings.unagile) {
 | |
|         this.translateX = 0;
 | |
|       } else {
 | |
|         if (this.currentSlide === null && this.countSlides) {
 | |
|           this.currentSlide = this.settings.initialSlide;
 | |
|         }
 | |
|         if (this.currentSlide > this.countSlides) {
 | |
|           this.currentSlide = this.countSlides - 1;
 | |
|         }
 | |
|         this.goTo(this.currentSlide, false, false);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| };
 | |
| const mixin$2 = {
 | |
|   props: {
 | |
|     /**
 | |
|      * Set the carousel to be the navigation of other carousels
 | |
|      */
 | |
|     asNavFor: {
 | |
|       type: Array,
 | |
|       default: function() {
 | |
|         return [];
 | |
|       }
 | |
|     },
 | |
|     /**
 | |
|      * Enable autoplay
 | |
|      */
 | |
|     autoplay: {
 | |
|       type: Boolean,
 | |
|       default: false
 | |
|     },
 | |
|     /**
 | |
|      * Autoplay interval in milliseconds
 | |
|      */
 | |
|     autoplaySpeed: {
 | |
|       type: Number,
 | |
|       default: 3e3
 | |
|     },
 | |
|     /**
 | |
|      * Enable centered view when slidesToShow > 1
 | |
|      */
 | |
|     centerMode: {
 | |
|       type: Boolean,
 | |
|       default: false
 | |
|     },
 | |
|     /**
 | |
|      * Slides padding in center mode
 | |
|      */
 | |
|     centerPadding: {
 | |
|       type: String,
 | |
|       default: "15%"
 | |
|     },
 | |
|     /**
 | |
|      * Slide change delay in milliseconds
 | |
|      */
 | |
|     changeDelay: {
 | |
|       type: Number,
 | |
|       default: 0
 | |
|     },
 | |
|     /**
 | |
|      * Enable dot indicators/pagination
 | |
|      */
 | |
|     dots: {
 | |
|       type: Boolean,
 | |
|       default: true
 | |
|     },
 | |
|     /**
 | |
|      * Enable fade effect
 | |
|      */
 | |
|     fade: {
 | |
|       type: Boolean,
 | |
|       default: false
 | |
|     },
 | |
|     /**
 | |
|      * Infinite loop sliding
 | |
|      */
 | |
|     infinite: {
 | |
|       type: Boolean,
 | |
|       default: true
 | |
|     },
 | |
|     /**
 | |
|      * Index of slide to start on
 | |
|      */
 | |
|     initialSlide: {
 | |
|       type: Number,
 | |
|       default: 0
 | |
|     },
 | |
|     /**
 | |
|      * Enable mobile first calculation for responsive settings
 | |
|      */
 | |
|     mobileFirst: {
 | |
|       type: Boolean,
 | |
|       default: true
 | |
|     },
 | |
|     /**
 | |
|      * Enable prev/next navigation buttons
 | |
|      */
 | |
|     navButtons: {
 | |
|       type: Boolean,
 | |
|       default: true
 | |
|     },
 | |
|     /**
 | |
|      * All settings as one object
 | |
|      */
 | |
|     options: {
 | |
|       type: Object,
 | |
|       default: () => null
 | |
|     },
 | |
|     /**
 | |
|      * Pause autoplay when a dot is hovered
 | |
|      */
 | |
|     pauseOnDotsHover: {
 | |
|       type: Boolean,
 | |
|       default: false
 | |
|     },
 | |
|     /**
 | |
|      * Pause autoplay when a slide is hovered
 | |
|      */
 | |
|     pauseOnHover: {
 | |
|       type: Boolean,
 | |
|       default: true
 | |
|     },
 | |
|     /**
 | |
|      * Object containing breakpoints and settings objects
 | |
|      */
 | |
|     responsive: {
 | |
|       type: Array,
 | |
|       default: () => null
 | |
|     },
 | |
|     /**
 | |
|      * Enable right-to-left mode
 | |
|      */
 | |
|     rtl: {
 | |
|       type: Boolean,
 | |
|       default: false
 | |
|     },
 | |
|     /**
 | |
|      * Number of slides to scroll
 | |
|      */
 | |
|     slidesToScroll: {
 | |
|       type: Number,
 | |
|       default: 1
 | |
|     },
 | |
|     /**
 | |
|      * Number of slides to show
 | |
|      */
 | |
|     slidesToShow: {
 | |
|       type: Number,
 | |
|       default: 1
 | |
|     },
 | |
|     /**
 | |
|      * Slide animation speed in milliseconds
 | |
|      */
 | |
|     speed: {
 | |
|       type: Number,
 | |
|       default: 300
 | |
|     },
 | |
|     /**
 | |
|      * Swipe distance
 | |
|      */
 | |
|     swipeDistance: {
 | |
|       type: Number,
 | |
|       default: 50
 | |
|     },
 | |
|     /**
 | |
|      * Throttle delay in milliseconds
 | |
|      */
 | |
|     throttleDelay: {
 | |
|       type: Number,
 | |
|       default: 500
 | |
|     },
 | |
|     /**
 | |
|      * Transition timing function
 | |
|      * Available: ease, linear, ease-in, ease-out, ease-in-out
 | |
|      */
 | |
|     timing: {
 | |
|       type: String,
 | |
|       default: "ease",
 | |
|       validator: (value) => {
 | |
|         return ["ease", "linear", "ease-in", "ease-out", "ease-in-out"].indexOf(value) !== -1;
 | |
|       }
 | |
|     },
 | |
|     /**
 | |
|      * Disable Agile carousel
 | |
|      */
 | |
|     unagile: {
 | |
|       type: Boolean,
 | |
|       default: false
 | |
|     }
 | |
|   },
 | |
|   computed: {
 | |
|     // Initial settings based on props and options object
 | |
|     initialSettings: function() {
 | |
|       let { options, ...initialSettings } = this.$props;
 | |
|       if (options) {
 | |
|         initialSettings = { ...initialSettings, ...options };
 | |
|       }
 | |
|       if (initialSettings.responsive) {
 | |
|         initialSettings.responsive = orderBy(initialSettings.responsive, "breakpoint");
 | |
|       }
 | |
|       return initialSettings;
 | |
|     },
 | |
|     // Settings for current breakpoint
 | |
|     settings: function() {
 | |
|       const { responsive, ...settings } = this.initialSettings;
 | |
|       if (responsive) {
 | |
|         responsive.forEach((option) => {
 | |
|           if (settings.mobileFirst ? option.breakpoint < this.widthWindow : option.breakpoint > this.widthWindow) {
 | |
|             for (const key in option.settings) {
 | |
|               settings[key] = option.settings[key];
 | |
|             }
 | |
|           }
 | |
|         });
 | |
|       }
 | |
|       return settings;
 | |
|     }
 | |
|   }
 | |
| };
 | |
| var throttle_1;
 | |
| var hasRequiredThrottle;
 | |
| function requireThrottle() {
 | |
|   if (hasRequiredThrottle) return throttle_1;
 | |
|   hasRequiredThrottle = 1;
 | |
|   var debounce = requireDebounce(), isObject = requireIsObject();
 | |
|   var FUNC_ERROR_TEXT = "Expected a function";
 | |
|   function throttle2(func, wait, options) {
 | |
|     var leading = true, trailing = true;
 | |
|     if (typeof func != "function") {
 | |
|       throw new TypeError(FUNC_ERROR_TEXT);
 | |
|     }
 | |
|     if (isObject(options)) {
 | |
|       leading = "leading" in options ? !!options.leading : leading;
 | |
|       trailing = "trailing" in options ? !!options.trailing : trailing;
 | |
|     }
 | |
|     return debounce(func, wait, {
 | |
|       "leading": leading,
 | |
|       "maxWait": wait,
 | |
|       "trailing": trailing
 | |
|     });
 | |
|   }
 | |
|   throttle_1 = throttle2;
 | |
|   return throttle_1;
 | |
| }
 | |
| var throttleExports = requireThrottle();
 | |
| const throttle = /* @__PURE__ */ getDefaultExportFromCjs(throttleExports);
 | |
| const mixin$1 = {
 | |
|   created() {
 | |
|     this.goTo = throttle(this.goTo, this.throttleDelay);
 | |
|     this.getWidth = throttle(this.getWidth, 500);
 | |
|   }
 | |
| };
 | |
| const mixin = {
 | |
|   watch: {
 | |
|     // Recalculate settings
 | |
|     currentBreakpoint() {
 | |
|       this.$emit("breakpoint", { breakpoint: this.currentBreakpoint });
 | |
|     },
 | |
|     // Watch current slide change
 | |
|     currentSlide() {
 | |
|       this.prepareSlidesClasses();
 | |
|       this.autoplayStartTimestamp = this.settings.autoplay ? +/* @__PURE__ */ new Date() : null;
 | |
|       this.$emit("after-change", { currentSlide: this.currentSlide });
 | |
|     },
 | |
|     // Watch drag distance change
 | |
|     dragDistance() {
 | |
|       if (this.isMouseDown) {
 | |
|         const { rtl } = this.settings;
 | |
|         const dragDistance = this.dragDistance * (rtl ? -1 : 1);
 | |
|         if (dragDistance > this.swipeDistance && this.canGoToPrev) {
 | |
|           this.goToPrev();
 | |
|           this.handleMouseUp();
 | |
|         }
 | |
|         if (dragDistance < -1 * this.swipeDistance && this.canGoToNext) {
 | |
|           this.goToNext();
 | |
|           this.handleMouseUp();
 | |
|         }
 | |
|       }
 | |
|     },
 | |
|     isAutoplayPaused(nevValue) {
 | |
|       if (nevValue) {
 | |
|         this.remaining = this.settings.autoplaySpeed - (+/* @__PURE__ */ new Date() - this.autoplayStartTimestamp);
 | |
|         this.disableAutoPlay();
 | |
|         this.clearAutoPlayPause();
 | |
|       } else {
 | |
|         this.autoplayTimeout = setTimeout(() => {
 | |
|           this.clearAutoPlayPause();
 | |
|           this.goToNext();
 | |
|           this.toggleAutoPlay();
 | |
|         }, this.remaining);
 | |
|       }
 | |
|     },
 | |
|     "settings.autoplay"() {
 | |
|       this.toggleAutoPlay();
 | |
|     },
 | |
|     "settings.fade"() {
 | |
|       this.toggleFade();
 | |
|     },
 | |
|     "settings.unagile"() {
 | |
|     },
 | |
|     widthSlide() {
 | |
|       for (let i = 0; i < this.countSlidesAll; i++) {
 | |
|         this.slidesAll[i].style.width = `${this.widthSlide}${this.widthSlide !== "auto" ? "px" : ""}`;
 | |
|       }
 | |
|     },
 | |
|     // Watch window width change
 | |
|     widthWindow(newValue, oldValue) {
 | |
|       if (oldValue) {
 | |
|         this.prepareCarousel();
 | |
|         this.toggleFade();
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| };
 | |
| const _sfc_main$3 = {
 | |
|   name: "agile",
 | |
|   mixins: [mixin$6, mixin$5, mixin$4, mixin$3, mixin$2, mixin$1, mixin],
 | |
|   emits: ["before-change", "after-change", "breakpoint"],
 | |
|   data() {
 | |
|     return {
 | |
|       autoplayInterval: null,
 | |
|       autoplayRemaining: null,
 | |
|       autoplayStartTimestamp: null,
 | |
|       autoplayTimeout: null,
 | |
|       currentSlide: null,
 | |
|       dragDistance: 0,
 | |
|       dragStartX: 0,
 | |
|       dragStartY: 0,
 | |
|       isAutoplayPaused: false,
 | |
|       isMouseDown: false,
 | |
|       slides: [],
 | |
|       slidesClonedAfter: [],
 | |
|       slidesClonedBefore: [],
 | |
|       isSSR: typeof window === "undefined",
 | |
|       transitionDelay: 0,
 | |
|       translateX: 0,
 | |
|       widthWindow: 0,
 | |
|       widthContainer: 0
 | |
|     };
 | |
|   },
 | |
|   computed: {
 | |
|     breakpoints: function() {
 | |
|       return !this.initialSettings.responsive ? [] : this.initialSettings.responsive.map((item2) => item2.breakpoint);
 | |
|     },
 | |
|     canGoToPrev: function() {
 | |
|       return this.settings.infinite || this.currentSlide > 0;
 | |
|     },
 | |
|     canGoToNext: function() {
 | |
|       return this.settings.infinite || this.currentSlide < this.countSlides - 1;
 | |
|     },
 | |
|     countSlides: function() {
 | |
|       return this.isSSR ? this.htmlCollectionToArray(this.$slots.default).length : this.slides.length;
 | |
|     },
 | |
|     countSlidesAll: function() {
 | |
|       return this.slidesAll.length;
 | |
|     },
 | |
|     currentBreakpoint: function() {
 | |
|       const breakpoints = this.breakpoints.map((item2) => item2).reverse();
 | |
|       return this.initialSettings.mobileFirst ? breakpoints.find((item2) => item2 < this.widthWindow) || 0 : breakpoints.find((item2) => item2 > this.widthWindow) || null;
 | |
|     },
 | |
|     marginX: function() {
 | |
|       if (this.settings.unagile) {
 | |
|         return 0;
 | |
|       }
 | |
|       let marginX = this.slidesCloned ? this.countSlides * this.widthSlide : 0;
 | |
|       if (this.settings.centerMode) {
 | |
|         marginX -= (Math.floor(this.settings.slidesToShow / 2) - +(this.settings.slidesToShow % 2 === 0)) * this.widthSlide;
 | |
|       }
 | |
|       return this.settings.rtl ? marginX : -1 * marginX;
 | |
|     },
 | |
|     slidesCloned: function() {
 | |
|       return !this.settings.unagile && !this.settings.fade && this.settings.infinite;
 | |
|     },
 | |
|     slidesAll: function() {
 | |
|       return this.slidesCloned ? [...this.slidesClonedBefore, ...this.slides, ...this.slidesClonedAfter] : this.slides;
 | |
|     },
 | |
|     widthSlide: function() {
 | |
|       return !this.settings.unagile ? this.widthContainer / this.settings.slidesToShow : "auto";
 | |
|     }
 | |
|   },
 | |
|   mounted() {
 | |
|     window.addEventListener("resize", this.getWidth);
 | |
|     this.$refs.track.addEventListener("touchstart", this.handleMouseDown);
 | |
|     this.$refs.track.addEventListener("touchend", this.handleMouseUp);
 | |
|     this.$refs.track.addEventListener("touchmove", this.handleMouseMove);
 | |
|     this.$refs.track.addEventListener("mousedown", this.handleMouseDown);
 | |
|     this.$refs.track.addEventListener("mouseup", this.handleMouseUp);
 | |
|     this.$refs.track.addEventListener("mousemove", this.handleMouseMove);
 | |
|     this.isSSR = false;
 | |
|     this.reload();
 | |
|   },
 | |
|   // Vue 3
 | |
|   beforeUnmount() {
 | |
|     this.destroy();
 | |
|   },
 | |
|   methods: {
 | |
|     destroy() {
 | |
|       window.removeEventListener("resize", this.getWidth);
 | |
|       this.$refs.track.removeEventListener("touchstart", this.handleMouseDown);
 | |
|       this.$refs.track.removeEventListener("touchend", this.handleMouseUp);
 | |
|       this.$refs.track.removeEventListener("touchmove", this.handleMouseMove);
 | |
|       this.$refs.track.removeEventListener("mousedown", this.handleMouseDown);
 | |
|       this.$refs.track.removeEventListener("mouseup", this.handleMouseUp);
 | |
|       this.$refs.track.removeEventListener("mousemove", this.handleMouseMove);
 | |
|       this.disableAutoPlay();
 | |
|     },
 | |
|     // Return current breakpoint
 | |
|     getCurrentBreakpoint() {
 | |
|       return this.currentBreakpoint;
 | |
|     },
 | |
|     // Return settings for current breakpoint
 | |
|     getCurrentSettings() {
 | |
|       return this.settings;
 | |
|     },
 | |
|     // Return current slide index
 | |
|     getCurrentSlide() {
 | |
|       return this.currentSlide;
 | |
|     },
 | |
|     // Return initial settings
 | |
|     getInitialSettings() {
 | |
|       return this.initialSettings;
 | |
|     },
 | |
|     // Go to slide
 | |
|     goTo(n, transition = true, asNav = false) {
 | |
|       if (this.settings.unagile) {
 | |
|         return false;
 | |
|       }
 | |
|       if (!asNav) {
 | |
|         this.settings.asNavFor.forEach((carousel) => {
 | |
|           if (carousel) {
 | |
|             carousel.goTo(n, transition, true);
 | |
|           }
 | |
|         });
 | |
|       }
 | |
|       let slideNextReal = n;
 | |
|       if (transition) {
 | |
|         if (this.settings.infinite && n < 0) {
 | |
|           slideNextReal = this.countSlides - 1;
 | |
|         } else if (n >= this.countSlides) {
 | |
|           slideNextReal = 0;
 | |
|         }
 | |
|         this.$emit("before-change", { currentSlide: this.currentSlide, nextSlide: slideNextReal });
 | |
|         this.currentSlide = slideNextReal;
 | |
|         if (n !== slideNextReal) {
 | |
|           setTimeout(() => {
 | |
|             this.goTo(slideNextReal, false);
 | |
|           }, this.settings.speed);
 | |
|         }
 | |
|       }
 | |
|       const translateX = !this.settings.fade ? n * this.widthSlide * this.settings.slidesToScroll : 0;
 | |
|       this.transitionDelay = transition ? this.speed : 0;
 | |
|       if (this.infinite || this.currentSlide + this.slidesToShow <= this.countSlides) {
 | |
|         this.translateX = this.settings.rtl ? translateX : -1 * translateX;
 | |
|       }
 | |
|     },
 | |
|     // Go to next slide
 | |
|     goToNext() {
 | |
|       if (this.canGoToNext) {
 | |
|         this.goTo(this.currentSlide + 1);
 | |
|       }
 | |
|     },
 | |
|     // Go to previous slide
 | |
|     goToPrev() {
 | |
|       if (this.canGoToPrev) {
 | |
|         this.goTo(this.currentSlide - 1);
 | |
|       }
 | |
|     },
 | |
|     // Reload carousel
 | |
|     reload() {
 | |
|       this.getWidth();
 | |
|       this.prepareSlides();
 | |
|       this.prepareCarousel();
 | |
|       this.toggleFade();
 | |
|       this.toggleAutoPlay();
 | |
|     }
 | |
|   }
 | |
| };
 | |
| const _hoisted_1$2 = {
 | |
|   ref: "list",
 | |
|   class: "agile__list"
 | |
| };
 | |
| const _hoisted_2$1 = {
 | |
|   ref: "slidesClonedBefore",
 | |
|   class: "agile__slides agile__slides--cloned"
 | |
| };
 | |
| const _hoisted_3 = {
 | |
|   ref: "slides",
 | |
|   class: "agile__slides agile__slides--regular"
 | |
| };
 | |
| const _hoisted_4 = {
 | |
|   ref: "slidesClonedAfter",
 | |
|   class: "agile__slides agile__slides--cloned"
 | |
| };
 | |
| const _hoisted_5 = {
 | |
|   key: 0,
 | |
|   class: "agile__caption"
 | |
| };
 | |
| const _hoisted_6 = {
 | |
|   key: 1,
 | |
|   class: "agile__actions"
 | |
| };
 | |
| const _hoisted_7 = ["disabled"];
 | |
| const _hoisted_8 = {
 | |
|   key: 1,
 | |
|   ref: "dots",
 | |
|   class: "agile__dots"
 | |
| };
 | |
| const _hoisted_9 = ["onClick"];
 | |
| const _hoisted_10 = ["disabled"];
 | |
| function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
 | |
|   return openBlock(), createElementBlock("div", {
 | |
|     class: normalizeClass([{ "agile--ssr": $data.isSSR, "agile--auto-play": _ctx.settings.autoplay, "agile--disabled": _ctx.settings.unagile, "agile--fade": _ctx.settings.fade && !_ctx.settings.unagile, "agile--rtl": _ctx.settings.rtl, "agile--no-nav-buttons": !_ctx.settings.navButtons }, "agile"]),
 | |
|     onTouchstart: () => {
 | |
|     }
 | |
|   }, [
 | |
|     createBaseVNode("div", _hoisted_1$2, [
 | |
|       createBaseVNode("div", {
 | |
|         ref: "track",
 | |
|         style: normalizeStyle({ transform: `translate(${$data.translateX + $options.marginX}px)`, transition: `transform ${_ctx.settings.timing} ${$data.transitionDelay}ms` }),
 | |
|         class: "agile__track",
 | |
|         onMouseout: _cache[0] || (_cache[0] = ($event) => _ctx.handleMouseOut("track")),
 | |
|         onMouseover: _cache[1] || (_cache[1] = ($event) => _ctx.handleMouseOver("track"))
 | |
|       }, [
 | |
|         withDirectives(createBaseVNode("div", _hoisted_2$1, [
 | |
|           renderSlot(_ctx.$slots, "default")
 | |
|         ], 512), [
 | |
|           [vShow, $options.slidesCloned]
 | |
|         ]),
 | |
|         createBaseVNode("div", _hoisted_3, [
 | |
|           renderSlot(_ctx.$slots, "default")
 | |
|         ], 512),
 | |
|         withDirectives(createBaseVNode("div", _hoisted_4, [
 | |
|           renderSlot(_ctx.$slots, "default")
 | |
|         ], 512), [
 | |
|           [vShow, $options.slidesCloned]
 | |
|         ])
 | |
|       ], 36)
 | |
|     ], 512),
 | |
|     _ctx.$slots.caption ? (openBlock(), createElementBlock("div", _hoisted_5, [
 | |
|       renderSlot(_ctx.$slots, "caption")
 | |
|     ])) : createCommentVNode("", true),
 | |
|     !_ctx.settings.unagile && (_ctx.settings.navButtons || _ctx.settings.dots) ? (openBlock(), createElementBlock("div", _hoisted_6, [
 | |
|       _ctx.settings.navButtons && !_ctx.settings.unagile ? (openBlock(), createElementBlock("button", {
 | |
|         key: 0,
 | |
|         ref: "prevButton",
 | |
|         disabled: !$options.canGoToPrev,
 | |
|         "aria-label": "Previous",
 | |
|         class: "agile__nav-button agile__nav-button--prev",
 | |
|         type: "button",
 | |
|         onClick: _cache[2] || (_cache[2] = ($event) => ($options.goToPrev(), _ctx.restartAutoPlay()))
 | |
|       }, [
 | |
|         renderSlot(_ctx.$slots, "prevButton", {}, () => [
 | |
|           _cache[6] || (_cache[6] = createTextVNode(" ← "))
 | |
|         ])
 | |
|       ], 8, _hoisted_7)) : createCommentVNode("", true),
 | |
|       _ctx.settings.dots && !_ctx.settings.unagile ? (openBlock(), createElementBlock("ul", _hoisted_8, [
 | |
|         (openBlock(true), createElementBlock(Fragment, null, renderList($options.countSlides, (n) => {
 | |
|           return openBlock(), createElementBlock("li", {
 | |
|             key: n,
 | |
|             class: normalizeClass([{ "agile__dot--current": n - 1 === $data.currentSlide }, "agile__dot"]),
 | |
|             onMouseout: _cache[3] || (_cache[3] = ($event) => _ctx.handleMouseOut("dot")),
 | |
|             onMouseover: _cache[4] || (_cache[4] = ($event) => _ctx.handleMouseOver("dot"))
 | |
|           }, [
 | |
|             createBaseVNode("button", {
 | |
|               type: "button",
 | |
|               onClick: ($event) => ($options.goTo(n - 1), _ctx.restartAutoPlay())
 | |
|             }, toDisplayString(n), 9, _hoisted_9)
 | |
|           ], 34);
 | |
|         }), 128))
 | |
|       ], 512)) : createCommentVNode("", true),
 | |
|       _ctx.settings.navButtons && !_ctx.settings.unagile ? (openBlock(), createElementBlock("button", {
 | |
|         key: 2,
 | |
|         ref: "nextButton",
 | |
|         disabled: !$options.canGoToNext,
 | |
|         "aria-label": "Next",
 | |
|         class: "agile__nav-button agile__nav-button--next",
 | |
|         type: "button",
 | |
|         onClick: _cache[5] || (_cache[5] = ($event) => ($options.goToNext(), _ctx.restartAutoPlay()))
 | |
|       }, [
 | |
|         renderSlot(_ctx.$slots, "nextButton", {}, () => [
 | |
|           _cache[7] || (_cache[7] = createTextVNode(" → "))
 | |
|         ])
 | |
|       ], 8, _hoisted_10)) : createCommentVNode("", true)
 | |
|     ])) : createCommentVNode("", true)
 | |
|   ], 34);
 | |
| }
 | |
| const VueAgile = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["render", _sfc_render]]);
 | |
| const _sfc_main$2 = /* @__PURE__ */ defineComponent({
 | |
|   __name: "TemplatesInfoCarousel",
 | |
|   props: {
 | |
|     collections: {},
 | |
|     loading: { type: Boolean, default: false },
 | |
|     showItemCount: { type: Boolean, default: true },
 | |
|     showNavigation: { type: Boolean, default: true },
 | |
|     cardsWidth: { default: "240px" }
 | |
|   },
 | |
|   emits: ["openCollection"],
 | |
|   setup(__props, { emit: __emit }) {
 | |
|     const props = __props;
 | |
|     const emit = __emit;
 | |
|     const carouselScrollPosition = ref(0);
 | |
|     const cardWidth = ref(parseInt(props.cardsWidth, 10));
 | |
|     const scrollEnd = ref(false);
 | |
|     const listElement = ref(null);
 | |
|     const sliderRef = ref(null);
 | |
|     const updateCarouselScroll = () => {
 | |
|       if (listElement.value) {
 | |
|         carouselScrollPosition.value = Number(listElement.value.scrollLeft.toFixed());
 | |
|         const width = listElement.value.clientWidth;
 | |
|         const scrollWidth = listElement.value.scrollWidth;
 | |
|         const scrollLeft2 = carouselScrollPosition.value;
 | |
|         scrollEnd.value = scrollWidth - width <= scrollLeft2 + 7;
 | |
|       }
 | |
|     };
 | |
|     const onCardClick = (event, id) => {
 | |
|       emit("openCollection", { event, id });
 | |
|     };
 | |
|     const scrollLeft = () => {
 | |
|       if (listElement.value) {
 | |
|         listElement.value.scrollBy({ left: -(cardWidth.value * 2), top: 0, behavior: "smooth" });
 | |
|       }
 | |
|     };
 | |
|     const scrollRight = () => {
 | |
|       if (listElement.value) {
 | |
|         listElement.value.scrollBy({ left: cardWidth.value * 2, top: 0, behavior: "smooth" });
 | |
|       }
 | |
|     };
 | |
|     watch(
 | |
|       () => props.collections,
 | |
|       () => {
 | |
|         setTimeout(() => {
 | |
|           updateCarouselScroll();
 | |
|         }, 0);
 | |
|       }
 | |
|     );
 | |
|     watch(
 | |
|       () => props.loading,
 | |
|       () => {
 | |
|         setTimeout(() => {
 | |
|           updateCarouselScroll();
 | |
|         }, 0);
 | |
|       }
 | |
|     );
 | |
|     onMounted(async () => {
 | |
|       await nextTick();
 | |
|       if (!sliderRef.value) {
 | |
|         return;
 | |
|       }
 | |
|       listElement.value = sliderRef.value.$el.querySelector(".agile__list");
 | |
|       if (listElement.value) {
 | |
|         listElement.value.addEventListener("scroll", updateCarouselScroll);
 | |
|       }
 | |
|     });
 | |
|     onBeforeMount(() => {
 | |
|       if (sliderRef.value) {
 | |
|         sliderRef.value.destroy();
 | |
|       }
 | |
|       window.addEventListener("scroll", updateCarouselScroll);
 | |
|     });
 | |
|     return (_ctx, _cache) => {
 | |
|       const _component_n8n_icon = N8nIcon;
 | |
|       return withDirectives((openBlock(), createElementBlock("div", {
 | |
|         class: normalizeClass(_ctx.$style.container)
 | |
|       }, [
 | |
|         createVNode(unref(VueAgile), {
 | |
|           ref_key: "sliderRef",
 | |
|           ref: sliderRef,
 | |
|           dots: false,
 | |
|           "nav-buttons": false,
 | |
|           infinite: false,
 | |
|           "slides-to-show": 4,
 | |
|           onAfterChange: updateCarouselScroll
 | |
|         }, {
 | |
|           default: withCtx(() => [
 | |
|             (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.loading ? 4 : 0, (n) => {
 | |
|               return openBlock(), createBlock(Card, {
 | |
|                 key: `loading-${n}`,
 | |
|                 loading: _ctx.loading
 | |
|               }, null, 8, ["loading"]);
 | |
|             }), 128)),
 | |
|             (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.loading ? [] : _ctx.collections, (collection) => {
 | |
|               return openBlock(), createBlock(_sfc_main$4, {
 | |
|                 key: collection.id,
 | |
|                 "data-test-id": "templates-info-card",
 | |
|                 collection,
 | |
|                 "show-item-count": _ctx.showItemCount,
 | |
|                 width: _ctx.cardsWidth,
 | |
|                 onClick: (e) => onCardClick(e, collection.id)
 | |
|               }, null, 8, ["collection", "show-item-count", "width", "onClick"]);
 | |
|             }), 128))
 | |
|           ]),
 | |
|           _: 1
 | |
|         }, 512),
 | |
|         withDirectives(createBaseVNode("button", {
 | |
|           class: normalizeClass({ [_ctx.$style.leftButton]: true }),
 | |
|           onClick: scrollLeft
 | |
|         }, [
 | |
|           createVNode(_component_n8n_icon, { icon: "chevron-left" })
 | |
|         ], 2), [
 | |
|           [vShow, _ctx.showNavigation && carouselScrollPosition.value > 0]
 | |
|         ]),
 | |
|         withDirectives(createBaseVNode("button", {
 | |
|           class: normalizeClass({ [_ctx.$style.rightButton]: true }),
 | |
|           onClick: scrollRight
 | |
|         }, [
 | |
|           createVNode(_component_n8n_icon, { icon: "chevron-right" })
 | |
|         ], 2), [
 | |
|           [vShow, _ctx.showNavigation && !scrollEnd.value]
 | |
|         ])
 | |
|       ], 2)), [
 | |
|         [vShow, _ctx.loading || _ctx.collections.length]
 | |
|       ]);
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const container = "_container_1rskb_123";
 | |
| const button$1 = "_button_1rskb_127";
 | |
| const leftButton = "_leftButton_1rskb_148 _button_1rskb_127";
 | |
| const rightButton = "_rightButton_1rskb_157 _button_1rskb_127";
 | |
| const style0$2 = {
 | |
|   container,
 | |
|   button: button$1,
 | |
|   leftButton,
 | |
|   rightButton
 | |
| };
 | |
| const cssModules$2 = {
 | |
|   "$style": style0$2
 | |
| };
 | |
| const TemplatesInfoCarousel = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__cssModules", cssModules$2]]);
 | |
| const _hoisted_1$1 = ["textContent"];
 | |
| const _hoisted_2 = ["data-test-id"];
 | |
| const _sfc_main$1 = /* @__PURE__ */ defineComponent({
 | |
|   __name: "TemplateFilters",
 | |
|   props: {
 | |
|     categories: { default: () => [] },
 | |
|     sortOnPopulate: { type: Boolean, default: false },
 | |
|     expandLimit: { default: 12 },
 | |
|     loading: { type: Boolean, default: false },
 | |
|     selected: { default: () => [] }
 | |
|   },
 | |
|   emits: ["clearAll", "select", "clear"],
 | |
|   setup(__props, { emit: __emit }) {
 | |
|     const props = __props;
 | |
|     const emit = __emit;
 | |
|     const i18n = useI18n();
 | |
|     const collapsed = ref(true);
 | |
|     const sortedCategories = ref([]);
 | |
|     const allSelected = computed(() => {
 | |
|       return props.selected.length === 0;
 | |
|     });
 | |
|     function sortCategories() {
 | |
|       if (!props.sortOnPopulate) {
 | |
|         sortedCategories.value = props.categories;
 | |
|       } else {
 | |
|         const selected = props.selected || [];
 | |
|         const selectedCategories = props.categories.filter((cat) => selected.includes(cat));
 | |
|         const notSelectedCategories = props.categories.filter((cat) => !selected.includes(cat));
 | |
|         sortedCategories.value = selectedCategories.concat(notSelectedCategories);
 | |
|       }
 | |
|     }
 | |
|     function collapseAction() {
 | |
|       collapsed.value = false;
 | |
|     }
 | |
|     function handleCheckboxChanged(value, selectedCategory) {
 | |
|       if (value) {
 | |
|         emit("select", selectedCategory);
 | |
|       } else {
 | |
|         emit("clear", selectedCategory);
 | |
|       }
 | |
|     }
 | |
|     function isSelected(category) {
 | |
|       return props.selected.includes(category);
 | |
|     }
 | |
|     function resetCategories() {
 | |
|       emit("clearAll");
 | |
|     }
 | |
|     watch(
 | |
|       () => props.sortOnPopulate,
 | |
|       (value) => {
 | |
|         if (value) {
 | |
|           sortCategories();
 | |
|         }
 | |
|       },
 | |
|       {
 | |
|         immediate: true
 | |
|       }
 | |
|     );
 | |
|     watch(
 | |
|       () => props.categories,
 | |
|       (categories2) => {
 | |
|         if (categories2.length > 0) {
 | |
|           sortCategories();
 | |
|         }
 | |
|       },
 | |
|       {
 | |
|         immediate: true
 | |
|       }
 | |
|     );
 | |
|     return (_ctx, _cache) => {
 | |
|       const _component_n8n_loading = N8nLoading;
 | |
|       const _component_el_checkbox = resolveComponent("el-checkbox");
 | |
|       const _component_n8n_text = N8nText;
 | |
|       return openBlock(), createElementBlock("div", {
 | |
|         class: normalizeClass([_ctx.$style.filters, "template-filters"]),
 | |
|         "data-test-id": "templates-filter-container"
 | |
|       }, [
 | |
|         createBaseVNode("div", {
 | |
|           class: normalizeClass(_ctx.$style.title),
 | |
|           textContent: toDisplayString(unref(i18n).baseText("templates.categoriesHeading"))
 | |
|         }, null, 10, _hoisted_1$1),
 | |
|         _ctx.loading ? (openBlock(), createElementBlock("div", {
 | |
|           key: 0,
 | |
|           class: normalizeClass(_ctx.$style.list)
 | |
|         }, [
 | |
|           createVNode(_component_n8n_loading, {
 | |
|             loading: _ctx.loading,
 | |
|             rows: _ctx.expandLimit
 | |
|           }, null, 8, ["loading", "rows"])
 | |
|         ], 2)) : createCommentVNode("", true),
 | |
|         !_ctx.loading ? (openBlock(), createElementBlock("ul", {
 | |
|           key: 1,
 | |
|           class: normalizeClass(_ctx.$style.categories)
 | |
|         }, [
 | |
|           createBaseVNode("li", {
 | |
|             class: normalizeClass(_ctx.$style.item),
 | |
|             "data-test-id": "template-filter-all-categories"
 | |
|           }, [
 | |
|             createVNode(_component_el_checkbox, {
 | |
|               "model-value": allSelected.value,
 | |
|               "onUpdate:modelValue": _cache[0] || (_cache[0] = () => resetCategories())
 | |
|             }, {
 | |
|               default: withCtx(() => [
 | |
|                 createTextVNode(toDisplayString(unref(i18n).baseText("templates.allCategories")), 1)
 | |
|               ]),
 | |
|               _: 1
 | |
|             }, 8, ["model-value"])
 | |
|           ], 2),
 | |
|           (openBlock(true), createElementBlock(Fragment, null, renderList(collapsed.value ? sortedCategories.value.slice(0, _ctx.expandLimit) : sortedCategories.value, (category, index) => {
 | |
|             return openBlock(), createElementBlock("li", {
 | |
|               key: index,
 | |
|               class: normalizeClass(_ctx.$style.item),
 | |
|               "data-test-id": `template-filter-${category.name.toLowerCase().replaceAll(" ", "-")}`
 | |
|             }, [
 | |
|               createVNode(_component_el_checkbox, {
 | |
|                 "model-value": isSelected(category),
 | |
|                 "onUpdate:modelValue": (value) => handleCheckboxChanged(value, category)
 | |
|               }, {
 | |
|                 default: withCtx(() => [
 | |
|                   createTextVNode(toDisplayString(category.name), 1)
 | |
|                 ]),
 | |
|                 _: 2
 | |
|               }, 1032, ["model-value", "onUpdate:modelValue"])
 | |
|             ], 10, _hoisted_2);
 | |
|           }), 128))
 | |
|         ], 2)) : createCommentVNode("", true),
 | |
|         sortedCategories.value.length > _ctx.expandLimit && collapsed.value && !_ctx.loading ? (openBlock(), createElementBlock("div", {
 | |
|           key: 2,
 | |
|           class: normalizeClass(_ctx.$style.button),
 | |
|           "data-test-id": "expand-categories-button",
 | |
|           onClick: collapseAction
 | |
|         }, [
 | |
|           createVNode(_component_n8n_text, {
 | |
|             size: "small",
 | |
|             color: "primary"
 | |
|           }, {
 | |
|             default: withCtx(() => [
 | |
|               createTextVNode(" + " + toDisplayString(`${sortedCategories.value.length - _ctx.expandLimit} more`), 1)
 | |
|             ]),
 | |
|             _: 1
 | |
|           })
 | |
|         ], 2)) : createCommentVNode("", true)
 | |
|       ], 2);
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const title = "_title_gndmi_123";
 | |
| const categories = "_categories_gndmi_128";
 | |
| const item = "_item_gndmi_133";
 | |
| const button = "_button_gndmi_140";
 | |
| const style0$1 = {
 | |
|   title,
 | |
|   categories,
 | |
|   item,
 | |
|   button
 | |
| };
 | |
| const cssModules$1 = {
 | |
|   "$style": style0$1
 | |
| };
 | |
| const TemplateFilters = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__cssModules", cssModules$1]]);
 | |
| const _hoisted_1 = ["textContent"];
 | |
| const _sfc_main = /* @__PURE__ */ defineComponent({
 | |
|   __name: "TemplatesSearchView",
 | |
|   setup(__props) {
 | |
|     const areCategoriesPrepopulated = ref(false);
 | |
|     const categories2 = ref([]);
 | |
|     const loadingCategories = ref(true);
 | |
|     const loadingCollections = ref(true);
 | |
|     const loadingWorkflows = ref(true);
 | |
|     const search2 = ref("");
 | |
|     const searchEventToTrack = ref(null);
 | |
|     const errorLoadingWorkflows = ref(false);
 | |
|     const { callDebounced } = useDebounce();
 | |
|     const toast = useToast();
 | |
|     const documentTitle = useDocumentTitle();
 | |
|     const settingsStore = useSettingsStore();
 | |
|     const templatesStore = useTemplatesStore();
 | |
|     const usersStore = useUsersStore();
 | |
|     const i18n = useI18n();
 | |
|     const route = useRoute();
 | |
|     const router = useRouter();
 | |
|     const telemetry = useTelemetry();
 | |
|     const createQueryObject = (categoryId) => {
 | |
|       return {
 | |
|         categories: categories2.value.map(
 | |
|           (category) => categoryId === "name" ? category.name : String(category.id)
 | |
|         ),
 | |
|         search: search2.value
 | |
|       };
 | |
|     };
 | |
|     const totalWorkflows = computed(
 | |
|       () => templatesStore.getSearchedWorkflowsTotal(createQueryObject("name"))
 | |
|     );
 | |
|     const workflows = computed(
 | |
|       () => templatesStore.getSearchedWorkflows(createQueryObject("name")) ?? []
 | |
|     );
 | |
|     const collections = computed(
 | |
|       () => templatesStore.getSearchedCollections(createQueryObject("id")) ?? []
 | |
|     );
 | |
|     const endOfSearchMessage = computed(() => {
 | |
|       if (loadingWorkflows.value) {
 | |
|         return null;
 | |
|       }
 | |
|       if (!loadingCollections.value && workflows.value.length === 0 && collections.value.length === 0) {
 | |
|         if (!settingsStore.isTemplatesEndpointReachable && errorLoadingWorkflows.value) {
 | |
|           return i18n.baseText("templates.connectionWarning");
 | |
|         }
 | |
|         return i18n.baseText("templates.noSearchResults");
 | |
|       }
 | |
|       return null;
 | |
|     });
 | |
|     const updateQueryParam = (search22, category) => {
 | |
|       const query = Object.assign({}, route.query);
 | |
|       if (category.length) {
 | |
|         query.categories = category;
 | |
|       } else {
 | |
|         delete query.categories;
 | |
|       }
 | |
|       if (search22.length) {
 | |
|         query.search = search22;
 | |
|       } else {
 | |
|         delete query.search;
 | |
|       }
 | |
|       void router.replace({ query });
 | |
|     };
 | |
|     const updateSearch = () => {
 | |
|       updateQueryParam(search2.value, categories2.value.map((category) => category.id).join(","));
 | |
|       void loadWorkflowsAndCollections(false);
 | |
|     };
 | |
|     const loadWorkflows = async () => {
 | |
|       try {
 | |
|         loadingWorkflows.value = true;
 | |
|         await templatesStore.getWorkflows({
 | |
|           search: search2.value,
 | |
|           categories: categories2.value.map((category) => category.name)
 | |
|         });
 | |
|         errorLoadingWorkflows.value = false;
 | |
|       } catch (e) {
 | |
|         errorLoadingWorkflows.value = true;
 | |
|       }
 | |
|       loadingWorkflows.value = false;
 | |
|     };
 | |
|     const loadCollections = async () => {
 | |
|       try {
 | |
|         loadingCollections.value = true;
 | |
|         await templatesStore.getCollections({
 | |
|           categories: categories2.value.map((category) => String(category.id)),
 | |
|           search: search2.value
 | |
|         });
 | |
|       } catch (e) {
 | |
|       }
 | |
|       loadingCollections.value = false;
 | |
|     };
 | |
|     const updateSearchTracking = (search22, categories22) => {
 | |
|       if (!search22) {
 | |
|         return;
 | |
|       }
 | |
|       if (searchEventToTrack.value && searchEventToTrack.value.search_string.length > search22.length) {
 | |
|         return;
 | |
|       }
 | |
|       searchEventToTrack.value = {
 | |
|         search_string: search22,
 | |
|         workflow_results_count: workflows.value.length,
 | |
|         collection_results_count: collections.value.length,
 | |
|         categories_applied: categories22.map(
 | |
|           (categoryId) => templatesStore.getCategoryById(categoryId.toString())
 | |
|         ),
 | |
|         wf_template_repo_session_id: templatesStore.currentSessionId
 | |
|       };
 | |
|     };
 | |
|     const trackCategories = () => {
 | |
|       if (categories2.value.length) {
 | |
|         telemetry.track("User changed template filters", {
 | |
|           search_string: search2.value,
 | |
|           categories_applied: categories2.value,
 | |
|           wf_template_repo_session_id: templatesStore.currentSessionId
 | |
|         });
 | |
|       }
 | |
|     };
 | |
|     const loadWorkflowsAndCollections = async (initialLoad) => {
 | |
|       const _categories = [...categories2.value];
 | |
|       const _search = search2.value;
 | |
|       await Promise.all([loadWorkflows(), loadCollections()]);
 | |
|       if (!initialLoad) {
 | |
|         updateSearchTracking(
 | |
|           _search,
 | |
|           _categories.map((category) => category.id)
 | |
|         );
 | |
|       }
 | |
|     };
 | |
|     const navigateTo = (e, page, id) => {
 | |
|       if (e.metaKey || e.ctrlKey) {
 | |
|         const route2 = router.resolve({ name: page, params: { id } });
 | |
|         window.open(route2.href, "_blank");
 | |
|         return;
 | |
|       } else {
 | |
|         void router.push({ name: page, params: { id } });
 | |
|       }
 | |
|     };
 | |
|     const onOpenCollection = ({ event, id }) => {
 | |
|       navigateTo(event, VIEWS.COLLECTION, id);
 | |
|     };
 | |
|     const onOpenTemplate = ({ event, id }) => {
 | |
|       navigateTo(event, VIEWS.TEMPLATE, id);
 | |
|     };
 | |
|     const trackSearch = () => {
 | |
|       if (searchEventToTrack.value) {
 | |
|         telemetry.track(
 | |
|           "User searched workflow templates",
 | |
|           searchEventToTrack.value
 | |
|         );
 | |
|         searchEventToTrack.value = null;
 | |
|       }
 | |
|     };
 | |
|     const onSearchInput = (searchText) => {
 | |
|       loadingWorkflows.value = true;
 | |
|       loadingCollections.value = true;
 | |
|       search2.value = searchText;
 | |
|       void callDebounced(updateSearch, {
 | |
|         debounceTime: 500,
 | |
|         trailing: true
 | |
|       });
 | |
|       if (searchText.length === 0) {
 | |
|         trackSearch();
 | |
|       }
 | |
|     };
 | |
|     const onCategorySelected = (selected) => {
 | |
|       categories2.value = categories2.value.concat(selected);
 | |
|       updateSearch();
 | |
|       trackCategories();
 | |
|     };
 | |
|     const onCategoryUnselected = (selected) => {
 | |
|       categories2.value = categories2.value.filter((category) => category.id !== selected.id);
 | |
|       updateSearch();
 | |
|       trackCategories();
 | |
|     };
 | |
|     const onCategoriesCleared = () => {
 | |
|       categories2.value = [];
 | |
|       updateSearch();
 | |
|     };
 | |
|     const onLoadMore = async () => {
 | |
|       if (workflows.value.length >= totalWorkflows.value) {
 | |
|         return;
 | |
|       }
 | |
|       try {
 | |
|         loadingWorkflows.value = true;
 | |
|         await templatesStore.getMoreWorkflows({
 | |
|           categories: categories2.value.map((category) => category.name),
 | |
|           search: search2.value
 | |
|         });
 | |
|       } catch (e) {
 | |
|         toast.showMessage({
 | |
|           title: "Error",
 | |
|           message: "Could not load more workflows",
 | |
|           type: "error"
 | |
|         });
 | |
|       } finally {
 | |
|         loadingWorkflows.value = false;
 | |
|       }
 | |
|     };
 | |
|     const loadCategories = async () => {
 | |
|       try {
 | |
|         await templatesStore.getCategories();
 | |
|       } catch (e) {
 | |
|       }
 | |
|       loadingCategories.value = false;
 | |
|     };
 | |
|     const scrollTo = (position, behavior = "smooth") => {
 | |
|       setTimeout(() => {
 | |
|         const contentArea = document.getElementById("content");
 | |
|         if (contentArea) {
 | |
|           contentArea.scrollTo({
 | |
|             top: position,
 | |
|             behavior
 | |
|           });
 | |
|         }
 | |
|       }, 0);
 | |
|     };
 | |
|     const restoreSearchFromRoute = () => {
 | |
|       let shouldUpdateSearch = false;
 | |
|       if (route.query.search && typeof route.query.search === "string") {
 | |
|         search2.value = route.query.search;
 | |
|         shouldUpdateSearch = true;
 | |
|       }
 | |
|       if (typeof route.query.categories === "string" && route.query.categories.length) {
 | |
|         const categoriesFromURL = route.query.categories.split(",");
 | |
|         categories2.value = templatesStore.allCategories.filter(
 | |
|           (category) => categoriesFromURL.includes(category.id.toString())
 | |
|         );
 | |
|         shouldUpdateSearch = true;
 | |
|       }
 | |
|       if (shouldUpdateSearch) {
 | |
|         updateSearch();
 | |
|         trackCategories();
 | |
|         areCategoriesPrepopulated.value = true;
 | |
|       }
 | |
|     };
 | |
|     onMounted(async () => {
 | |
|       documentTitle.set("Templates");
 | |
|       await loadCategories();
 | |
|       void loadWorkflowsAndCollections(true);
 | |
|       void usersStore.showPersonalizationSurvey();
 | |
|       restoreSearchFromRoute();
 | |
|       if (settingsStore.isTemplatesEnabled) {
 | |
|         settingsStore.testTemplatesEndpoint().catch(() => {
 | |
|         });
 | |
|       }
 | |
|       setTimeout(() => {
 | |
|         const scrollOffset = route.meta?.scrollOffset;
 | |
|         if (typeof scrollOffset === "number" && scrollOffset > 0) {
 | |
|           scrollTo(scrollOffset, "auto");
 | |
|         }
 | |
|       }, 100);
 | |
|     });
 | |
|     onBeforeRouteLeave((_to, _from, next) => {
 | |
|       const contentArea = document.getElementById("content");
 | |
|       if (contentArea) {
 | |
|         route.meta?.setScrollPosition?.(contentArea.scrollTop);
 | |
|       }
 | |
|       trackSearch();
 | |
|       next();
 | |
|     });
 | |
|     watch(workflows, (newWorkflows) => {
 | |
|       if (newWorkflows.length === 0) {
 | |
|         window.scrollTo(0, 0);
 | |
|       }
 | |
|     });
 | |
|     return (_ctx, _cache) => {
 | |
|       const _component_n8n_heading = N8nHeading;
 | |
|       const _component_n8n_button = N8nButton;
 | |
|       const _component_n8n_icon = N8nIcon;
 | |
|       const _component_n8n_input = N8nInput;
 | |
|       const _component_n8n_text = N8nText;
 | |
|       const _directive_n8n_html = resolveDirective("n8n-html");
 | |
|       return openBlock(), createBlock(TemplatesView, null, {
 | |
|         header: withCtx(() => [
 | |
|           createBaseVNode("div", {
 | |
|             class: normalizeClass(_ctx.$style.wrapper)
 | |
|           }, [
 | |
|             createBaseVNode("div", {
 | |
|               class: normalizeClass(_ctx.$style.title)
 | |
|             }, [
 | |
|               createVNode(_component_n8n_heading, {
 | |
|                 tag: "h1",
 | |
|                 size: "2xlarge"
 | |
|               }, {
 | |
|                 default: withCtx(() => [
 | |
|                   createTextVNode(toDisplayString(unref(i18n).baseText("templates.heading")), 1)
 | |
|                 ]),
 | |
|                 _: 1
 | |
|               })
 | |
|             ], 2),
 | |
|             createBaseVNode("div", {
 | |
|               class: normalizeClass(_ctx.$style.button)
 | |
|             }, [
 | |
|               createVNode(_component_n8n_button, {
 | |
|                 size: "large",
 | |
|                 type: "secondary",
 | |
|                 element: "a",
 | |
|                 href: unref(CREATOR_HUB_URL),
 | |
|                 label: unref(i18n).baseText("templates.shareWorkflow"),
 | |
|                 target: "_blank"
 | |
|               }, null, 8, ["href", "label"])
 | |
|             ], 2)
 | |
|           ], 2)
 | |
|         ]),
 | |
|         content: withCtx(() => [
 | |
|           createBaseVNode("div", {
 | |
|             class: normalizeClass(_ctx.$style.contentWrapper)
 | |
|           }, [
 | |
|             createBaseVNode("div", {
 | |
|               class: normalizeClass(_ctx.$style.filters)
 | |
|             }, [
 | |
|               createVNode(TemplateFilters, {
 | |
|                 categories: unref(templatesStore).allCategories,
 | |
|                 "sort-on-populate": areCategoriesPrepopulated.value,
 | |
|                 selected: categories2.value,
 | |
|                 loading: loadingCategories.value,
 | |
|                 onClear: onCategoryUnselected,
 | |
|                 onClearAll: onCategoriesCleared,
 | |
|                 onSelect: onCategorySelected
 | |
|               }, null, 8, ["categories", "sort-on-populate", "selected", "loading"])
 | |
|             ], 2),
 | |
|             createBaseVNode("div", {
 | |
|               class: normalizeClass(_ctx.$style.search)
 | |
|             }, [
 | |
|               createVNode(_component_n8n_input, {
 | |
|                 "model-value": search2.value,
 | |
|                 placeholder: unref(i18n).baseText("templates.searchPlaceholder"),
 | |
|                 clearable: "",
 | |
|                 "data-test-id": "template-search-input",
 | |
|                 "onUpdate:modelValue": onSearchInput,
 | |
|                 onBlur: trackSearch
 | |
|               }, {
 | |
|                 prefix: withCtx(() => [
 | |
|                   createVNode(_component_n8n_icon, { icon: "search" })
 | |
|                 ]),
 | |
|                 _: 1
 | |
|               }, 8, ["model-value", "placeholder"]),
 | |
|               withDirectives(createBaseVNode("div", {
 | |
|                 class: normalizeClass(_ctx.$style.carouselContainer)
 | |
|               }, [
 | |
|                 createBaseVNode("div", {
 | |
|                   class: normalizeClass(_ctx.$style.header)
 | |
|                 }, [
 | |
|                   createVNode(_component_n8n_heading, {
 | |
|                     bold: true,
 | |
|                     size: "medium",
 | |
|                     color: "text-light"
 | |
|                   }, {
 | |
|                     default: withCtx(() => [
 | |
|                       createTextVNode(toDisplayString(unref(i18n).baseText("templates.collections")) + " ", 1),
 | |
|                       !loadingCollections.value ? (openBlock(), createElementBlock("span", {
 | |
|                         key: 0,
 | |
|                         "data-test-id": "collection-count-label",
 | |
|                         textContent: toDisplayString(`(${collections.value.length})`)
 | |
|                       }, null, 8, _hoisted_1)) : createCommentVNode("", true)
 | |
|                     ]),
 | |
|                     _: 1
 | |
|                   })
 | |
|                 ], 2),
 | |
|                 createVNode(TemplatesInfoCarousel, {
 | |
|                   collections: collections.value,
 | |
|                   loading: loadingCollections.value,
 | |
|                   onOpenCollection
 | |
|                 }, null, 8, ["collections", "loading"])
 | |
|               ], 2), [
 | |
|                 [vShow, collections.value.length || loadingCollections.value]
 | |
|               ]),
 | |
|               createVNode(TemplateList, {
 | |
|                 "infinite-scroll-enabled": true,
 | |
|                 loading: loadingWorkflows.value,
 | |
|                 workflows: workflows.value,
 | |
|                 "total-count": totalWorkflows.value,
 | |
|                 onLoadMore,
 | |
|                 onOpenTemplate
 | |
|               }, null, 8, ["loading", "workflows", "total-count"]),
 | |
|               endOfSearchMessage.value ? (openBlock(), createElementBlock("div", {
 | |
|                 key: 0,
 | |
|                 class: normalizeClass(_ctx.$style.endText)
 | |
|               }, [
 | |
|                 createVNode(_component_n8n_text, {
 | |
|                   size: "medium",
 | |
|                   color: "text-base"
 | |
|                 }, {
 | |
|                   default: withCtx(() => [
 | |
|                     withDirectives(createBaseVNode("span", null, null, 512), [
 | |
|                       [_directive_n8n_html, endOfSearchMessage.value]
 | |
|                     ])
 | |
|                   ]),
 | |
|                   _: 1
 | |
|                 })
 | |
|               ], 2)) : createCommentVNode("", true)
 | |
|             ], 2)
 | |
|           ], 2)
 | |
|         ]),
 | |
|         _: 1
 | |
|       });
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const wrapper = "_wrapper_15fkc_123";
 | |
| const contentWrapper = "_contentWrapper_15fkc_128";
 | |
| const filters = "_filters_15fkc_138";
 | |
| const search = "_search_15fkc_144";
 | |
| const header = "_header_15fkc_156";
 | |
| const style0 = {
 | |
|   wrapper,
 | |
|   contentWrapper,
 | |
|   filters,
 | |
|   search,
 | |
|   header
 | |
| };
 | |
| const cssModules = {
 | |
|   "$style": style0
 | |
| };
 | |
| const TemplatesSearchView = /* @__PURE__ */ _export_sfc(_sfc_main, [["__cssModules", cssModules]]);
 | |
| export {
 | |
|   TemplatesSearchView as default
 | |
| };
 |