3172 lines
		
	
	
		
			126 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			3172 lines
		
	
	
		
			126 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
| import { d as defineComponent, a2 as useRoute, b as useRouter, av as useFoldersStore, r as ref, x as computed, c as useI18n, aF as ProjectTypes, V as VIEWS, a8 as resolveComponent, h as createElementBlock, g as openBlock, i as createVNode, w as withCtx, s as N8nCard, n as normalizeClass, j as createBaseVNode, f as createCommentVNode, e as createBlock, fY as ProjectCardBadge, l as unref, aS as ResourceType, e6 as N8nActionToggle, B as withModifiers, p as N8nText, k as createTextVNode, t as toDisplayString, eD as _sfc_main$7, m as N8nHeading, aK as N8nBadge, N as N8nIcon, _ as _export_sfc, a as useToast, v as useSettingsStore, Q as useUIStore, u as useUsersStore, a1 as useWorkflowsStore, au as useProjectsStore, aB as getResourcePermissions, fQ as dateFormat, b2 as withDirectives, b3 as vShow, aN as WORKFLOW_SHARE_MODAL_KEY, al as useTelemetry, aR as DUPLICATE_MODAL_KEY, am as useMessage, an as MODAL_CONFIRM, aT as PROJECT_MOVE_RESOURCE_MODAL, fZ as FOLDER_NAME_ILLEGAL_CHARACTERS_REGEX, f_ as ILLEGAL_FOLDER_CHARACTERS, f$ as FOLDER_NAME_ONLY_DOTS_REGEX, g0 as FOLDER_NAME_MAX_LENGTH, $ as defineStore, d7 as usePostHog, bb as useCloudPlanStore, bk as useTemplatesStore, bc as useStorage, g1 as LOCAL_STORAGE_EXPERIMENTAL_DISMISSED_SUGGESTED_WORKFLOWS, de as jsonParse, a7 as watch, fh as TEMPLATE_ONBOARDING_EXPERIMENT, a4 as STORES, z as N8nCallout, C as N8nLink, X as renderSlot, ad as useNodeTypesStore, bl as usePersonalizedTemplatesV2Store, o as onMounted, bW as NodeIcon, bu as EXPERIMENT_TEMPLATE_RECO_V2_KEY, F as Fragment, A as renderList, af as useSourceControlStore, ar as useTagsStore, eU as useUsageStore, g2 as useInsightsStore, ax as useDocumentTitle, P as useDebounce, aE as EnterpriseEditionFeature, g3 as isExtraTemplateLinksExperimentEnabled, aq as createEventBus, W as onBeforeUnmount, ao as debounce, g4 as PROJECT_ROOT, aG as useTemplateRef, bq as createSlots, a9 as Tooltip, q as N8nButton, cK as InfoTip, dR as N8nActionBox, d_ as N8nInputLabel, aJ as _sfc_main$9, e1 as N8nSelect, e2 as _sfc_main$a, eS as N8nCheckbox, g5 as Draggable, dD as N8nLoading, aH as InlineRename, g6 as DEFAULT_WORKFLOW_PAGE_SIZE, bv as trackTemplatesClick, bw as TemplateClickSource, g7 as getEasyAiWorkflowJson, eW as COMMUNITY_PLUS_ENROLLMENT_MODAL } from "./index-CeNA_ukL.js";
 | |
| import { _ as _sfc_main$8 } from "./EmptySharedSectionActionBox.vue_vue_type_script_setup_true_lang-CHWBnByP.js";
 | |
| import { B as Breadcrumbs } from "./ProjectBreadcrumb-CcYMzyYS.js";
 | |
| import { W as WorkflowActivator, _ as __unplugin_components_0 } from "./WorkflowActivator-BxX80zGr.js";
 | |
| import { R as ResourcesListLayout } from "./ResourcesListLayout-CHxMfd0o.js";
 | |
| import { P as ProjectHeader } from "./ProjectHeader-BGjOBBZs.js";
 | |
| import { T as Tags } from "./Tags-DxSdhB5Q.js";
 | |
| import { u as useProjectPages } from "./useProjectPages-xv6Eq2Y5.js";
 | |
| import { u as useAITemplatesStarterCollectionStore, a as useReadyToRunWorkflowsStore } from "./readyToRunWorkflows.store-DGBtTmGX.js";
 | |
| import { I as InsightsSummary } from "./InsightsSummary-Bypgyn1_.js";
 | |
| import "./useWorkflowActivate-CuNKq-WZ.js";
 | |
| import "./TableBase-DmNxoh-V.js";
 | |
| import "./Tag-ZyDcgFEj.js";
 | |
| const FOLDER_LIST_ITEM_ACTIONS = {
 | |
|   OPEN: "open",
 | |
|   CREATE: "create",
 | |
|   CREATE_WORKFLOW: "create_workflow",
 | |
|   RENAME: "rename",
 | |
|   MOVE: "move",
 | |
|   DELETE: "delete"
 | |
| };
 | |
| const _hoisted_1$3 = { "data-test-id": "folder-card" };
 | |
| const _hoisted_2$1 = { key: 0 };
 | |
| const _sfc_main$6 = /* @__PURE__ */ defineComponent({
 | |
|   __name: "FolderCard",
 | |
|   props: {
 | |
|     data: {},
 | |
|     personalProject: {},
 | |
|     actions: { default: () => [] },
 | |
|     readOnly: { type: Boolean, default: true },
 | |
|     showOwnershipBadge: { type: Boolean, default: false }
 | |
|   },
 | |
|   emits: ["action", "folderOpened"],
 | |
|   setup(__props, { emit: __emit }) {
 | |
|     const props = __props;
 | |
|     const i18n = useI18n();
 | |
|     const route = useRoute();
 | |
|     const router = useRouter();
 | |
|     const foldersStore = useFoldersStore();
 | |
|     const emit = __emit;
 | |
|     const hiddenBreadcrumbsItemsAsync = ref(new Promise(() => {
 | |
|     }));
 | |
|     const cachedHiddenBreadcrumbsItems = ref([]);
 | |
|     const resourceTypeLabel = computed(() => i18n.baseText("generic.folder").toLowerCase());
 | |
|     const cardUrl = computed(() => {
 | |
|       return getFolderUrl(props.data.id);
 | |
|     });
 | |
|     const projectName = computed(() => {
 | |
|       if (props.data.homeProject?.type === ProjectTypes.Personal) {
 | |
|         return i18n.baseText("projects.menu.personal");
 | |
|       }
 | |
|       return props.data.homeProject?.name;
 | |
|     });
 | |
|     const cardBreadcrumbs = computed(() => {
 | |
|       if (props.data.parentFolder) {
 | |
|         return [
 | |
|           {
 | |
|             id: props.data.parentFolder.id,
 | |
|             name: props.data.parentFolder.name,
 | |
|             label: props.data.parentFolder.name,
 | |
|             href: router.resolve({
 | |
|               name: VIEWS.PROJECTS_FOLDERS,
 | |
|               params: {
 | |
|                 projectId: props.data.homeProject?.id,
 | |
|                 folderId: props.data.parentFolder.id
 | |
|               }
 | |
|             }).href
 | |
|           }
 | |
|         ];
 | |
|       }
 | |
|       return [];
 | |
|     });
 | |
|     const showCardBreadcrumbs = computed(() => {
 | |
|       return props.showOwnershipBadge && cardBreadcrumbs.value.length;
 | |
|     });
 | |
|     const getFolderUrl = (folderId) => {
 | |
|       return router.resolve({
 | |
|         name: VIEWS.PROJECTS_FOLDERS,
 | |
|         params: {
 | |
|           projectId: route.params.projectId,
 | |
|           folderId
 | |
|         },
 | |
|         query: route.query
 | |
|       }).href;
 | |
|     };
 | |
|     const onAction = async (action) => {
 | |
|       if (action === FOLDER_LIST_ITEM_ACTIONS.OPEN) {
 | |
|         emit("folderOpened", { folder: props.data });
 | |
|         await router.push(cardUrl.value);
 | |
|         return;
 | |
|       }
 | |
|       emit("action", { action, folderId: props.data.id });
 | |
|     };
 | |
|     const fetchHiddenBreadCrumbsItems = async () => {
 | |
|       if (!props.data.homeProject?.id || !projectName.value || !props.data.parentFolder) {
 | |
|         hiddenBreadcrumbsItemsAsync.value = Promise.resolve([]);
 | |
|       } else {
 | |
|         if (cachedHiddenBreadcrumbsItems.value.length) {
 | |
|           hiddenBreadcrumbsItemsAsync.value = Promise.resolve(cachedHiddenBreadcrumbsItems.value);
 | |
|           return;
 | |
|         }
 | |
|         const loadedItem = foldersStore.getHiddenBreadcrumbsItems(
 | |
|           { id: props.data.homeProject.id, name: projectName.value },
 | |
|           props.data.parentFolder.id
 | |
|         );
 | |
|         hiddenBreadcrumbsItemsAsync.value = loadedItem;
 | |
|         cachedHiddenBreadcrumbsItems.value = await loadedItem;
 | |
|       }
 | |
|     };
 | |
|     const onBreadcrumbItemClick = async (item) => {
 | |
|       if (item.href) {
 | |
|         await router.push(item.href);
 | |
|       }
 | |
|     };
 | |
|     return (_ctx, _cache) => {
 | |
|       const _component_n8n_icon = N8nIcon;
 | |
|       const _component_n8n_heading = N8nHeading;
 | |
|       const _component_N8nBadge = N8nBadge;
 | |
|       const _component_n8n_text = N8nText;
 | |
|       const _component_TimeAgo = _sfc_main$7;
 | |
|       const _component_n8n_breadcrumbs = Breadcrumbs;
 | |
|       const _component_ProjectCardBadge = ProjectCardBadge;
 | |
|       const _component_n8n_action_toggle = N8nActionToggle;
 | |
|       const _component_n8n_card = N8nCard;
 | |
|       const _component_router_link = resolveComponent("router-link");
 | |
|       return openBlock(), createElementBlock("div", _hoisted_1$3, [
 | |
|         createVNode(_component_router_link, {
 | |
|           to: cardUrl.value,
 | |
|           onClick: _cache[1] || (_cache[1] = () => emit("folderOpened", { folder: props.data }))
 | |
|         }, {
 | |
|           default: withCtx(() => [
 | |
|             createVNode(_component_n8n_card, {
 | |
|               class: normalizeClass(_ctx.$style.card)
 | |
|             }, {
 | |
|               prepend: withCtx(() => [
 | |
|                 createVNode(_component_n8n_icon, {
 | |
|                   "data-test-id": "folder-card-icon",
 | |
|                   class: normalizeClass(_ctx.$style["folder-icon"]),
 | |
|                   icon: "folder",
 | |
|                   size: "xlarge",
 | |
|                   "stroke-width": 1
 | |
|                 }, null, 8, ["class"])
 | |
|               ]),
 | |
|               header: withCtx(() => [
 | |
|                 createBaseVNode("div", {
 | |
|                   class: normalizeClass(_ctx.$style["card-header"])
 | |
|                 }, [
 | |
|                   createVNode(_component_n8n_heading, {
 | |
|                     tag: "h2",
 | |
|                     bold: "",
 | |
|                     size: "small",
 | |
|                     "data-test-id": "folder-card-name"
 | |
|                   }, {
 | |
|                     default: withCtx(() => [
 | |
|                       createTextVNode(toDisplayString(_ctx.data.name), 1)
 | |
|                     ]),
 | |
|                     _: 1
 | |
|                   }),
 | |
|                   _ctx.readOnly ? (openBlock(), createBlock(_component_N8nBadge, {
 | |
|                     key: 0,
 | |
|                     class: "ml-3xs",
 | |
|                     theme: "tertiary",
 | |
|                     bold: ""
 | |
|                   }, {
 | |
|                     default: withCtx(() => [
 | |
|                       createTextVNode(toDisplayString(unref(i18n).baseText("workflows.item.readonly")), 1)
 | |
|                     ]),
 | |
|                     _: 1
 | |
|                   })) : createCommentVNode("", true)
 | |
|                 ], 2)
 | |
|               ]),
 | |
|               footer: withCtx(() => [
 | |
|                 createBaseVNode("div", {
 | |
|                   class: normalizeClass(_ctx.$style["card-footer"])
 | |
|                 }, [
 | |
|                   _ctx.data.workflowCount > 0 ? (openBlock(), createBlock(_component_n8n_text, {
 | |
|                     key: 0,
 | |
|                     size: "small",
 | |
|                     color: "text-light",
 | |
|                     class: normalizeClass([_ctx.$style["info-cell"], _ctx.$style["info-cell--workflow-count"]]),
 | |
|                     "data-test-id": "folder-card-folder-count"
 | |
|                   }, {
 | |
|                     default: withCtx(() => [
 | |
|                       createTextVNode(toDisplayString(unref(i18n).baseText("generic.workflow", { interpolate: { count: _ctx.data.workflowCount } })), 1)
 | |
|                     ]),
 | |
|                     _: 1
 | |
|                   }, 8, ["class"])) : createCommentVNode("", true),
 | |
|                   _ctx.data.subFolderCount > 0 ? (openBlock(), createBlock(_component_n8n_text, {
 | |
|                     key: 1,
 | |
|                     size: "small",
 | |
|                     color: "text-light",
 | |
|                     class: normalizeClass([_ctx.$style["info-cell"], _ctx.$style["info-cell--workflow-count"]]),
 | |
|                     "data-test-id": "folder-card-workflow-count"
 | |
|                   }, {
 | |
|                     default: withCtx(() => [
 | |
|                       createTextVNode(toDisplayString(unref(i18n).baseText("generic.folderCount", {
 | |
|                         interpolate: { count: _ctx.data.subFolderCount }
 | |
|                       })), 1)
 | |
|                     ]),
 | |
|                     _: 1
 | |
|                   }, 8, ["class"])) : createCommentVNode("", true),
 | |
|                   createVNode(_component_n8n_text, {
 | |
|                     size: "small",
 | |
|                     color: "text-light",
 | |
|                     class: normalizeClass([_ctx.$style["info-cell"], _ctx.$style["info-cell--updated"]]),
 | |
|                     "data-test-id": "folder-card-last-updated"
 | |
|                   }, {
 | |
|                     default: withCtx(() => [
 | |
|                       createTextVNode(toDisplayString(unref(i18n).baseText("workerList.item.lastUpdated")) + " ", 1),
 | |
|                       createVNode(_component_TimeAgo, {
 | |
|                         date: String(_ctx.data.updatedAt)
 | |
|                       }, null, 8, ["date"])
 | |
|                     ]),
 | |
|                     _: 1
 | |
|                   }, 8, ["class"]),
 | |
|                   createVNode(_component_n8n_text, {
 | |
|                     size: "small",
 | |
|                     color: "text-light",
 | |
|                     class: normalizeClass([_ctx.$style["info-cell"], _ctx.$style["info-cell--created"]]),
 | |
|                     "data-test-id": "folder-card-created"
 | |
|                   }, {
 | |
|                     default: withCtx(() => [
 | |
|                       createTextVNode(toDisplayString(unref(i18n).baseText("workflows.item.created")) + " ", 1),
 | |
|                       createVNode(_component_TimeAgo, {
 | |
|                         date: String(_ctx.data.createdAt)
 | |
|                       }, null, 8, ["date"])
 | |
|                     ]),
 | |
|                     _: 1
 | |
|                   }, 8, ["class"])
 | |
|                 ], 2)
 | |
|               ]),
 | |
|               append: withCtx(() => [
 | |
|                 createBaseVNode("div", {
 | |
|                   class: normalizeClass(_ctx.$style["card-actions"]),
 | |
|                   onClick: _cache[0] || (_cache[0] = withModifiers(() => {
 | |
|                   }, ["prevent"]))
 | |
|                 }, [
 | |
|                   _ctx.data.homeProject && _ctx.showOwnershipBadge ? (openBlock(), createElementBlock("div", _hoisted_2$1, [
 | |
|                     createVNode(_component_ProjectCardBadge, {
 | |
|                       class: normalizeClass({
 | |
|                         [_ctx.$style.cardBadge]: true,
 | |
|                         [_ctx.$style["with-breadcrumbs"]]: showCardBreadcrumbs.value
 | |
|                       }),
 | |
|                       resource: _ctx.data,
 | |
|                       "resource-type": unref(ResourceType).Workflow,
 | |
|                       "resource-type-label": resourceTypeLabel.value,
 | |
|                       "personal-project": _ctx.personalProject,
 | |
|                       "show-badge-border": false
 | |
|                     }, {
 | |
|                       default: withCtx(() => [
 | |
|                         showCardBreadcrumbs.value ? (openBlock(), createElementBlock("div", {
 | |
|                           key: 0,
 | |
|                           class: normalizeClass(_ctx.$style.breadcrumbs)
 | |
|                         }, [
 | |
|                           createVNode(_component_n8n_breadcrumbs, {
 | |
|                             items: cardBreadcrumbs.value,
 | |
|                             "hidden-items": _ctx.data.parentFolder?.parentFolderId !== null ? hiddenBreadcrumbsItemsAsync.value : void 0,
 | |
|                             "path-truncated": _ctx.data.parentFolder?.parentFolderId !== null,
 | |
|                             "highlight-last-item": false,
 | |
|                             "hidden-items-trigger": "hover",
 | |
|                             theme: "small",
 | |
|                             "data-test-id": "folder-card-breadcrumbs",
 | |
|                             onTooltipOpened: fetchHiddenBreadCrumbsItems,
 | |
|                             onItemSelected: onBreadcrumbItemClick
 | |
|                           }, {
 | |
|                             prepend: withCtx(() => _cache[2] || (_cache[2] = [])),
 | |
|                             _: 1
 | |
|                           }, 8, ["items", "hidden-items", "path-truncated"])
 | |
|                         ], 2)) : createCommentVNode("", true)
 | |
|                       ]),
 | |
|                       _: 1
 | |
|                     }, 8, ["class", "resource", "resource-type", "resource-type-label", "personal-project"])
 | |
|                   ])) : createCommentVNode("", true),
 | |
|                   _ctx.actions.length ? (openBlock(), createBlock(_component_n8n_action_toggle, {
 | |
|                     key: 1,
 | |
|                     actions: _ctx.actions,
 | |
|                     theme: "dark",
 | |
|                     "data-test-id": "folder-card-actions",
 | |
|                     onAction
 | |
|                   }, null, 8, ["actions"])) : createCommentVNode("", true)
 | |
|                 ], 2)
 | |
|               ]),
 | |
|               _: 1
 | |
|             }, 8, ["class"])
 | |
|           ]),
 | |
|           _: 1
 | |
|         }, 8, ["to"])
 | |
|       ]);
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const card = "_card_pt4ir_123";
 | |
| const cardBadge$1 = "_cardBadge_pt4ir_157";
 | |
| const style0$6 = {
 | |
|   card,
 | |
|   "folder-icon": "_folder-icon_pt4ir_131",
 | |
|   "card-header": "_card-header_pt4ir_140",
 | |
|   "card-footer": "_card-footer_pt4ir_148",
 | |
|   "info-cell": "_info-cell_pt4ir_152",
 | |
|   cardBadge: cardBadge$1,
 | |
|   "with-breadcrumbs": "_with-breadcrumbs_pt4ir_157",
 | |
|   "card-actions": "_card-actions_pt4ir_164",
 | |
|   "info-cell--created": "_info-cell--created_pt4ir_182"
 | |
| };
 | |
| const cssModules$6 = {
 | |
|   "$style": style0$6
 | |
| };
 | |
| const __unplugin_components_4 = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["__cssModules", cssModules$6]]);
 | |
| const _sfc_main$5 = /* @__PURE__ */ defineComponent({
 | |
|   __name: "WorkflowCard",
 | |
|   props: {
 | |
|     data: {},
 | |
|     readOnly: { type: Boolean, default: false },
 | |
|     workflowListEventBus: { default: void 0 },
 | |
|     showOwnershipBadge: { type: Boolean, default: false }
 | |
|   },
 | |
|   emits: ["expand:tags", "click:tag", "workflow:deleted", "workflow:archived", "workflow:unarchived", "workflow:active-toggle", "action:move-to-folder"],
 | |
|   setup(__props, { emit: __emit }) {
 | |
|     const WORKFLOW_LIST_ITEM_ACTIONS = {
 | |
|       OPEN: "open",
 | |
|       SHARE: "share",
 | |
|       DUPLICATE: "duplicate",
 | |
|       DELETE: "delete",
 | |
|       ARCHIVE: "archive",
 | |
|       UNARCHIVE: "unarchive",
 | |
|       MOVE: "move",
 | |
|       MOVE_TO_FOLDER: "moveToFolder"
 | |
|     };
 | |
|     const props = __props;
 | |
|     const emit = __emit;
 | |
|     const toast = useToast();
 | |
|     const message = useMessage();
 | |
|     const locale = useI18n();
 | |
|     const router = useRouter();
 | |
|     const route = useRoute();
 | |
|     const telemetry = useTelemetry();
 | |
|     const settingsStore = useSettingsStore();
 | |
|     const uiStore = useUIStore();
 | |
|     const usersStore = useUsersStore();
 | |
|     const workflowsStore = useWorkflowsStore();
 | |
|     const projectsStore = useProjectsStore();
 | |
|     const foldersStore = useFoldersStore();
 | |
|     const hiddenBreadcrumbsItemsAsync = ref(new Promise(() => {
 | |
|     }));
 | |
|     const cachedHiddenBreadcrumbsItems = ref([]);
 | |
|     const resourceTypeLabel = computed(() => locale.baseText("generic.workflow").toLowerCase());
 | |
|     const currentUser = computed(() => usersStore.currentUser ?? {});
 | |
|     const workflowPermissions = computed(() => getResourcePermissions(props.data.scopes).workflow);
 | |
|     const showFolders = computed(() => {
 | |
|       return settingsStore.isFoldersFeatureEnabled && route.name !== VIEWS.WORKFLOWS;
 | |
|     });
 | |
|     const showCardBreadcrumbs = computed(() => {
 | |
|       return props.showOwnershipBadge && !isSomeoneElsesWorkflow.value && cardBreadcrumbs.value.length;
 | |
|     });
 | |
|     const projectName = computed(() => {
 | |
|       if (props.data.homeProject?.type === ProjectTypes.Personal) {
 | |
|         return locale.baseText("projects.menu.personal");
 | |
|       }
 | |
|       return props.data.homeProject?.name;
 | |
|     });
 | |
|     const cardBreadcrumbs = computed(() => {
 | |
|       if (props.data.parentFolder) {
 | |
|         return [
 | |
|           {
 | |
|             id: props.data.parentFolder.id,
 | |
|             name: props.data.parentFolder.name,
 | |
|             label: props.data.parentFolder.name,
 | |
|             href: router.resolve({
 | |
|               name: VIEWS.PROJECTS_FOLDERS,
 | |
|               params: {
 | |
|                 projectId: props.data.homeProject?.id,
 | |
|                 folderId: props.data.parentFolder.id
 | |
|               }
 | |
|             }).href
 | |
|           }
 | |
|         ];
 | |
|       }
 | |
|       return [];
 | |
|     });
 | |
|     const actions = computed(() => {
 | |
|       const items = [
 | |
|         {
 | |
|           label: locale.baseText("workflows.item.open"),
 | |
|           value: WORKFLOW_LIST_ITEM_ACTIONS.OPEN
 | |
|         },
 | |
|         {
 | |
|           label: locale.baseText("workflows.item.share"),
 | |
|           value: WORKFLOW_LIST_ITEM_ACTIONS.SHARE
 | |
|         }
 | |
|       ];
 | |
|       if (workflowPermissions.value.create && !props.readOnly && !props.data.isArchived) {
 | |
|         items.push({
 | |
|           label: locale.baseText("workflows.item.duplicate"),
 | |
|           value: WORKFLOW_LIST_ITEM_ACTIONS.DUPLICATE
 | |
|         });
 | |
|       }
 | |
|       if ((workflowPermissions.value.update && !props.readOnly || workflowPermissions.value.move && projectsStore.isTeamProjectFeatureEnabled) && showFolders.value && route.name !== VIEWS.SHARED_WORKFLOWS) {
 | |
|         items.push({
 | |
|           label: locale.baseText("folders.actions.moveToFolder"),
 | |
|           value: WORKFLOW_LIST_ITEM_ACTIONS.MOVE_TO_FOLDER
 | |
|         });
 | |
|       }
 | |
|       if (workflowPermissions.value.delete && !props.readOnly) {
 | |
|         if (!props.data.isArchived) {
 | |
|           items.push({
 | |
|             label: locale.baseText("workflows.item.archive"),
 | |
|             value: WORKFLOW_LIST_ITEM_ACTIONS.ARCHIVE
 | |
|           });
 | |
|         } else {
 | |
|           items.push({
 | |
|             label: locale.baseText("workflows.item.delete"),
 | |
|             value: WORKFLOW_LIST_ITEM_ACTIONS.DELETE
 | |
|           });
 | |
|           items.push({
 | |
|             label: locale.baseText("workflows.item.unarchive"),
 | |
|             value: WORKFLOW_LIST_ITEM_ACTIONS.UNARCHIVE
 | |
|           });
 | |
|         }
 | |
|       }
 | |
|       return items;
 | |
|     });
 | |
|     const formattedCreatedAtDate = computed(() => {
 | |
|       const currentYear = (/* @__PURE__ */ new Date()).getFullYear().toString();
 | |
|       return dateFormat(
 | |
|         props.data.createdAt,
 | |
|         `d mmmm${String(props.data.createdAt).startsWith(currentYear) ? "" : ", yyyy"}`
 | |
|       );
 | |
|     });
 | |
|     const isSomeoneElsesWorkflow = computed(
 | |
|       () => props.data.homeProject?.type !== ProjectTypes.Team && props.data.homeProject?.id !== projectsStore.personalProject?.id
 | |
|     );
 | |
|     async function onClick(event) {
 | |
|       if (event?.ctrlKey || event?.metaKey) {
 | |
|         const route2 = router.resolve({
 | |
|           name: VIEWS.WORKFLOW,
 | |
|           params: { name: props.data.id }
 | |
|         });
 | |
|         window.open(route2.href, "_blank");
 | |
|         return;
 | |
|       }
 | |
|       await router.push({
 | |
|         name: VIEWS.WORKFLOW,
 | |
|         params: { name: props.data.id }
 | |
|       });
 | |
|     }
 | |
|     function onClickTag(tagId, event) {
 | |
|       event.stopPropagation();
 | |
|       emit("click:tag", tagId, event);
 | |
|     }
 | |
|     function onExpandTags() {
 | |
|       emit("expand:tags");
 | |
|     }
 | |
|     async function onAction(action) {
 | |
|       switch (action) {
 | |
|         case WORKFLOW_LIST_ITEM_ACTIONS.OPEN:
 | |
|           await onClick();
 | |
|           break;
 | |
|         case WORKFLOW_LIST_ITEM_ACTIONS.DUPLICATE:
 | |
|           uiStore.openModalWithData({
 | |
|             name: DUPLICATE_MODAL_KEY,
 | |
|             data: {
 | |
|               id: props.data.id,
 | |
|               name: props.data.name,
 | |
|               tags: (props.data.tags ?? []).map(
 | |
|                 (tag) => typeof tag !== "string" && "id" in tag ? tag.id : tag
 | |
|               ),
 | |
|               externalEventBus: props.workflowListEventBus,
 | |
|               parentFolderId: props.data.parentFolder?.id
 | |
|             }
 | |
|           });
 | |
|           break;
 | |
|         case WORKFLOW_LIST_ITEM_ACTIONS.SHARE:
 | |
|           uiStore.openModalWithData({
 | |
|             name: WORKFLOW_SHARE_MODAL_KEY,
 | |
|             data: { id: props.data.id }
 | |
|           });
 | |
|           telemetry.track("User opened sharing modal", {
 | |
|             workflow_id: props.data.id,
 | |
|             user_id_sharer: currentUser.value.id,
 | |
|             sub_view: "Workflows listing"
 | |
|           });
 | |
|           break;
 | |
|         case WORKFLOW_LIST_ITEM_ACTIONS.DELETE:
 | |
|           await deleteWorkflow();
 | |
|           break;
 | |
|         case WORKFLOW_LIST_ITEM_ACTIONS.ARCHIVE:
 | |
|           await archiveWorkflow();
 | |
|           break;
 | |
|         case WORKFLOW_LIST_ITEM_ACTIONS.UNARCHIVE:
 | |
|           await unarchiveWorkflow();
 | |
|           break;
 | |
|         case WORKFLOW_LIST_ITEM_ACTIONS.MOVE:
 | |
|           moveResource();
 | |
|           break;
 | |
|         case WORKFLOW_LIST_ITEM_ACTIONS.MOVE_TO_FOLDER:
 | |
|           emit("action:move-to-folder", {
 | |
|             id: props.data.id,
 | |
|             name: props.data.name,
 | |
|             parentFolderId: props.data.parentFolder?.id,
 | |
|             sharedWithProjects: props.data.sharedWithProjects
 | |
|           });
 | |
|           break;
 | |
|       }
 | |
|     }
 | |
|     async function deleteWorkflow() {
 | |
|       const deleteConfirmed = await message.confirm(
 | |
|         locale.baseText("mainSidebar.confirmMessage.workflowDelete.message", {
 | |
|           interpolate: { workflowName: props.data.name }
 | |
|         }),
 | |
|         locale.baseText("mainSidebar.confirmMessage.workflowDelete.headline"),
 | |
|         {
 | |
|           type: "warning",
 | |
|           confirmButtonText: locale.baseText(
 | |
|             "mainSidebar.confirmMessage.workflowDelete.confirmButtonText"
 | |
|           ),
 | |
|           cancelButtonText: locale.baseText(
 | |
|             "mainSidebar.confirmMessage.workflowDelete.cancelButtonText"
 | |
|           )
 | |
|         }
 | |
|       );
 | |
|       if (deleteConfirmed !== MODAL_CONFIRM) {
 | |
|         return;
 | |
|       }
 | |
|       try {
 | |
|         await workflowsStore.deleteWorkflow(props.data.id);
 | |
|       } catch (error) {
 | |
|         toast.showError(error, locale.baseText("generic.deleteWorkflowError"));
 | |
|         return;
 | |
|       }
 | |
|       toast.showMessage({
 | |
|         title: locale.baseText("mainSidebar.showMessage.handleSelect1.title", {
 | |
|           interpolate: { workflowName: props.data.name }
 | |
|         }),
 | |
|         type: "success"
 | |
|       });
 | |
|       emit("workflow:deleted");
 | |
|     }
 | |
|     async function archiveWorkflow() {
 | |
|       if (props.data.active) {
 | |
|         const archiveConfirmed = await message.confirm(
 | |
|           locale.baseText("mainSidebar.confirmMessage.workflowArchive.message", {
 | |
|             interpolate: { workflowName: props.data.name }
 | |
|           }),
 | |
|           locale.baseText("mainSidebar.confirmMessage.workflowArchive.headline"),
 | |
|           {
 | |
|             type: "warning",
 | |
|             confirmButtonText: locale.baseText(
 | |
|               "mainSidebar.confirmMessage.workflowArchive.confirmButtonText"
 | |
|             ),
 | |
|             cancelButtonText: locale.baseText(
 | |
|               "mainSidebar.confirmMessage.workflowArchive.cancelButtonText"
 | |
|             )
 | |
|           }
 | |
|         );
 | |
|         if (archiveConfirmed !== MODAL_CONFIRM) {
 | |
|           return;
 | |
|         }
 | |
|       }
 | |
|       try {
 | |
|         await workflowsStore.archiveWorkflow(props.data.id);
 | |
|       } catch (error) {
 | |
|         toast.showError(error, locale.baseText("generic.archiveWorkflowError"));
 | |
|         return;
 | |
|       }
 | |
|       toast.showMessage({
 | |
|         title: locale.baseText("mainSidebar.showMessage.handleArchive.title", {
 | |
|           interpolate: { workflowName: props.data.name }
 | |
|         }),
 | |
|         type: "success"
 | |
|       });
 | |
|       emit("workflow:archived");
 | |
|     }
 | |
|     async function unarchiveWorkflow() {
 | |
|       try {
 | |
|         await workflowsStore.unarchiveWorkflow(props.data.id);
 | |
|       } catch (error) {
 | |
|         toast.showError(error, locale.baseText("generic.unarchiveWorkflowError"));
 | |
|         return;
 | |
|       }
 | |
|       toast.showMessage({
 | |
|         title: locale.baseText("mainSidebar.showMessage.handleUnarchive.title", {
 | |
|           interpolate: { workflowName: props.data.name }
 | |
|         }),
 | |
|         type: "success"
 | |
|       });
 | |
|       emit("workflow:unarchived");
 | |
|     }
 | |
|     const fetchHiddenBreadCrumbsItems = async () => {
 | |
|       if (!props.data.homeProject?.id || !projectName.value || !props.data.parentFolder) {
 | |
|         hiddenBreadcrumbsItemsAsync.value = Promise.resolve([]);
 | |
|       } else {
 | |
|         if (cachedHiddenBreadcrumbsItems.value.length) {
 | |
|           hiddenBreadcrumbsItemsAsync.value = Promise.resolve(cachedHiddenBreadcrumbsItems.value);
 | |
|           return;
 | |
|         }
 | |
|         const loadedItem = foldersStore.getHiddenBreadcrumbsItems(
 | |
|           { id: props.data.homeProject.id, name: projectName.value },
 | |
|           props.data.parentFolder.id
 | |
|         );
 | |
|         hiddenBreadcrumbsItemsAsync.value = loadedItem;
 | |
|         cachedHiddenBreadcrumbsItems.value = await loadedItem;
 | |
|       }
 | |
|     };
 | |
|     function moveResource() {
 | |
|       uiStore.openModalWithData({
 | |
|         name: PROJECT_MOVE_RESOURCE_MODAL,
 | |
|         data: {
 | |
|           resource: props.data,
 | |
|           resourceType: ResourceType.Workflow,
 | |
|           resourceTypeLabel: resourceTypeLabel.value,
 | |
|           eventBus: props.workflowListEventBus
 | |
|         }
 | |
|       });
 | |
|     }
 | |
|     const emitWorkflowActiveToggle = (value) => {
 | |
|       emit("workflow:active-toggle", value);
 | |
|     };
 | |
|     const onBreadcrumbItemClick = async (item) => {
 | |
|       if (item.href) {
 | |
|         await router.push(item.href);
 | |
|       }
 | |
|     };
 | |
|     const tags = computed(
 | |
|       () => props.data.tags?.map((tag) => typeof tag === "string" ? { id: tag, name: tag } : tag) ?? []
 | |
|     );
 | |
|     return (_ctx, _cache) => {
 | |
|       const _component_N8nBadge = N8nBadge;
 | |
|       const _component_n8n_text = N8nText;
 | |
|       const _component_n8n_tags = Tags;
 | |
|       const _component_n8n_breadcrumbs = Breadcrumbs;
 | |
|       const _component_n8n_action_toggle = N8nActionToggle;
 | |
|       const _component_n8n_card = N8nCard;
 | |
|       return openBlock(), createBlock(_component_n8n_card, {
 | |
|         class: normalizeClass({
 | |
|           [_ctx.$style.cardLink]: true,
 | |
|           [_ctx.$style.cardArchived]: _ctx.data.isArchived
 | |
|         }),
 | |
|         "data-test-id": "workflow-card",
 | |
|         onClick
 | |
|       }, {
 | |
|         header: withCtx(() => [
 | |
|           createVNode(_component_n8n_text, {
 | |
|             tag: "h2",
 | |
|             bold: "",
 | |
|             class: normalizeClass({
 | |
|               [_ctx.$style.cardHeading]: true,
 | |
|               [_ctx.$style.cardHeadingArchived]: _ctx.data.isArchived
 | |
|             }),
 | |
|             "data-test-id": "workflow-card-name"
 | |
|           }, {
 | |
|             default: withCtx(() => [
 | |
|               createTextVNode(toDisplayString(_ctx.data.name) + " ", 1),
 | |
|               !workflowPermissions.value.update ? (openBlock(), createBlock(_component_N8nBadge, {
 | |
|                 key: 0,
 | |
|                 class: "ml-3xs",
 | |
|                 theme: "tertiary",
 | |
|                 bold: ""
 | |
|               }, {
 | |
|                 default: withCtx(() => [
 | |
|                   createTextVNode(toDisplayString(unref(locale).baseText("workflows.item.readonly")), 1)
 | |
|                 ]),
 | |
|                 _: 1
 | |
|               })) : createCommentVNode("", true)
 | |
|             ]),
 | |
|             _: 1
 | |
|           }, 8, ["class"])
 | |
|         ]),
 | |
|         append: withCtx(() => [
 | |
|           createBaseVNode("div", {
 | |
|             class: normalizeClass(_ctx.$style.cardActions),
 | |
|             onClick: _cache[0] || (_cache[0] = withModifiers(() => {
 | |
|             }, ["stop"]))
 | |
|           }, [
 | |
|             _ctx.showOwnershipBadge ? (openBlock(), createBlock(ProjectCardBadge, {
 | |
|               key: 0,
 | |
|               class: normalizeClass({ [_ctx.$style.cardBadge]: true, [_ctx.$style["with-breadcrumbs"]]: showCardBreadcrumbs.value }),
 | |
|               resource: _ctx.data,
 | |
|               "resource-type": unref(ResourceType).Workflow,
 | |
|               "resource-type-label": resourceTypeLabel.value,
 | |
|               "personal-project": unref(projectsStore).personalProject,
 | |
|               "show-badge-border": false
 | |
|             }, {
 | |
|               default: withCtx(() => [
 | |
|                 showCardBreadcrumbs.value ? (openBlock(), createElementBlock("div", {
 | |
|                   key: 0,
 | |
|                   class: normalizeClass(_ctx.$style.breadcrumbs)
 | |
|                 }, [
 | |
|                   createVNode(_component_n8n_breadcrumbs, {
 | |
|                     items: cardBreadcrumbs.value,
 | |
|                     "hidden-items": _ctx.data.parentFolder?.parentFolderId !== null ? hiddenBreadcrumbsItemsAsync.value : void 0,
 | |
|                     "path-truncated": _ctx.data.parentFolder?.parentFolderId !== null,
 | |
|                     "highlight-last-item": false,
 | |
|                     "hidden-items-trigger": "hover",
 | |
|                     theme: "small",
 | |
|                     "data-test-id": "workflow-card-breadcrumbs",
 | |
|                     onTooltipOpened: fetchHiddenBreadCrumbsItems,
 | |
|                     onItemSelected: onBreadcrumbItemClick
 | |
|                   }, {
 | |
|                     prepend: withCtx(() => _cache[2] || (_cache[2] = [])),
 | |
|                     _: 1
 | |
|                   }, 8, ["items", "hidden-items", "path-truncated"])
 | |
|                 ], 2)) : createCommentVNode("", true)
 | |
|               ]),
 | |
|               _: 1
 | |
|             }, 8, ["class", "resource", "resource-type", "resource-type-label", "personal-project"])) : createCommentVNode("", true),
 | |
|             _ctx.data.isArchived ? (openBlock(), createBlock(_component_n8n_text, {
 | |
|               key: 1,
 | |
|               color: "text-light",
 | |
|               size: "small",
 | |
|               bold: "",
 | |
|               class: "ml-s mr-s",
 | |
|               "data-test-id": "workflow-card-archived"
 | |
|             }, {
 | |
|               default: withCtx(() => [
 | |
|                 createTextVNode(toDisplayString(unref(locale).baseText("workflows.item.archived")), 1)
 | |
|               ]),
 | |
|               _: 1
 | |
|             })) : (openBlock(), createBlock(WorkflowActivator, {
 | |
|               key: 2,
 | |
|               class: "mr-s",
 | |
|               "is-archived": _ctx.data.isArchived,
 | |
|               "workflow-active": _ctx.data.active,
 | |
|               "workflow-id": _ctx.data.id,
 | |
|               "workflow-permissions": workflowPermissions.value,
 | |
|               "data-test-id": "workflow-card-activator",
 | |
|               "onUpdate:workflowActive": emitWorkflowActiveToggle
 | |
|             }, null, 8, ["is-archived", "workflow-active", "workflow-id", "workflow-permissions"])),
 | |
|             createVNode(_component_n8n_action_toggle, {
 | |
|               actions: actions.value,
 | |
|               theme: "dark",
 | |
|               "data-test-id": "workflow-card-actions",
 | |
|               onAction
 | |
|             }, null, 8, ["actions"])
 | |
|           ], 2)
 | |
|         ]),
 | |
|         default: withCtx(() => [
 | |
|           createBaseVNode("div", {
 | |
|             class: normalizeClass(_ctx.$style.cardDescription)
 | |
|           }, [
 | |
|             createVNode(_component_n8n_text, {
 | |
|               color: "text-light",
 | |
|               size: "small"
 | |
|             }, {
 | |
|               default: withCtx(() => [
 | |
|                 withDirectives(createBaseVNode("span", null, [
 | |
|                   createTextVNode(toDisplayString(unref(locale).baseText("workflows.item.updated")) + " ", 1),
 | |
|                   createVNode(_sfc_main$7, {
 | |
|                     date: String(_ctx.data.updatedAt)
 | |
|                   }, null, 8, ["date"]),
 | |
|                   _cache[1] || (_cache[1] = createTextVNode(" | "))
 | |
|                 ], 512), [
 | |
|                   [vShow, _ctx.data]
 | |
|                 ]),
 | |
|                 withDirectives(createBaseVNode("span", { class: "mr-2xs" }, toDisplayString(unref(locale).baseText("workflows.item.created")) + " " + toDisplayString(formattedCreatedAtDate.value), 513), [
 | |
|                   [vShow, _ctx.data]
 | |
|                 ]),
 | |
|                 unref(settingsStore).areTagsEnabled && _ctx.data.tags && _ctx.data.tags.length > 0 ? withDirectives((openBlock(), createElementBlock("span", {
 | |
|                   key: 0,
 | |
|                   class: normalizeClass(_ctx.$style.cardTags)
 | |
|                 }, [
 | |
|                   createVNode(_component_n8n_tags, {
 | |
|                     tags: tags.value,
 | |
|                     "truncate-at": 3,
 | |
|                     truncate: "",
 | |
|                     "data-test-id": "workflow-card-tags",
 | |
|                     "onClick:tag": onClickTag,
 | |
|                     onExpand: onExpandTags
 | |
|                   }, null, 8, ["tags"])
 | |
|                 ], 2)), [
 | |
|                   [vShow, _ctx.data]
 | |
|                 ]) : createCommentVNode("", true)
 | |
|               ]),
 | |
|               _: 1
 | |
|             })
 | |
|           ], 2)
 | |
|         ]),
 | |
|         _: 1
 | |
|       }, 8, ["class"]);
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const cardLink = "_cardLink_9y0d7_123";
 | |
| const cardHeading = "_cardHeading_9y0d7_133";
 | |
| const cardHeadingArchived = "_cardHeadingArchived_9y0d7_142";
 | |
| const cardDescription = "_cardDescription_9y0d7_146";
 | |
| const cardTags = "_cardTags_9y0d7_153";
 | |
| const cardActions = "_cardActions_9y0d7_158";
 | |
| const cardBadge = "_cardBadge_9y0d7_169";
 | |
| const cardArchived = "_cardArchived_9y0d7_180";
 | |
| const breadcrumbs = "_breadcrumbs_9y0d7_198";
 | |
| const style0$5 = {
 | |
|   cardLink,
 | |
|   cardHeading,
 | |
|   cardHeadingArchived,
 | |
|   cardDescription,
 | |
|   cardTags,
 | |
|   cardActions,
 | |
|   cardBadge,
 | |
|   "with-breadcrumbs": "_with-breadcrumbs_9y0d7_173",
 | |
|   cardArchived,
 | |
|   breadcrumbs
 | |
| };
 | |
| const cssModules$5 = {
 | |
|   "$style": style0$5
 | |
| };
 | |
| const WorkflowCard = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__cssModules", cssModules$5]]);
 | |
| function isDropTarget(target) {
 | |
|   return target.type === "folder" || target.type === "project";
 | |
| }
 | |
| function isValidResourceType(value) {
 | |
|   return ["folder", "workflow", "project"].includes(value);
 | |
| }
 | |
| function useFolders() {
 | |
|   const i18n = useI18n();
 | |
|   const foldersStore = useFoldersStore();
 | |
|   const isDragging = computed(() => {
 | |
|     return foldersStore.draggedElement !== null;
 | |
|   });
 | |
|   function validateFolderName(folderName) {
 | |
|     if (FOLDER_NAME_ILLEGAL_CHARACTERS_REGEX.test(folderName)) {
 | |
|       return i18n.baseText("folders.invalidName.invalidCharacters.message", {
 | |
|         interpolate: {
 | |
|           illegalChars: ILLEGAL_FOLDER_CHARACTERS.join(" ")
 | |
|         }
 | |
|       });
 | |
|     }
 | |
|     if (FOLDER_NAME_ONLY_DOTS_REGEX.test(folderName)) {
 | |
|       return i18n.baseText("folders.invalidName.only.dots.message");
 | |
|     }
 | |
|     if (folderName.startsWith(".")) {
 | |
|       return i18n.baseText("folders.invalidName.starts.with.dot..message");
 | |
|     }
 | |
|     if (folderName.trim() === "") {
 | |
|       return i18n.baseText("folders.invalidName.empty.message");
 | |
|     }
 | |
|     if (folderName.length > FOLDER_NAME_MAX_LENGTH) {
 | |
|       return i18n.baseText("folders.invalidName.tooLong.message", {
 | |
|         interpolate: {
 | |
|           maxLength: FOLDER_NAME_MAX_LENGTH
 | |
|         }
 | |
|       });
 | |
|     }
 | |
|     return true;
 | |
|   }
 | |
|   function onDragStart(el) {
 | |
|     const eventTarget = el.closest("[data-target]");
 | |
|     if (!eventTarget) return;
 | |
|     const dragTarget = getDragAndDropTarget(eventTarget);
 | |
|     if (!dragTarget) return;
 | |
|     if (dragTarget.type === "folder" || dragTarget.type === "workflow") {
 | |
|       foldersStore.draggedElement = {
 | |
|         type: dragTarget.type,
 | |
|         id: dragTarget.id,
 | |
|         name: dragTarget.name
 | |
|       };
 | |
|     }
 | |
|   }
 | |
|   function onDragEnd() {
 | |
|     foldersStore.draggedElement = null;
 | |
|     foldersStore.activeDropTarget = null;
 | |
|   }
 | |
|   function onDragEnter(event) {
 | |
|     const eventTarget = event.target;
 | |
|     if (!eventTarget || !isDragging.value) return;
 | |
|     event.preventDefault();
 | |
|     event.stopPropagation();
 | |
|     const dragTarget = getDragAndDropTarget(eventTarget);
 | |
|     if (!dragTarget || dragTarget.type !== "folder") return;
 | |
|     foldersStore.activeDropTarget = {
 | |
|       type: dragTarget.type,
 | |
|       id: dragTarget.id,
 | |
|       name: dragTarget.name
 | |
|     };
 | |
|   }
 | |
|   function resetDropTarget() {
 | |
|     foldersStore.activeDropTarget = null;
 | |
|   }
 | |
|   function getDragAndDropTarget(el) {
 | |
|     const dragTarget = el.closest("[data-target]");
 | |
|     if (!dragTarget) return null;
 | |
|     const targetResource = dragTarget.dataset.target;
 | |
|     const targetId = dragTarget.dataset.resourceid;
 | |
|     const targetName = dragTarget.dataset.resourcename;
 | |
|     if (!targetResource || !targetId || !targetName || !isValidResourceType(targetResource))
 | |
|       return null;
 | |
|     return {
 | |
|       type: targetResource,
 | |
|       id: targetId,
 | |
|       name: targetName
 | |
|     };
 | |
|   }
 | |
|   function handleDrop(event) {
 | |
|     const eventTarget = event.target;
 | |
|     if (!eventTarget || !isDragging.value) return {};
 | |
|     event.preventDefault();
 | |
|     const draggedResourceId = foldersStore.draggedElement?.id;
 | |
|     const draggedResourceType = foldersStore.draggedElement?.type;
 | |
|     const draggedResourceName = foldersStore.draggedElement?.name;
 | |
|     if (!draggedResourceId || !draggedResourceType || !draggedResourceName) return {};
 | |
|     onDragEnd();
 | |
|     const dropTarget = getDragAndDropTarget(eventTarget);
 | |
|     if (!dropTarget || !isDropTarget(dropTarget)) return {};
 | |
|     return {
 | |
|       draggedResource: {
 | |
|         type: draggedResourceType,
 | |
|         id: draggedResourceId,
 | |
|         name: draggedResourceName
 | |
|       },
 | |
|       dropTarget: {
 | |
|         type: dropTarget.type,
 | |
|         id: dropTarget.id,
 | |
|         name: dropTarget.name
 | |
|       }
 | |
|     };
 | |
|   }
 | |
|   return {
 | |
|     validateFolderName,
 | |
|     onDragStart,
 | |
|     onDragEnd,
 | |
|     onDragEnter,
 | |
|     resetDropTarget,
 | |
|     handleDrop
 | |
|   };
 | |
| }
 | |
| const SIMPLE_TEMPLATES = [6270, 5271, 2178];
 | |
| const PREDEFINED_TEMPLATES_BY_NODE = {
 | |
|   "n8n-nodes-base.gmail": [5678, 4722, 5694],
 | |
|   "n8n-nodes-base.googleSheets": [5694, 5690, 5906],
 | |
|   "n8n-nodes-base.telegram": [5626, 2114, 4875],
 | |
|   "@n8n/n8n-nodes-langchain.openAi": [2462, 2722, 2178],
 | |
|   "@n8n/n8n-nodes-langchain.googleGemini": [5993, 6270, 5677],
 | |
|   "n8n-nodes-base.googleCalendar": [2328, 3393, 2110],
 | |
|   "n8n-nodes-base.youTube": [3188, 4846, 4506],
 | |
|   "n8n-nodes-base.airtable": [3053, 2700, 2579]
 | |
| };
 | |
| function getPredefinedFromSelected(selectedApps) {
 | |
|   const predefinedNodes = Object.keys(PREDEFINED_TEMPLATES_BY_NODE);
 | |
|   const predefinedSelected = predefinedNodes.filter((node) => selectedApps.includes(node));
 | |
|   return predefinedSelected.reduce(
 | |
|     (acc, app) => [
 | |
|       ...acc,
 | |
|       ...PREDEFINED_TEMPLATES_BY_NODE[app]
 | |
|     ],
 | |
|     []
 | |
|   );
 | |
| }
 | |
| function getSuggestedTemplatesForLowCodingSkill(selectedApps) {
 | |
|   if (selectedApps.length === 0) {
 | |
|     return SIMPLE_TEMPLATES;
 | |
|   }
 | |
|   const predefinedSelected = getPredefinedFromSelected(selectedApps);
 | |
|   if (predefinedSelected.length > 0) {
 | |
|     return predefinedSelected;
 | |
|   }
 | |
|   return [];
 | |
| }
 | |
| function keepTop3Templates(templates) {
 | |
|   if (templates.length <= 3) {
 | |
|     return templates;
 | |
|   }
 | |
|   return Array.from(new Map(templates.map((t) => [t.id, t])).values()).sort((a, b) => b.totalViews - a.totalViews).slice(0, 3);
 | |
| }
 | |
| const usePersonalizedTemplatesStore = defineStore(STORES.PERSONALIZED_TEMPLATES, () => {
 | |
|   const telemetry = useTelemetry();
 | |
|   const posthogStore = usePostHog();
 | |
|   const cloudPlanStore = useCloudPlanStore();
 | |
|   const templatesStore = useTemplatesStore();
 | |
|   const allSuggestedWorkflows = ref([]);
 | |
|   const dismissedSuggestedWorkflowsStorage = useStorage(
 | |
|     LOCAL_STORAGE_EXPERIMENTAL_DISMISSED_SUGGESTED_WORKFLOWS
 | |
|   );
 | |
|   const dismissedSuggestedWorkflows = computed(() => {
 | |
|     return dismissedSuggestedWorkflowsStorage.value ? jsonParse(dismissedSuggestedWorkflowsStorage.value, { fallbackValue: [] }) : [];
 | |
|   });
 | |
|   const suggestedWorkflows = computed(
 | |
|     () => allSuggestedWorkflows.value.filter(({ id }) => !dismissedSuggestedWorkflows.value.includes(id))
 | |
|   );
 | |
|   const dismissSuggestedWorkflow = (id) => {
 | |
|     dismissedSuggestedWorkflowsStorage.value = JSON.stringify([
 | |
|       ...dismissedSuggestedWorkflows.value ?? [],
 | |
|       id
 | |
|     ]);
 | |
|   };
 | |
|   const isFeatureEnabled = () => {
 | |
|     return posthogStore.getVariant(TEMPLATE_ONBOARDING_EXPERIMENT.name) === TEMPLATE_ONBOARDING_EXPERIMENT.variantSuggestedTemplates && cloudPlanStore.userIsTrialing;
 | |
|   };
 | |
|   const trackUserWasRecommendedTemplates = (templateIds) => {
 | |
|     telemetry.track("User was recommended personalized templates", {
 | |
|       templateIds
 | |
|     });
 | |
|   };
 | |
|   const trackUserClickedOnPersonalizedTemplate = (templateId) => {
 | |
|     telemetry.track("User clicked on personalized template callout", {
 | |
|       templateId
 | |
|     });
 | |
|   };
 | |
|   const trackUserDismissedCallout = (templateId) => {
 | |
|     telemetry.track("User dismissed personalized template callout", {
 | |
|       templateId
 | |
|     });
 | |
|   };
 | |
|   const fetchSuggestedWorkflows = async (codingSkill, selectedApps) => {
 | |
|     if (!isFeatureEnabled()) {
 | |
|       return;
 | |
|     }
 | |
|     try {
 | |
|       if (codingSkill === 1) {
 | |
|         const predefinedSelected = getSuggestedTemplatesForLowCodingSkill(selectedApps);
 | |
|         if (predefinedSelected.length > 0) {
 | |
|           const suggestedWorkflowsPromises2 = predefinedSelected.map(
 | |
|             async (id) => await templatesStore.fetchTemplateById(id.toString())
 | |
|           );
 | |
|           const allWorkflows2 = await Promise.all(suggestedWorkflowsPromises2);
 | |
|           const top3Templates2 = keepTop3Templates(allWorkflows2);
 | |
|           allSuggestedWorkflows.value = top3Templates2;
 | |
|           trackUserWasRecommendedTemplates(top3Templates2.map((t) => t.id));
 | |
|           return;
 | |
|         }
 | |
|       }
 | |
|       const topWorkflowsByApp = await templatesStore.getWorkflows({
 | |
|         categories: [],
 | |
|         search: "",
 | |
|         sort: "rank:desc",
 | |
|         nodes: selectedApps.length > 0 ? selectedApps : void 0,
 | |
|         combineWith: "or"
 | |
|       });
 | |
|       const topWorkflowsIds = topWorkflowsByApp.slice(0, 3).map((workflow) => workflow.id);
 | |
|       const suggestedWorkflowsPromises = topWorkflowsIds.map(
 | |
|         async (id) => await templatesStore.fetchTemplateById(id.toString())
 | |
|       );
 | |
|       const allWorkflows = await Promise.all(suggestedWorkflowsPromises);
 | |
|       const top3Templates = keepTop3Templates(allWorkflows);
 | |
|       allSuggestedWorkflows.value = top3Templates;
 | |
|       trackUserWasRecommendedTemplates(top3Templates.map((t) => t.id));
 | |
|     } catch (error) {
 | |
|     }
 | |
|   };
 | |
|   const getTemplateRoute = (id) => {
 | |
|     return { name: VIEWS.TEMPLATE, params: { id } };
 | |
|   };
 | |
|   watch(
 | |
|     () => cloudPlanStore.currentUserCloudInfo,
 | |
|     async (userInfo) => {
 | |
|       if (!userInfo) return;
 | |
|       const codingSkill = cloudPlanStore.codingSkill;
 | |
|       const selectedApps = cloudPlanStore.selectedApps ?? [];
 | |
|       await fetchSuggestedWorkflows(codingSkill, selectedApps);
 | |
|     }
 | |
|   );
 | |
|   return {
 | |
|     isFeatureEnabled,
 | |
|     suggestedWorkflows,
 | |
|     dismissSuggestedWorkflow,
 | |
|     trackUserClickedOnPersonalizedTemplate,
 | |
|     trackUserDismissedCallout,
 | |
|     getTemplateRoute
 | |
|   };
 | |
| });
 | |
| const _sfc_main$4 = /* @__PURE__ */ defineComponent({
 | |
|   __name: "SuggestedWorkflowCard",
 | |
|   props: {
 | |
|     data: {}
 | |
|   },
 | |
|   setup(__props) {
 | |
|     const props = __props;
 | |
|     const { data } = props;
 | |
|     const {
 | |
|       dismissSuggestedWorkflow,
 | |
|       getTemplateRoute,
 | |
|       trackUserClickedOnPersonalizedTemplate,
 | |
|       trackUserDismissedCallout
 | |
|     } = usePersonalizedTemplatesStore();
 | |
|     const locale = useI18n();
 | |
|     const onDismissCallout = () => {
 | |
|       trackUserDismissedCallout(data.id);
 | |
|       dismissSuggestedWorkflow(data.id);
 | |
|     };
 | |
|     const onTryTemplate = () => {
 | |
|       trackUserClickedOnPersonalizedTemplate(data.id);
 | |
|       dismissSuggestedWorkflow(data.id);
 | |
|     };
 | |
|     return (_ctx, _cache) => {
 | |
|       const _component_N8nLink = N8nLink;
 | |
|       const _component_N8nIcon = N8nIcon;
 | |
|       const _component_N8nCallout = N8nCallout;
 | |
|       return openBlock(), createBlock(_component_N8nCallout, {
 | |
|         theme: "secondary",
 | |
|         iconless: true,
 | |
|         class: normalizeClass(_ctx.$style["suggested-workflow-callout"]),
 | |
|         slim: true
 | |
|       }, {
 | |
|         trailingContent: withCtx(() => [
 | |
|           createBaseVNode("div", {
 | |
|             class: normalizeClass(_ctx.$style["callout-trailing-content"])
 | |
|           }, [
 | |
|             createVNode(_component_N8nLink, {
 | |
|               "data-test-id": "suggested-workflow-button",
 | |
|               size: "small",
 | |
|               to: unref(getTemplateRoute)(unref(data).id),
 | |
|               onClick: onTryTemplate
 | |
|             }, {
 | |
|               default: withCtx(() => [
 | |
|                 createTextVNode(toDisplayString(unref(locale).baseText("workflows.itemSuggestion.try")), 1)
 | |
|               ]),
 | |
|               _: 1
 | |
|             }, 8, ["to"]),
 | |
|             createVNode(_component_N8nIcon, {
 | |
|               size: "small",
 | |
|               icon: "x",
 | |
|               title: unref(locale).baseText("generic.dismiss"),
 | |
|               class: "clickable",
 | |
|               onClick: onDismissCallout
 | |
|             }, null, 8, ["title"])
 | |
|           ], 2)
 | |
|         ]),
 | |
|         default: withCtx(() => [
 | |
|           createBaseVNode("div", {
 | |
|             class: normalizeClass(_ctx.$style["callout-content"])
 | |
|           }, toDisplayString(unref(data).name), 3)
 | |
|         ]),
 | |
|         _: 1
 | |
|       }, 8, ["class"]);
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const style0$4 = {
 | |
|   "suggested-workflow-callout": "_suggested-workflow-callout_1alzo_123",
 | |
|   "callout-content": "_callout-content_1alzo_129",
 | |
|   "callout-trailing-content": "_callout-trailing-content_1alzo_133"
 | |
| };
 | |
| const cssModules$4 = {
 | |
|   "$style": style0$4
 | |
| };
 | |
| const SuggestedWorkflowCard = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["__cssModules", cssModules$4]]);
 | |
| const style0$3 = {
 | |
|   "suggested-workflows": "_suggested-workflows_t3ed6_123"
 | |
| };
 | |
| const _sfc_main$3 = {};
 | |
| const _hoisted_1$2 = {
 | |
|   class: "suggested-workflows",
 | |
|   "data-test-id": "suggested-workflows"
 | |
| };
 | |
| function _sfc_render(_ctx, _cache) {
 | |
|   return openBlock(), createElementBlock("div", _hoisted_1$2, [
 | |
|     renderSlot(_ctx.$slots, "default")
 | |
|   ]);
 | |
| }
 | |
| const cssModules$3 = {
 | |
|   "$style": style0$3
 | |
| };
 | |
| const SuggestedWorkflows = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["render", _sfc_render], ["__cssModules", cssModules$3]]);
 | |
| const _sfc_main$2 = /* @__PURE__ */ defineComponent({
 | |
|   __name: "NodeRecommendationCard",
 | |
|   props: {
 | |
|     nodeName: {}
 | |
|   },
 | |
|   setup(__props) {
 | |
|     const props = __props;
 | |
|     const uiStore = useUIStore();
 | |
|     const nodeTypesStore = useNodeTypesStore();
 | |
|     const { trackMinicardClick } = usePersonalizedTemplatesV2Store();
 | |
|     const nodeType = computed(() => nodeTypesStore.getNodeType(props.nodeName));
 | |
|     const openModal = () => {
 | |
|       trackMinicardClick(nodeType.value?.displayName ?? props.nodeName);
 | |
|       uiStore.openModalWithData({
 | |
|         name: EXPERIMENT_TEMPLATE_RECO_V2_KEY,
 | |
|         data: { nodeName: props.nodeName }
 | |
|       });
 | |
|     };
 | |
|     onMounted(async () => {
 | |
|       await nodeTypesStore.loadNodeTypesIfNotLoaded();
 | |
|     });
 | |
|     return (_ctx, _cache) => {
 | |
|       const _component_NodeIcon = NodeIcon;
 | |
|       const _component_N8nText = N8nText;
 | |
|       const _component_N8nCard = N8nCard;
 | |
|       return openBlock(), createElementBlock("div", null, [
 | |
|         createVNode(_component_N8nCard, {
 | |
|           class: normalizeClass(_ctx.$style.nodeCard),
 | |
|           hoverable: "",
 | |
|           onClick: openModal
 | |
|         }, {
 | |
|           default: withCtx(() => [
 | |
|             createBaseVNode("div", {
 | |
|               class: normalizeClass(_ctx.$style.emptyStateCardContent)
 | |
|             }, [
 | |
|               createVNode(_component_NodeIcon, {
 | |
|                 "node-type": nodeType.value,
 | |
|                 class: normalizeClass(_ctx.$style.nodeIcon),
 | |
|                 "stroke-width": 1.5
 | |
|               }, null, 8, ["node-type", "class"]),
 | |
|               createVNode(_component_N8nText, {
 | |
|                 size: "xsmall",
 | |
|                 class: "mt-xs pl-2xs pr-2xs",
 | |
|                 bold: true
 | |
|               }, {
 | |
|                 default: withCtx(() => [
 | |
|                   createTextVNode(toDisplayString(nodeType.value?.displayName), 1)
 | |
|                 ]),
 | |
|                 _: 1
 | |
|               })
 | |
|             ], 2)
 | |
|           ]),
 | |
|           _: 1
 | |
|         }, 8, ["class"])
 | |
|       ]);
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const nodeCard = "_nodeCard_1ub18_123";
 | |
| const nodeIcon = "_nodeIcon_1ub18_133";
 | |
| const emptyStateCardContent$1 = "_emptyStateCardContent_1ub18_137";
 | |
| const style0$2 = {
 | |
|   nodeCard,
 | |
|   nodeIcon,
 | |
|   emptyStateCardContent: emptyStateCardContent$1
 | |
| };
 | |
| const cssModules$2 = {
 | |
|   "$style": style0$2
 | |
| };
 | |
| const NodeRecommendationCard = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__cssModules", cssModules$2]]);
 | |
| const _hoisted_1$1 = {
 | |
|   key: 0,
 | |
|   class: "text-center mt-3xl",
 | |
|   "data-test-id": "list-empty-state"
 | |
| };
 | |
| const _sfc_main$1 = /* @__PURE__ */ defineComponent({
 | |
|   __name: "TemplateRecommendationV2",
 | |
|   setup(__props) {
 | |
|     const templateRecoV2Store = usePersonalizedTemplatesV2Store();
 | |
|     const locale = useI18n();
 | |
|     return (_ctx, _cache) => {
 | |
|       const _component_N8nHeading = N8nHeading;
 | |
|       return unref(templateRecoV2Store).nodes.length ? (openBlock(), createElementBlock("div", _hoisted_1$1, [
 | |
|         createVNode(_component_N8nHeading, {
 | |
|           tag: "h2",
 | |
|           size: "medium",
 | |
|           class: "mb-2xs",
 | |
|           color: "text-light"
 | |
|         }, {
 | |
|           default: withCtx(() => [
 | |
|             createTextVNode(toDisplayString(unref(locale).baseText("workflows.templateRecoV2.exploreTemplates")), 1)
 | |
|           ]),
 | |
|           _: 1
 | |
|         }),
 | |
|         createBaseVNode("div", {
 | |
|           class: normalizeClass(_ctx.$style.nodeCardsContainer)
 | |
|         }, [
 | |
|           (openBlock(true), createElementBlock(Fragment, null, renderList(unref(templateRecoV2Store).nodes, (node) => {
 | |
|             return openBlock(), createBlock(NodeRecommendationCard, {
 | |
|               key: node,
 | |
|               "node-name": node
 | |
|             }, null, 8, ["node-name"]);
 | |
|           }), 128))
 | |
|         ], 2)
 | |
|       ])) : createCommentVNode("", true);
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const nodeCardsContainer = "_nodeCardsContainer_7g2he_123";
 | |
| const style0$1 = {
 | |
|   nodeCardsContainer
 | |
| };
 | |
| const cssModules$1 = {
 | |
|   "$style": style0$1
 | |
| };
 | |
| const TemplateRecommendationV2 = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__cssModules", cssModules$1]]);
 | |
| const _hoisted_1 = { key: 0 };
 | |
| const _hoisted_2 = { key: 0 };
 | |
| const _hoisted_3 = { key: 1 };
 | |
| const _hoisted_4 = { key: 1 };
 | |
| const _hoisted_5 = { key: 1 };
 | |
| const _hoisted_6 = {
 | |
|   class: "text-center mt-s",
 | |
|   "data-test-id": "list-empty-state"
 | |
| };
 | |
| const _hoisted_7 = {
 | |
|   key: 0,
 | |
|   class: "mb-s"
 | |
| };
 | |
| const _hoisted_8 = { class: "mb-s" };
 | |
| const _hoisted_9 = { class: "mb-s" };
 | |
| const SEARCH_DEBOUNCE_TIME = 300;
 | |
| const FILTERS_DEBOUNCE_TIME = 100;
 | |
| const _sfc_main = /* @__PURE__ */ defineComponent({
 | |
|   __name: "WorkflowsView",
 | |
|   setup(__props) {
 | |
|     const StatusFilter = {
 | |
|       ALL: "",
 | |
|       ACTIVE: "active",
 | |
|       DEACTIVATED: "deactivated"
 | |
|     };
 | |
|     const WORKFLOWS_SORT_MAP = {
 | |
|       lastUpdated: "updatedAt:desc",
 | |
|       lastCreated: "createdAt:desc",
 | |
|       nameAsc: "name:asc",
 | |
|       nameDesc: "name:desc"
 | |
|     };
 | |
|     const i18n = useI18n();
 | |
|     const route = useRoute();
 | |
|     const router = useRouter();
 | |
|     const message = useMessage();
 | |
|     const toast = useToast();
 | |
|     const folderHelpers = useFolders();
 | |
|     const sourceControlStore = useSourceControlStore();
 | |
|     const usersStore = useUsersStore();
 | |
|     const workflowsStore = useWorkflowsStore();
 | |
|     const settingsStore = useSettingsStore();
 | |
|     const projectsStore = useProjectsStore();
 | |
|     const telemetry = useTelemetry();
 | |
|     const uiStore = useUIStore();
 | |
|     const tagsStore = useTagsStore();
 | |
|     const foldersStore = useFoldersStore();
 | |
|     const usageStore = useUsageStore();
 | |
|     const insightsStore = useInsightsStore();
 | |
|     const templatesStore = useTemplatesStore();
 | |
|     const aiStarterTemplatesStore = useAITemplatesStarterCollectionStore();
 | |
|     const personalizedTemplatesStore = usePersonalizedTemplatesStore();
 | |
|     const readyToRunWorkflowsStore = useReadyToRunWorkflowsStore();
 | |
|     const personalizedTemplatesV2Store = usePersonalizedTemplatesV2Store();
 | |
|     const documentTitle = useDocumentTitle();
 | |
|     const { callDebounced } = useDebounce();
 | |
|     const projectPages = useProjectPages();
 | |
|     const loading = ref(true);
 | |
|     const breadcrumbsLoading = ref(false);
 | |
|     const filters = ref({
 | |
|       search: "",
 | |
|       homeProject: "",
 | |
|       status: StatusFilter.ALL,
 | |
|       showArchived: false,
 | |
|       tags: []
 | |
|     });
 | |
|     const workflowListEventBus = createEventBus();
 | |
|     const workflowsAndFolders = ref([]);
 | |
|     const easyAICalloutVisible = ref(true);
 | |
|     const currentPage = ref(1);
 | |
|     const pageSize = ref(DEFAULT_WORKFLOW_PAGE_SIZE);
 | |
|     const currentSort = ref("updatedAt:desc");
 | |
|     const currentFolderId = ref(null);
 | |
|     const showCardsBadge = ref(false);
 | |
|     const folderActions = computed(() => [
 | |
|       {
 | |
|         label: i18n.baseText("generic.open"),
 | |
|         value: FOLDER_LIST_ITEM_ACTIONS.OPEN,
 | |
|         disabled: false,
 | |
|         onlyAvailableOn: "card"
 | |
|       },
 | |
|       {
 | |
|         label: i18n.baseText("folders.actions.create"),
 | |
|         value: FOLDER_LIST_ITEM_ACTIONS.CREATE,
 | |
|         disabled: readOnlyEnv.value || !hasPermissionToCreateFolders.value
 | |
|       },
 | |
|       {
 | |
|         label: i18n.baseText("folders.actions.create.workflow"),
 | |
|         value: FOLDER_LIST_ITEM_ACTIONS.CREATE_WORKFLOW,
 | |
|         disabled: readOnlyEnv.value || !hasPermissionToCreateWorkflows.value
 | |
|       },
 | |
|       {
 | |
|         label: i18n.baseText("generic.rename"),
 | |
|         value: FOLDER_LIST_ITEM_ACTIONS.RENAME,
 | |
|         disabled: readOnlyEnv.value || !hasPermissionToUpdateFolders.value
 | |
|       },
 | |
|       {
 | |
|         label: i18n.baseText("folders.actions.moveToFolder"),
 | |
|         value: FOLDER_LIST_ITEM_ACTIONS.MOVE,
 | |
|         disabled: readOnlyEnv.value || !hasPermissionToUpdateFolders.value
 | |
|       },
 | |
|       {
 | |
|         label: i18n.baseText("generic.delete"),
 | |
|         value: FOLDER_LIST_ITEM_ACTIONS.DELETE,
 | |
|         disabled: readOnlyEnv.value || !hasPermissionToDeleteFolders.value
 | |
|       }
 | |
|     ]);
 | |
|     const folderCardActions = computed(
 | |
|       () => folderActions.value.filter(
 | |
|         (action) => !action.onlyAvailableOn || action.onlyAvailableOn === "card"
 | |
|       )
 | |
|     );
 | |
|     const mainBreadcrumbsActions = computed(
 | |
|       () => folderActions.value.filter(
 | |
|         (action) => !action.onlyAvailableOn || action.onlyAvailableOn === "mainBreadcrumbs"
 | |
|       )
 | |
|     );
 | |
|     const readOnlyEnv = computed(() => sourceControlStore.preferences.branchReadOnly);
 | |
|     const currentUser = computed(() => usersStore.currentUser ?? {});
 | |
|     const isShareable = computed(
 | |
|       () => settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Sharing]
 | |
|     );
 | |
|     const foldersEnabled = computed(() => {
 | |
|       return settingsStore.isFoldersFeatureEnabled;
 | |
|     });
 | |
|     const teamProjectsEnabled = computed(() => {
 | |
|       return projectsStore.isTeamProjectFeatureEnabled;
 | |
|     });
 | |
|     const showFolders = computed(() => {
 | |
|       return foldersEnabled.value && !projectPages.isOverviewSubPage && !projectPages.isSharedSubPage;
 | |
|     });
 | |
|     const currentFolder = computed(() => {
 | |
|       return currentFolderId.value ? foldersStore.breadcrumbsCache[currentFolderId.value] : null;
 | |
|     });
 | |
|     const currentFolderParent = computed(() => {
 | |
|       return currentFolder.value?.parentFolder ? foldersStore.breadcrumbsCache[currentFolder.value.parentFolder] : null;
 | |
|     });
 | |
|     const isDragging = computed(() => {
 | |
|       return foldersStore.draggedElement !== null;
 | |
|     });
 | |
|     const isDragNDropEnabled = computed(() => {
 | |
|       return !readOnlyEnv.value && hasPermissionToUpdateFolders.value;
 | |
|     });
 | |
|     const hasPermissionToCreateFolders = computed(() => {
 | |
|       if (!currentProject.value) return false;
 | |
|       return getResourcePermissions(currentProject.value.scopes).folder.create === true;
 | |
|     });
 | |
|     const hasPermissionToUpdateFolders = computed(() => {
 | |
|       if (!currentProject.value) return false;
 | |
|       return getResourcePermissions(currentProject.value.scopes).folder.update === true;
 | |
|     });
 | |
|     const hasPermissionToDeleteFolders = computed(() => {
 | |
|       if (!currentProject.value) return false;
 | |
|       return getResourcePermissions(currentProject.value.scopes).folder.delete === true;
 | |
|     });
 | |
|     const hasPermissionToCreateWorkflows = computed(() => {
 | |
|       if (!currentProject.value) return false;
 | |
|       return getResourcePermissions(currentProject.value.scopes).workflow.create === true;
 | |
|     });
 | |
|     const currentProject = computed(() => projectsStore.currentProject);
 | |
|     const projectName = computed(() => {
 | |
|       if (currentProject.value?.type === ProjectTypes.Personal) {
 | |
|         return i18n.baseText("projects.menu.personal");
 | |
|       }
 | |
|       return currentProject.value?.name;
 | |
|     });
 | |
|     const currentParentName = computed(() => {
 | |
|       if (currentFolder.value) {
 | |
|         return currentFolder.value.name;
 | |
|       }
 | |
|       return projectName.value;
 | |
|     });
 | |
|     const personalProject = computed(() => {
 | |
|       return projectsStore.personalProject;
 | |
|     });
 | |
|     const workflowListResources = computed(() => {
 | |
|       const resources = (workflowsAndFolders.value || []).map((resource) => {
 | |
|         if (resource.resource === "folder") {
 | |
|           return {
 | |
|             resourceType: "folder",
 | |
|             id: resource.id,
 | |
|             name: resource.name,
 | |
|             createdAt: resource.createdAt.toString(),
 | |
|             updatedAt: resource.updatedAt.toString(),
 | |
|             homeProject: resource.homeProject,
 | |
|             workflowCount: resource.workflowCount,
 | |
|             subFolderCount: resource.subFolderCount,
 | |
|             parentFolder: resource.parentFolder
 | |
|           };
 | |
|         } else {
 | |
|           return {
 | |
|             resourceType: "workflow",
 | |
|             id: resource.id,
 | |
|             name: resource.name,
 | |
|             active: resource.active ?? false,
 | |
|             isArchived: resource.isArchived,
 | |
|             updatedAt: resource.updatedAt.toString(),
 | |
|             createdAt: resource.createdAt.toString(),
 | |
|             homeProject: resource.homeProject,
 | |
|             scopes: resource.scopes,
 | |
|             sharedWithProjects: resource.sharedWithProjects,
 | |
|             readOnly: !getResourcePermissions(resource.scopes).workflow.update,
 | |
|             tags: resource.tags,
 | |
|             parentFolder: resource.parentFolder
 | |
|           };
 | |
|         }
 | |
|       });
 | |
|       return resources;
 | |
|     });
 | |
|     const statusFilterOptions = computed(() => [
 | |
|       {
 | |
|         label: i18n.baseText("workflows.filters.status.all"),
 | |
|         value: StatusFilter.ALL
 | |
|       },
 | |
|       {
 | |
|         label: i18n.baseText("workflows.filters.status.active"),
 | |
|         value: StatusFilter.ACTIVE
 | |
|       },
 | |
|       {
 | |
|         label: i18n.baseText("workflows.filters.status.deactivated"),
 | |
|         value: StatusFilter.DEACTIVATED
 | |
|       }
 | |
|     ]);
 | |
|     const showEasyAIWorkflowCallout = computed(() => {
 | |
|       const easyAIWorkflowOnboardingDone = usersStore.isEasyAIWorkflowOnboardingDone;
 | |
|       return !easyAIWorkflowOnboardingDone;
 | |
|     });
 | |
|     const templatesCardEnabled = computed(() => {
 | |
|       return isExtraTemplateLinksExperimentEnabled() && settingsStore.isTemplatesEnabled;
 | |
|     });
 | |
|     const projectPermissions = computed(() => {
 | |
|       return getResourcePermissions(
 | |
|         projectsStore.currentProject?.scopes ?? personalProject.value?.scopes
 | |
|       );
 | |
|     });
 | |
|     const showReadyToRunWorkflowsCallout = computed(() => {
 | |
|       const isEnabled = readyToRunWorkflowsStore.isFeatureEnabled;
 | |
|       const isDismissed = readyToRunWorkflowsStore.isCalloutDismissed;
 | |
|       return isEnabled && !isDismissed && !loading.value && !readOnlyEnv.value && (projectPages.isOverviewSubPage || hasPermissionToCreateFolders.value && hasPermissionToCreateWorkflows.value);
 | |
|     });
 | |
|     const emptyListDescription = computed(() => {
 | |
|       if (readOnlyEnv.value) {
 | |
|         return i18n.baseText("workflows.empty.description.readOnlyEnv");
 | |
|       } else if (!projectPermissions.value.workflow.create) {
 | |
|         return i18n.baseText("workflows.empty.description.noPermission");
 | |
|       } else {
 | |
|         return i18n.baseText("workflows.empty.description");
 | |
|       }
 | |
|     });
 | |
|     const hasFilters = computed(() => {
 | |
|       return !!(filters.value.search || filters.value.status !== StatusFilter.ALL || filters.value.showArchived || filters.value.tags.length);
 | |
|     });
 | |
|     const showArchivedOnlyHint = computed(() => {
 | |
|       return workflowsAndFolders.value.length === 0 && !hasFilters.value && !filters.value.showArchived && foldersStore.totalWorkflowCount > 0;
 | |
|     });
 | |
|     const isSelfHostedDeployment = computed(() => settingsStore.deploymentType === "default");
 | |
|     const canUserRegisterCommunityPlus = computed(
 | |
|       () => getResourcePermissions(usersStore.currentUser?.globalScopes).community.register
 | |
|     );
 | |
|     const showRegisteredCommunityCTA = computed(
 | |
|       () => isSelfHostedDeployment.value && !foldersEnabled.value && canUserRegisterCommunityPlus.value
 | |
|     );
 | |
|     const showAIStarterCollectionCallout = computed(() => {
 | |
|       return !loading.value && aiStarterTemplatesStore.isFeatureEnabled && !aiStarterTemplatesStore.calloutDismissed && !readOnlyEnv.value && // We want to show the callout only if the user has permissions to create folders and workflows
 | |
|       // but also on the overview page
 | |
|       (projectPages.isOverviewSubPage || hasPermissionToCreateFolders.value && hasPermissionToCreateWorkflows.value);
 | |
|     });
 | |
|     const showPersonalizedTemplates = computed(
 | |
|       () => !loading.value && personalizedTemplatesStore.isFeatureEnabled()
 | |
|     );
 | |
|     watch([() => route.params?.projectId, () => route.name], async () => {
 | |
|       loading.value = true;
 | |
|     });
 | |
|     watch(
 | |
|       () => route.params?.folderId,
 | |
|       async (newVal) => {
 | |
|         currentFolderId.value = newVal;
 | |
|         filters.value.search = "";
 | |
|         saveFiltersOnQueryString();
 | |
|         await fetchWorkflows();
 | |
|       }
 | |
|     );
 | |
|     sourceControlStore.$onAction(({ name: name2, after }) => {
 | |
|       if (name2 !== "pullWorkfolder") return;
 | |
|       after(async () => await initialize());
 | |
|     });
 | |
|     const refreshWorkflows = async () => {
 | |
|       await Promise.all([
 | |
|         fetchWorkflows(),
 | |
|         foldersStore.fetchTotalWorkflowsAndFoldersCount(route.params.projectId)
 | |
|       ]);
 | |
|     };
 | |
|     const onFolderDeleted = async (payload) => {
 | |
|       const folderInfo = foldersStore.getCachedFolder(payload.folderId);
 | |
|       foldersStore.deleteFoldersFromCache([payload.folderId, folderInfo?.parentFolder ?? ""]);
 | |
|       await foldersStore.fetchTotalWorkflowsAndFoldersCount(
 | |
|         route.params.projectId
 | |
|       );
 | |
|       if (currentFolderId.value === payload.folderId) {
 | |
|         void router.push({
 | |
|           name: VIEWS.PROJECTS_FOLDERS,
 | |
|           params: { projectId: route.params.projectId, folderId: folderInfo?.parentFolder ?? "" }
 | |
|         });
 | |
|       } else {
 | |
|         await fetchWorkflows();
 | |
|       }
 | |
|       telemetry.track("User deleted folder", {
 | |
|         folder_id: payload.folderId,
 | |
|         deleted_sub_folders: payload.folderCount,
 | |
|         deleted_sub_workflows: payload.workflowCount
 | |
|       });
 | |
|     };
 | |
|     const showInsights = computed(() => {
 | |
|       return projectPages.isOverviewSubPage && insightsStore.isSummaryEnabled && (!personalizedTemplatesV2Store.isFeatureEnabled() || workflowListResources.value.length > 0);
 | |
|     });
 | |
|     const showTemplateRecommendationV2 = computed(() => {
 | |
|       return personalizedTemplatesV2Store.isFeatureEnabled() && !loading.value;
 | |
|     });
 | |
|     onMounted(async () => {
 | |
|       documentTitle.set(i18n.baseText("workflows.heading"));
 | |
|       void usersStore.showPersonalizationSurvey();
 | |
|       workflowListEventBus.on("resource-moved", fetchWorkflows);
 | |
|       workflowListEventBus.on("workflow-duplicated", fetchWorkflows);
 | |
|       workflowListEventBus.on("folder-deleted", onFolderDeleted);
 | |
|       workflowListEventBus.on("folder-moved", moveFolder);
 | |
|       workflowListEventBus.on("folder-transferred", onFolderTransferred);
 | |
|       workflowListEventBus.on("workflow-moved", onWorkflowMoved);
 | |
|       workflowListEventBus.on("workflow-transferred", onWorkflowTransferred);
 | |
|     });
 | |
|     onBeforeUnmount(() => {
 | |
|       workflowListEventBus.off("resource-moved", fetchWorkflows);
 | |
|       workflowListEventBus.off("workflow-duplicated", fetchWorkflows);
 | |
|       workflowListEventBus.off("folder-deleted", onFolderDeleted);
 | |
|       workflowListEventBus.off("folder-moved", moveFolder);
 | |
|       workflowListEventBus.off("folder-transferred", onFolderTransferred);
 | |
|       workflowListEventBus.off("workflow-moved", onWorkflowMoved);
 | |
|       workflowListEventBus.off("workflow-transferred", onWorkflowTransferred);
 | |
|     });
 | |
|     const initialize = async () => {
 | |
|       loading.value = true;
 | |
|       await setFiltersFromQueryString();
 | |
|       currentFolderId.value = route.params.folderId;
 | |
|       const [, resourcesPage] = await Promise.all([
 | |
|         usersStore.fetchUsers(),
 | |
|         fetchWorkflows(),
 | |
|         workflowsStore.fetchActiveWorkflows(),
 | |
|         usageStore.getLicenseInfo(),
 | |
|         foldersStore.fetchTotalWorkflowsAndFoldersCount(route.params.projectId)
 | |
|       ]);
 | |
|       breadcrumbsLoading.value = false;
 | |
|       workflowsAndFolders.value = resourcesPage;
 | |
|       loading.value = false;
 | |
|     };
 | |
|     const fetchWorkflows = async () => {
 | |
|       const delayedLoading = debounce(() => {
 | |
|         loading.value = true;
 | |
|       }, 300);
 | |
|       const routeProjectId = route.params?.projectId;
 | |
|       const homeProjectFilter = filters.value.homeProject || void 0;
 | |
|       const parentFolder = route.params?.folderId || void 0;
 | |
|       const tags = filters.value.tags.length ? filters.value.tags.map((tagId) => tagsStore.tagsById[tagId]?.name) : [];
 | |
|       const activeFilter = filters.value.status === StatusFilter.ALL ? void 0 : filters.value.status === StatusFilter.ACTIVE;
 | |
|       const archivedFilter = filters.value.showArchived ? void 0 : false;
 | |
|       const fetchFolders = showFolders.value && !tags.length && activeFilter === void 0;
 | |
|       try {
 | |
|         const fetchedResources = await workflowsStore.fetchWorkflowsPage(
 | |
|           routeProjectId ?? homeProjectFilter,
 | |
|           currentPage.value,
 | |
|           pageSize.value,
 | |
|           currentSort.value,
 | |
|           {
 | |
|             name: filters.value.search || void 0,
 | |
|             active: activeFilter,
 | |
|             isArchived: archivedFilter,
 | |
|             tags: tags.length ? tags : void 0,
 | |
|             parentFolderId: getParentFolderId(parentFolder)
 | |
|           },
 | |
|           fetchFolders,
 | |
|           projectPages.isSharedSubPage
 | |
|         );
 | |
|         foldersStore.cacheFolders(
 | |
|           fetchedResources.filter((resource) => resource.resource === "folder").map((r) => ({ id: r.id, name: r.name, parentFolder: r.parentFolder?.id }))
 | |
|         );
 | |
|         const isCurrentFolderCached = foldersStore.breadcrumbsCache[parentFolder ?? ""] !== void 0;
 | |
|         const needToFetchFolderPath = parentFolder && !isCurrentFolderCached && routeProjectId;
 | |
|         if (needToFetchFolderPath) {
 | |
|           breadcrumbsLoading.value = true;
 | |
|           await foldersStore.getFolderPath(routeProjectId, parentFolder);
 | |
|           breadcrumbsLoading.value = false;
 | |
|         }
 | |
|         workflowsAndFolders.value = fetchedResources;
 | |
|         showCardsBadge.value = projectPages.isOverviewSubPage || projectPages.isSharedSubPage || filters.value.search !== "";
 | |
|         return fetchedResources;
 | |
|       } catch (error) {
 | |
|         toast.showError(error, i18n.baseText("workflows.list.error.fetching"));
 | |
|         void router.push({ name: VIEWS.PROJECTS_FOLDERS, params: { projectId: routeProjectId } });
 | |
|         return [];
 | |
|       } finally {
 | |
|         delayedLoading.cancel();
 | |
|         loading.value = false;
 | |
|         if (breadcrumbsLoading.value) {
 | |
|           breadcrumbsLoading.value = false;
 | |
|         }
 | |
|       }
 | |
|     };
 | |
|     const getParentFolderId = (routeId) => {
 | |
|       if (routeId !== null && routeId !== void 0) {
 | |
|         return routeId;
 | |
|       }
 | |
|       if (projectPages.isOverviewSubPage || projectPages.isSharedSubPage || filters?.value.search) {
 | |
|         return void 0;
 | |
|       }
 | |
|       return PROJECT_ROOT;
 | |
|     };
 | |
|     const onFiltersUpdated = async () => {
 | |
|       currentPage.value = 1;
 | |
|       saveFiltersOnQueryString();
 | |
|       if (!loading.value) {
 | |
|         await callDebounced(fetchWorkflows, { debounceTime: FILTERS_DEBOUNCE_TIME, trailing: true });
 | |
|       }
 | |
|     };
 | |
|     const onSearchUpdated = async (search) => {
 | |
|       currentPage.value = 1;
 | |
|       saveFiltersOnQueryString();
 | |
|       if (search) {
 | |
|         await callDebounced(fetchWorkflows, { debounceTime: SEARCH_DEBOUNCE_TIME, trailing: true });
 | |
|       } else {
 | |
|         await fetchWorkflows();
 | |
|       }
 | |
|     };
 | |
|     const setPaginationAndSort = async (payload) => {
 | |
|       if (payload.page) {
 | |
|         currentPage.value = payload.page;
 | |
|       }
 | |
|       if (payload.pageSize) {
 | |
|         pageSize.value = payload.pageSize;
 | |
|       }
 | |
|       if (payload.sort) {
 | |
|         currentSort.value = WORKFLOWS_SORT_MAP[payload.sort] ?? "updatedAt:desc";
 | |
|       }
 | |
|       if (!loading.value) {
 | |
|         await callDebounced(fetchWorkflows, { debounceTime: FILTERS_DEBOUNCE_TIME, trailing: true });
 | |
|       }
 | |
|     };
 | |
|     const onClickTag = async (tagId) => {
 | |
|       if (!filters.value.tags.includes(tagId)) {
 | |
|         filters.value.tags.push(tagId);
 | |
|         currentPage.value = 1;
 | |
|         saveFiltersOnQueryString();
 | |
|         await fetchWorkflows();
 | |
|       }
 | |
|     };
 | |
|     const saveFiltersOnQueryString = () => {
 | |
|       const currentQuery = { ...route.query };
 | |
|       if (filters.value.search) {
 | |
|         currentQuery.search = filters.value.search;
 | |
|       } else {
 | |
|         delete currentQuery.search;
 | |
|       }
 | |
|       if (filters.value.status !== StatusFilter.ALL) {
 | |
|         currentQuery.status = (filters.value.status === StatusFilter.ACTIVE).toString();
 | |
|       } else {
 | |
|         delete currentQuery.status;
 | |
|       }
 | |
|       if (filters.value.showArchived) {
 | |
|         currentQuery.showArchived = "true";
 | |
|       } else {
 | |
|         delete currentQuery.showArchived;
 | |
|       }
 | |
|       if (filters.value.tags.length) {
 | |
|         currentQuery.tags = filters.value.tags.join(",");
 | |
|       } else {
 | |
|         delete currentQuery.tags;
 | |
|       }
 | |
|       if (filters.value.homeProject) {
 | |
|         currentQuery.homeProject = filters.value.homeProject;
 | |
|       } else {
 | |
|         delete currentQuery.homeProject;
 | |
|       }
 | |
|       void router.replace({
 | |
|         query: Object.keys(currentQuery).length ? currentQuery : void 0
 | |
|       });
 | |
|     };
 | |
|     const setFiltersFromQueryString = async () => {
 | |
|       const newQuery = { ...route.query };
 | |
|       const { tags, status, search, homeProject, sort, showArchived } = route.query ?? {};
 | |
|       const isValidString = (value) => typeof value === "string" && value.trim().length > 0;
 | |
|       if (isValidString(homeProject)) {
 | |
|         await projectsStore.getAvailableProjects();
 | |
|         if (isValidProjectId(homeProject)) {
 | |
|           newQuery.homeProject = homeProject;
 | |
|           filters.value.homeProject = homeProject;
 | |
|         } else {
 | |
|           delete newQuery.homeProject;
 | |
|         }
 | |
|       } else {
 | |
|         delete newQuery.homeProject;
 | |
|       }
 | |
|       if (isValidString(search)) {
 | |
|         newQuery.search = search;
 | |
|         filters.value.search = search;
 | |
|       } else {
 | |
|         delete newQuery.search;
 | |
|       }
 | |
|       if (isValidString(tags)) {
 | |
|         await tagsStore.fetchAll();
 | |
|         const validTags = tags.split(",").filter((tag) => tagsStore.allTags.map((t) => t.id).includes(tag));
 | |
|         if (validTags.length) {
 | |
|           newQuery.tags = validTags.join(",");
 | |
|           filters.value.tags = validTags;
 | |
|         } else {
 | |
|           delete newQuery.tags;
 | |
|         }
 | |
|       } else {
 | |
|         delete newQuery.tags;
 | |
|       }
 | |
|       if (isValidString(status)) {
 | |
|         newQuery.status = status;
 | |
|         filters.value.status = status === "true" ? StatusFilter.ACTIVE : StatusFilter.DEACTIVATED;
 | |
|       } else {
 | |
|         delete newQuery.status;
 | |
|       }
 | |
|       if (isValidString(sort)) {
 | |
|         const newSort = WORKFLOWS_SORT_MAP[sort] ?? "updatedAt:desc";
 | |
|         newQuery.sort = sort;
 | |
|         currentSort.value = newSort;
 | |
|       } else {
 | |
|         delete newQuery.sort;
 | |
|       }
 | |
|       if (isValidString(showArchived)) {
 | |
|         newQuery.showArchived = showArchived;
 | |
|         filters.value.showArchived = showArchived === "true";
 | |
|       } else {
 | |
|         delete newQuery.showArchived;
 | |
|         filters.value.showArchived = false;
 | |
|       }
 | |
|       void router.replace({ query: newQuery });
 | |
|     };
 | |
|     const addWorkflow = () => {
 | |
|       uiStore.nodeViewInitialized = false;
 | |
|       void router.push({
 | |
|         name: VIEWS.NEW_WORKFLOW,
 | |
|         query: { projectId: route.params?.projectId, parentFolderId: route.params?.folderId }
 | |
|       });
 | |
|       telemetry.track("User clicked add workflow button", {
 | |
|         source: "Workflows list"
 | |
|       });
 | |
|       trackEmptyCardClick("blank");
 | |
|     };
 | |
|     const openTemplatesRepository = async () => {
 | |
|       trackTemplatesClick(TemplateClickSource.emptyInstanceCard);
 | |
|       if (templatesStore.hasCustomTemplatesHost) {
 | |
|         await router.push({ name: VIEWS.TEMPLATES });
 | |
|         return;
 | |
|       }
 | |
|       window.open(templatesStore.websiteTemplateRepositoryURL, "_blank");
 | |
|     };
 | |
|     const trackEmptyCardClick = (option) => {
 | |
|       telemetry.track("User clicked empty page option", {
 | |
|         option
 | |
|       });
 | |
|     };
 | |
|     function isValidProjectId(projectId) {
 | |
|       return projectsStore.availableProjects.some((project) => project.id === projectId);
 | |
|     }
 | |
|     const createAIStarterWorkflows = async (source) => {
 | |
|       try {
 | |
|         const projectId = projectPages.isOverviewSubPage ? personalProject.value?.id : route.params.projectId;
 | |
|         if (typeof projectId !== "string") {
 | |
|           toast.showError(new Error(), i18n.baseText("workflows.ai.starter.collection.error"));
 | |
|           return;
 | |
|         }
 | |
|         const newFolder = await aiStarterTemplatesStore.createStarterWorkflows(
 | |
|           projectId,
 | |
|           currentFolderId.value ?? void 0
 | |
|         );
 | |
|         if (projectPages.isOverviewSubPage) {
 | |
|           await router.push({
 | |
|             name: VIEWS.PROJECTS_FOLDERS,
 | |
|             params: { projectId, folderId: newFolder.id }
 | |
|           });
 | |
|         } else {
 | |
|           workflowsAndFolders.value.unshift({
 | |
|             id: newFolder.id,
 | |
|             name: newFolder.name,
 | |
|             resource: "folder",
 | |
|             createdAt: newFolder.createdAt,
 | |
|             updatedAt: newFolder.updatedAt,
 | |
|             subFolderCount: 0,
 | |
|             workflowCount: 3,
 | |
|             parentFolder: newFolder.parentFolder
 | |
|           });
 | |
|         }
 | |
|         aiStarterTemplatesStore.trackUserCreatedStarterCollection(source);
 | |
|       } catch (error) {
 | |
|         toast.showError(error, i18n.baseText("workflows.ai.starter.collection.error"));
 | |
|         return;
 | |
|       }
 | |
|     };
 | |
|     const handleCreateReadyToRunWorkflows = async (source) => {
 | |
|       try {
 | |
|         const projectId = projectPages.isOverviewSubPage ? personalProject.value?.id : route.params.projectId;
 | |
|         if (typeof projectId !== "string") {
 | |
|           toast.showError(new Error(), i18n.baseText("workflows.readyToRunWorkflows.error"));
 | |
|           return;
 | |
|         }
 | |
|         const newFolder = await readyToRunWorkflowsStore.createWorkflows(
 | |
|           projectId,
 | |
|           currentFolderId.value ?? void 0
 | |
|         );
 | |
|         readyToRunWorkflowsStore.trackCreateWorkflows(source);
 | |
|         if (projectPages.isOverviewSubPage) {
 | |
|           await router.push({
 | |
|             name: VIEWS.PROJECTS_FOLDERS,
 | |
|             params: { projectId, folderId: newFolder.id }
 | |
|           });
 | |
|         } else {
 | |
|           workflowsAndFolders.value.unshift({
 | |
|             id: newFolder.id,
 | |
|             name: newFolder.name,
 | |
|             resource: "folder",
 | |
|             createdAt: newFolder.createdAt,
 | |
|             updatedAt: newFolder.updatedAt,
 | |
|             subFolderCount: 0,
 | |
|             workflowCount: 4,
 | |
|             parentFolder: newFolder.parentFolder
 | |
|           });
 | |
|         }
 | |
|       } catch (error) {
 | |
|         toast.showError(error, i18n.baseText("workflows.readyToRunWorkflows.error"));
 | |
|         return;
 | |
|       }
 | |
|     };
 | |
|     const dismissStarterCollectionCallout = () => {
 | |
|       aiStarterTemplatesStore.dismissCallout();
 | |
|       aiStarterTemplatesStore.trackUserDismissedCallout();
 | |
|     };
 | |
|     const dismissEasyAICallout = () => {
 | |
|       easyAICalloutVisible.value = false;
 | |
|     };
 | |
|     const openAIWorkflow = async (source) => {
 | |
|       dismissEasyAICallout();
 | |
|       telemetry.track("User clicked test AI workflow", {
 | |
|         source
 | |
|       });
 | |
|       const easyAiWorkflowJson = getEasyAiWorkflowJson();
 | |
|       await router.push({
 | |
|         name: VIEWS.TEMPLATE_IMPORT,
 | |
|         params: { id: easyAiWorkflowJson.meta.templateId },
 | |
|         query: { fromJson: "true", parentFolderId: route.params.folderId }
 | |
|       });
 | |
|     };
 | |
|     const onShowArchived = async () => {
 | |
|       filters.value.showArchived = true;
 | |
|       await onFiltersUpdated();
 | |
|     };
 | |
|     const handleDismissReadyToRunCallout = () => {
 | |
|       readyToRunWorkflowsStore.dismissCallout();
 | |
|       readyToRunWorkflowsStore.trackDismissCallout();
 | |
|     };
 | |
|     const onWorkflowActiveToggle = (data) => {
 | |
|       const workflow = workflowsAndFolders.value.find(
 | |
|         (w) => w.id === data.id
 | |
|       );
 | |
|       if (!workflow) return;
 | |
|       workflow.active = data.active;
 | |
|     };
 | |
|     const getFolderListItem = (folderId) => {
 | |
|       return workflowsAndFolders.value.find(
 | |
|         (resource) => resource.resource === "folder" && resource.id === folderId
 | |
|       );
 | |
|     };
 | |
|     const getFolderContent = async (folderId) => {
 | |
|       const folderListItem = getFolderListItem(folderId);
 | |
|       if (folderListItem) {
 | |
|         return {
 | |
|           workflowCount: folderListItem.workflowCount,
 | |
|           subFolderCount: folderListItem.subFolderCount
 | |
|         };
 | |
|       }
 | |
|       try {
 | |
|         const content = await foldersStore.fetchFolderContent(currentProject.value?.id ?? "", folderId);
 | |
|         return { workflowCount: content.totalWorkflows, subFolderCount: content.totalSubFolders };
 | |
|       } catch (error) {
 | |
|         toast.showMessage({
 | |
|           title: i18n.baseText("folders.delete.error.message"),
 | |
|           message: i18n.baseText("folders.not.found.message"),
 | |
|           type: "error"
 | |
|         });
 | |
|         return { workflowCount: 0, subFolderCount: 0 };
 | |
|       }
 | |
|     };
 | |
|     const onFolderCardDrop = async (event) => {
 | |
|       const { draggedResource, dropTarget } = folderHelpers.handleDrop(event);
 | |
|       if (!draggedResource || !dropTarget) return;
 | |
|       await moveResourceOnDrop(draggedResource, dropTarget);
 | |
|     };
 | |
|     const onBreadCrumbsItemDrop = async (item) => {
 | |
|       if (!foldersStore.draggedElement) return;
 | |
|       await moveResourceOnDrop(
 | |
|         {
 | |
|           id: foldersStore.draggedElement.id,
 | |
|           type: foldersStore.draggedElement.type,
 | |
|           name: foldersStore.draggedElement.name
 | |
|         },
 | |
|         {
 | |
|           id: item.id,
 | |
|           type: "folder",
 | |
|           name: item.label
 | |
|         }
 | |
|       );
 | |
|       folderHelpers.onDragEnd();
 | |
|     };
 | |
|     const moveFolderToProjectRoot = async (id, name2) => {
 | |
|       if (!foldersStore.draggedElement) return;
 | |
|       await moveResourceOnDrop(
 | |
|         {
 | |
|           id: foldersStore.draggedElement.id,
 | |
|           type: foldersStore.draggedElement.type,
 | |
|           name: foldersStore.draggedElement.name
 | |
|         },
 | |
|         {
 | |
|           id,
 | |
|           type: "project",
 | |
|           name: name2
 | |
|         }
 | |
|       );
 | |
|       folderHelpers.onDragEnd();
 | |
|     };
 | |
|     const moveResourceOnDrop = async (draggedResource, dropTarget) => {
 | |
|       if (draggedResource.type === "folder") {
 | |
|         await moveFolder({
 | |
|           folder: { id: draggedResource.id, name: draggedResource.name },
 | |
|           newParent: { id: dropTarget.id, name: dropTarget.name, type: dropTarget.type },
 | |
|           options: { skipFetch: true, skipNavigation: true }
 | |
|         });
 | |
|         workflowsAndFolders.value = workflowsAndFolders.value.filter(
 | |
|           (folder) => folder.id !== draggedResource.id
 | |
|         );
 | |
|         const targetFolder = getFolderListItem(dropTarget.id);
 | |
|         if (targetFolder) {
 | |
|           targetFolder.subFolderCount += 1;
 | |
|         }
 | |
|       } else if (draggedResource.type === "workflow") {
 | |
|         await onWorkflowMoved({
 | |
|           workflow: {
 | |
|             id: draggedResource.id,
 | |
|             name: draggedResource.name,
 | |
|             oldParentId: currentFolderId.value ?? ""
 | |
|           },
 | |
|           newParent: { id: dropTarget.id, name: dropTarget.name, type: dropTarget.type },
 | |
|           options: { skipFetch: true }
 | |
|         });
 | |
|         workflowsAndFolders.value = workflowsAndFolders.value.filter(
 | |
|           (workflow) => workflow.id !== draggedResource.id
 | |
|         );
 | |
|         const targetFolder = getFolderListItem(dropTarget.id);
 | |
|         if (targetFolder) {
 | |
|           targetFolder.workflowCount += 1;
 | |
|         }
 | |
|       }
 | |
|     };
 | |
|     const onBreadcrumbItemClick = (item) => {
 | |
|       if (item.href) {
 | |
|         loading.value = true;
 | |
|         void router.push(item.href).then(() => {
 | |
|           currentFolderId.value = item.id;
 | |
|           loading.value = false;
 | |
|         }).catch((error) => {
 | |
|           toast.showError(error, i18n.baseText("folders.open.error.title"));
 | |
|         });
 | |
|       }
 | |
|     };
 | |
|     const onBreadCrumbsAction = async (action) => {
 | |
|       switch (action) {
 | |
|         case FOLDER_LIST_ITEM_ACTIONS.CREATE:
 | |
|           if (!route.params.projectId) return;
 | |
|           const currentParent = currentFolder.value?.name || projectName.value;
 | |
|           if (!currentParent) return;
 | |
|           await createFolder({
 | |
|             id: route.params.folderId ?? "-1",
 | |
|             name: currentParent,
 | |
|             type: currentFolder.value ? "folder" : "project"
 | |
|           });
 | |
|           break;
 | |
|         case FOLDER_LIST_ITEM_ACTIONS.CREATE_WORKFLOW:
 | |
|           addWorkflow();
 | |
|           break;
 | |
|         case FOLDER_LIST_ITEM_ACTIONS.DELETE:
 | |
|           if (!route.params.folderId) return;
 | |
|           const content = await getFolderContent(route.params.folderId);
 | |
|           await deleteFolder(
 | |
|             route.params.folderId,
 | |
|             content.workflowCount,
 | |
|             content.subFolderCount
 | |
|           );
 | |
|           break;
 | |
|         case FOLDER_LIST_ITEM_ACTIONS.RENAME:
 | |
|           onNameToggle();
 | |
|           break;
 | |
|         case FOLDER_LIST_ITEM_ACTIONS.MOVE:
 | |
|           if (!currentFolder.value) return;
 | |
|           uiStore.openMoveToFolderModal(
 | |
|             "folder",
 | |
|             {
 | |
|               id: currentFolder.value?.id,
 | |
|               name: currentFolder.value?.name,
 | |
|               parentFolderId: currentFolder.value?.parentFolder
 | |
|             },
 | |
|             workflowListEventBus
 | |
|           );
 | |
|           break;
 | |
|       }
 | |
|     };
 | |
|     const onFolderCardAction = async (payload) => {
 | |
|       const clickedFolder = foldersStore.getCachedFolder(payload.folderId);
 | |
|       if (!clickedFolder) return;
 | |
|       switch (payload.action) {
 | |
|         case FOLDER_LIST_ITEM_ACTIONS.CREATE:
 | |
|           await createFolder(
 | |
|             {
 | |
|               id: clickedFolder.id,
 | |
|               name: clickedFolder.name,
 | |
|               type: "folder"
 | |
|             },
 | |
|             { openAfterCreate: true }
 | |
|           );
 | |
|           break;
 | |
|         case FOLDER_LIST_ITEM_ACTIONS.CREATE_WORKFLOW:
 | |
|           currentFolderId.value = clickedFolder.id;
 | |
|           void router.push({
 | |
|             name: VIEWS.NEW_WORKFLOW,
 | |
|             query: { projectId: route.params?.projectId, parentFolderId: clickedFolder.id }
 | |
|           });
 | |
|           break;
 | |
|         case FOLDER_LIST_ITEM_ACTIONS.DELETE: {
 | |
|           const content = await getFolderContent(clickedFolder.id);
 | |
|           await deleteFolder(clickedFolder.id, content.workflowCount, content.subFolderCount);
 | |
|           break;
 | |
|         }
 | |
|         case FOLDER_LIST_ITEM_ACTIONS.RENAME:
 | |
|           await renameFolder(clickedFolder.id);
 | |
|           break;
 | |
|         case FOLDER_LIST_ITEM_ACTIONS.MOVE:
 | |
|           uiStore.openMoveToFolderModal(
 | |
|             "folder",
 | |
|             {
 | |
|               id: clickedFolder.id,
 | |
|               name: clickedFolder.name,
 | |
|               parentFolderId: clickedFolder.parentFolder
 | |
|             },
 | |
|             workflowListEventBus
 | |
|           );
 | |
|           break;
 | |
|       }
 | |
|     };
 | |
|     const createFolder = async (parent, options = { openAfterCreate: false }) => {
 | |
|       const promptResponsePromise = message.prompt(
 | |
|         i18n.baseText("folders.add.to.parent.message", { interpolate: { parent: parent.name } }),
 | |
|         {
 | |
|           confirmButtonText: i18n.baseText("generic.create"),
 | |
|           cancelButtonText: i18n.baseText("generic.cancel"),
 | |
|           inputValidator: folderHelpers.validateFolderName,
 | |
|           customClass: "add-folder-modal"
 | |
|         }
 | |
|       );
 | |
|       const promptResponse = await promptResponsePromise;
 | |
|       if (promptResponse.action === MODAL_CONFIRM) {
 | |
|         const folderName = promptResponse.value;
 | |
|         try {
 | |
|           const newFolder = await foldersStore.createFolder(
 | |
|             folderName,
 | |
|             route.params.projectId,
 | |
|             parent.type === "folder" ? parent.id : void 0
 | |
|           );
 | |
|           const newFolderURL = router.resolve({
 | |
|             name: VIEWS.PROJECTS_FOLDERS,
 | |
|             params: { projectId: route.params.projectId, folderId: newFolder.id }
 | |
|           }).href;
 | |
|           toast.showToast({
 | |
|             title: i18n.baseText("folders.add.success.title"),
 | |
|             message: i18n.baseText("folders.add.success.message", {
 | |
|               interpolate: {
 | |
|                 link: newFolderURL,
 | |
|                 folderName: newFolder.name
 | |
|               }
 | |
|             }),
 | |
|             onClick: (event) => {
 | |
|               if (event?.target instanceof HTMLAnchorElement) {
 | |
|                 event.preventDefault();
 | |
|                 void router.push(newFolderURL);
 | |
|               }
 | |
|             },
 | |
|             type: "success"
 | |
|           });
 | |
|           telemetry.track("User created folder", {
 | |
|             folder_id: newFolder.id
 | |
|           });
 | |
|           if (options.openAfterCreate) {
 | |
|             await router.push({
 | |
|               name: VIEWS.PROJECTS_FOLDERS,
 | |
|               params: { projectId: route.params.projectId, folderId: parent.id }
 | |
|             });
 | |
|           } else {
 | |
|             if (!workflowsAndFolders.value.length) {
 | |
|               workflowsAndFolders.value = [
 | |
|                 {
 | |
|                   id: newFolder.id,
 | |
|                   name: newFolder.name,
 | |
|                   resource: "folder",
 | |
|                   createdAt: newFolder.createdAt,
 | |
|                   updatedAt: newFolder.updatedAt,
 | |
|                   homeProject: projectsStore.currentProject,
 | |
|                   workflowCount: 0,
 | |
|                   subFolderCount: 0
 | |
|                 }
 | |
|               ];
 | |
|               foldersStore.cacheFolders([
 | |
|                 { id: newFolder.id, name: newFolder.name, parentFolder: currentFolder.value?.id }
 | |
|               ]);
 | |
|             } else {
 | |
|               await fetchWorkflows();
 | |
|             }
 | |
|           }
 | |
|         } catch (error) {
 | |
|           toast.showError(error, i18n.baseText("folders.create.error.title"));
 | |
|         }
 | |
|       }
 | |
|     };
 | |
|     const renameFolder = async (folderId) => {
 | |
|       const folder = foldersStore.getCachedFolder(folderId);
 | |
|       if (!folder || !currentProject.value) return;
 | |
|       const promptResponsePromise = message.prompt(
 | |
|         i18n.baseText("folders.rename.message", { interpolate: { folderName: folder.name } }),
 | |
|         {
 | |
|           confirmButtonText: i18n.baseText("generic.rename"),
 | |
|           cancelButtonText: i18n.baseText("generic.cancel"),
 | |
|           inputValue: folder.name,
 | |
|           customClass: "rename-folder-modal",
 | |
|           inputValidator: folderHelpers.validateFolderName
 | |
|         }
 | |
|       );
 | |
|       const promptResponse = await promptResponsePromise;
 | |
|       if (promptResponse.action === MODAL_CONFIRM) {
 | |
|         const newFolderName = promptResponse.value;
 | |
|         try {
 | |
|           await foldersStore.renameFolder(currentProject.value?.id, folderId, newFolderName);
 | |
|           foldersStore.breadcrumbsCache[folderId].name = newFolderName;
 | |
|           toast.showMessage({
 | |
|             title: i18n.baseText("folders.rename.success.message", {
 | |
|               interpolate: { folderName: newFolderName }
 | |
|             }),
 | |
|             type: "success"
 | |
|           });
 | |
|           await fetchWorkflows();
 | |
|           telemetry.track("User renamed folder", {
 | |
|             folder_id: folderId
 | |
|           });
 | |
|         } catch (error) {
 | |
|           toast.showError(error, i18n.baseText("folders.rename.error.title"));
 | |
|         }
 | |
|       }
 | |
|     };
 | |
|     const createFolderInCurrent = async () => {
 | |
|       if (showRegisteredCommunityCTA.value) {
 | |
|         uiStore.openModalWithData({
 | |
|           name: COMMUNITY_PLUS_ENROLLMENT_MODAL,
 | |
|           data: { customHeading: i18n.baseText("folders.registeredCommunity.cta.heading") }
 | |
|         });
 | |
|         return;
 | |
|       }
 | |
|       if (!route.params.projectId) return;
 | |
|       const currentParent = currentFolder.value?.name || projectName.value;
 | |
|       if (!currentParent) return;
 | |
|       await createFolder({
 | |
|         id: route.params.folderId ?? "-1",
 | |
|         name: currentParent,
 | |
|         type: currentFolder.value ? "folder" : "project"
 | |
|       });
 | |
|     };
 | |
|     const deleteFolder = async (folderId, workflowCount, subFolderCount) => {
 | |
|       if (subFolderCount || workflowCount) {
 | |
|         uiStore.openDeleteFolderModal(folderId, workflowListEventBus, {
 | |
|           workflowCount,
 | |
|           subFolderCount
 | |
|         });
 | |
|       } else {
 | |
|         await foldersStore.deleteFolder(route.params.projectId, folderId);
 | |
|         toast.showMessage({
 | |
|           title: i18n.baseText("folders.delete.success.message"),
 | |
|           type: "success"
 | |
|         });
 | |
|         await onFolderDeleted({ folderId, workflowCount, folderCount: subFolderCount });
 | |
|       }
 | |
|     };
 | |
|     const moveFolder = async (payload) => {
 | |
|       if (!route.params.projectId) return;
 | |
|       try {
 | |
|         await foldersStore.moveFolder(
 | |
|           route.params.projectId,
 | |
|           payload.folder.id,
 | |
|           payload.newParent.type === "folder" ? payload.newParent.id : "0"
 | |
|         );
 | |
|         const isCurrentFolder = currentFolderId.value === payload.folder.id;
 | |
|         const newFolderURL = router.resolve({
 | |
|           name: VIEWS.PROJECTS_FOLDERS,
 | |
|           params: {
 | |
|             projectId: route.params.projectId,
 | |
|             folderId: payload.newParent.type === "folder" ? payload.newParent.id : void 0
 | |
|           }
 | |
|         }).href;
 | |
|         if (isCurrentFolder && !payload.options?.skipNavigation) {
 | |
|           void router.push(newFolderURL);
 | |
|         } else {
 | |
|           toast.showToast({
 | |
|             title: i18n.baseText("folders.move.success.title"),
 | |
|             message: i18n.baseText("folders.move.success.message", {
 | |
|               interpolate: {
 | |
|                 folderName: payload.folder.name,
 | |
|                 newFolderName: payload.newParent.name
 | |
|               }
 | |
|             }),
 | |
|             onClick: (event) => {
 | |
|               if (event?.target instanceof HTMLAnchorElement) {
 | |
|                 event.preventDefault();
 | |
|                 void router.push(newFolderURL);
 | |
|               }
 | |
|             },
 | |
|             type: "success"
 | |
|           });
 | |
|           if (!payload.options?.skipFetch) {
 | |
|             await fetchWorkflows();
 | |
|           }
 | |
|         }
 | |
|       } catch (error) {
 | |
|         toast.showError(error, i18n.baseText("folders.move.error.title"));
 | |
|       }
 | |
|     };
 | |
|     const onFolderTransferred = async (payload) => {
 | |
|       try {
 | |
|         await foldersStore.moveFolderToProject(
 | |
|           payload.source.projectId,
 | |
|           payload.source.folder.id,
 | |
|           payload.destination.projectId,
 | |
|           payload.destination.parentFolder.id,
 | |
|           payload.shareCredentials
 | |
|         );
 | |
|         const isCurrentFolder = currentFolderId.value === payload.source.folder.id;
 | |
|         const newFolderURL = router.resolve({
 | |
|           name: VIEWS.PROJECTS_FOLDERS,
 | |
|           params: {
 | |
|             projectId: payload.destination.canAccess ? payload.destination.projectId : payload.source.projectId,
 | |
|             folderId: payload.destination.canAccess ? payload.source.folder.id : void 0
 | |
|           }
 | |
|         }).href;
 | |
|         if (isCurrentFolder) {
 | |
|           if (payload.destination.canAccess) {
 | |
|             void router.push(newFolderURL);
 | |
|           } else {
 | |
|             void router.push({
 | |
|               name: VIEWS.PROJECTS_WORKFLOWS,
 | |
|               params: {
 | |
|                 projectId: payload.source.projectId
 | |
|               }
 | |
|             });
 | |
|           }
 | |
|         } else {
 | |
|           await refreshWorkflows();
 | |
|           if (payload.destination.canAccess) {
 | |
|             toast.showToast({
 | |
|               title: i18n.baseText("folders.move.success.title"),
 | |
|               message: i18n.baseText("folders.move.success.message", {
 | |
|                 interpolate: {
 | |
|                   folderName: payload.source.folder.name,
 | |
|                   newFolderName: payload.destination.parentFolder.name
 | |
|                 }
 | |
|               }),
 | |
|               onClick: (event) => {
 | |
|                 if (event?.target instanceof HTMLAnchorElement) {
 | |
|                   event.preventDefault();
 | |
|                   void router.push(newFolderURL);
 | |
|                 }
 | |
|               },
 | |
|               type: "success"
 | |
|             });
 | |
|           } else {
 | |
|             toast.showToast({
 | |
|               title: i18n.baseText("folders.move.success.title"),
 | |
|               message: i18n.baseText("folders.move.success.messageNoAccess", {
 | |
|                 interpolate: {
 | |
|                   folderName: payload.source.folder.name,
 | |
|                   newFolderName: payload.destination.parentFolder.name
 | |
|                 }
 | |
|               }),
 | |
|               type: "success"
 | |
|             });
 | |
|           }
 | |
|         }
 | |
|       } catch (error) {
 | |
|         toast.showError(error, i18n.baseText("folders.move.error.title"));
 | |
|       }
 | |
|     };
 | |
|     const moveWorkflowToFolder = async (payload) => {
 | |
|       if (showRegisteredCommunityCTA.value) {
 | |
|         uiStore.openModalWithData({
 | |
|           name: COMMUNITY_PLUS_ENROLLMENT_MODAL,
 | |
|           data: { customHeading: i18n.baseText("folders.registeredCommunity.cta.heading") }
 | |
|         });
 | |
|         return;
 | |
|       }
 | |
|       uiStore.openMoveToFolderModal(
 | |
|         "workflow",
 | |
|         {
 | |
|           id: payload.id,
 | |
|           name: payload.name,
 | |
|           parentFolderId: payload.parentFolderId,
 | |
|           sharedWithProjects: payload.sharedWithProjects
 | |
|         },
 | |
|         workflowListEventBus
 | |
|       );
 | |
|     };
 | |
|     const onWorkflowTransferred = async (payload) => {
 | |
|       try {
 | |
|         await projectsStore.moveResourceToProject(
 | |
|           "workflow",
 | |
|           payload.source.workflow.id,
 | |
|           payload.destination.projectId,
 | |
|           payload.destination.parentFolder.id,
 | |
|           payload.shareCredentials
 | |
|         );
 | |
|         await refreshWorkflows();
 | |
|         if (payload.destination.canAccess) {
 | |
|           toast.showToast({
 | |
|             title: i18n.baseText("folders.move.workflow.success.title"),
 | |
|             message: i18n.baseText("folders.move.workflow.success.message", {
 | |
|               interpolate: {
 | |
|                 workflowName: payload.source.workflow.name,
 | |
|                 newFolderName: payload.destination.parentFolder.name
 | |
|               }
 | |
|             }),
 | |
|             onClick: (event) => {
 | |
|               if (event?.target instanceof HTMLAnchorElement) {
 | |
|                 event.preventDefault();
 | |
|                 void router.push({
 | |
|                   name: VIEWS.PROJECTS_FOLDERS,
 | |
|                   params: {
 | |
|                     projectId: payload.destination.projectId,
 | |
|                     folderId: payload.destination.parentFolder.id
 | |
|                   }
 | |
|                 });
 | |
|               }
 | |
|             },
 | |
|             type: "success"
 | |
|           });
 | |
|         } else {
 | |
|           toast.showToast({
 | |
|             title: i18n.baseText("folders.move.workflow.success.title"),
 | |
|             message: i18n.baseText("folders.move.workflow.success.messageNoAccess", {
 | |
|               interpolate: {
 | |
|                 workflowName: payload.source.workflow.name,
 | |
|                 newFolderName: payload.destination.parentFolder.name
 | |
|               }
 | |
|             }),
 | |
|             type: "success"
 | |
|           });
 | |
|         }
 | |
|       } catch (error) {
 | |
|         toast.showError(error, i18n.baseText("folders.move.workflow.error.title"));
 | |
|       }
 | |
|     };
 | |
|     const onWorkflowMoved = async (payload) => {
 | |
|       if (!route.params.projectId) return;
 | |
|       try {
 | |
|         const newFolderURL = router.resolve({
 | |
|           name: VIEWS.PROJECTS_FOLDERS,
 | |
|           params: {
 | |
|             projectId: route.params.projectId,
 | |
|             folderId: payload.newParent.type === "folder" ? payload.newParent.id : void 0
 | |
|           }
 | |
|         }).href;
 | |
|         const workflowResource = workflowsAndFolders.value.find(
 | |
|           (resource) => resource.id === payload.workflow.id
 | |
|         );
 | |
|         await workflowsStore.updateWorkflow(payload.workflow.id, {
 | |
|           parentFolderId: payload.newParent.type === "folder" ? payload.newParent.id : "0",
 | |
|           versionId: workflowResource?.versionId
 | |
|         });
 | |
|         if (!payload.options?.skipFetch) {
 | |
|           await fetchWorkflows();
 | |
|         }
 | |
|         toast.showToast({
 | |
|           title: i18n.baseText("folders.move.workflow.success.title"),
 | |
|           message: i18n.baseText("folders.move.workflow.success.message", {
 | |
|             interpolate: {
 | |
|               workflowName: payload.workflow.name,
 | |
|               newFolderName: payload.newParent.name
 | |
|             }
 | |
|           }),
 | |
|           onClick: (event) => {
 | |
|             if (event?.target instanceof HTMLAnchorElement) {
 | |
|               event.preventDefault();
 | |
|               void router.push(newFolderURL);
 | |
|             }
 | |
|           },
 | |
|           type: "success"
 | |
|         });
 | |
|         telemetry.track("User moved content", {
 | |
|           workflow_id: payload.workflow.id,
 | |
|           source_folder_id: payload.workflow.oldParentId,
 | |
|           destination_folder_id: payload.newParent.id
 | |
|         });
 | |
|       } catch (error) {
 | |
|         toast.showError(error, i18n.baseText("folders.move.workflow.error.title"));
 | |
|       }
 | |
|     };
 | |
|     const onCreateWorkflowClick = () => {
 | |
|       void router.push({
 | |
|         name: VIEWS.NEW_WORKFLOW,
 | |
|         query: {
 | |
|           projectId: currentProject.value?.id,
 | |
|           parentFolderId: route.params.folderId
 | |
|         }
 | |
|       });
 | |
|     };
 | |
|     const renameInput = useTemplateRef("renameInput");
 | |
|     function onNameToggle() {
 | |
|       setTimeout(() => {
 | |
|         if (renameInput.value?.forceFocus) {
 | |
|           renameInput.value.forceFocus();
 | |
|         }
 | |
|       }, 0);
 | |
|     }
 | |
|     const onNameSubmit = async (name2) => {
 | |
|       if (!currentFolder.value || !currentProject.value) return;
 | |
|       const newName = name2.trim();
 | |
|       if (!newName) {
 | |
|         toast.showMessage({
 | |
|           title: i18n.baseText("renameAction.emptyName.title"),
 | |
|           message: i18n.baseText("renameAction.emptyName.message"),
 | |
|           type: "error"
 | |
|         });
 | |
|         return;
 | |
|       }
 | |
|       if (newName === currentFolder.value.name) {
 | |
|         renameInput.value?.forceCancel();
 | |
|         return;
 | |
|       }
 | |
|       const validationResult = folderHelpers.validateFolderName(newName);
 | |
|       if (typeof validationResult === "string") {
 | |
|         toast.showMessage({
 | |
|           title: i18n.baseText("renameAction.invalidName.title"),
 | |
|           message: validationResult,
 | |
|           type: "error"
 | |
|         });
 | |
|         renameInput.value?.forceCancel();
 | |
|         return;
 | |
|       } else {
 | |
|         try {
 | |
|           await foldersStore.renameFolder(currentProject.value?.id, currentFolder.value.id, newName);
 | |
|           foldersStore.breadcrumbsCache[currentFolder.value.id].name = newName;
 | |
|           toast.showMessage({
 | |
|             title: i18n.baseText("folders.rename.success.message", {
 | |
|               interpolate: { folderName: newName }
 | |
|             }),
 | |
|             type: "success"
 | |
|           });
 | |
|           telemetry.track("User renamed folder", {
 | |
|             folder_id: currentFolder.value.id
 | |
|           });
 | |
|         } catch (error) {
 | |
|           toast.showError(error, i18n.baseText("folders.rename.error.title"));
 | |
|           renameInput.value?.forceCancel();
 | |
|         }
 | |
|       }
 | |
|     };
 | |
|     return (_ctx, _cache) => {
 | |
|       const _component_N8nTooltip = Tooltip;
 | |
|       const _component_N8nCallout = N8nCallout;
 | |
|       const _component_n8n_loading = N8nLoading;
 | |
|       const _component_FolderBreadcrumbs = __unplugin_components_0;
 | |
|       const _component_FolderCard = __unplugin_components_4;
 | |
|       const _component_EmptySharedSectionActionBox = _sfc_main$8;
 | |
|       const _component_N8nCheckbox = N8nCheckbox;
 | |
|       const _component_N8nLink = N8nLink;
 | |
|       const _component_N8nInfoTip = InfoTip;
 | |
|       const _component_N8nActionBox = N8nActionBox;
 | |
|       return openBlock(), createBlock(ResourcesListLayout, {
 | |
|         filters: filters.value,
 | |
|         "onUpdate:filters": [
 | |
|           _cache[6] || (_cache[6] = ($event) => filters.value = $event),
 | |
|           onFiltersUpdated
 | |
|         ],
 | |
|         "resource-key": "workflows",
 | |
|         type: "list-paginated",
 | |
|         resources: workflowListResources.value,
 | |
|         "type-props": { itemSize: 80 },
 | |
|         shareable: isShareable.value,
 | |
|         initialize,
 | |
|         disabled: readOnlyEnv.value || !projectPermissions.value.workflow.create,
 | |
|         loading: false,
 | |
|         "resources-refreshing": loading.value,
 | |
|         "custom-page-size": unref(DEFAULT_WORKFLOW_PAGE_SIZE),
 | |
|         "total-items": unref(workflowsStore).totalWorkflowCount,
 | |
|         "dont-perform-sorting-and-filtering": true,
 | |
|         "has-empty-state": unref(foldersStore).totalWorkflowCount === 0 && !currentFolderId.value,
 | |
|         "onClick:add": addWorkflow,
 | |
|         "onUpdate:search": onSearchUpdated,
 | |
|         "onUpdate:paginationAndSort": setPaginationAndSort,
 | |
|         onMouseleave: unref(folderHelpers).resetDropTarget
 | |
|       }, createSlots({
 | |
|         header: withCtx(() => [
 | |
|           createVNode(ProjectHeader, { onCreateFolder: createFolderInCurrent }, {
 | |
|             default: withCtx(() => [
 | |
|               showInsights.value ? (openBlock(), createBlock(InsightsSummary, {
 | |
|                 key: 0,
 | |
|                 loading: unref(insightsStore).weeklySummary.isLoading,
 | |
|                 summary: unref(insightsStore).weeklySummary.state,
 | |
|                 "time-range": "week"
 | |
|               }, null, 8, ["loading", "summary"])) : createCommentVNode("", true)
 | |
|             ]),
 | |
|             _: 1
 | |
|           })
 | |
|         ]),
 | |
|         callout: withCtx(() => [
 | |
|           showAIStarterCollectionCallout.value ? (openBlock(), createBlock(_component_N8nCallout, {
 | |
|             key: 0,
 | |
|             theme: "secondary",
 | |
|             icon: "gift",
 | |
|             class: normalizeClass(_ctx.$style["easy-ai-workflow-callout"])
 | |
|           }, {
 | |
|             trailingContent: withCtx(() => [
 | |
|               createBaseVNode("div", {
 | |
|                 class: normalizeClass(_ctx.$style["callout-trailing-content"])
 | |
|               }, [
 | |
|                 createVNode(unref(N8nButton), {
 | |
|                   "data-test-id": "easy-ai-button",
 | |
|                   size: "small",
 | |
|                   type: "secondary",
 | |
|                   onClick: _cache[0] || (_cache[0] = ($event) => createAIStarterWorkflows("callout"))
 | |
|                 }, {
 | |
|                   default: withCtx(() => [
 | |
|                     createTextVNode(toDisplayString(unref(i18n).baseText("generic.startNow")), 1)
 | |
|                   ]),
 | |
|                   _: 1
 | |
|                 }),
 | |
|                 createVNode(unref(N8nIcon), {
 | |
|                   size: "small",
 | |
|                   icon: "x",
 | |
|                   title: unref(i18n).baseText("generic.dismiss"),
 | |
|                   class: "clickable",
 | |
|                   onClick: dismissStarterCollectionCallout
 | |
|                 }, null, 8, ["title"])
 | |
|               ], 2)
 | |
|             ]),
 | |
|             default: withCtx(() => [
 | |
|               createTextVNode(toDisplayString(unref(i18n).baseText("workflows.ai.starter.collection.callout")) + " ", 1)
 | |
|             ]),
 | |
|             _: 1
 | |
|           }, 8, ["class"])) : showPersonalizedTemplates.value ? (openBlock(), createBlock(SuggestedWorkflows, { key: 1 }, {
 | |
|             default: withCtx(() => [
 | |
|               (openBlock(true), createElementBlock(Fragment, null, renderList(unref(personalizedTemplatesStore).suggestedWorkflows, (workflow) => {
 | |
|                 return openBlock(), createBlock(SuggestedWorkflowCard, {
 | |
|                   key: workflow.id,
 | |
|                   "data-test-id": "resource-list-item-suggested-workflow",
 | |
|                   data: {
 | |
|                     id: workflow.id,
 | |
|                     name: workflow.name
 | |
|                   }
 | |
|                 }, null, 8, ["data"]);
 | |
|               }), 128))
 | |
|             ]),
 | |
|             _: 1
 | |
|           })) : createCommentVNode("", true),
 | |
|           showReadyToRunWorkflowsCallout.value ? (openBlock(), createBlock(_component_N8nCallout, {
 | |
|             key: 2,
 | |
|             theme: "secondary",
 | |
|             icon: "bolt-filled",
 | |
|             class: normalizeClass(_ctx.$style["easy-ai-workflow-callout"])
 | |
|           }, {
 | |
|             trailingContent: withCtx(() => [
 | |
|               createBaseVNode("div", {
 | |
|                 class: normalizeClass(_ctx.$style["callout-trailing-content"])
 | |
|               }, [
 | |
|                 createVNode(unref(N8nButton), {
 | |
|                   "data-test-id": "easy-ai-button",
 | |
|                   size: "small",
 | |
|                   type: "secondary",
 | |
|                   onClick: _cache[1] || (_cache[1] = ($event) => handleCreateReadyToRunWorkflows("callout"))
 | |
|                 }, {
 | |
|                   default: withCtx(() => [
 | |
|                     createTextVNode(toDisplayString(unref(i18n).baseText("generic.startNow")), 1)
 | |
|                   ]),
 | |
|                   _: 1
 | |
|                 }),
 | |
|                 createVNode(unref(N8nIcon), {
 | |
|                   size: "small",
 | |
|                   icon: "x",
 | |
|                   title: unref(i18n).baseText("generic.dismiss"),
 | |
|                   class: "clickable",
 | |
|                   onClick: handleDismissReadyToRunCallout
 | |
|                 }, null, 8, ["title"])
 | |
|               ], 2)
 | |
|             ]),
 | |
|             default: withCtx(() => [
 | |
|               createTextVNode(toDisplayString(unref(readyToRunWorkflowsStore).getCalloutText()) + " ", 1)
 | |
|             ]),
 | |
|             _: 1
 | |
|           }, 8, ["class"])) : createCommentVNode("", true)
 | |
|         ]),
 | |
|         breadcrumbs: withCtx(() => [
 | |
|           breadcrumbsLoading.value ? (openBlock(), createElementBlock("div", {
 | |
|             key: 0,
 | |
|             class: normalizeClass(_ctx.$style["breadcrumbs-loading"])
 | |
|           }, [
 | |
|             createVNode(_component_n8n_loading, {
 | |
|               loading: breadcrumbsLoading.value,
 | |
|               rows: 1,
 | |
|               variant: "p"
 | |
|             }, null, 8, ["loading"])
 | |
|           ], 2)) : showFolders.value && currentFolder.value ? (openBlock(), createElementBlock("div", {
 | |
|             key: 1,
 | |
|             class: normalizeClass(_ctx.$style["breadcrumbs-container"]),
 | |
|             "data-test-id": "main-breadcrumbs"
 | |
|           }, [
 | |
|             createVNode(_component_FolderBreadcrumbs, {
 | |
|               "current-folder": currentFolderParent.value,
 | |
|               actions: mainBreadcrumbsActions.value,
 | |
|               "hidden-items-trigger": isDragging.value ? "hover" : "click",
 | |
|               "current-folder-as-link": true,
 | |
|               onItemSelected: onBreadcrumbItemClick,
 | |
|               onAction: onBreadCrumbsAction,
 | |
|               onItemDrop: onBreadCrumbsItemDrop,
 | |
|               onProjectDrop: moveFolderToProjectRoot
 | |
|             }, {
 | |
|               append: withCtx(() => [
 | |
|                 createBaseVNode("span", {
 | |
|                   class: normalizeClass(_ctx.$style["path-separator"])
 | |
|                 }, "/", 2),
 | |
|                 (openBlock(), createBlock(unref(InlineRename), {
 | |
|                   ref_key: "renameInput",
 | |
|                   ref: renameInput,
 | |
|                   key: currentFolder.value?.id,
 | |
|                   "data-test-id": "breadcrumbs-item-current",
 | |
|                   placeholder: unref(i18n).baseText("folders.rename.placeholder"),
 | |
|                   "model-value": currentFolder.value.name,
 | |
|                   "max-length": 30,
 | |
|                   "read-only": readOnlyEnv.value || !hasPermissionToUpdateFolders.value,
 | |
|                   class: normalizeClass({ [_ctx.$style.name]: true, [_ctx.$style["pointer-disabled"]]: isDragging.value }),
 | |
|                   "onUpdate:modelValue": onNameSubmit
 | |
|                 }, null, 8, ["placeholder", "model-value", "read-only", "class"]))
 | |
|               ]),
 | |
|               _: 1
 | |
|             }, 8, ["current-folder", "actions", "hidden-items-trigger"])
 | |
|           ], 2)) : createCommentVNode("", true)
 | |
|         ]),
 | |
|         item: withCtx(({ item: data, index }) => [
 | |
|           data.resourceType === "folder" ? (openBlock(), createBlock(Draggable, {
 | |
|             key: `folder-${index}`,
 | |
|             disabled: !isDragNDropEnabled.value,
 | |
|             type: "move",
 | |
|             "target-data-key": "folder",
 | |
|             onDragstart: unref(folderHelpers).onDragStart,
 | |
|             onDragend: unref(folderHelpers).onDragEnd
 | |
|           }, {
 | |
|             preview: withCtx(() => [
 | |
|               createVNode(unref(N8nCard), null, {
 | |
|                 default: withCtx(() => [
 | |
|                   createVNode(unref(N8nText), {
 | |
|                     tag: "h2",
 | |
|                     bold: ""
 | |
|                   }, {
 | |
|                     default: withCtx(() => [
 | |
|                       createTextVNode(toDisplayString(data.name), 1)
 | |
|                     ]),
 | |
|                     _: 2
 | |
|                   }, 1024)
 | |
|                 ]),
 | |
|                 _: 2
 | |
|               }, 1024)
 | |
|             ]),
 | |
|             default: withCtx(() => [
 | |
|               createVNode(_component_FolderCard, {
 | |
|                 data,
 | |
|                 actions: folderCardActions.value,
 | |
|                 "read-only": readOnlyEnv.value || !hasPermissionToDeleteFolders.value && !hasPermissionToCreateFolders.value,
 | |
|                 "personal-project": personalProject.value,
 | |
|                 "data-resourceid": data.id,
 | |
|                 "data-resourcename": data.name,
 | |
|                 class: normalizeClass([{
 | |
|                   ["mb-2xs"]: true,
 | |
|                   [_ctx.$style["drag-active"]]: isDragging.value,
 | |
|                   [_ctx.$style.dragging]: unref(foldersStore).draggedElement?.type === "folder" && unref(foldersStore).draggedElement?.id === data.id,
 | |
|                   [_ctx.$style["drop-active"]]: unref(foldersStore).activeDropTarget?.id === data.id
 | |
|                 }, "mb-2xs"]),
 | |
|                 "show-ownership-badge": showCardsBadge.value,
 | |
|                 "data-target": "folder",
 | |
|                 onAction: onFolderCardAction,
 | |
|                 onMouseenter: unref(folderHelpers).onDragEnter,
 | |
|                 onMouseup: onFolderCardDrop
 | |
|               }, null, 8, ["data", "actions", "read-only", "personal-project", "data-resourceid", "data-resourcename", "class", "show-ownership-badge", "onMouseenter"])
 | |
|             ]),
 | |
|             _: 2
 | |
|           }, 1032, ["disabled", "onDragstart", "onDragend"])) : (openBlock(), createBlock(Draggable, {
 | |
|             key: `workflow-${index}`,
 | |
|             disabled: !isDragNDropEnabled.value,
 | |
|             type: "move",
 | |
|             "target-data-key": "workflow",
 | |
|             onDragstart: unref(folderHelpers).onDragStart,
 | |
|             onDragend: unref(folderHelpers).onDragEnd
 | |
|           }, {
 | |
|             preview: withCtx(() => [
 | |
|               createVNode(unref(N8nCard), null, {
 | |
|                 default: withCtx(() => [
 | |
|                   createVNode(unref(N8nText), {
 | |
|                     tag: "h2",
 | |
|                     bold: ""
 | |
|                   }, {
 | |
|                     default: withCtx(() => [
 | |
|                       createTextVNode(toDisplayString(data.name), 1)
 | |
|                     ]),
 | |
|                     _: 2
 | |
|                   }, 1024)
 | |
|                 ]),
 | |
|                 _: 2
 | |
|               }, 1024)
 | |
|             ]),
 | |
|             default: withCtx(() => [
 | |
|               createVNode(WorkflowCard, {
 | |
|                 "data-test-id": "resources-list-item-workflow",
 | |
|                 class: normalizeClass({
 | |
|                   ["mb-2xs"]: true,
 | |
|                   [_ctx.$style["drag-active"]]: isDragging.value,
 | |
|                   [_ctx.$style.dragging]: unref(foldersStore).draggedElement?.type === "workflow" && unref(foldersStore).draggedElement?.id === data.id
 | |
|                 }),
 | |
|                 data,
 | |
|                 "workflow-list-event-bus": unref(workflowListEventBus),
 | |
|                 "read-only": readOnlyEnv.value,
 | |
|                 "data-resourceid": data.id,
 | |
|                 "data-resourcename": data.name,
 | |
|                 "show-ownership-badge": showCardsBadge.value,
 | |
|                 "data-target": "workflow",
 | |
|                 "onClick:tag": onClickTag,
 | |
|                 "onWorkflow:deleted": refreshWorkflows,
 | |
|                 "onWorkflow:archived": refreshWorkflows,
 | |
|                 "onWorkflow:unarchived": refreshWorkflows,
 | |
|                 "onWorkflow:moved": fetchWorkflows,
 | |
|                 "onWorkflow:duplicated": fetchWorkflows,
 | |
|                 "onWorkflow:activeToggle": onWorkflowActiveToggle,
 | |
|                 "onAction:moveToFolder": moveWorkflowToFolder,
 | |
|                 onMouseenter: _cache[2] || (_cache[2] = ($event) => isDragging.value ? unref(folderHelpers).resetDropTarget() : {})
 | |
|               }, null, 8, ["class", "data", "workflow-list-event-bus", "read-only", "data-resourceid", "data-resourcename", "show-ownership-badge"])
 | |
|             ]),
 | |
|             _: 2
 | |
|           }, 1032, ["disabled", "onDragstart", "onDragend"]))
 | |
|         ]),
 | |
|         empty: withCtx(() => [
 | |
|           unref(projectPages).isSharedSubPage && personalProject.value ? (openBlock(), createBlock(_component_EmptySharedSectionActionBox, {
 | |
|             key: 0,
 | |
|             "personal-project": personalProject.value,
 | |
|             "resource-type": "workflows"
 | |
|           }, null, 8, ["personal-project"])) : (openBlock(), createElementBlock("div", _hoisted_5, [
 | |
|             createBaseVNode("div", _hoisted_6, [
 | |
|               createVNode(unref(N8nHeading), {
 | |
|                 tag: "h2",
 | |
|                 size: "xlarge",
 | |
|                 class: "mb-2xs"
 | |
|               }, {
 | |
|                 default: withCtx(() => [
 | |
|                   createTextVNode(toDisplayString(currentUser.value.firstName ? unref(i18n).baseText("workflows.empty.heading", {
 | |
|                     interpolate: { name: currentUser.value.firstName }
 | |
|                   }) : unref(i18n).baseText("workflows.empty.heading.userNotSetup")), 1)
 | |
|                 ]),
 | |
|                 _: 1
 | |
|               }),
 | |
|               createVNode(unref(N8nText), {
 | |
|                 size: "large",
 | |
|                 color: "text-base"
 | |
|               }, {
 | |
|                 default: withCtx(() => [
 | |
|                   createTextVNode(toDisplayString(emptyListDescription.value), 1)
 | |
|                 ]),
 | |
|                 _: 1
 | |
|               })
 | |
|             ]),
 | |
|             !readOnlyEnv.value && projectPermissions.value.workflow.create ? (openBlock(), createElementBlock("div", {
 | |
|               key: 0,
 | |
|               class: normalizeClass(["text-center", "mt-2xl", _ctx.$style.actionsContainer])
 | |
|             }, [
 | |
|               createVNode(unref(N8nCard), {
 | |
|                 class: normalizeClass(_ctx.$style.emptyStateCard),
 | |
|                 hoverable: "",
 | |
|                 "data-test-id": "new-workflow-card",
 | |
|                 onClick: addWorkflow
 | |
|               }, {
 | |
|                 default: withCtx(() => [
 | |
|                   createBaseVNode("div", {
 | |
|                     class: normalizeClass(_ctx.$style.emptyStateCardContent)
 | |
|                   }, [
 | |
|                     createVNode(unref(N8nIcon), {
 | |
|                       class: normalizeClass(_ctx.$style.emptyStateCardIcon),
 | |
|                       icon: "file",
 | |
|                       color: "foreground-dark",
 | |
|                       "stroke-width": 1.5
 | |
|                     }, null, 8, ["class"]),
 | |
|                     createVNode(unref(N8nText), {
 | |
|                       size: "large",
 | |
|                       class: "mt-xs"
 | |
|                     }, {
 | |
|                       default: withCtx(() => [
 | |
|                         createTextVNode(toDisplayString(unref(i18n).baseText("workflows.empty.startFromScratch")), 1)
 | |
|                       ]),
 | |
|                       _: 1
 | |
|                     })
 | |
|                   ], 2)
 | |
|                 ]),
 | |
|                 _: 1
 | |
|               }, 8, ["class"]),
 | |
|               showAIStarterCollectionCallout.value ? (openBlock(), createBlock(unref(N8nCard), {
 | |
|                 key: 0,
 | |
|                 class: normalizeClass(_ctx.$style.emptyStateCard),
 | |
|                 hoverable: "",
 | |
|                 "data-test-id": "easy-ai-workflow-card",
 | |
|                 onClick: _cache[3] || (_cache[3] = ($event) => createAIStarterWorkflows("card"))
 | |
|               }, {
 | |
|                 default: withCtx(() => [
 | |
|                   createBaseVNode("div", {
 | |
|                     class: normalizeClass(_ctx.$style.emptyStateCardContent)
 | |
|                   }, [
 | |
|                     createVNode(unref(N8nIcon), {
 | |
|                       class: normalizeClass(_ctx.$style.emptyStateCardIcon),
 | |
|                       "stroke-width": 1.5,
 | |
|                       icon: "gift",
 | |
|                       color: "foreground-dark"
 | |
|                     }, null, 8, ["class"]),
 | |
|                     createVNode(unref(N8nText), {
 | |
|                       size: "large",
 | |
|                       class: "mt-xs pl-2xs pr-2xs"
 | |
|                     }, {
 | |
|                       default: withCtx(() => [
 | |
|                         createTextVNode(toDisplayString(unref(i18n).baseText("workflows.ai.starter.collection.card")), 1)
 | |
|                       ]),
 | |
|                       _: 1
 | |
|                     })
 | |
|                   ], 2)
 | |
|                 ]),
 | |
|                 _: 1
 | |
|               }, 8, ["class"])) : showEasyAIWorkflowCallout.value ? (openBlock(), createBlock(unref(N8nCard), {
 | |
|                 key: 1,
 | |
|                 class: normalizeClass(_ctx.$style.emptyStateCard),
 | |
|                 hoverable: "",
 | |
|                 "data-test-id": "easy-ai-workflow-card",
 | |
|                 onClick: _cache[4] || (_cache[4] = ($event) => openAIWorkflow("empty"))
 | |
|               }, {
 | |
|                 default: withCtx(() => [
 | |
|                   createBaseVNode("div", {
 | |
|                     class: normalizeClass(_ctx.$style.emptyStateCardContent)
 | |
|                   }, [
 | |
|                     createVNode(unref(N8nIcon), {
 | |
|                       class: normalizeClass(_ctx.$style.emptyStateCardIcon),
 | |
|                       "stroke-width": 1.5,
 | |
|                       icon: "bot",
 | |
|                       color: "foreground-dark"
 | |
|                     }, null, 8, ["class"]),
 | |
|                     createVNode(unref(N8nText), {
 | |
|                       size: "large",
 | |
|                       class: "mt-xs pl-2xs pr-2xs"
 | |
|                     }, {
 | |
|                       default: withCtx(() => [
 | |
|                         createTextVNode(toDisplayString(unref(i18n).baseText("workflows.empty.easyAI")), 1)
 | |
|                       ]),
 | |
|                       _: 1
 | |
|                     })
 | |
|                   ], 2)
 | |
|                 ]),
 | |
|                 _: 1
 | |
|               }, 8, ["class"])) : createCommentVNode("", true),
 | |
|               showReadyToRunWorkflowsCallout.value ? (openBlock(), createBlock(unref(N8nCard), {
 | |
|                 key: 2,
 | |
|                 class: normalizeClass(_ctx.$style.emptyStateCard),
 | |
|                 hoverable: "",
 | |
|                 "data-test-id": "ready-to-run-workflows-card",
 | |
|                 onClick: _cache[5] || (_cache[5] = ($event) => handleCreateReadyToRunWorkflows("card"))
 | |
|               }, {
 | |
|                 default: withCtx(() => [
 | |
|                   createBaseVNode("div", {
 | |
|                     class: normalizeClass(_ctx.$style.emptyStateCardContent)
 | |
|                   }, [
 | |
|                     createVNode(unref(N8nIcon), {
 | |
|                       class: normalizeClass(_ctx.$style.emptyStateCardIcon),
 | |
|                       "stroke-width": 1.5,
 | |
|                       icon: "package-open",
 | |
|                       color: "foreground-dark"
 | |
|                     }, null, 8, ["class"]),
 | |
|                     createVNode(unref(N8nText), {
 | |
|                       size: "large",
 | |
|                       class: "mt-xs pl-2xs pr-2xs"
 | |
|                     }, {
 | |
|                       default: withCtx(() => [
 | |
|                         createTextVNode(toDisplayString(unref(readyToRunWorkflowsStore).getCardText()), 1)
 | |
|                       ]),
 | |
|                       _: 1
 | |
|                     })
 | |
|                   ], 2)
 | |
|                 ]),
 | |
|                 _: 1
 | |
|               }, 8, ["class"])) : createCommentVNode("", true),
 | |
|               templatesCardEnabled.value ? (openBlock(), createBlock(unref(N8nCard), {
 | |
|                 key: 3,
 | |
|                 class: normalizeClass(_ctx.$style.emptyStateCard),
 | |
|                 hoverable: "",
 | |
|                 "data-test-id": "new-workflow-from-template-card",
 | |
|                 onClick: openTemplatesRepository
 | |
|               }, {
 | |
|                 default: withCtx(() => [
 | |
|                   createBaseVNode("div", {
 | |
|                     class: normalizeClass(_ctx.$style.emptyStateCardContent)
 | |
|                   }, [
 | |
|                     createVNode(unref(N8nIcon), {
 | |
|                       class: normalizeClass(_ctx.$style.emptyStateCardIcon),
 | |
|                       "stroke-width": 1.5,
 | |
|                       icon: "package-open",
 | |
|                       color: "foreground-dark"
 | |
|                     }, null, 8, ["class"]),
 | |
|                     createVNode(unref(N8nText), {
 | |
|                       size: "large",
 | |
|                       class: "mt-xs pl-2xs pr-2xs"
 | |
|                     }, {
 | |
|                       default: withCtx(() => [
 | |
|                         createTextVNode(toDisplayString(unref(i18n).baseText("workflows.empty.startWithTemplate")), 1)
 | |
|                       ]),
 | |
|                       _: 1
 | |
|                     })
 | |
|                   ], 2)
 | |
|                 ]),
 | |
|                 _: 1
 | |
|               }, 8, ["class"])) : createCommentVNode("", true)
 | |
|             ], 2)) : createCommentVNode("", true),
 | |
|             showTemplateRecommendationV2.value ? (openBlock(), createBlock(TemplateRecommendationV2, { key: 1 })) : createCommentVNode("", true)
 | |
|           ]))
 | |
|         ]),
 | |
|         filters: withCtx(({ setKeyValue }) => [
 | |
|           unref(settingsStore).areTagsEnabled ? (openBlock(), createElementBlock("div", _hoisted_7, [
 | |
|             createVNode(unref(N8nInputLabel), {
 | |
|               label: unref(i18n).baseText("workflows.filters.tags"),
 | |
|               bold: false,
 | |
|               size: "small",
 | |
|               color: "text-base",
 | |
|               class: "mb-3xs"
 | |
|             }, null, 8, ["label"]),
 | |
|             createVNode(_sfc_main$9, {
 | |
|               placeholder: unref(i18n).baseText("workflowOpen.filterWorkflows"),
 | |
|               "model-value": filters.value.tags,
 | |
|               "create-enabled": false,
 | |
|               "onUpdate:modelValue": ($event) => setKeyValue("tags", $event)
 | |
|             }, null, 8, ["placeholder", "model-value", "onUpdate:modelValue"])
 | |
|           ])) : createCommentVNode("", true),
 | |
|           createBaseVNode("div", _hoisted_8, [
 | |
|             createVNode(unref(N8nInputLabel), {
 | |
|               label: unref(i18n).baseText("workflows.filters.status"),
 | |
|               bold: false,
 | |
|               size: "small",
 | |
|               color: "text-base",
 | |
|               class: "mb-3xs"
 | |
|             }, null, 8, ["label"]),
 | |
|             createVNode(unref(N8nSelect), {
 | |
|               "data-test-id": "status-dropdown",
 | |
|               "model-value": filters.value.status,
 | |
|               "onUpdate:modelValue": ($event) => setKeyValue("status", $event)
 | |
|             }, {
 | |
|               default: withCtx(() => [
 | |
|                 (openBlock(true), createElementBlock(Fragment, null, renderList(statusFilterOptions.value, (option) => {
 | |
|                   return openBlock(), createBlock(unref(_sfc_main$a), {
 | |
|                     key: option.label,
 | |
|                     label: option.label,
 | |
|                     value: option.value,
 | |
|                     "data-test-id": "status"
 | |
|                   }, null, 8, ["label", "value"]);
 | |
|                 }), 128))
 | |
|               ]),
 | |
|               _: 2
 | |
|             }, 1032, ["model-value", "onUpdate:modelValue"])
 | |
|           ]),
 | |
|           createBaseVNode("div", _hoisted_9, [
 | |
|             createVNode(_component_N8nCheckbox, {
 | |
|               label: unref(i18n).baseText("workflows.filters.showArchived"),
 | |
|               "model-value": filters.value.showArchived || false,
 | |
|               "data-test-id": "show-archived-checkbox",
 | |
|               "onUpdate:modelValue": ($event) => setKeyValue("showArchived", $event)
 | |
|             }, null, 8, ["label", "model-value", "onUpdate:modelValue"])
 | |
|           ])
 | |
|         ]),
 | |
|         postamble: withCtx(() => [
 | |
|           workflowsAndFolders.value.length === 0 && !hasFilters.value ? (openBlock(), createElementBlock("div", {
 | |
|             key: 0,
 | |
|             class: normalizeClass(_ctx.$style["empty-folder-container"]),
 | |
|             "data-test-id": "empty-folder-container"
 | |
|           }, [
 | |
|             showArchivedOnlyHint.value ? (openBlock(), createBlock(_component_N8nInfoTip, {
 | |
|               key: 0,
 | |
|               bold: false
 | |
|             }, {
 | |
|               default: withCtx(() => [
 | |
|                 createTextVNode(toDisplayString(unref(i18n).baseText("workflows.archivedOnly.hint")) + " ", 1),
 | |
|                 createVNode(_component_N8nLink, {
 | |
|                   size: "small",
 | |
|                   "data-test-id": "show-archived-link",
 | |
|                   onClick: onShowArchived
 | |
|                 }, {
 | |
|                   default: withCtx(() => [
 | |
|                     createTextVNode(toDisplayString(unref(i18n).baseText("workflows.archivedOnly.hint.link")), 1)
 | |
|                   ]),
 | |
|                   _: 1
 | |
|                 })
 | |
|               ]),
 | |
|               _: 1
 | |
|             })) : createCommentVNode("", true),
 | |
|             unref(projectPages).isSharedSubPage && personalProject.value ? (openBlock(), createBlock(_component_EmptySharedSectionActionBox, {
 | |
|               key: 1,
 | |
|               "personal-project": personalProject.value,
 | |
|               "resource-type": "workflows"
 | |
|             }, null, 8, ["personal-project"])) : currentFolder.value ? (openBlock(), createBlock(_component_N8nActionBox, {
 | |
|               key: 2,
 | |
|               "data-test-id": "empty-folder-action-box",
 | |
|               heading: unref(i18n).baseText("folders.empty.actionbox.title", {
 | |
|                 interpolate: { folderName: currentFolder.value.name }
 | |
|               }),
 | |
|               "button-text": unref(i18n).baseText("generic.create.workflow"),
 | |
|               "button-type": "secondary",
 | |
|               "button-disabled": readOnlyEnv.value || !projectPermissions.value.workflow.create,
 | |
|               "onClick:button": onCreateWorkflowClick
 | |
|             }, {
 | |
|               disabledButtonTooltip: withCtx(() => [
 | |
|                 createTextVNode(toDisplayString(readOnlyEnv.value ? unref(i18n).baseText("readOnlyEnv.cantAdd.workflow") : unref(i18n).baseText("generic.missing.permissions")), 1)
 | |
|               ]),
 | |
|               _: 1
 | |
|             }, 8, ["heading", "button-text", "button-disabled"])) : createCommentVNode("", true)
 | |
|           ], 2)) : createCommentVNode("", true)
 | |
|         ]),
 | |
|         _: 2
 | |
|       }, [
 | |
|         foldersEnabled.value || showRegisteredCommunityCTA.value ? {
 | |
|           name: "add-button",
 | |
|           fn: withCtx(() => [
 | |
|             createVNode(_component_N8nTooltip, {
 | |
|               placement: "top",
 | |
|               disabled: !(unref(projectPages).isOverviewSubPage || unref(projectPages).isSharedSubPage || !readOnlyEnv.value && hasPermissionToCreateFolders.value)
 | |
|             }, {
 | |
|               content: withCtx(() => [
 | |
|                 (unref(projectPages).isOverviewSubPage || unref(projectPages).isSharedSubPage) && !showRegisteredCommunityCTA.value ? (openBlock(), createElementBlock("span", _hoisted_1, [
 | |
|                   teamProjectsEnabled.value ? (openBlock(), createElementBlock("span", _hoisted_2, toDisplayString(unref(i18n).baseText("folders.add.overview.withProjects.message")), 1)) : (openBlock(), createElementBlock("span", _hoisted_3, toDisplayString(unref(i18n).baseText("folders.add.overview.community.message")), 1))
 | |
|                 ])) : (openBlock(), createElementBlock("span", _hoisted_4, toDisplayString(currentParentName.value ? unref(i18n).baseText("folders.add.to.parent.message", {
 | |
|                   interpolate: { parent: currentParentName.value }
 | |
|                 }) : unref(i18n).baseText("folders.add.here.message")), 1))
 | |
|               ]),
 | |
|               default: withCtx(() => [
 | |
|                 createVNode(unref(N8nButton), {
 | |
|                   size: "small",
 | |
|                   icon: "folder-plus",
 | |
|                   type: "tertiary",
 | |
|                   "data-test-id": "add-folder-button",
 | |
|                   class: normalizeClass(_ctx.$style["add-folder-button"]),
 | |
|                   disabled: !showRegisteredCommunityCTA.value && (readOnlyEnv.value || !hasPermissionToCreateFolders.value),
 | |
|                   onClick: createFolderInCurrent
 | |
|                 }, null, 8, ["class", "disabled"])
 | |
|               ]),
 | |
|               _: 1
 | |
|             }, 8, ["disabled"])
 | |
|           ]),
 | |
|           key: "0"
 | |
|         } : void 0
 | |
|       ]), 1032, ["filters", "resources", "shareable", "disabled", "resources-refreshing", "custom-page-size", "total-items", "has-empty-state", "onMouseleave"]);
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const actionsContainer = "_actionsContainer_1puyr_123";
 | |
| const emptyStateCard = "_emptyStateCard_1puyr_139";
 | |
| const emptyStateCardContent = "_emptyStateCardContent_1puyr_152";
 | |
| const emptyStateCardIcon = "_emptyStateCardIcon_1puyr_159";
 | |
| const dragging = "_dragging_1puyr_192";
 | |
| const name = "_name_1puyr_210";
 | |
| const style0 = {
 | |
|   actionsContainer,
 | |
|   "easy-ai-workflow-callout": "_easy-ai-workflow-callout_1puyr_128",
 | |
|   "callout-trailing-content": "_callout-trailing-content_1puyr_133",
 | |
|   emptyStateCard,
 | |
|   emptyStateCardContent,
 | |
|   emptyStateCardIcon,
 | |
|   "add-folder-button": "_add-folder-button_1puyr_166",
 | |
|   "breadcrumbs-container": "_breadcrumbs-container_1puyr_171",
 | |
|   "breadcrumbs-loading": "_breadcrumbs-loading_1puyr_177",
 | |
|   "empty-folder-container": "_empty-folder-container_1puyr_183",
 | |
|   "drag-active": "_drag-active_1puyr_187",
 | |
|   dragging,
 | |
|   "drop-active": "_drop-active_1puyr_199",
 | |
|   "path-separator": "_path-separator_1puyr_204",
 | |
|   name,
 | |
|   "pointer-disabled": "_pointer-disabled_1puyr_216"
 | |
| };
 | |
| const cssModules = {
 | |
|   "$style": style0
 | |
| };
 | |
| const WorkflowsView = /* @__PURE__ */ _export_sfc(_sfc_main, [["__cssModules", cssModules]]);
 | |
| export {
 | |
|   WorkflowsView as default
 | |
| };
 |