n8n-editor-ui 1.112.1 → 1.113.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/.build/cache-marker +1 -0
  2. package/.build/node-popularity.json +3918 -0
  3. package/dist/assets/{AddDataStoreModal-C9lDhooH.js → AddDataStoreModal-BpBgou0E.js} +1 -1
  4. package/dist/assets/{AnimatedSpinner-DoiaSsyo.js → AnimatedSpinner-BVVzuhy8.js} +1 -1
  5. package/dist/assets/{AnnotationTagsDropdown.ee.vue_vue_type_script_setup_true_lang-C68foyxp.js → AnnotationTagsDropdown.ee.vue_vue_type_script_setup_true_lang-D9y_kml7.js} +1 -1
  6. package/dist/assets/{AuthView-CLDlKRpw.js → AuthView-DLJKQ74o.js} +2 -2
  7. package/dist/assets/{ChangePasswordView-iG7PgYdd.js → ChangePasswordView-BMWrkaiq.js} +3 -3
  8. package/dist/assets/CollectionParameter-Cb7K8toD.js +4 -0
  9. package/dist/assets/{ConsumedTokensDetails.vue_vue_type_script_setup_true_lang-DlF8qxM5.js → ConsumedTokensDetails.vue_vue_type_script_setup_true_lang-CgS2Cb5Q.js} +1 -1
  10. package/dist/assets/{CredentialsView-CYgIFP1z.js → CredentialsView-DHSg9xJ1.js} +10 -10
  11. package/dist/assets/{DataStoreActions.vue_vue_type_script_setup_true_lang-BC-HriQ3.js → DataStoreActions.vue_vue_type_script_setup_true_lang-C2Dn9B2o.js} +1 -1
  12. package/dist/assets/{DataStoreDetailsView-C8fMxukz.css → DataStoreDetailsView-Bc-J9ZrW.css} +224 -46
  13. package/dist/assets/{DataStoreDetailsView-CtMeAyyY.js → DataStoreDetailsView-yJ7Ifouw.js} +8117 -339
  14. package/dist/assets/{DataStoreView-D0R0E_jH.css → DataStoreView-BqQv7QeU.css} +10 -9
  15. package/dist/assets/{DataStoreView-B1Kxtjnl.js → DataStoreView-jb9J_g-Y.js} +35 -16
  16. package/dist/assets/{DemoFooter-BPQy7EdR.js → DemoFooter-BYvzzkpQ.js} +6 -6
  17. package/dist/assets/{EmptySharedSectionActionBox.vue_vue_type_script_setup_true_lang-D9e3ObnE.js → EmptySharedSectionActionBox.vue_vue_type_script_setup_true_lang-BfHfE-dU.js} +1 -1
  18. package/dist/assets/{EntityNotFound-DDHiVWRe.js → EntityNotFound-lPracI2m.js} +1 -1
  19. package/dist/assets/{EntityUnAuthorised-Clm3_4En.js → EntityUnAuthorised-zuygLqjz.js} +1 -1
  20. package/dist/assets/{ErrorView-CrYsrADA.js → ErrorView-C_k5_sJ0.js} +1 -1
  21. package/dist/assets/{EvaluationsRootView-C0OyvjOt.js → EvaluationsRootView-DP2_MhvN.js} +1 -1
  22. package/dist/assets/{EvaluationsView-BcMhW8o6.js → EvaluationsView-BHRPpTsS.js} +3 -3
  23. package/dist/assets/{ExecutionsTime.vue_vue_type_script_setup_true_lang-BmjUbn85.js → ExecutionsTime.vue_vue_type_script_setup_true_lang-DTpILxvC.js} +2 -2
  24. package/dist/assets/{ExecutionsView-GKNLT5Ec.css → ExecutionsView-B5yiPX6U.css} +1 -1
  25. package/dist/assets/{ExecutionsView-CdMuQ6Ay.js → ExecutionsView-Bv3YVM-6.js} +26 -20
  26. package/dist/assets/{FixedCollectionParameter-DNRbGHuU.js → FixedCollectionParameter-CZc3TqBt.js} +1 -1
  27. package/dist/assets/{ForgotMyPasswordView-CVYkGoS6.js → ForgotMyPasswordView-CaiqDg42.js} +3 -3
  28. package/dist/assets/{InfoAccordion-DXq9DJ4j.js → InfoAccordion-TbgnFURd.js} +1 -1
  29. package/dist/assets/{InsightsChartAverageRuntime-CXByy6Zo.js → InsightsChartAverageRuntime-BqCmV_C3.js} +4 -4
  30. package/dist/assets/{InsightsChartFailed-9zaeZgek.js → InsightsChartFailed-nhNAvWJ-.js} +4 -4
  31. package/dist/assets/{InsightsChartFailureRate-DT96wC8C.js → InsightsChartFailureRate-Ca8Ar9nD.js} +4 -4
  32. package/dist/assets/{InsightsChartTimeSaved-C6pLWWxa.js → InsightsChartTimeSaved-CuO9b6Em.js} +4 -4
  33. package/dist/assets/{InsightsChartTotal-Cc0YLVD7.js → InsightsChartTotal-Dk2_nvoT.js} +4 -4
  34. package/dist/assets/{InsightsDashboard-C27Avzrv.css → InsightsDashboard-Bo0U18-6.css} +18 -12
  35. package/dist/assets/{InsightsDashboard-qL2EE60l.js → InsightsDashboard-zCjTFLpM.js} +68 -35
  36. package/dist/assets/{InsightsPaywall-C_2IPEhI.js → InsightsPaywall-CBtrv5fk.js} +1 -1
  37. package/dist/assets/{InsightsSummary-tylKFBgw.js → InsightsSummary-BWRporX0.js} +1 -1
  38. package/dist/assets/{InsightsTableWorkflows-BwRj0aXe.js → InsightsTableWorkflows-DlGA2gWN.js} +4 -4
  39. package/dist/assets/{Logo-DqC1X5we.js → Logo-ayCSvzHf.js} +1 -1
  40. package/dist/assets/{LogsPanel-DZguGtyt.js → LogsPanel-DwPSXTSp.js} +34 -26
  41. package/dist/assets/{MainHeader-IFzZPcNW.js → MainHeader-BGOzl1ir.js} +11 -11
  42. package/dist/assets/{MainSidebar-D-2Yb5yU.js → MainSidebar-CGhxTuih.js} +27 -10
  43. package/dist/assets/{NodeCreation-CrPTESjn.js → NodeCreation-C2TX7WTu.js} +3 -3
  44. package/dist/assets/{NodeCreator-Db1k7Npw.js → NodeCreator-tQVCw9Uh.js} +1 -1
  45. package/dist/assets/{NodeDetailsView-T6l22FLo.js → NodeDetailsView-C-BCfvgR.js} +13 -13
  46. package/dist/assets/{NodeDetailsViewV2-Caf-LQD7.js → NodeDetailsViewV2-CHkxHxvz.js} +13 -13
  47. package/dist/assets/{NodeView-B08ajmmZ.js → NodeView-B6Bv6TYS.js} +13 -12
  48. package/dist/assets/{PageViewLayout-B01Cj9Ag.js → PageViewLayout-_SQAsKsq.js} +1 -1
  49. package/dist/assets/{PrebuiltAgentTemplatesView-ZbB8Spq8.js → PrebuiltAgentTemplatesView-DOI6Oras.js} +2 -2
  50. package/dist/assets/{ProjectBreadcrumb-vTjbzQHC.js → ProjectBreadcrumb-DdovGxoT.js} +1 -1
  51. package/dist/assets/{ProjectHeader-CsH8YD16.js → ProjectHeader-CmNr3RiV.js} +3 -3
  52. package/dist/assets/{ProjectSettings-CCVXNK3G.css → ProjectSettings-B5z1mrGW.css} +155 -9
  53. package/dist/assets/{ProjectSettings-CYy5LBLu.js → ProjectSettings-BLw1-aa2.js} +490 -121
  54. package/dist/assets/{PushConnectionTracker.vue_vue_type_script_setup_true_lang-DOMRXCVj.js → PushConnectionTracker.vue_vue_type_script_setup_true_lang-BvsEzRu6.js} +1 -1
  55. package/dist/assets/{ResourcesListLayout-CEq6DTya.js → ResourcesListLayout-CFoOOQpo.js} +4 -4
  56. package/dist/assets/{RunDataJson-CM54dhgQ.js → RunDataJson-KBqmqbfA.js} +3 -3
  57. package/dist/assets/{RunDataJsonActions-BGkwaXF1.js → RunDataJsonActions-CKFc7ymK.js} +1 -1
  58. package/dist/assets/{RunDataParsedAiContent-CCScHhrV.js → RunDataParsedAiContent-Ce_ctsro.js} +2 -2
  59. package/dist/assets/{RunDataSearch-D8tSIc5y.js → RunDataSearch-gM--YmOH.js} +1 -1
  60. package/dist/assets/{RunDataTable-y4SItH7m.js → RunDataTable-CV1IQEC1.js} +1 -1
  61. package/dist/assets/{SamlOnboarding-B-qxZA7T.js → SamlOnboarding-sD7YkjXE.js} +3 -3
  62. package/dist/assets/{SelectedItemsInfo-8rTveqLV.js → SelectedItemsInfo-CWRoXt5N.js} +1 -1
  63. package/dist/assets/{SettingsApiView-Crwc7f2q.js → SettingsApiView-CjxSweZ2.js} +1 -1
  64. package/dist/assets/{SettingsCommunityNodesView-D_CDclON.js → SettingsCommunityNodesView-BZS-1Pu8.js} +6 -6
  65. package/dist/assets/{SettingsExternalSecrets-D9EYRw94.js → SettingsExternalSecrets-CUP7WmUX.js} +1 -1
  66. package/dist/assets/{SettingsLdapView-IWmIFFmQ.js → SettingsLdapView-CAcFtpvb.js} +1 -1
  67. package/dist/assets/{SettingsLogStreamingView-T9ajKTLt.js → SettingsLogStreamingView-Db06ainF.js} +1 -1
  68. package/dist/assets/{SettingsPersonalView-ClpcCCUK.js → SettingsPersonalView-CFAcW525.js} +15 -2
  69. package/dist/assets/{SettingsSourceControl-D4MKPsIp.js → SettingsSourceControl-Cl0Z45op.js} +1 -1
  70. package/dist/assets/{SettingsSso-Dh0TCa3N.js → SettingsSso-hvpitcmh.js} +1 -1
  71. package/dist/assets/{SettingsUsageAndPlan-_VxSs28G.css → SettingsUsageAndPlan-CfFJy6fo.css} +3 -3
  72. package/dist/assets/{SettingsUsageAndPlan-DMz52D_8.js → SettingsUsageAndPlan-pIa02R8X.js} +3 -7
  73. package/dist/assets/{SettingsUsersView-CyOqQQ1T.js → SettingsUsersView-Bc_d_j_C.js} +10 -24
  74. package/dist/assets/{SettingsView-9XSvAxZn.js → SettingsView-k1Qk6b9u.js} +1 -1
  75. package/dist/assets/{SetupView-CaQUQHtZ.js → SetupView-CgueTipX.js} +3 -3
  76. package/dist/assets/{SetupWorkflowCredentialsButton-CLPdPWR-.js → SetupWorkflowCredentialsButton-9ZdgoxH6.js} +1 -1
  77. package/dist/assets/{SetupWorkflowFromTemplateView-Cwy86CRf.js → SetupWorkflowFromTemplateView-DImn3MLc.js} +3 -3
  78. package/dist/assets/{SigninView-B1CFcKZW.js → SigninView-Dy2njlT9.js} +3 -3
  79. package/dist/assets/{SignoutView-tXEnZbBW.js → SignoutView-BW4OLG4T.js} +1 -1
  80. package/dist/assets/{SignupView-tG0nF3IX.js → SignupView-DqiOjgU_.js} +3 -3
  81. package/dist/assets/{TableBase-Bk0Ksvri.js → TableBase-J7qyS7Oi.js} +1 -1
  82. package/dist/assets/{Tags-bLJnzJ9O.js → Tags-DHmekS5b.js} +1 -1
  83. package/dist/assets/{TemplateDetails-DwB2MNDs.js → TemplateDetails-lA7coCfr.js} +2 -2
  84. package/dist/assets/{TemplateList-xz6dq_b_.js → TemplateList-C_enJUC-.js} +1 -1
  85. package/dist/assets/{TemplatesCollectionView-CBHrX6qh.js → TemplatesCollectionView-Bvr4Jl4e.js} +6 -6
  86. package/dist/assets/{TemplatesSearchView-DlCohPQw.js → TemplatesSearchView-DNEWIXcA.js} +3 -3
  87. package/dist/assets/{TemplatesView-BWRC7u13.js → TemplatesView-D6kBDKHq.js} +1 -1
  88. package/dist/assets/{TemplatesWorkflowView-IFi-aXTJ.js → TemplatesWorkflowView-CxpvFC33.js} +6 -6
  89. package/dist/assets/{TriggerPanel-CGEgWBP1.js → TriggerPanel-aOMoGQPb.js} +5 -5
  90. package/dist/assets/{VariablesView-DCIpb3py.js → VariablesView-CF7zW6sO.js} +6 -6
  91. package/dist/assets/{WorkerView-BNJtp3_b.js → WorkerView-CPSFDQ3M.js} +8 -8
  92. package/dist/assets/{WorkflowActivator-GWpvfdPq.js → WorkflowActivator-2k4uBcXx.js} +3 -3
  93. package/dist/assets/{WorkflowExecutionsInfoAccordion-DyC6zINy.js → WorkflowExecutionsInfoAccordion-DLSyy7P3.js} +2 -2
  94. package/dist/assets/{WorkflowExecutionsLandingPage-CHU6rsbS.js → WorkflowExecutionsLandingPage-B0lwEkzs.js} +3 -3
  95. package/dist/assets/{WorkflowExecutionsPreview-BRZcVWz8.js → WorkflowExecutionsPreview-fdG8WvjQ.js} +4 -4
  96. package/dist/assets/{WorkflowExecutionsView-D2avX462.js → WorkflowExecutionsView-DoOsdRNS.js} +12 -14
  97. package/dist/assets/{WorkflowExecutionsView-C_xuUSa8.css → WorkflowExecutionsView-DqWqyiNg.css} +2 -2
  98. package/dist/assets/{WorkflowHistory-CezxUWJ3.js → WorkflowHistory-BmCEHmbX.js} +2 -2
  99. package/dist/assets/{WorkflowOnboardingView-CoLRNMn7.js → WorkflowOnboardingView-DoANwef9.js} +1 -1
  100. package/dist/assets/{WorkflowPreview-6_5498ls.js → WorkflowPreview-BcVSQJ1r.js} +1 -1
  101. package/dist/assets/{WorkflowsView-yo-aPIAy.js → WorkflowsView-DfkdEDYd.js} +14 -14
  102. package/dist/assets/{canvas-CNbb2A4n.js → canvas-DjkOwLgJ.js} +1 -1
  103. package/dist/assets/{chartjs.utils-BuEfxZRs.js → chartjs.utils-P0M5ijsc.js} +2 -2
  104. package/dist/assets/{core-BmUd0ZQy.js → core-WbBbE4BE.js} +1 -1
  105. package/dist/assets/{global-link-actions-DLwTpw-D.js → global-link-actions-Cq9wmyMP.js} +1 -1
  106. package/dist/assets/{index-B7wrqKiF.css → index-CpPc1kM8.css} +331 -206
  107. package/dist/assets/{index-BqqmY62y.js → index-DGLJxfnn.js} +8240 -4664
  108. package/dist/assets/{index-B4kldndn.js → index-vcIMPEwS.js} +1 -1
  109. package/dist/assets/{pickBy-D_Xqfu3B.js → pickBy-ClKklBll.js} +1 -1
  110. package/dist/assets/{readyToRunWorkflows.store-DV_gQvCM.js → readyToRunWorkflows.store-By37rv7G.js} +1 -1
  111. package/dist/assets/readyToRunWorkflowsV2.store-Dl9lSVnl.js +648 -0
  112. package/dist/assets/{templateActions-BswjlHEI.js → templateActions-DIHXnHcb.js} +1 -1
  113. package/dist/assets/{useBeforeUnload-BfDs84Xo.js → useBeforeUnload-DixKQhw1.js} +1 -1
  114. package/dist/assets/{useExecutionDebugging-ZrtkQtcL.js → useExecutionDebugging-CONIO3Vz.js} +1 -1
  115. package/dist/assets/{useImportCurlCommand-TipLhFW-.js → useImportCurlCommand-CcLwFKyp.js} +1 -1
  116. package/dist/assets/{useProjectPages-DGeR5Bq7.js → useProjectPages-eaNvpOz-.js} +1 -1
  117. package/dist/assets/{usePushConnection-BxoIfCAQ.js → usePushConnection-C9lQfiNc.js} +12 -7
  118. package/dist/assets/{useWorkflowActivate-Dk_tmPQm.js → useWorkflowActivate-ByzVgA6z.js} +1 -1
  119. package/dist/index.html +2 -2
  120. package/package.json +1 -1
  121. package/scripts/fetch-node-popularity.mjs +90 -0
  122. package/turbo.json +19 -0
  123. package/vite/vite-plugin-node-popularity.mts +32 -0
  124. package/vite.config.mts +2 -0
  125. package/dist/assets/CollectionParameter-CYXwrQBH.js +0 -4
  126. package/dist/assets/readyToRunWorkflowsV2.store-ZhxGm4dM.js +0 -137
@@ -1,8 +1,8 @@
1
- import { d as defineComponent, r as ref, x as computed, e as createBlock, g as openBlock, bs as createSlots, w as withCtx, Y as renderSlot, h as createElementBlock, F as Fragment, A as renderList, l as unref, ed as _sfc_main$5, n as normalizeClass, i as createVNode, J as N8nUserInfo, K as mergeProps, D as useI18n, ec as N8nSelect, _ as _export_sfc, ej as mergeModels, ek as useModel, br as onClickOutside, j as createBaseVNode, f as createCommentVNode, aa as Tooltip, ab as _sfc_main$6, q as N8nButton, k as createTextVNode, t as toDisplayString, gn as N8nTabs, N as N8nIcon, c as useI18n$1, a9 as resolveComponent, p as N8nText, fI as ProjectSharing, e9 as N8nInputLabel, d2 as N8nInput, B as withModifiers, aB as usePageRedirectionHelper, ac as I18nT, u as useUsersStore, av as useProjectsStore, gA as useRolesStore, bc as useCloudPlanStore, a as useToast, b as useRouter, ay as useDocumentTitle, a8 as watch, b2 as onBeforeMount, o as onMounted, e$ as N8nFormInput, gB as N8nUsersList, dT as deepCopy, am as useTelemetry, Z as nextTick, fx as isIconOrEmoji, V as VIEWS } from "./index-BqqmY62y.js";
2
- import { P as ProjectHeader } from "./ProjectHeader-CsH8YD16.js";
3
- import "./useProjectPages-DGeR5Bq7.js";
4
- import "./readyToRunWorkflowsV2.store-ZhxGm4dM.js";
5
- const _sfc_main$4 = /* @__PURE__ */ defineComponent({
1
+ import { d as defineComponent, r as ref, x as computed, e as createBlock, g as openBlock, bs as createSlots, w as withCtx, Y as renderSlot, h as createElementBlock, F as Fragment, A as renderList, l as unref, ed as _sfc_main$8, n as normalizeClass, i as createVNode, J as N8nUserInfo, K as mergeProps, D as useI18n, ec as N8nSelect, _ as _export_sfc, el as mergeModels, em as useModel, br as onClickOutside, j as createBaseVNode, f as createCommentVNode, aa as Tooltip, ab as _sfc_main$9, q as N8nButton, k as createTextVNode, t as toDisplayString, gn as N8nTabs, N as N8nIcon, c as useI18n$1, a9 as resolveComponent, p as N8nText, fI as ProjectSharing, e9 as N8nInputLabel, d2 as N8nInput, B as withModifiers, aB as usePageRedirectionHelper, ac as I18nT, a8 as watch, gA as isProjectRole, gB as ElRadio, aN as N8nActionDropdown, ej as N8nActionToggle, en as N8nDataTableServer, c3 as normalizeProps, c4 as guardReactiveProps, u as useUsersStore, av as useProjectsStore, gC as useRolesStore, bc as useCloudPlanStore, a as useToast, b as useRouter, ay as useDocumentTitle, b2 as onBeforeMount, o as onMounted, f1 as N8nFormInput, dT as deepCopy, am as useTelemetry, Z as nextTick, fx as isIconOrEmoji, V as VIEWS, er as useDebounceFn } from "./index-DGLJxfnn.js";
2
+ import { P as ProjectHeader } from "./ProjectHeader-CmNr3RiV.js";
3
+ import "./useProjectPages-eaNvpOz-.js";
4
+ import "./readyToRunWorkflowsV2.store-Dl9lSVnl.js";
5
+ const _sfc_main$7 = /* @__PURE__ */ defineComponent({
6
6
  __name: "UserSelect",
7
7
  props: {
8
8
  users: { default: () => [] },
@@ -68,7 +68,7 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
68
68
  }), createSlots({
69
69
  default: withCtx(() => [
70
70
  (openBlock(true), createElementBlock(Fragment, null, renderList(sortedUsers.value, (user) => {
71
- return openBlock(), createBlock(unref(_sfc_main$5), {
71
+ return openBlock(), createBlock(unref(_sfc_main$8), {
72
72
  id: `user-select-option-id-${user.id}`,
73
73
  key: user.id,
74
74
  value: user.id,
@@ -100,14 +100,14 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
100
100
  });
101
101
  const itemContainer = "_itemContainer_9rnse_123";
102
102
  const limitPopperWidth = "_limitPopperWidth_9rnse_128";
103
- const style0$3 = {
103
+ const style0$4 = {
104
104
  itemContainer,
105
105
  limitPopperWidth
106
106
  };
107
- const cssModules$3 = {
108
- "$style": style0$3
107
+ const cssModules$4 = {
108
+ "$style": style0$4
109
109
  };
110
- const N8nUserSelect = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["__cssModules", cssModules$3]]);
110
+ const N8nUserSelect = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["__cssModules", cssModules$4]]);
111
111
  var cache = /* @__PURE__ */ new Map();
112
112
  function isEmojiSupported(unicode) {
113
113
  if (cache.has(unicode)) {
@@ -343,9 +343,9 @@ const ALL_ICON_PICKER_ICONS = [
343
343
  "toolbox",
344
344
  "spinner"
345
345
  ];
346
- const _hoisted_1$3 = ["aria-expanded"];
346
+ const _hoisted_1$5 = ["aria-expanded"];
347
347
  const _hoisted_2$2 = ["onClick"];
348
- const _sfc_main$3 = /* @__PURE__ */ defineComponent({
348
+ const _sfc_main$6 = /* @__PURE__ */ defineComponent({
349
349
  ...{ name: "N8nIconPicker" },
350
350
  __name: "IconPicker",
351
351
  props: /* @__PURE__ */ mergeModels({
@@ -430,7 +430,7 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
430
430
  createTextVNode(toDisplayString(props.buttonTooltip ?? unref(t)("iconPicker.button.defaultToolTip")), 1)
431
431
  ]),
432
432
  default: withCtx(() => [
433
- model.value.type === "icon" ? (openBlock(), createBlock(unref(_sfc_main$6), {
433
+ model.value.type === "icon" ? (openBlock(), createBlock(unref(_sfc_main$9), {
434
434
  key: 0,
435
435
  class: normalizeClass(_ctx.$style["icon-button"]),
436
436
  icon: model.value.value,
@@ -501,7 +501,7 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
501
501
  }), 128))
502
502
  ], 2)) : createCommentVNode("", true)
503
503
  ], 2)) : createCommentVNode("", true)
504
- ], 10, _hoisted_1$3);
504
+ ], 10, _hoisted_1$5);
505
505
  };
506
506
  }
507
507
  });
@@ -511,7 +511,7 @@ const tabs = "_tabs_15yfs_144";
511
511
  const content = "_content_15yfs_148";
512
512
  const icon = "_icon_15yfs_154";
513
513
  const emoji = "_emoji_15yfs_127";
514
- const style0$2 = {
514
+ const style0$3 = {
515
515
  container,
516
516
  "emoji-button": "_emoji-button_15yfs_127",
517
517
  popup,
@@ -520,18 +520,18 @@ const style0$2 = {
520
520
  icon,
521
521
  emoji
522
522
  };
523
- const cssModules$2 = {
524
- "$style": style0$2
523
+ const cssModules$3 = {
524
+ "$style": style0$3
525
525
  };
526
- const IconPicker = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__cssModules", cssModules$2]]);
527
- const _hoisted_1$2 = { key: 1 };
526
+ const IconPicker = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["__cssModules", cssModules$3]]);
527
+ const _hoisted_1$4 = { key: 1 };
528
528
  const _hoisted_2$1 = { class: "pt-l" };
529
- const _sfc_main$2 = /* @__PURE__ */ defineComponent({
529
+ const _sfc_main$5 = /* @__PURE__ */ defineComponent({
530
530
  __name: "ProjectDeleteDialog",
531
531
  props: /* @__PURE__ */ mergeModels({
532
532
  currentProject: {},
533
533
  projects: {},
534
- isCurrentProjectEmpty: { type: Boolean }
534
+ resourceCounts: {}
535
535
  }, {
536
536
  "modelValue": { type: Boolean },
537
537
  "modelModifiers": {}
@@ -545,11 +545,14 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
545
545
  const selectedProject = ref(null);
546
546
  const operation2 = ref(null);
547
547
  const wipeConfirmText = ref("");
548
+ const hasMovableResources = computed(
549
+ () => props.resourceCounts.credentials + props.resourceCounts.workflows + props.resourceCounts.dataTables > 0
550
+ );
548
551
  const isValid = computed(() => {
549
552
  const expectedWipeConfirmation = locale.baseText(
550
553
  "projects.settings.delete.question.wipe.placeholder"
551
554
  );
552
- return props.isCurrentProjectEmpty || operation2.value === "transfer" && !!selectedProject.value || operation2.value === "wipe" && wipeConfirmText.value === expectedWipeConfirmation;
555
+ return !hasMovableResources.value || operation2.value === "transfer" && !!selectedProject.value || operation2.value === "wipe" && wipeConfirmText.value === expectedWipeConfirmation;
553
556
  });
554
557
  const onDelete = () => {
555
558
  if (!isValid.value) {
@@ -573,7 +576,7 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
573
576
  title: unref(locale).baseText("projects.settings.delete.title", {
574
577
  interpolate: { projectName: props.currentProject?.name ?? "" }
575
578
  }),
576
- width: "500"
579
+ width: "650"
577
580
  }, {
578
581
  footer: withCtx(() => [
579
582
  createVNode(_component_N8nButton, {
@@ -590,7 +593,7 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
590
593
  }, 8, ["disabled"])
591
594
  ]),
592
595
  default: withCtx(() => [
593
- _ctx.isCurrentProjectEmpty ? (openBlock(), createBlock(_component_n8n_text, {
596
+ !hasMovableResources.value ? (openBlock(), createBlock(_component_n8n_text, {
594
597
  key: 0,
595
598
  color: "text-base"
596
599
  }, {
@@ -598,7 +601,7 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
598
601
  createTextVNode(toDisplayString(unref(locale).baseText("projects.settings.delete.message.empty")), 1)
599
602
  ]),
600
603
  _: 1
601
- })) : (openBlock(), createElementBlock("div", _hoisted_1$2, [
604
+ })) : hasMovableResources.value ? (openBlock(), createElementBlock("div", _hoisted_1$4, [
602
605
  createVNode(_component_n8n_text, { color: "text-base" }, {
603
606
  default: withCtx(() => [
604
607
  createTextVNode(toDisplayString(unref(locale).baseText("projects.settings.delete.message")), 1)
@@ -675,7 +678,7 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
675
678
  }, 8, ["label"])
676
679
  ], 2)) : createCommentVNode("", true)
677
680
  ])
678
- ]))
681
+ ])) : createCommentVNode("", true)
679
682
  ]),
680
683
  _: 1
681
684
  }, 8, ["modelValue", "title"]);
@@ -683,15 +686,15 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
683
686
  }
684
687
  });
685
688
  const operation = "_operation_18zmn_123";
686
- const style0$1 = {
689
+ const style0$2 = {
687
690
  operation
688
691
  };
689
- const cssModules$1 = {
690
- "$style": style0$1
692
+ const cssModules$2 = {
693
+ "$style": style0$2
691
694
  };
692
- const ProjectDeleteDialog = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__cssModules", cssModules$1]]);
693
- const _hoisted_1$1 = { class: "pt-l" };
694
- const _sfc_main$1 = /* @__PURE__ */ defineComponent({
695
+ const ProjectDeleteDialog = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__cssModules", cssModules$2]]);
696
+ const _hoisted_1$3 = { class: "pt-l" };
697
+ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
695
698
  __name: "ProjectRoleUpgradeDialog",
696
699
  props: /* @__PURE__ */ mergeModels({
697
700
  limit: {},
@@ -742,7 +745,7 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
742
745
  })
743
746
  ]),
744
747
  default: withCtx(() => [
745
- createBaseVNode("div", _hoisted_1$1, [
748
+ createBaseVNode("div", _hoisted_1$3, [
746
749
  createVNode(unref(I18nT), {
747
750
  keypath: "projects.settings.role.upgrade.message",
748
751
  scope: "global"
@@ -765,6 +768,269 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
765
768
  };
766
769
  }
767
770
  });
771
+ const _hoisted_1$2 = { key: 1 };
772
+ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
773
+ __name: "ProjectMembersRoleCell",
774
+ props: {
775
+ data: {},
776
+ roles: {},
777
+ actions: {}
778
+ },
779
+ emits: ["update:role"],
780
+ setup(__props, { emit: __emit }) {
781
+ const props = __props;
782
+ const emit = __emit;
783
+ const selectedRole = ref(props.data.role);
784
+ const isEditable = computed(() => props.data.role !== "project:personalOwner");
785
+ watch(
786
+ () => props.data.role,
787
+ (newRole) => {
788
+ selectedRole.value = newRole;
789
+ }
790
+ );
791
+ const roleLabel2 = computed(
792
+ () => isProjectRole(selectedRole.value) ? props.roles[selectedRole.value]?.label || selectedRole.value : selectedRole.value
793
+ );
794
+ const onActionSelect = (role) => {
795
+ emit("update:role", {
796
+ role,
797
+ userId: props.data.id
798
+ });
799
+ };
800
+ return (_ctx, _cache) => {
801
+ return isEditable.value ? (openBlock(), createBlock(unref(N8nActionDropdown), {
802
+ key: 0,
803
+ placement: "bottom-start",
804
+ items: props.actions,
805
+ "max-height": 280,
806
+ "data-test-id": "project-member-role-dropdown",
807
+ onSelect: onActionSelect
808
+ }, {
809
+ activator: withCtx(() => [
810
+ createBaseVNode("button", {
811
+ class: normalizeClass(_ctx.$style.roleLabel),
812
+ type: "button"
813
+ }, [
814
+ createVNode(unref(N8nText), { color: "text-dark" }, {
815
+ default: withCtx(() => [
816
+ createTextVNode(toDisplayString(roleLabel2.value), 1)
817
+ ]),
818
+ _: 1
819
+ }),
820
+ createVNode(unref(N8nIcon), {
821
+ color: "text-dark",
822
+ icon: "chevron-down",
823
+ size: "large"
824
+ })
825
+ ], 2)
826
+ ]),
827
+ menuItem: withCtx((item) => [
828
+ createVNode(unref(ElRadio), {
829
+ "model-value": selectedRole.value,
830
+ label: item.id,
831
+ disabled: item.disabled,
832
+ "onUpdate:modelValue": ($event) => selectedRole.value = item.id
833
+ }, {
834
+ default: withCtx(() => [
835
+ createBaseVNode("span", {
836
+ class: normalizeClass(_ctx.$style.radioLabel)
837
+ }, [
838
+ createVNode(unref(N8nText), {
839
+ color: "text-dark",
840
+ class: "pb-3xs"
841
+ }, {
842
+ default: withCtx(() => [
843
+ createTextVNode(toDisplayString(item.label), 1)
844
+ ]),
845
+ _: 2
846
+ }, 1024),
847
+ createVNode(unref(N8nText), {
848
+ color: "text-dark",
849
+ size: "small"
850
+ }, {
851
+ default: withCtx(() => [
852
+ createTextVNode(toDisplayString(unref(isProjectRole)(item.id) ? props.roles[item.id]?.desc || "" : ""), 1)
853
+ ]),
854
+ _: 2
855
+ }, 1024)
856
+ ], 2)
857
+ ]),
858
+ _: 2
859
+ }, 1032, ["model-value", "label", "disabled", "onUpdate:modelValue"])
860
+ ]),
861
+ _: 1
862
+ }, 8, ["items"])) : (openBlock(), createElementBlock("span", _hoisted_1$2, toDisplayString(roleLabel2.value), 1));
863
+ };
864
+ }
865
+ });
866
+ const roleLabel = "_roleLabel_1hpnu_123";
867
+ const radioLabel = "_radioLabel_1hpnu_133";
868
+ const style0$1 = {
869
+ roleLabel,
870
+ radioLabel
871
+ };
872
+ const cssModules$1 = {
873
+ "$style": style0$1
874
+ };
875
+ const ProjectMembersRoleCell = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__cssModules", cssModules$1]]);
876
+ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
877
+ __name: "ProjectMembersActionsCell",
878
+ props: {
879
+ data: {},
880
+ actions: {}
881
+ },
882
+ emits: ["action"],
883
+ setup(__props, { emit: __emit }) {
884
+ const props = __props;
885
+ const emit = __emit;
886
+ const onAction = (action) => {
887
+ emit("action", { action, userId: props.data.id });
888
+ };
889
+ return (_ctx, _cache) => {
890
+ const _component_N8nActionToggle = N8nActionToggle;
891
+ return props.actions.length > 0 ? (openBlock(), createBlock(_component_N8nActionToggle, {
892
+ key: 0,
893
+ placement: "bottom",
894
+ actions: props.actions,
895
+ theme: "dark",
896
+ onAction
897
+ }, null, 8, ["actions"])) : createCommentVNode("", true);
898
+ };
899
+ }
900
+ });
901
+ const _hoisted_1$1 = { class: "pt-xs pb-xs" };
902
+ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
903
+ __name: "ProjectMembersTable",
904
+ props: /* @__PURE__ */ mergeModels({
905
+ data: {},
906
+ loading: { type: Boolean },
907
+ currentUserId: {},
908
+ projectRoles: {},
909
+ actions: {}
910
+ }, {
911
+ "tableOptions": {
912
+ default: () => ({
913
+ page: 0,
914
+ itemsPerPage: 10,
915
+ sortBy: []
916
+ })
917
+ },
918
+ "tableOptionsModifiers": {}
919
+ }),
920
+ emits: /* @__PURE__ */ mergeModels(["update:options", "update:role", "action"], ["update:tableOptions"]),
921
+ setup(__props, { emit: __emit }) {
922
+ const i18n = useI18n$1();
923
+ const props = __props;
924
+ const emit = __emit;
925
+ const tableOptions = useModel(__props, "tableOptions");
926
+ const rows = computed(() => props.data.items);
927
+ const headers = ref([
928
+ {
929
+ title: i18n.baseText("projects.settings.table.header.user"),
930
+ key: "name",
931
+ width: 400,
932
+ disableSort: true,
933
+ value: (row) => row
934
+ },
935
+ {
936
+ title: i18n.baseText("projects.settings.table.header.role"),
937
+ key: "role",
938
+ disableSort: true
939
+ },
940
+ {
941
+ title: "",
942
+ key: "actions",
943
+ align: "end",
944
+ width: 46,
945
+ disableSort: true,
946
+ value() {
947
+ return;
948
+ }
949
+ }
950
+ ]);
951
+ const roles = computed(() => ({
952
+ "project:admin": {
953
+ label: i18n.baseText("projects.settings.role.admin"),
954
+ desc: i18n.baseText("projects.settings.role.admin.description")
955
+ },
956
+ "project:editor": {
957
+ label: i18n.baseText("projects.settings.role.editor"),
958
+ desc: i18n.baseText("projects.settings.role.editor.description")
959
+ },
960
+ "project:viewer": {
961
+ label: i18n.baseText("projects.settings.role.viewer"),
962
+ desc: i18n.baseText("projects.settings.role.viewer.description")
963
+ },
964
+ "project:personalOwner": {
965
+ label: i18n.baseText("projects.settings.role.personalOwner"),
966
+ desc: ""
967
+ }
968
+ }));
969
+ const roleActions = computed(() => [
970
+ ...props.projectRoles.map((role) => ({
971
+ id: role.slug,
972
+ label: role.displayName,
973
+ disabled: !role.licensed
974
+ }))
975
+ ]);
976
+ const canUpdateRole = (member) => member.id !== props.currentUserId;
977
+ const onRoleChange = ({ role, userId }) => {
978
+ emit("update:role", { role, userId });
979
+ };
980
+ const filterActions = (member) => {
981
+ if (member.id === props.currentUserId || member.role === "project:personalOwner") return [];
982
+ return (props.actions ?? []).filter((action) => action.guard?.(member) ?? true);
983
+ };
984
+ return (_ctx, _cache) => {
985
+ return openBlock(), createElementBlock("div", null, [
986
+ createVNode(unref(N8nDataTableServer), {
987
+ "sort-by": tableOptions.value.sortBy,
988
+ "onUpdate:sortBy": _cache[1] || (_cache[1] = ($event) => tableOptions.value.sortBy = $event),
989
+ page: tableOptions.value.page,
990
+ "onUpdate:page": _cache[2] || (_cache[2] = ($event) => tableOptions.value.page = $event),
991
+ "items-per-page": _ctx.data.count,
992
+ headers: headers.value,
993
+ items: rows.value,
994
+ "items-length": _ctx.data.count,
995
+ loading: _ctx.loading,
996
+ "page-sizes": [_ctx.data.count + 1],
997
+ "onUpdate:options": _cache[3] || (_cache[3] = ($event) => emit("update:options", $event))
998
+ }, {
999
+ [`item.name`]: withCtx(({ value }) => [
1000
+ createBaseVNode("div", _hoisted_1$1, [
1001
+ createVNode(unref(N8nUserInfo), normalizeProps(guardReactiveProps(value)), null, 16)
1002
+ ])
1003
+ ]),
1004
+ [`item.role`]: withCtx(({ item }) => [
1005
+ canUpdateRole(item) ? (openBlock(), createBlock(ProjectMembersRoleCell, {
1006
+ key: 0,
1007
+ data: item,
1008
+ roles: roles.value,
1009
+ actions: roleActions.value,
1010
+ "onUpdate:role": onRoleChange
1011
+ }, null, 8, ["data", "roles", "actions"])) : (openBlock(), createBlock(unref(N8nText), {
1012
+ key: 1,
1013
+ color: "text-dark"
1014
+ }, {
1015
+ default: withCtx(() => [
1016
+ createTextVNode(toDisplayString(roles.value[item.role]?.label ?? item.role), 1)
1017
+ ]),
1018
+ _: 2
1019
+ }, 1024))
1020
+ ]),
1021
+ [`item.actions`]: withCtx(({ item }) => [
1022
+ createVNode(_sfc_main$2, {
1023
+ data: item,
1024
+ actions: filterActions(item),
1025
+ onAction: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("action", $event))
1026
+ }, null, 8, ["data", "actions"])
1027
+ ]),
1028
+ _: 2
1029
+ }, 1032, ["sort-by", "page", "items-per-page", "headers", "items", "items-length", "loading", "page-sizes"])
1030
+ ]);
1031
+ };
1032
+ }
1033
+ });
768
1034
  const _hoisted_1 = { for: "projectName" };
769
1035
  const _hoisted_2 = { for: "projectDescription" };
770
1036
  const _hoisted_3 = { for: "projectMembers" };
@@ -789,12 +1055,17 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
789
1055
  const upgradeDialogVisible = ref(false);
790
1056
  const isDirty = ref(false);
791
1057
  const isValid = ref(false);
792
- const isCurrentProjectEmpty = ref(true);
1058
+ const resourceCounts = ref({
1059
+ credentials: -1,
1060
+ dataTables: -1,
1061
+ workflows: -1
1062
+ });
793
1063
  const formData = ref({
794
1064
  name: "",
795
1065
  description: "",
796
1066
  relations: []
797
1067
  });
1068
+ const suppressNextSync = ref(false);
798
1069
  const projectRoleTranslations = ref({
799
1070
  "project:viewer": i18n.baseText("projects.settings.role.viewer"),
800
1071
  "project:editor": i18n.baseText("projects.settings.role.editor"),
@@ -805,6 +1076,16 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
805
1076
  type: "icon",
806
1077
  value: "layers"
807
1078
  });
1079
+ const search2 = ref("");
1080
+ const membersTableState = ref({
1081
+ page: 0,
1082
+ itemsPerPage: 10,
1083
+ sortBy: [
1084
+ { id: "firstName", desc: false },
1085
+ { id: "lastName", desc: false },
1086
+ { id: "email", desc: false }
1087
+ ]
1088
+ });
808
1089
  const usersList = computed(
809
1090
  () => usersStore.allUsers.filter((user) => {
810
1091
  const isAlreadySharedWithUser = (formData.value.relations || []).find(
@@ -825,6 +1106,13 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
825
1106
  }))
826
1107
  );
827
1108
  const firstLicensedRole = computed(() => projectRoles.value.find((role) => role.licensed)?.slug);
1109
+ const projectMembersActions = computed(() => [
1110
+ {
1111
+ label: i18n.baseText("projects.settings.table.row.removeUser"),
1112
+ value: "remove",
1113
+ guard: (member) => member.id !== usersStore.currentUser?.id && member.role !== "project:personalOwner"
1114
+ }
1115
+ ]);
828
1116
  const onAddMember = (userId) => {
829
1117
  isDirty.value = true;
830
1118
  const user = usersStore.usersById[userId];
@@ -836,18 +1124,73 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
836
1124
  }
837
1125
  formData.value.relations.push(relation);
838
1126
  };
839
- const onRoleAction = (userId, role) => {
840
- isDirty.value = true;
841
- const index = formData.value.relations.findIndex((r) => r.id === userId);
842
- if (role === "remove") {
843
- formData.value.relations.splice(index, 1);
844
- } else {
845
- formData.value.relations[index].role = role;
1127
+ const onUpdateMemberRole = async ({ userId, role }) => {
1128
+ if (!projectsStore.currentProject) {
1129
+ return;
1130
+ }
1131
+ const memberIndex = formData.value.relations.findIndex((r) => r.id === userId);
1132
+ if (memberIndex === -1) {
1133
+ return;
1134
+ }
1135
+ const originalRole = formData.value.relations[memberIndex].role;
1136
+ formData.value.relations[memberIndex].role = role;
1137
+ try {
1138
+ await projectsStore.updateProject(projectsStore.currentProject.id, {
1139
+ relations: formData.value.relations.map((r) => ({
1140
+ userId: r.id,
1141
+ role: r.role
1142
+ }))
1143
+ });
1144
+ toast.showMessage({
1145
+ type: "success",
1146
+ title: i18n.baseText("projects.settings.memberRole.updated.title")
1147
+ });
1148
+ telemetry.track("User changed member role on project", {
1149
+ project_id: projectsStore.currentProject.id,
1150
+ target_user_id: userId,
1151
+ role
1152
+ });
1153
+ } catch (error) {
1154
+ formData.value.relations[memberIndex].role = originalRole;
1155
+ toast.showError(error, i18n.baseText("projects.settings.memberRole.update.error.title"));
846
1156
  }
847
1157
  };
848
1158
  const onTextInput = () => {
849
1159
  isDirty.value = true;
850
1160
  };
1161
+ async function onRemoveMember(userId) {
1162
+ const current = projectsStore.currentProject;
1163
+ if (!current) return;
1164
+ const idx = formData.value.relations.findIndex((r) => r.id === userId);
1165
+ if (idx === -1) return;
1166
+ const removed = formData.value.relations.splice(idx, 1)[0];
1167
+ const isPersisted = current.relations.some((r) => r.id === userId);
1168
+ if (!isPersisted) return;
1169
+ try {
1170
+ suppressNextSync.value = true;
1171
+ await projectsStore.updateProject(current.id, {
1172
+ relations: current.relations.filter((r) => r.id !== userId).map((r) => ({ userId: r.id, role: r.role }))
1173
+ });
1174
+ toast.showMessage({
1175
+ type: "success",
1176
+ title: i18n.baseText("projects.settings.member.removed.title")
1177
+ });
1178
+ telemetry.track("User removed member from project", {
1179
+ project_id: current.id,
1180
+ target_user_id: userId
1181
+ });
1182
+ } catch (error) {
1183
+ formData.value.relations.splice(idx, 0, removed);
1184
+ toast.showError(error, i18n.baseText("projects.settings.save.error.title"));
1185
+ }
1186
+ }
1187
+ const onMembersListAction = async ({ action, userId }) => {
1188
+ switch (action) {
1189
+ case "remove":
1190
+ await onRemoveMember(userId);
1191
+ break;
1192
+ }
1193
+ };
851
1194
  const onCancel = () => {
852
1195
  formData.value.relations = projectsStore.currentProject?.relations ? deepCopy(projectsStore.currentProject.relations) : [];
853
1196
  formData.value.name = projectsStore.currentProject?.name ?? "";
@@ -922,9 +1265,9 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
922
1265
  throw new Error("Invalid role selected for this project.");
923
1266
  }
924
1267
  await projectsStore.updateProject(projectsStore.currentProject.id, {
925
- name: formData.value.name,
1268
+ name: formData.value.name ?? "",
926
1269
  icon: projectIcon.value,
927
- description: formData.value.description,
1270
+ description: formData.value.description ?? "",
928
1271
  relations: formData.value.relations.map((r) => ({
929
1272
  userId: r.id,
930
1273
  role: r.role
@@ -933,28 +1276,30 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
933
1276
  isDirty.value = false;
934
1277
  } catch (error) {
935
1278
  toast.showError(error, i18n.baseText("projects.settings.save.error.title"));
1279
+ throw error;
936
1280
  }
937
1281
  };
938
1282
  const onSubmit = async () => {
939
1283
  if (!isDirty.value) {
940
1284
  return;
941
1285
  }
942
- await updateProject();
943
- const diff = makeFormDataDiff();
944
- sendTelemetry(diff);
945
- toast.showMessage({
946
- title: i18n.baseText("projects.settings.save.successful.title", {
947
- interpolate: { projectName: formData.value.name ?? "" }
948
- }),
949
- type: "success"
950
- });
1286
+ try {
1287
+ await updateProject();
1288
+ const diff = makeFormDataDiff();
1289
+ sendTelemetry(diff);
1290
+ toast.showMessage({
1291
+ title: i18n.baseText("projects.settings.save.successful.title", {
1292
+ interpolate: { projectName: formData.value.name ?? "" }
1293
+ }),
1294
+ type: "success"
1295
+ });
1296
+ } catch (error) {
1297
+ }
951
1298
  };
952
1299
  const onDelete = async () => {
953
1300
  await projectsStore.getAvailableProjects();
954
1301
  if (projectsStore.currentProjectId) {
955
- isCurrentProjectEmpty.value = await projectsStore.isProjectEmpty(
956
- projectsStore.currentProjectId
957
- );
1302
+ resourceCounts.value = await projectsStore.getResourceCounts(projectsStore.currentProjectId);
958
1303
  }
959
1304
  dialogVisible.value = true;
960
1305
  };
@@ -992,6 +1337,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
992
1337
  watch(
993
1338
  () => projectsStore.currentProject,
994
1339
  async () => {
1340
+ if (suppressNextSync.value) {
1341
+ suppressNextSync.value = false;
1342
+ return;
1343
+ }
995
1344
  formData.value.name = projectsStore.currentProject?.name ?? "";
996
1345
  formData.value.description = projectsStore.currentProject?.description ?? "";
997
1346
  formData.value.relations = projectsStore.currentProject?.relations ? deepCopy(projectsStore.currentProject.relations) : [];
@@ -1006,13 +1355,52 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1006
1355
  const relationUsers = computed(
1007
1356
  () => formData.value.relations.map((relation) => {
1008
1357
  const user = usersStore.usersById[relation.id];
1009
- if (!user) return relation;
1358
+ const safeRole = isProjectRole(relation.role) ? relation.role : "project:viewer";
1359
+ if (!user) {
1360
+ return {
1361
+ ...relation,
1362
+ role: safeRole,
1363
+ firstName: null,
1364
+ lastName: null,
1365
+ email: null
1366
+ };
1367
+ }
1010
1368
  return {
1011
1369
  ...user,
1012
- ...relation
1370
+ ...relation,
1371
+ role: safeRole
1013
1372
  };
1014
1373
  })
1015
1374
  );
1375
+ const membersTableData = computed(() => ({
1376
+ items: relationUsers.value,
1377
+ count: relationUsers.value.length
1378
+ }));
1379
+ const filteredMembersData = computed(() => {
1380
+ if (!search2.value.trim()) {
1381
+ return membersTableData.value;
1382
+ }
1383
+ const searchTerm = search2.value.toLowerCase();
1384
+ const filtered = relationUsers.value.filter((member) => {
1385
+ const fullName = `${member.firstName || ""} ${member.lastName || ""}`.toLowerCase();
1386
+ const email = (member.email || "").toLowerCase();
1387
+ return fullName.includes(searchTerm) || email.includes(searchTerm);
1388
+ });
1389
+ return {
1390
+ items: filtered,
1391
+ count: filtered.length
1392
+ };
1393
+ });
1394
+ const debouncedSearch = useDebounceFn(() => {
1395
+ membersTableState.value.page = 0;
1396
+ }, 300);
1397
+ const onSearch = (value) => {
1398
+ search2.value = value;
1399
+ void debouncedSearch();
1400
+ };
1401
+ const onUpdateMembersTableOptions = (options) => {
1402
+ membersTableState.value = options;
1403
+ };
1016
1404
  onBeforeMount(async () => {
1017
1405
  await usersStore.fetchUsers();
1018
1406
  });
@@ -1024,12 +1412,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1024
1412
  const _component_N8nIconPicker = IconPicker;
1025
1413
  const _component_N8nIcon = N8nIcon;
1026
1414
  const _component_N8nUserSelect = N8nUserSelect;
1027
- const _component_N8nOption = _sfc_main$5;
1028
- const _component_N8nSelect = N8nSelect;
1029
1415
  const _component_N8nButton = N8nButton;
1030
- const _component_N8nUsersList = N8nUsersList;
1031
1416
  return openBlock(), createElementBlock("div", {
1032
- class: normalizeClass(_ctx.$style.projectSettings)
1417
+ class: normalizeClass(_ctx.$style.projectSettings),
1418
+ "data-test-id": "project-settings-container"
1033
1419
  }, [
1034
1420
  createBaseVNode("div", {
1035
1421
  class: normalizeClass(_ctx.$style.header)
@@ -1104,57 +1490,36 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1104
1490
  ]),
1105
1491
  _: 1
1106
1492
  }, 8, ["users", "current-user-id", "placeholder"]),
1107
- createVNode(_component_N8nUsersList, {
1108
- actions: [],
1109
- users: relationUsers.value,
1110
- "current-user-id": unref(usersStore).currentUser?.id,
1111
- "delete-label": unref(i18n).baseText("workflows.shareModal.list.delete")
1112
- }, {
1113
- actions: withCtx(({ user }) => [
1114
- createBaseVNode("div", {
1115
- class: normalizeClass(_ctx.$style.buttons)
1116
- }, [
1117
- createVNode(_component_N8nSelect, {
1118
- class: "mr-2xs",
1119
- "model-value": user?.role || projectRoles.value[0].slug,
1120
- size: "small",
1121
- "data-test-id": "projects-settings-user-role-select",
1122
- "onUpdate:modelValue": ($event) => onRoleAction(user.id, $event)
1123
- }, {
1124
- default: withCtx(() => [
1125
- (openBlock(true), createElementBlock(Fragment, null, renderList(projectRoles.value, (role) => {
1126
- return openBlock(), createBlock(_component_N8nOption, {
1127
- key: role.slug,
1128
- value: role.slug,
1129
- label: role.displayName,
1130
- disabled: !role.licensed
1131
- }, {
1132
- default: withCtx(() => [
1133
- createTextVNode(toDisplayString(role.displayName), 1),
1134
- !role.licensed ? (openBlock(), createElementBlock("span", {
1135
- key: 0,
1136
- class: normalizeClass(_ctx.$style.upgrade),
1137
- onClick: _cache[5] || (_cache[5] = ($event) => upgradeDialogVisible.value = true)
1138
- }, "  - " + toDisplayString(unref(i18n).baseText("generic.upgrade")), 3)) : createCommentVNode("", true)
1139
- ]),
1140
- _: 2
1141
- }, 1032, ["value", "label", "disabled"]);
1142
- }), 128))
1143
- ]),
1144
- _: 2
1145
- }, 1032, ["model-value", "onUpdate:modelValue"]),
1146
- createVNode(_component_N8nButton, {
1147
- type: "tertiary",
1148
- "native-type": "button",
1149
- square: "",
1150
- icon: "trash-2",
1151
- "data-test-id": "project-user-remove",
1152
- onClick: ($event) => onRoleAction(user.id, "remove")
1153
- }, null, 8, ["onClick"])
1154
- ], 2)
1155
- ]),
1156
- _: 1
1157
- }, 8, ["users", "current-user-id", "delete-label"])
1493
+ relationUsers.value.length > 0 ? (openBlock(), createElementBlock("div", {
1494
+ key: 0,
1495
+ class: normalizeClass(_ctx.$style.membersTableContainer)
1496
+ }, [
1497
+ createVNode(unref(N8nInput), {
1498
+ class: normalizeClass(_ctx.$style.search),
1499
+ "model-value": search2.value,
1500
+ placeholder: unref(i18n).baseText("projects.settings.members.search.placeholder"),
1501
+ clearable: "",
1502
+ "data-test-id": "project-members-search",
1503
+ "onUpdate:modelValue": onSearch
1504
+ }, {
1505
+ prefix: withCtx(() => [
1506
+ createVNode(_component_N8nIcon, { icon: "search" })
1507
+ ]),
1508
+ _: 1
1509
+ }, 8, ["class", "model-value", "placeholder"]),
1510
+ createVNode(_sfc_main$1, {
1511
+ "table-options": membersTableState.value,
1512
+ "onUpdate:tableOptions": _cache[5] || (_cache[5] = ($event) => membersTableState.value = $event),
1513
+ "data-test-id": "project-members-table",
1514
+ data: filteredMembersData.value,
1515
+ "current-user-id": unref(usersStore).currentUser?.id,
1516
+ "project-roles": projectRoles.value,
1517
+ actions: projectMembersActions.value,
1518
+ "onUpdate:options": onUpdateMembersTableOptions,
1519
+ "onUpdate:role": onUpdateMemberRole,
1520
+ onAction: onMembersListAction
1521
+ }, null, 8, ["table-options", "data", "current-user-id", "project-roles", "actions"])
1522
+ ], 2)) : createCommentVNode("", true)
1158
1523
  ]),
1159
1524
  createBaseVNode("fieldset", {
1160
1525
  class: normalizeClass(_ctx.$style.buttons)
@@ -1209,11 +1574,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1209
1574
  modelValue: dialogVisible.value,
1210
1575
  "onUpdate:modelValue": _cache[6] || (_cache[6] = ($event) => dialogVisible.value = $event),
1211
1576
  "current-project": unref(projectsStore).currentProject,
1212
- "is-current-project-empty": isCurrentProjectEmpty.value,
1577
+ "resource-counts": resourceCounts.value,
1213
1578
  projects: projects.value,
1214
1579
  onConfirmDelete
1215
- }, null, 8, ["modelValue", "current-project", "is-current-project-empty", "projects"]),
1216
- createVNode(_sfc_main$1, {
1580
+ }, null, 8, ["modelValue", "current-project", "resource-counts", "projects"]),
1581
+ createVNode(_sfc_main$4, {
1217
1582
  modelValue: upgradeDialogVisible.value,
1218
1583
  "onUpdate:modelValue": _cache[7] || (_cache[7] = ($event) => upgradeDialogVisible.value = $event),
1219
1584
  limit: unref(projectsStore).teamProjectsLimit,
@@ -1223,17 +1588,21 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1223
1588
  };
1224
1589
  }
1225
1590
  });
1226
- const projectSettings = "_projectSettings_g68s8_123";
1227
- const header = "_header_g68s8_143";
1228
- const upgrade = "_upgrade_g68s8_149";
1229
- const buttons = "_buttons_g68s8_153";
1591
+ const projectSettings = "_projectSettings_2n0pf_123";
1592
+ const header = "_header_2n0pf_143";
1593
+ const upgrade = "_upgrade_2n0pf_149";
1594
+ const buttons = "_buttons_2n0pf_153";
1595
+ const membersTableContainer = "_membersTableContainer_2n0pf_159";
1596
+ const search = "_search_2n0pf_163";
1230
1597
  const style0 = {
1231
1598
  projectSettings,
1232
1599
  header,
1233
1600
  upgrade,
1234
1601
  buttons,
1235
- "project-name": "_project-name_g68s8_159",
1236
- "project-name-input": "_project-name-input_g68s8_163"
1602
+ membersTableContainer,
1603
+ search,
1604
+ "project-name": "_project-name_2n0pf_168",
1605
+ "project-name-input": "_project-name-input_2n0pf_172"
1237
1606
  };
1238
1607
  const cssModules = {
1239
1608
  "$style": style0