UNPKG

n8n-editor-ui

Version:

Workflow Editor UI for n8n

480 lines (479 loc) 26.5 kB
; (function () { System.register(["./chunk-legacy-Re9CbdfL.js", "./vue.runtime.esm-bundler-legacy--Sn1h8On.js", "./_MapCache-legacy-DlYNX_X1.js", "./src-legacy-uZTNWMC0.js", "./en-legacy-DJK4SpPN.js", "./preload-helper-legacy-CXRjoQ0T.js", "./_plugin-vue_export-helper-legacy-DZMI5HPp.js", "./truncate-legacy-BGje52Or.js", "./icon-legacy-CqVXaCIS.js", "./overlay-legacy-o1gtoD8p.js", "./empty-legacy-CA9D6itE.js", "./useMessage-legacy-M2m6s8Ce.js", "./useTelemetry-legacy-B3pzzkAE.js", "./useToast-legacy-C4Vu5mt9.js", "./sanitize-html-legacy-DLqXJu-U.js", "./CalendarDate-legacy-BUvNgcoo.js", "./path-browserify-legacy-C6ml8BkF.js", "./constants-legacy-TKxWCqvM.js", "./merge-legacy-8xjIc_ts.js", "./_baseOrderBy-legacy-CB2Dh5d_.js", "./dateformat-legacy-C4HUJTCr.js", "./useDebounce-legacy-CqZ-fJEm.js", "./useExternalHooks-legacy-8pg6K3ln.js", "./useStyles-legacy-E8NPEyeD.js", "./roles.store-legacy-DLKI2yRw.js"], function (_export, _context) { "use strict"; var __toESM, toRaw, computed, toDisplayString, createElementBlock, createCommentVNode, unref, ref, createVNode, defineComponent, createBlock, Fragment, withCtx, openBlock, renderList, createTextVNode, normalizeClass, createBaseVNode, useI18n, useAsyncState, N8nButton_default, N8nFormInput_default, N8nText_default, N8nTooltip_default, N8nLoading_default, N8nHeading_default, __plugin_vue_export_helper_default, useRouter, useMessage, require_sortBy, useTelemetry, useToast, VIEWS, require_isEqual, MODAL_CONFIRM, useRolesStore, __vite_style__, import_isEqual, import_sortBy, _hoisted_1, _hoisted_2, _hoisted_3, ProjectRoleView_vue_vue_type_script_setup_true_lang_default, container, cardContainer, card, cardTitle, backButton, headerContainer, formContainer, presetsContainer, checkbox, ProjectRoleView_vue_vue_type_style_index_0_lang_module_default, cssModules, ProjectRoleView_default; return { setters: [function (_chunkLegacy001Js) { __toESM = _chunkLegacy001Js.o; }, function (_vueRuntimeEsmBundlerLegacy003Js) { toRaw = _vueRuntimeEsmBundlerLegacy003Js.Bt; computed = _vueRuntimeEsmBundlerLegacy003Js.C; toDisplayString = _vueRuntimeEsmBundlerLegacy003Js.Cn; createElementBlock = _vueRuntimeEsmBundlerLegacy003Js.D; createCommentVNode = _vueRuntimeEsmBundlerLegacy003Js.E; unref = _vueRuntimeEsmBundlerLegacy003Js.Gt; ref = _vueRuntimeEsmBundlerLegacy003Js.It; createVNode = _vueRuntimeEsmBundlerLegacy003Js.M; defineComponent = _vueRuntimeEsmBundlerLegacy003Js.P; createBlock = _vueRuntimeEsmBundlerLegacy003Js.T; Fragment = _vueRuntimeEsmBundlerLegacy003Js._; withCtx = _vueRuntimeEsmBundlerLegacy003Js.bt; openBlock = _vueRuntimeEsmBundlerLegacy003Js.et; renderList = _vueRuntimeEsmBundlerLegacy003Js.it; createTextVNode = _vueRuntimeEsmBundlerLegacy003Js.j; normalizeClass = _vueRuntimeEsmBundlerLegacy003Js.vn; createBaseVNode = _vueRuntimeEsmBundlerLegacy003Js.w; }, function (_MapCacheLegacy005Js) { useI18n = _MapCacheLegacy005Js.gt; useAsyncState = _MapCacheLegacy005Js.x; }, function (_srcLegacy007Js) { N8nButton_default = _srcLegacy007Js.Hn; N8nFormInput_default = _srcLegacy007Js.V; N8nText_default = _srcLegacy007Js.Vn; N8nTooltip_default = _srcLegacy007Js.mt; N8nLoading_default = _srcLegacy007Js.tt; N8nHeading_default = _srcLegacy007Js.zn; }, function (_enLegacy00bJs) {}, function (_preloadHelperLegacy00dJs) {}, function (_pluginVue_exportHelperLegacy00fJs) { __plugin_vue_export_helper_default = _pluginVue_exportHelperLegacy00fJs.t; }, function (_truncateLegacy00hJs) { useRouter = _truncateLegacy00hJs.y; }, function (_iconLegacy00nJs) {}, function (_overlayLegacy00rJs) {}, function (_emptyLegacy00vJs) {}, function (_useMessageLegacy00xJs) { useMessage = _useMessageLegacy00xJs.t; }, function (_useTelemetryLegacy00HJs) { require_sortBy = _useTelemetryLegacy00HJs.Lt; useTelemetry = _useTelemetryLegacy00HJs.t; }, function (_useToastLegacy00JJs) { useToast = _useToastLegacy00JJs.t; }, function (_sanitizeHtmlLegacy00LJs) {}, function (_CalendarDateLegacy00NJs) {}, function (_pathBrowserifyLegacy00RJs) {}, function (_constantsLegacy00TJs) { VIEWS = _constantsLegacy00TJs.Io; require_isEqual = _constantsLegacy00TJs._o; MODAL_CONFIRM = _constantsLegacy00TJs.ts; }, function (_mergeLegacy00VJs) {}, function (_baseOrderByLegacy00ZJs) {}, function (_dateformatLegacy00$Js) {}, function (_useDebounceLegacy011Js) {}, function (_useExternalHooksLegacy013Js) {}, function (_useStylesLegacy015Js) {}, function (_rolesStoreLegacy02ZJs) { useRolesStore = _rolesStoreLegacy02ZJs.t; }], execute: function () { __vite_style__ = document.createElement('style'); __vite_style__.textContent = "\n._container_14r2u_2 {\n\tmax-width: 700px;\n\tmargin: 0 auto;\n\tdisplay: flex;\n\tflex-direction: column;\n}\n._cardContainer_14r2u_9 {\n\tpadding: 8px 16px;\n\tborder-radius: 4px;\n\tborder: var(--border);\n\tbackground-color: var(--color--background--light-3);\n.el-skeleton__p {\n\t\tmargin-bottom: 8px;\n\t\tmargin-top: 0;\n}\n}\n._card_14r2u_9 {\n\tdisplay: flex;\n}\n._card_14r2u_9:not(:last-child) {\n\tborder-bottom: var(--border);\n}\n._cardTitle_14r2u_28 {\n\twidth: 133px;\n}\n._backButton_14r2u_32 {\n\tposition: absolute;\n\ttop: 10px;\n\tleft: 10px;\n}\n._headerContainer_14r2u_38 {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\talign-items: center;\n}\n._formContainer_14r2u_44 {\n\tmax-width: 415px;\n}\n._presetsContainer_14r2u_48 {\n\tdisplay: flex;\n\tgap: 8px;\n}\n._checkbox_14r2u_53 {\n\tdisplay: inline-flex !important;\n\tmargin-bottom: 0 !important;\nlabel {\n\t\tpadding-bottom: 0 !important;\n}\n}\n/*$vite$:1*/"; document.head.appendChild(__vite_style__); //#region src/features/project-roles/ProjectRoleView.vue?vue&type=script&setup=true&lang.ts import_isEqual = /* @__PURE__ */__toESM(require_isEqual()); import_sortBy = /* @__PURE__ */__toESM(require_sortBy()); _hoisted_1 = { key: 0 }; _hoisted_2 = { style: { "flex": "1" } }; _hoisted_3 = { key: 0, class: "mt-xl" }; ProjectRoleView_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */defineComponent({ __name: "ProjectRoleView", props: { roleSlug: {} }, setup(__props) { const rolesStore = useRolesStore(); const router = useRouter(); const { showError, showMessage } = useToast(); const i18n = useI18n(); const message = useMessage(); const telemetry = useTelemetry(); const props = __props; const defaultForm = () => ({ displayName: "", description: "", scopes: structuredClone(toRaw(rolesStore.processedProjectRoles.find(role => role.slug === "project:viewer")?.scopes || [])) }); const initialState = ref(); const { state: form, isLoading } = useAsyncState(async () => { if (!props.roleSlug) return defaultForm(); try { const role = await rolesStore.fetchRoleBySlug({ slug: props.roleSlug }); initialState.value = structuredClone(role); return { displayName: role.displayName, description: role.description, scopes: role.scopes }; } catch (error) { showError(error, "Error fetching role"); return defaultForm(); } }, defaultForm(), { shallow: false }); const hasUnsavedChanges = computed(() => { if (!initialState.value) return false; if (!(0, import_isEqual.default)(initialState.value.displayName, form.value.displayName)) return true; if (!(0, import_isEqual.default)(initialState.value.description ?? null, form.value.description || null)) return true; if (!(0, import_isEqual.default)((0, import_sortBy.default)(initialState.value.scopes), (0, import_sortBy.default)(form.value.scopes))) return true; return false; }); function resetForm(payload) { form.value = payload ? { displayName: payload.displayName, description: payload.description, scopes: payload.scopes } : defaultForm(); } const project = ["read", "update", "delete"].map(action => `project:${action}`); const folder = ["read", "update", "create", "move", "delete"].map(action => `folder:${action}`); const workflow = ["read", "update", "create", "move", "delete"].map(action => `workflow:${action}`); const credential = ["read", "update", "create", "share", "move", "delete"].map(action => `credential:${action}`); const sourceControl = ["push"].map(action => `sourceControl:${action}`); const dataTable = ["read", "readRow", "update", "writeRow", "create", "delete"].map(action => `dataTable:${action}`); const projectVariable = ["read", "update", "create", "delete"].map(action => `projectVariable:${action}`); const scopeTypes = ["project", "folder", "workflow", "credential", "dataTable", "projectVariable", "sourceControl"]; const scopes = { project, folder, workflow, credential, sourceControl, dataTable, projectVariable }; function toggleScope(scope) { const index = form.value.scopes.indexOf(scope); if (index !== -1) form.value.scopes.splice(index, 1);else form.value.scopes.push(scope); if (scope.startsWith("dataTable:") && scope.endsWith(":read")) { toggleScope(scope.replace(":read", ":listProject")); return; } if (scope.endsWith(":read")) toggleScope(scope.replace(":read", ":list")); if (scope === "workflow:update") toggleScope("workflow:execute"); } async function createProjectRole() { try { const role = await rolesStore.createProjectRole({ ...form.value, description: form.value.description ?? void 0, roleType: "project" }); rolesStore.fetchRoles(); telemetry.track("User successfully created new role", { role_id: role.slug, role_name: role.displayName, permissions: role.scopes }); router.replace({ name: VIEWS.PROJECT_ROLE_SETTINGS, params: { roleSlug: role.slug } }); showMessage({ type: "success", message: i18n.baseText("projectRoles.action.create.success") }); initialState.value = structuredClone(role); return role; } catch (error) { showError(error, i18n.baseText("projectRoles.action.create.error")); return; } } async function confirmRoleUpdate(usedByUsers) { if (!usedByUsers) return true; return (await message.confirm(i18n.baseText("projectRoles.action.update.text", { interpolate: { count: usedByUsers } }), i18n.baseText("projectRoles.action.update.title", { interpolate: { count: usedByUsers } }), { type: "warning", confirmButtonText: i18n.baseText("projectRoles.action.update"), cancelButtonText: i18n.baseText("projectRoles.action.cancel") })) === MODAL_CONFIRM; } async function updateProjectRole(slug) { if (!(await confirmRoleUpdate(initialState?.value?.usedByUsers))) return; try { const role = await rolesStore.updateProjectRole(slug, { ...form.value, description: form.value.description ?? void 0 }); rolesStore.fetchRoles(); telemetry.track("User updated role", { role_id: role.slug, role_name: role.displayName, permissions_from: initialState.value?.scopes, permissions_to: role.scopes }); initialState.value = structuredClone(role); showMessage({ type: "success", message: i18n.baseText("projectRoles.action.update.success") }); return role; } catch (error) { showError(error, i18n.baseText("projectRoles.action.update.error")); return; } } async function handleSubmit() { if (props.roleSlug) await updateProjectRole(props.roleSlug);else await createProjectRole(); } function setPreset(slug) { const preset = rolesStore.processedProjectRoles.find(role => role.slug === slug); if (!preset) return; form.value.scopes = structuredClone(toRaw(preset.scopes)); } async function deleteRole() { if (!initialState?.value) return; if ((await message.confirm(i18n.baseText("projectRoles.action.delete.text", { interpolate: { roleName: initialState.value.displayName } }), i18n.baseText("projectRoles.action.delete.title", { interpolate: { roleName: initialState.value.displayName } }), { type: "warning", confirmButtonText: i18n.baseText("projectRoles.action.delete"), cancelButtonText: i18n.baseText("projectRoles.action.cancel") })) !== "confirm") return; telemetry.track("User clicked delete role", { role_id: initialState.value.slug, role_name: initialState.value.displayName, permissions: initialState.value?.scopes }); try { await rolesStore.deleteProjectRole(initialState.value.slug); const index = rolesStore.roles.project.findIndex(role => role.slug === initialState.value?.slug); if (index !== -1) rolesStore.roles.project.splice(index, 1); showMessage({ title: i18n.baseText("projectRoles.action.delete.success"), type: "success" }); telemetry.track("User successfully deleted role", { role_id: initialState.value.slug, role_name: initialState.value.displayName, permissions: initialState.value?.scopes }); router.back(); } catch (error) { showError(error, i18n.baseText("projectRoles.action.delete.error")); return; } } const displayNameValidationRules = [{ name: "REQUIRED" }, { name: "MIN_LENGTH", config: { minimum: 2 } }]; return (_ctx, _cache) => { return openBlock(), createElementBlock("div", { class: normalizeClass(["pb-xl", _ctx.$style.container]) }, [createVNode(unref(N8nButton_default), { icon: "arrow-left", type: "secondary", class: normalizeClass(_ctx.$style.backButton), text: "", onClick: _cache[0] || (_cache[0] = () => unref(router).back()) }, { default: withCtx(() => [createTextVNode(toDisplayString(unref(i18n).baseText("projectRoles.backToRoleList")), 1)]), _: 1 }, 8, ["class"]), createBaseVNode("div", { class: normalizeClass(["mb-xl", _ctx.$style.headerContainer]) }, [createVNode(unref(N8nHeading_default), { tag: "h1", size: "2xlarge" }, { default: withCtx(() => [createTextVNode(toDisplayString(_ctx.roleSlug ? `Role "${unref(form).displayName}"` : unref(i18n).baseText("projectRoles.newRole")), 1)]), _: 1 }), initialState.value ? (openBlock(), createElementBlock("div", _hoisted_1, [createVNode(unref(N8nButton_default), { type: "secondary", disabled: !hasUnsavedChanges.value, class: "mr-xs", onClick: _cache[1] || (_cache[1] = $event => resetForm(initialState.value)) }, { default: withCtx(() => [createTextVNode(toDisplayString(unref(i18n).baseText("projectRoles.discardChanges")), 1)]), _: 1 }, 8, ["disabled"]), createVNode(unref(N8nButton_default), { disabled: !hasUnsavedChanges.value, onClick: handleSubmit }, { default: withCtx(() => [createTextVNode(toDisplayString(unref(i18n).baseText("projectRoles.save")), 1)]), _: 1 }, 8, ["disabled"])])) : (openBlock(), createBlock(unref(N8nButton_default), { key: 1, onClick: handleSubmit }, { default: withCtx(() => [createTextVNode(toDisplayString(unref(i18n).baseText("projectRoles.create")), 1)]), _: 1 }))], 2), createBaseVNode("div", { class: normalizeClass(["mb-l", _ctx.$style.formContainer]) }, [createVNode(unref(N8nFormInput_default), { modelValue: unref(form).displayName, "onUpdate:modelValue": _cache[2] || (_cache[2] = $event => unref(form).displayName = $event), label: unref(i18n).baseText("projectRoles.roleName"), "validate-on-blur": "", "validation-rules": displayNameValidationRules, class: "mb-s", "show-required-asterisk": "", required: "", maxlength: 100 }, null, 8, ["modelValue", "label"]), createVNode(unref(N8nFormInput_default), { modelValue: unref(form).description, "onUpdate:modelValue": _cache[3] || (_cache[3] = $event => unref(form).description = $event), label: unref(i18n).baseText("projectRoles.description"), placeholder: unref(i18n).baseText("projectRoles.optional"), type: "textarea", maxlength: 500, autosize: { minRows: 2, maxRows: 4 } }, null, 8, ["modelValue", "label", "placeholder"])], 2), createVNode(unref(N8nHeading_default), { tag: "h2", size: "xlarge", class: "mb-s" }, { default: withCtx(() => [createTextVNode(toDisplayString(unref(i18n).baseText("projectRoles.permissions")), 1)]), _: 1 }), createVNode(unref(N8nText_default), { color: "text-light", class: "mb-2xs", tag: "p" }, { default: withCtx(() => [createTextVNode(toDisplayString(unref(i18n).baseText("projectRoles.preset")), 1)]), _: 1 }), createBaseVNode("div", { class: normalizeClass(["mb-s", _ctx.$style.presetsContainer]) }, [createVNode(unref(N8nButton_default), { type: "secondary", onClick: _cache[4] || (_cache[4] = $event => setPreset("project:admin")) }, { default: withCtx(() => [createTextVNode(toDisplayString(unref(i18n).baseText("projectRoles.admin")), 1)]), _: 1 }), createVNode(unref(N8nButton_default), { type: "secondary", onClick: _cache[5] || (_cache[5] = $event => setPreset("project:editor")) }, { default: withCtx(() => [createTextVNode(toDisplayString(unref(i18n).baseText("projectRoles.editor")), 1)]), _: 1 }), createVNode(unref(N8nButton_default), { type: "secondary", onClick: _cache[6] || (_cache[6] = $event => setPreset("project:viewer")) }, { default: withCtx(() => [createTextVNode(toDisplayString(unref(i18n).baseText("projectRoles.viewer")), 1)]), _: 1 })], 2), createBaseVNode("div", { class: normalizeClass(_ctx.$style.cardContainer) }, [(openBlock(), createElementBlock(Fragment, null, renderList(scopeTypes, type => { return createBaseVNode("div", { key: type, class: normalizeClass(["mb-s mt-s", _ctx.$style.card]) }, [createBaseVNode("div", { class: normalizeClass(_ctx.$style.cardTitle) }, toDisplayString(unref(i18n).baseText(`projectRoles.type.${type}`)), 3), createBaseVNode("div", _hoisted_2, [unref(isLoading) ? (openBlock(), createBlock(unref(N8nLoading_default), { key: 0, rows: scopes[type].length, "shrink-last": false }, null, 8, ["rows"])) : (openBlock(true), createElementBlock(Fragment, { key: 1 }, renderList(scopes[type], scope => { return openBlock(), createElementBlock("div", { key: scope, class: "mb-2xs" }, [createVNode(unref(N8nTooltip_default), { content: unref(i18n).baseText(`projectRoles.${scope}.tooltip`), placement: "right", enterable: false, "show-after": 250 }, { default: withCtx(() => [createVNode(unref(N8nFormInput_default), { "data-test-id": `scope-checkbox-${scope}`, "model-value": unref(form).scopes.includes(scope), label: unref(i18n).baseText(`projectRoles.${scope}`), "validate-on-blur": "", type: "checkbox", class: normalizeClass(_ctx.$style.checkbox), "onUpdate:modelValue": () => toggleScope(scope) }, null, 8, ["data-test-id", "model-value", "label", "class", "onUpdate:modelValue"])]), _: 2 }, 1032, ["content"])]); }), 128))])], 2); }), 64))], 2), _ctx.roleSlug && !initialState.value?.systemRole ? (openBlock(), createElementBlock("div", _hoisted_3, [createVNode(unref(N8nHeading_default), { tag: "h2", class: "mb-2xs", size: "large" }, { default: withCtx(() => [createTextVNode(toDisplayString(unref(i18n).baseText("projectRoles.dangerZone")), 1)]), _: 1 }), createVNode(unref(N8nText_default), { tag: "p", class: "mb-s" }, { default: withCtx(() => [initialState.value?.usedByUsers ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createTextVNode(toDisplayString(unref(i18n).baseText("projectRoles.action.delete.useWarning", { interpolate: { count: initialState.value.usedByUsers } })), 1)], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [createTextVNode(toDisplayString(unref(i18n).baseText("projectRoles.action.delete.warning")), 1)], 64))]), _: 1 }), createVNode(unref(N8nButton_default), { type: "danger", disabled: Boolean(initialState.value?.usedByUsers), onClick: deleteRole }, { default: withCtx(() => [createTextVNode(toDisplayString(unref(i18n).baseText("projectRoles.action.delete.button")), 1)]), _: 1 }, 8, ["disabled"])])) : createCommentVNode("", true)], 2); }; } }); //#endregion //#region src/features/project-roles/ProjectRoleView.vue?vue&type=style&index=0&lang.module.css container = "_container_14r2u_2"; cardContainer = "_cardContainer_14r2u_9"; card = "_card_14r2u_9"; cardTitle = "_cardTitle_14r2u_28"; backButton = "_backButton_14r2u_32"; headerContainer = "_headerContainer_14r2u_38"; formContainer = "_formContainer_14r2u_44"; presetsContainer = "_presetsContainer_14r2u_48"; checkbox = "_checkbox_14r2u_53"; ProjectRoleView_vue_vue_type_style_index_0_lang_module_default = { container, cardContainer, card, cardTitle, backButton, headerContainer, formContainer, presetsContainer, checkbox }; //#endregion //#region src/features/project-roles/ProjectRoleView.vue cssModules = { "$style": ProjectRoleView_vue_vue_type_style_index_0_lang_module_default }; _export("default", ProjectRoleView_default = /* @__PURE__ */__plugin_vue_export_helper_default(ProjectRoleView_vue_vue_type_script_setup_true_lang_default, [["__cssModules", cssModules]])); //#endregion } }; }); })();