@northern.tech/store 0.3.2 → 0.3.4

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 (251) hide show
  1. package/dist/BillingProfile-ChP2_Sqw.d.cts +45 -0
  2. package/dist/BillingProfile-ChP2_Sqw.d.ts +45 -0
  3. package/dist/actions.cjs +22 -23
  4. package/dist/actions.cjs.map +1 -1
  5. package/dist/actions.js +12 -12
  6. package/dist/api/general-api.cjs.map +1 -1
  7. package/dist/api/general-api.js +5 -5
  8. package/dist/api/types/Tenant.ts +17 -12
  9. package/dist/api/users-api.cjs.map +1 -1
  10. package/dist/api/users-api.js +6 -6
  11. package/dist/appSlice/constants.cjs +18 -10
  12. package/dist/appSlice/constants.cjs.map +1 -1
  13. package/dist/appSlice/constants.d.cts +41 -84
  14. package/dist/appSlice/constants.d.ts +41 -84
  15. package/dist/appSlice/constants.js +1 -1
  16. package/dist/appSlice/index.cjs +1 -3
  17. package/dist/appSlice/index.cjs.map +1 -1
  18. package/dist/appSlice/index.js +4 -4
  19. package/dist/appSlice/thunks.cjs +153 -120
  20. package/dist/appSlice/thunks.cjs.map +1 -1
  21. package/dist/appSlice/thunks.js +28 -27
  22. package/dist/auth.cjs.map +1 -1
  23. package/dist/auth.js +4 -4
  24. package/dist/{chunk-NI4SZOCF.js → chunk-4RWZR3BN.js} +23 -25
  25. package/dist/{chunk-NI4SZOCF.js.map → chunk-4RWZR3BN.js.map} +1 -1
  26. package/dist/{chunk-YGBFDXXA.js → chunk-7YZCUAXZ.js} +2 -2
  27. package/dist/{chunk-7PVGDMNM.js → chunk-AFICTIVU.js} +3 -5
  28. package/dist/{chunk-7PVGDMNM.js.map → chunk-AFICTIVU.js.map} +1 -1
  29. package/dist/{chunk-YT73QWCN.js → chunk-AUBJUUP3.js} +3 -3
  30. package/dist/{chunk-UEP36GCI.js → chunk-AVX7VVOK.js} +3 -3
  31. package/dist/{chunk-4B3IMP4I.js → chunk-BSN2TOQC.js} +1 -1
  32. package/dist/{chunk-4B3IMP4I.js.map → chunk-BSN2TOQC.js.map} +1 -1
  33. package/dist/{chunk-VOCOFE4I.js → chunk-DCEKU6UV.js} +2 -2
  34. package/dist/{chunk-E5LEU5PF.js → chunk-DGQKXSRI.js} +3 -3
  35. package/dist/{chunk-74OJIKXF.js → chunk-EQLHIPPR.js} +182 -142
  36. package/dist/chunk-EQLHIPPR.js.map +1 -0
  37. package/dist/{chunk-MDC7Y3EX.js → chunk-EYCORLYU.js} +44 -40
  38. package/dist/chunk-EYCORLYU.js.map +1 -0
  39. package/dist/{chunk-KAQJH2YL.js → chunk-FQDSV3NK.js} +13 -5
  40. package/dist/chunk-FQDSV3NK.js.map +1 -0
  41. package/dist/{chunk-XTRPX7JZ.js → chunk-FRSA2YB5.js} +3 -3
  42. package/dist/chunk-FRSA2YB5.js.map +1 -0
  43. package/dist/{chunk-ANB5BM5J.js → chunk-FVCYB5OP.js} +37 -32
  44. package/dist/chunk-FVCYB5OP.js.map +1 -0
  45. package/dist/{chunk-AMGWP7A4.js → chunk-GAI4VYRZ.js} +2 -2
  46. package/dist/{chunk-YETZPQFR.js → chunk-GWJIY56H.js} +19 -20
  47. package/dist/chunk-GWJIY56H.js.map +1 -0
  48. package/dist/{chunk-Q6M5TTDQ.js → chunk-JO33IORF.js} +2 -2
  49. package/dist/chunk-JO33IORF.js.map +1 -0
  50. package/dist/chunk-K4MMUDYT.js +391 -0
  51. package/dist/chunk-K4MMUDYT.js.map +1 -0
  52. package/dist/{chunk-XXHONFSQ.js → chunk-L3SY3J5M.js} +4 -4
  53. package/dist/{chunk-XXHONFSQ.js.map → chunk-L3SY3J5M.js.map} +1 -1
  54. package/dist/{chunk-JAROCU6M.js → chunk-NCSKCF2S.js} +3 -3
  55. package/dist/{chunk-CYV6632F.js → chunk-NOQR3TE7.js} +2 -2
  56. package/dist/{chunk-A6CT6GTI.js → chunk-OEP2D6QL.js} +18 -12
  57. package/dist/chunk-OEP2D6QL.js.map +1 -0
  58. package/dist/{chunk-2RJIDREZ.js → chunk-PAIB5V27.js} +32 -23
  59. package/dist/chunk-PAIB5V27.js.map +1 -0
  60. package/dist/{chunk-FGKMJS3B.js → chunk-RX32WLVJ.js} +2 -4
  61. package/dist/chunk-RX32WLVJ.js.map +1 -0
  62. package/dist/{chunk-YTQUNAZP.js → chunk-X3GZILYD.js} +3 -3
  63. package/dist/{chunk-25AKG5HH.js → chunk-Y575RZHR.js} +19 -11
  64. package/dist/chunk-Y575RZHR.js.map +1 -0
  65. package/dist/{chunk-RX55KAKX.js → chunk-ZWOAFHAR.js} +2 -2
  66. package/dist/{chunk-NNADGHSL.js → chunk-ZZMFXRQK.js} +14 -14
  67. package/dist/commonConstants.cjs.map +1 -1
  68. package/dist/commonConstants.d.cts +1 -1
  69. package/dist/commonConstants.d.ts +1 -1
  70. package/dist/commonConstants.js +1 -1
  71. package/dist/commonSelectors.cjs +47 -29
  72. package/dist/commonSelectors.cjs.map +1 -1
  73. package/dist/commonSelectors.d.cts +55 -46
  74. package/dist/commonSelectors.d.ts +55 -46
  75. package/dist/commonSelectors.js +11 -11
  76. package/dist/constants.cjs +35 -19
  77. package/dist/constants.cjs.map +1 -1
  78. package/dist/constants.d.cts +3 -3
  79. package/dist/constants.d.ts +3 -3
  80. package/dist/constants.js +7 -3
  81. package/dist/deploymentdevicehook.cjs +159 -125
  82. package/dist/deploymentdevicehook.cjs.map +1 -1
  83. package/dist/deploymentdevicehook.d.cts +1 -1
  84. package/dist/deploymentdevicehook.d.ts +1 -1
  85. package/dist/deploymentdevicehook.js +34 -31
  86. package/dist/deploymentdevicehook.js.map +1 -1
  87. package/dist/deploymentsSlice/constants.cjs +8 -8
  88. package/dist/deploymentsSlice/constants.cjs.map +1 -1
  89. package/dist/deploymentsSlice/constants.js +3 -3
  90. package/dist/deploymentsSlice/index.cjs +8 -8
  91. package/dist/deploymentsSlice/index.cjs.map +1 -1
  92. package/dist/deploymentsSlice/index.js +4 -4
  93. package/dist/deploymentsSlice/selectors.cjs +8 -8
  94. package/dist/deploymentsSlice/selectors.cjs.map +1 -1
  95. package/dist/deploymentsSlice/selectors.js +4 -4
  96. package/dist/deploymentsSlice/thunks.cjs +153 -120
  97. package/dist/deploymentsSlice/thunks.cjs.map +1 -1
  98. package/dist/deploymentsSlice/thunks.js +28 -27
  99. package/dist/devicesSlice/constants.cjs +11 -8
  100. package/dist/devicesSlice/constants.cjs.map +1 -1
  101. package/dist/devicesSlice/constants.d.cts +2 -1
  102. package/dist/devicesSlice/constants.d.ts +2 -1
  103. package/dist/devicesSlice/constants.js +5 -3
  104. package/dist/devicesSlice/index.cjs +8 -8
  105. package/dist/devicesSlice/index.cjs.map +1 -1
  106. package/dist/devicesSlice/index.js +4 -4
  107. package/dist/devicesSlice/selectors.cjs +9 -9
  108. package/dist/devicesSlice/selectors.cjs.map +1 -1
  109. package/dist/devicesSlice/selectors.js +4 -4
  110. package/dist/devicesSlice/thunks.cjs +155 -120
  111. package/dist/devicesSlice/thunks.cjs.map +1 -1
  112. package/dist/devicesSlice/thunks.d.cts +12 -2
  113. package/dist/devicesSlice/thunks.d.ts +12 -2
  114. package/dist/devicesSlice/thunks.js +30 -27
  115. package/dist/flag-eu-5477R2P4.svg +130 -0
  116. package/dist/flag-us-HNQAF66I.svg +63 -0
  117. package/dist/liststatehook.cjs +971 -0
  118. package/dist/liststatehook.cjs.map +1 -0
  119. package/dist/liststatehook.d.cts +246 -0
  120. package/dist/liststatehook.d.ts +246 -0
  121. package/dist/liststatehook.js +88 -0
  122. package/dist/liststatehook.js.map +1 -0
  123. package/dist/locationutils.cjs +942 -0
  124. package/dist/locationutils.cjs.map +1 -0
  125. package/dist/locationutils.d.cts +113 -0
  126. package/dist/locationutils.d.ts +113 -0
  127. package/dist/locationutils.js +46 -0
  128. package/dist/locationutils.js.map +1 -0
  129. package/dist/monitorSlice/constants.cjs +8 -8
  130. package/dist/monitorSlice/constants.cjs.map +1 -1
  131. package/dist/monitorSlice/constants.js +3 -3
  132. package/dist/monitorSlice/index.cjs +8 -8
  133. package/dist/monitorSlice/index.cjs.map +1 -1
  134. package/dist/monitorSlice/index.js +4 -4
  135. package/dist/monitorSlice/thunks.cjs +74 -62
  136. package/dist/monitorSlice/thunks.cjs.map +1 -1
  137. package/dist/monitorSlice/thunks.js +24 -24
  138. package/dist/onboardingSlice/index.cjs +1 -3
  139. package/dist/onboardingSlice/index.cjs.map +1 -1
  140. package/dist/onboardingSlice/index.js +1 -1
  141. package/dist/onboardingSlice/thunks.cjs +157 -124
  142. package/dist/onboardingSlice/thunks.cjs.map +1 -1
  143. package/dist/onboardingSlice/thunks.d.cts +2 -34
  144. package/dist/onboardingSlice/thunks.d.ts +2 -34
  145. package/dist/onboardingSlice/thunks.js +28 -29
  146. package/dist/organizationSlice/constants.cjs +22 -17
  147. package/dist/organizationSlice/constants.cjs.map +1 -1
  148. package/dist/organizationSlice/constants.d.cts +33 -1
  149. package/dist/organizationSlice/constants.d.ts +33 -1
  150. package/dist/organizationSlice/constants.js +5 -3
  151. package/dist/organizationSlice/index.cjs +18 -15
  152. package/dist/organizationSlice/index.cjs.map +1 -1
  153. package/dist/organizationSlice/index.d.cts +27 -1012
  154. package/dist/organizationSlice/index.d.ts +27 -1012
  155. package/dist/organizationSlice/index.js +4 -4
  156. package/dist/organizationSlice/selectors.cjs.map +1 -1
  157. package/dist/organizationSlice/selectors.d.cts +10 -1
  158. package/dist/organizationSlice/selectors.d.ts +10 -1
  159. package/dist/organizationSlice/selectors.js +4 -4
  160. package/dist/organizationSlice/thunks.cjs +1619 -1559
  161. package/dist/organizationSlice/thunks.cjs.map +1 -1
  162. package/dist/organizationSlice/thunks.d.cts +62 -37
  163. package/dist/organizationSlice/thunks.d.ts +62 -37
  164. package/dist/organizationSlice/thunks.js +28 -27
  165. package/dist/organizationSlice/types.cjs +19 -0
  166. package/dist/organizationSlice/types.cjs.map +1 -0
  167. package/dist/organizationSlice/types.d.cts +5 -0
  168. package/dist/organizationSlice/types.d.ts +5 -0
  169. package/dist/organizationSlice/types.js +1 -0
  170. package/dist/organizationSlice/types.js.map +1 -0
  171. package/dist/releasesSlice/index.cjs.map +1 -1
  172. package/dist/releasesSlice/index.js +4 -4
  173. package/dist/releasesSlice/selectors.cjs +17 -8
  174. package/dist/releasesSlice/selectors.cjs.map +1 -1
  175. package/dist/releasesSlice/selectors.js +5 -5
  176. package/dist/releasesSlice/thunks.cjs +123 -94
  177. package/dist/releasesSlice/thunks.cjs.map +1 -1
  178. package/dist/releasesSlice/thunks.d.cts +1 -4
  179. package/dist/releasesSlice/thunks.d.ts +1 -4
  180. package/dist/releasesSlice/thunks.js +25 -24
  181. package/dist/selectors.cjs +53 -29
  182. package/dist/selectors.cjs.map +1 -1
  183. package/dist/selectors.d.cts +10 -1
  184. package/dist/selectors.d.ts +10 -1
  185. package/dist/selectors.js +49 -43
  186. package/dist/sockethook.cjs +529 -0
  187. package/dist/sockethook.cjs.map +1 -0
  188. package/dist/sockethook.d.cts +10 -0
  189. package/dist/sockethook.d.ts +10 -0
  190. package/dist/sockethook.js +141 -0
  191. package/dist/sockethook.js.map +1 -0
  192. package/dist/store.cjs +38 -29
  193. package/dist/store.cjs.map +1 -1
  194. package/dist/store.d.cts +13 -231
  195. package/dist/store.d.ts +13 -231
  196. package/dist/store.js +18 -16
  197. package/dist/storehooks.cjs +273 -198
  198. package/dist/storehooks.cjs.map +1 -1
  199. package/dist/storehooks.js +38 -37
  200. package/dist/storehooks.js.map +1 -1
  201. package/dist/thunks.cjs +259 -184
  202. package/dist/thunks.cjs.map +1 -1
  203. package/dist/thunks.d.cts +6 -2
  204. package/dist/thunks.d.ts +6 -2
  205. package/dist/thunks.js +30 -29
  206. package/dist/types-DBj17FZO.d.cts +135 -0
  207. package/dist/types-DnfZa6xd.d.ts +135 -0
  208. package/dist/usersSlice/constants.cjs +10 -10
  209. package/dist/usersSlice/constants.cjs.map +1 -1
  210. package/dist/usersSlice/constants.d.cts +6 -6
  211. package/dist/usersSlice/constants.d.ts +6 -6
  212. package/dist/usersSlice/constants.js +3 -3
  213. package/dist/usersSlice/index.cjs +10 -10
  214. package/dist/usersSlice/index.cjs.map +1 -1
  215. package/dist/usersSlice/index.js +4 -4
  216. package/dist/usersSlice/selectors.cjs +35 -13
  217. package/dist/usersSlice/selectors.cjs.map +1 -1
  218. package/dist/usersSlice/selectors.d.cts +44 -1
  219. package/dist/usersSlice/selectors.d.ts +44 -1
  220. package/dist/usersSlice/selectors.js +13 -7
  221. package/dist/usersSlice/thunks.cjs +151 -120
  222. package/dist/usersSlice/thunks.cjs.map +1 -1
  223. package/dist/usersSlice/thunks.d.cts +10 -9
  224. package/dist/usersSlice/thunks.d.ts +10 -9
  225. package/dist/usersSlice/thunks.js +28 -27
  226. package/dist/utils.cjs +23 -24
  227. package/dist/utils.cjs.map +1 -1
  228. package/dist/utils.js +4 -4
  229. package/package.json +7 -6
  230. package/dist/chunk-25AKG5HH.js.map +0 -1
  231. package/dist/chunk-2RJIDREZ.js.map +0 -1
  232. package/dist/chunk-74OJIKXF.js.map +0 -1
  233. package/dist/chunk-A6CT6GTI.js.map +0 -1
  234. package/dist/chunk-ANB5BM5J.js.map +0 -1
  235. package/dist/chunk-FGKMJS3B.js.map +0 -1
  236. package/dist/chunk-KAQJH2YL.js.map +0 -1
  237. package/dist/chunk-MDC7Y3EX.js.map +0 -1
  238. package/dist/chunk-Q6M5TTDQ.js.map +0 -1
  239. package/dist/chunk-XTRPX7JZ.js.map +0 -1
  240. package/dist/chunk-YETZPQFR.js.map +0 -1
  241. /package/dist/{chunk-YGBFDXXA.js.map → chunk-7YZCUAXZ.js.map} +0 -0
  242. /package/dist/{chunk-YT73QWCN.js.map → chunk-AUBJUUP3.js.map} +0 -0
  243. /package/dist/{chunk-UEP36GCI.js.map → chunk-AVX7VVOK.js.map} +0 -0
  244. /package/dist/{chunk-VOCOFE4I.js.map → chunk-DCEKU6UV.js.map} +0 -0
  245. /package/dist/{chunk-E5LEU5PF.js.map → chunk-DGQKXSRI.js.map} +0 -0
  246. /package/dist/{chunk-AMGWP7A4.js.map → chunk-GAI4VYRZ.js.map} +0 -0
  247. /package/dist/{chunk-JAROCU6M.js.map → chunk-NCSKCF2S.js.map} +0 -0
  248. /package/dist/{chunk-CYV6632F.js.map → chunk-NOQR3TE7.js.map} +0 -0
  249. /package/dist/{chunk-YTQUNAZP.js.map → chunk-X3GZILYD.js.map} +0 -0
  250. /package/dist/{chunk-RX55KAKX.js.map → chunk-ZWOAFHAR.js.map} +0 -0
  251. /package/dist/{chunk-NNADGHSL.js.map → chunk-ZZMFXRQK.js.map} +0 -0
@@ -67,6 +67,14 @@ module.exports = __toCommonJS(thunks_exports);
67
67
 
68
68
  // src/appSlice/constants.ts
69
69
  var import_icons_material = require("@mui/icons-material");
70
+
71
+ // ../../assets/img/flag-eu.svg
72
+ var flag_eu_default = "../flag-eu-5477R2P4.svg";
73
+
74
+ // ../../assets/img/flag-us.svg
75
+ var flag_us_default = "../flag-us-HNQAF66I.svg";
76
+
77
+ // src/appSlice/constants.ts
70
78
  var startingDeviceCount = {
71
79
  os: "for first 50 devices",
72
80
  professional: "for first 250 devices"
@@ -89,36 +97,36 @@ var emptyChartSelection = { software: "", group: "", chartType: chartTypes.bar.k
89
97
  var defaultReportType = "distribution";
90
98
  var defaultReports = [{ ...emptyChartSelection, group: null, attribute: "artifact_name", type: defaultReportType }];
91
99
  var locations = {
92
- eu: { key: "eu", title: "EU", location: "eu.hosted.mender.io" },
93
- us: { key: "us", title: "US", location: "hosted.mender.io" }
100
+ eu: { key: "eu", title: "EU", location: "eu.hosted.mender.io", icon: flag_eu_default },
101
+ us: { key: "us", title: "US", location: "hosted.mender.io", icon: flag_us_default }
94
102
  };
95
103
  var PLANS = {
96
104
  os: {
97
105
  id: "os",
98
106
  name: "Basic",
99
107
  offer: true,
100
- price: "$32/month",
108
+ price: "$32 / month",
101
109
  deviceCount: startingDeviceCount.os,
102
- offerprice: "$23/month for first 50 devices",
110
+ offerprice: "$23 / month for first 50 devices",
103
111
  price2: "for first 6 months;\n$29/month thereafter",
104
- features: ["Basic OTA features"]
112
+ features: ["Access to core features of Mender", "Basic support"]
105
113
  },
106
114
  professional: {
107
115
  id: "professional",
108
116
  name: "Professional",
109
117
  offer: true,
110
- price: "$269/month",
118
+ price: "$269 / month",
111
119
  deviceCount: startingDeviceCount.professional,
112
- offerprice: "$200/month for first 50 devices",
120
+ offerprice: "$200 / month for first 50 devices",
113
121
  price2: "for first 6 months;\n$249/month thereafter",
114
- features: ["+ Advanced OTA features", "+ Standard support"]
122
+ features: ["Advanced OTA features", "Higher priority support"]
115
123
  },
116
124
  enterprise: {
117
125
  id: "enterprise",
118
126
  name: "Enterprise",
119
127
  price: "Custom pricing",
120
- deviceCount: "unlimited devices",
121
- features: ["+ Enterprise-grade OTA features", "+ Premium support"]
128
+ deviceCount: "Unlimited devices",
129
+ features: ["All Mender features", "Advanced security features", "SLA-backed support"]
122
130
  }
123
131
  };
124
132
  var ADDONS = {
@@ -589,6 +597,7 @@ var DEVICE_STATES = {
589
597
  rejected: "rejected"
590
598
  };
591
599
  var geoAttributes = ["geo-lat", "geo-lon"].map((attribute) => ({ attribute, scope: "inventory" }));
600
+ var REPORT_CHART_SIZE_LIMIT = 6;
592
601
 
593
602
  // src/monitorSlice/constants.ts
594
603
  var alertChannels = { email: "email" };
@@ -670,13 +679,16 @@ var SSO_TYPES = {
670
679
  configDetails: [{ key: "startURL", label: "Start Url", getValue: getOidcStartUrl }]
671
680
  }
672
681
  };
673
- var AUDIT_LOGS_TYPES = [
674
- { title: "Artifact", queryParameter: "object_type", value: "artifact" },
675
- { title: "Deployment", queryParameter: "object_deployment_name", value: "deployment" },
676
- { title: "Device", queryParameter: "object_id", value: "device" },
677
- { title: "User", queryParameter: "object_id", value: "user" }
678
- ];
679
- var SP_AUDIT_LOGS_TYPES = [AUDIT_LOGS_TYPES[3], { title: "Tenant", queryParameter: "object_id", value: "tenant" }];
682
+ var auditlogTypes = {
683
+ artifact: { title: "Artifact", queryParameter: "object_type", value: "artifact" },
684
+ deployment: { title: "Deployment", queryParameter: "object_deployment_name", value: "deployment" },
685
+ device: { title: "Device", queryParameter: "object_id", value: "device" },
686
+ user_access_token: { title: "Personal Access Token", queryParameter: "user_access_token", value: "user_access_token" },
687
+ user: { title: "User", queryParameter: "object_id", value: "user" },
688
+ tenant: { title: "Tenant", queryParameter: "object_id", value: "tenant" }
689
+ };
690
+ var AUDIT_LOGS_TYPES = [auditlogTypes.artifact, auditlogTypes.deployment, auditlogTypes.device, auditlogTypes.user_access_token, auditlogTypes.user];
691
+ var SP_AUDIT_LOGS_TYPES = [auditlogTypes.user, auditlogTypes.tenant];
680
692
  var emptyWebhook = {
681
693
  description: "",
682
694
  enabled: true,
@@ -809,7 +821,7 @@ var uiPermissionsByArea = {
809
821
  explanation: "Granting access to the audit log will allow tracing changes to devices, releases and user accounts, as well as providing information about deployments.",
810
822
  key: "auditlog",
811
823
  uiPermissions: [uiPermissionsById.read],
812
- title: "System audit log"
824
+ title: "System Audit Log"
813
825
  },
814
826
  deployments: {
815
827
  endpoints: [
@@ -960,7 +972,7 @@ var serviceProviderRolesById = {
960
972
  },
961
973
  readOnly: {
962
974
  name: "Read access",
963
- value: staticRolesByName.admin,
975
+ value: staticRolesByName.readOnly,
964
976
  description: "This role can see all linked organizations but cannot make any changes",
965
977
  permissions: [],
966
978
  uiPermissions: {
@@ -1218,9 +1230,7 @@ var appSlice = (0, import_toolkit.createSlice)({
1218
1230
  ...action.payload
1219
1231
  };
1220
1232
  },
1221
- setEnvironmentData: (state, action) => {
1222
- return { ...state, ...action.payload };
1223
- }
1233
+ setEnvironmentData: (state, action) => ({ ...state, ...action.payload })
1224
1234
  }
1225
1235
  });
1226
1236
  var actions = appSlice.actions;
@@ -1595,9 +1605,7 @@ var onboardingSlice = (0, import_toolkit5.createSlice)({
1595
1605
  name: sliceName5,
1596
1606
  initialState: initialState5,
1597
1607
  reducers: {
1598
- setOnboardingState: (state, action) => {
1599
- return { ...state, ...action.payload };
1600
- },
1608
+ setOnboardingState: (state, action) => ({ ...state, ...action.payload }),
1601
1609
  setDemoArtifactPort: (state, action) => {
1602
1610
  state.demoArtifactPort = action.payload;
1603
1611
  },
@@ -2037,6 +2045,9 @@ var Api = {
2037
2045
  };
2038
2046
  var general_api_default = Api;
2039
2047
 
2048
+ // src/devicesSlice/thunks.tsx
2049
+ var import_react_router_dom = require("react-router-dom");
2050
+
2040
2051
  // src/appSlice/selectors.ts
2041
2052
  var import_helpers2 = require("@northern.tech/utils/helpers");
2042
2053
  var import_toolkit9 = require("@reduxjs/toolkit");
@@ -2165,7 +2176,7 @@ var getGroups = (0, import_toolkit11.createSelector)([getGroupsById], (groupsByI
2165
2176
  (accu, [groupname, group]) => {
2166
2177
  const name = groupname === UNGROUPED_GROUP.id ? UNGROUPED_GROUP.name : groupname;
2167
2178
  const groupItem = { ...group, groupId: name, name: groupname };
2168
- if (group.filters.length > 0) {
2179
+ if (group.filters?.length > 0) {
2169
2180
  if (groupname !== UNGROUPED_GROUP.id) {
2170
2181
  accu.dynamic.push(groupItem);
2171
2182
  } else {
@@ -2240,14 +2251,15 @@ var getAuditLogEntry = (0, import_toolkit12.createSelector)([getAuditLog, getAud
2240
2251
  // src/utils.ts
2241
2252
  var import_helpers4 = require("@northern.tech/utils/helpers");
2242
2253
  var filterProcessors = {
2243
- $gt: (val) => Number(val) || val,
2244
- $gte: (val) => Number(val) || val,
2245
- $lt: (val) => Number(val) || val,
2246
- $lte: (val) => Number(val) || val,
2247
- $in: (val) => ("" + val).split(",").map((i) => i.trim()),
2248
- $nin: (val) => ("" + val).split(",").map((i) => i.trim()),
2249
- $exists: import_helpers4.yes,
2250
- $nexists: () => false
2254
+ [DEVICE_FILTERING_OPTIONS.$gt.key]: (val) => Number(val) || val,
2255
+ [DEVICE_FILTERING_OPTIONS.$gte.key]: (val) => Number(val) || val,
2256
+ [DEVICE_FILTERING_OPTIONS.$lt.key]: (val) => Number(val) || val,
2257
+ [DEVICE_FILTERING_OPTIONS.$lte.key]: (val) => Number(val) || val,
2258
+ [DEVICE_FILTERING_OPTIONS.$ltne.key]: (val) => Number(val) || val,
2259
+ [DEVICE_FILTERING_OPTIONS.$in.key]: (val) => ("" + val).split(",").map((i) => i.trim()),
2260
+ [DEVICE_FILTERING_OPTIONS.$nin.key]: (val) => ("" + val).split(",").map((i) => i.trim()),
2261
+ [DEVICE_FILTERING_OPTIONS.$exists.key]: import_helpers4.yes,
2262
+ [DEVICE_FILTERING_OPTIONS.$nexists.key]: () => false
2251
2263
  };
2252
2264
  var filterAliases = {
2253
2265
  $nexists: { alias: DEVICE_FILTERING_OPTIONS.$exists.key, value: false }
@@ -2291,14 +2303,12 @@ var filtersFilter = (item, index, array) => {
2291
2303
  const firstIndex = array.findIndex((filter) => filterCompare(filter, item));
2292
2304
  return firstIndex === index;
2293
2305
  };
2294
- var listItemMapper = (byId, ids, { defaultObject = {}, cutOffSize = DEVICE_LIST_MAXIMUM_LENGTH }) => {
2295
- return ids.slice(0, cutOffSize).reduce((accu, id) => {
2296
- if (id && byId[id]) {
2297
- accu.push({ ...defaultObject, ...byId[id] });
2298
- }
2299
- return accu;
2300
- }, []);
2301
- };
2306
+ var listItemMapper = (byId, ids, { defaultObject = {}, cutOffSize = DEVICE_LIST_MAXIMUM_LENGTH }) => ids.slice(0, cutOffSize).reduce((accu, id) => {
2307
+ if (id && byId[id]) {
2308
+ accu.push({ ...defaultObject, ...byId[id] });
2309
+ }
2310
+ return accu;
2311
+ }, []);
2302
2312
  var mergePermissions = (existingPermissions = { ...emptyUiPermissions }, addedPermissions) => Object.entries(existingPermissions).reduce(
2303
2313
  (accu, [key, value]) => {
2304
2314
  let values;
@@ -2371,8 +2381,13 @@ var getTooltipsById = (state) => state.users.tooltips.byId;
2371
2381
  var getGlobalSettings = (state) => state.users.globalSettings;
2372
2382
  var getCurrentUserId = (state) => state.users.currentUser;
2373
2383
  var getUsersById = (state) => state.users.byId;
2384
+ var getUsersList = (0, import_toolkit14.createSelector)([getUsersById], (usersById) => Object.values(usersById));
2374
2385
  var getCurrentUser = (0, import_toolkit14.createSelector)([getUsersById, getCurrentUserId], (usersById, userId) => usersById[userId] ?? {});
2375
2386
  var getUserSettings = (state) => state.users.userSettings;
2387
+ var getSelectedDeviceAttribute = (0, import_toolkit14.createSelector)(
2388
+ [getUserSettings],
2389
+ ({ columnSelection }) => columnSelection.map((attribute) => ({ attribute: attribute.key, scope: attribute.scope }))
2390
+ );
2376
2391
  var getIsDarkMode = (0, import_toolkit14.createSelector)([getUserSettings], ({ mode }) => isDarkMode(mode));
2377
2392
  var getShowHelptips = (0, import_toolkit14.createSelector)(
2378
2393
  [getTooltipsById],
@@ -2397,7 +2412,7 @@ var getOfflineThresholdSettings = (0, import_toolkit14.createSelector)([getGloba
2397
2412
  interval: offlineThreshold?.interval || DEVICE_ONLINE_CUTOFF.interval,
2398
2413
  intervalUnit: offlineThreshold?.intervalUnit || DEVICE_ONLINE_CUTOFF.intervalName
2399
2414
  }));
2400
- var getRolesList = (0, import_toolkit14.createSelector)([getRolesById], (rolesById2) => Object.entries(rolesById2).map(([id, role]) => ({ id, ...role })));
2415
+ var getRolesList = (0, import_toolkit14.createSelector)([getRolesById], (rolesById2) => Object.entries(rolesById2).map(([value, role]) => ({ value, ...role })));
2401
2416
  var getCurrentSession = (state) => state.users.currentSession;
2402
2417
 
2403
2418
  // src/commonSelectors.ts
@@ -2459,12 +2474,18 @@ var getUserCapabilities = (0, import_toolkit15.createSelector)([getUserRoles, ge
2459
2474
  });
2460
2475
  var getTenantCapabilities = (0, import_toolkit15.createSelector)(
2461
2476
  [getFeatures, getOrganization, getIsEnterprise],
2462
- ({ hasAuditlogs: isAuditlogEnabled, hasDeviceConfig: isDeviceConfigEnabled, hasDeviceConnect: isDeviceConnectEnabled, hasMonitor: isMonitorEnabled }, { addons = [], plan = PLANS.os.id }, isEnterprise) => {
2477
+ ({
2478
+ hasAuditlogs: isAuditlogEnabled,
2479
+ hasDeviceConfig: isDeviceConfigEnabled,
2480
+ hasDeviceConnect: isDeviceConnectEnabled,
2481
+ hasMonitor: isMonitorEnabled,
2482
+ isHosted
2483
+ }, { addons = [], plan = PLANS.os.id }, isEnterprise) => {
2463
2484
  const canDelta = isEnterprise || plan === PLANS.professional.id;
2464
2485
  const hasAuditlogs = isAuditlogEnabled && isEnterprise;
2465
- const hasDeviceConfig = isDeviceConfigEnabled && addons.some((addon) => addon.name === "configure" && Boolean(addon.enabled));
2466
- const hasDeviceConnect = isDeviceConnectEnabled && (!isEnterprise || addons.some((addon) => addon.name === "troubleshoot" && Boolean(addon.enabled)));
2467
- const hasMonitor = isMonitorEnabled && addons.some((addon) => addon.name === "monitor" && Boolean(addon.enabled));
2486
+ const hasDeviceConfig = addons.some((addon) => addon.name === ADDONS.configure.id && addon.enabled) || isDeviceConfigEnabled && !isHosted;
2487
+ const hasDeviceConnect = addons.some((addon) => addon.name === ADDONS.troubleshoot.id && addon.enabled) || isDeviceConnectEnabled && !isHosted;
2488
+ const hasMonitor = isMonitorEnabled && addons.some((addon) => addon.name === ADDONS.monitor.id && addon.enabled);
2468
2489
  return {
2469
2490
  canDelta,
2470
2491
  canRetry: canDelta,
@@ -2568,9 +2589,7 @@ var getGroupNames = (0, import_toolkit15.createSelector)([getGroupsById, getUser
2568
2589
  });
2569
2590
  var getDeviceReportsForUser = (0, import_toolkit15.createSelector)(
2570
2591
  [getUserSettings, getCurrentUser, getGlobalSettings, getDevicesById],
2571
- ({ reports }, { id: currentUserId }, globalSettings, devicesById) => {
2572
- return reports || globalSettings[`${currentUserId}-reports`] || (Object.keys(devicesById).length ? defaultReports : []);
2573
- }
2592
+ ({ reports }, { id: currentUserId }, globalSettings, devicesById) => reports || globalSettings[`${currentUserId}-reports`] || (Object.keys(devicesById).length ? defaultReports : [])
2574
2593
  );
2575
2594
  var listTypeDeviceIdMap = {
2576
2595
  deviceList: getListedDevices,
@@ -2594,7 +2613,7 @@ var getAuditlogDevice = (0, import_toolkit15.createSelector)([getAuditLogEntry,
2594
2613
  var getRelevantRoles = (0, import_toolkit15.createSelector)([getOrganization, getRolesList], ({ service_provider }, roles) => {
2595
2614
  if (service_provider) {
2596
2615
  return roles.reduce((accu, role) => {
2597
- if (rolesById[role.id]) {
2616
+ if (rolesById[role.value]) {
2598
2617
  return accu;
2599
2618
  }
2600
2619
  accu.push(role);
@@ -2602,20 +2621,19 @@ var getRelevantRoles = (0, import_toolkit15.createSelector)([getOrganization, ge
2602
2621
  }, Object.values(serviceProviderRolesById));
2603
2622
  }
2604
2623
  return Object.keys(rolesById).reverse().reduce((accu, key) => {
2605
- const index = accu.findIndex(({ id }) => id === key);
2624
+ const index = accu.findIndex(({ value }) => value === key);
2606
2625
  accu = [accu[index], ...accu.filter((item, itemIndex) => index !== itemIndex)];
2607
2626
  return accu;
2608
2627
  }, roles);
2609
2628
  });
2610
2629
 
2611
2630
  // src/store.ts
2631
+ var import_react_redux = require("react-redux");
2612
2632
  var import_helpers6 = require("@northern.tech/utils/helpers");
2613
2633
  var import_toolkit16 = require("@reduxjs/toolkit");
2614
2634
  var { setSnackbar, uploadProgress } = actions_default;
2615
2635
  var keys = ["sessionDeploymentChecker", settingsKeys.initialized];
2616
- var resetEnvironment = () => {
2617
- keys.map((key) => window.sessionStorage.removeItem(key));
2618
- };
2636
+ var resetEnvironment = () => keys.forEach((key) => window.sessionStorage.removeItem(key));
2619
2637
  resetEnvironment();
2620
2638
  var commonErrorFallback = "Please check your connection.";
2621
2639
  var commonErrorHandler = (err, errorContext, dispatch, fallback, mightBeAuthRelated = false) => {
@@ -2641,6 +2659,14 @@ var sessionReducer = (state, action) => {
2641
2659
  }
2642
2660
  return rootReducer(state, action);
2643
2661
  };
2662
+ var rejectionLoggerMiddleware = () => (next) => (action) => {
2663
+ if (action.type.endsWith("/rejected")) {
2664
+ const { error } = action;
2665
+ console.error("Rejection in action:", action);
2666
+ console.error(error.stack);
2667
+ }
2668
+ return next(action);
2669
+ };
2644
2670
  var getConfiguredStore = (options = {}) => {
2645
2671
  const { preloadedState = {}, ...config } = options;
2646
2672
  return (0, import_toolkit16.configureStore)({
@@ -2656,7 +2682,7 @@ var getConfiguredStore = (options = {}) => {
2656
2682
  ignoredActionPaths: ["uploads", "snackbar", /payload\..*$/],
2657
2683
  ignoredPaths: ["app.uploadsById", "app.snackbar", "organization.externalDeviceIntegrations"]
2658
2684
  }
2659
- })
2685
+ }).concat(rejectionLoggerMiddleware)
2660
2686
  });
2661
2687
  };
2662
2688
  var store = getConfiguredStore({
@@ -2773,12 +2799,13 @@ var setSearchState = (0, import_toolkit17.createAsyncThunk)(`${sliceName}/setSea
2773
2799
 
2774
2800
  // src/deploymentsSlice/thunks.ts
2775
2801
  var import_helpers8 = require("@northern.tech/utils/helpers");
2802
+ var import_tracking = __toESM(require("@northern.tech/utils/tracking"), 1);
2776
2803
  var import_toolkit18 = require("@reduxjs/toolkit");
2777
2804
  var import_validator = require("validator");
2778
2805
  var { receivedDevice, setSnackbar: setSnackbar2 } = actions_default;
2779
2806
  var { page: defaultPage, perPage: defaultPerPage } = DEVICE_LIST_DEFAULTS;
2780
2807
  var deriveDeploymentGroup = ({ filter = {}, group, groups = [], name }) => group || groups.length === 1 && !(0, import_validator.isUUID)(name) ? groups[0] : filter.name;
2781
- var transformDeployments = (deployments, deploymentsById) => deployments.sort(import_helpers8.startTimeSort).reduce(
2808
+ var transformDeployments = (deployments, deploymentsById) => deployments.sort((0, import_helpers8.customSort)(true, "created")).reduce(
2782
2809
  (accu, item) => {
2783
2810
  const filter = item.filter ?? {};
2784
2811
  let deployment = {
@@ -2829,6 +2856,26 @@ var getDeploymentsByStatus2 = (0, import_toolkit18.createAsyncThunk)(`${sliceNam
2829
2856
  return Promise.all(tasks);
2830
2857
  });
2831
2858
  });
2859
+ var isWithinFirstMonth = (expirationDate) => {
2860
+ if (!expirationDate) {
2861
+ return false;
2862
+ }
2863
+ const endOfFirstMonth = new Date(expirationDate);
2864
+ endOfFirstMonth.setMonth(endOfFirstMonth.getMonth() - 11);
2865
+ return endOfFirstMonth > /* @__PURE__ */ new Date();
2866
+ };
2867
+ var trackDeploymentCreation = (totalDeploymentCount, hasDeployments, trial_expiration) => {
2868
+ import_tracking.default.event({ category: "deployments", action: "create" });
2869
+ if (!totalDeploymentCount) {
2870
+ if (!hasDeployments) {
2871
+ import_tracking.default.event({ category: "deployments", action: "create_initial_deployment" });
2872
+ if (isWithinFirstMonth(trial_expiration)) {
2873
+ import_tracking.default.event({ category: "deployments", action: "create_initial_deployment_first_month" });
2874
+ }
2875
+ }
2876
+ import_tracking.default.event({ category: "deployments", action: "create_initial_deployment_user" });
2877
+ }
2878
+ };
2832
2879
  var MAX_PREVIOUS_PHASES_COUNT = 5;
2833
2880
  var createDeployment = (0, import_toolkit18.createAsyncThunk)(`${sliceName2}/createDeployment`, ({ newDeployment, hasNewRetryDefault = false }, { dispatch, getState }) => {
2834
2881
  let request;
@@ -2839,6 +2886,9 @@ var createDeployment = (0, import_toolkit18.createAsyncThunk)(`${sliceName2}/cre
2839
2886
  } else {
2840
2887
  request = general_api_default.post(`${deploymentsApiUrl}/deployments`, newDeployment);
2841
2888
  }
2889
+ const totalDeploymentCount = Object.values(getDeploymentsByStatus(getState())).reduce((accu, item) => accu + item.total, 0);
2890
+ const { hasDeployments } = getGlobalSettings(getState());
2891
+ const { trial_expiration } = getOrganization(getState());
2842
2892
  return request.catch((err) => commonErrorHandler(err, "Error creating deployment.", dispatch)).then((data) => {
2843
2893
  const lastslashindex = data.headers.location.lastIndexOf("/");
2844
2894
  const deploymentId = data.headers.location.substring(lastslashindex + 1);
@@ -2853,6 +2903,7 @@ var createDeployment = (0, import_toolkit18.createAsyncThunk)(`${sliceName2}/cre
2853
2903
  dispatch(getSingleDeployment(deploymentId)),
2854
2904
  dispatch(setSnackbar2("Deployment created successfully", TIMEOUTS.fiveSeconds))
2855
2905
  ];
2906
+ trackDeploymentCreation(totalDeploymentCount, hasDeployments, trial_expiration);
2856
2907
  const { canManageUsers } = getUserCapabilities(getState());
2857
2908
  if (canManageUsers) {
2858
2909
  const { phases, retries } = newDeployment;
@@ -3090,1610 +3141,1602 @@ var saveDeltaDeploymentsConfig = (0, import_toolkit18.createAsyncThunk)(`${slice
3090
3141
  });
3091
3142
  });
3092
3143
 
3093
- // src/devicesSlice/thunks.tsx
3094
- var import_react_router_dom = require("react-router-dom");
3095
- var import_helpers9 = require("@northern.tech/utils/helpers");
3144
+ // src/monitorSlice/thunks.ts
3096
3145
  var import_toolkit19 = require("@reduxjs/toolkit");
3097
- var import_axios2 = require("axios");
3098
- var import_pluralize = __toESM(require("pluralize"), 1);
3099
- var import_uuid = require("uuid");
3100
- var import_jsx_runtime2 = require("react/jsx-runtime");
3101
- var { cleanUpUpload, initUpload, setSnackbar: setSnackbar3, uploadProgress: uploadProgress2 } = actions_default;
3102
3146
  var { page: defaultPage2, perPage: defaultPerPage2 } = DEVICE_LIST_DEFAULTS;
3103
- var defaultAttributes = [
3104
- { scope: "identity", attribute: "status" },
3105
- { scope: "inventory", attribute: "artifact_name" },
3106
- { scope: "inventory", attribute: "device_type" },
3107
- { scope: "inventory", attribute: "mender_is_gateway" },
3108
- { scope: "inventory", attribute: "mender_gateway_system_id" },
3109
- { scope: "inventory", attribute: rootfsImageVersion },
3110
- { scope: "monitor", attribute: "alerts" },
3111
- { scope: "system", attribute: "created_ts" },
3112
- { scope: "system", attribute: "updated_ts" },
3113
- { scope: "system", attribute: "check_in_time" },
3114
- { scope: "system", attribute: "group" },
3115
- { scope: "tags", attribute: "name" }
3116
- ];
3117
- var getGroups2 = (0, import_toolkit19.createAsyncThunk)(
3118
- `${sliceName3}/getGroups`,
3119
- (_, { dispatch, getState }) => general_api_default.get(`${inventoryApiUrl}/groups`).then((res) => {
3120
- const state = getGroupsById(getState());
3121
- const dynamicGroups = Object.entries(state).reduce((accu, [id, group]) => {
3122
- if (group.id || group.filters?.length && id !== UNGROUPED_GROUP.id) {
3123
- accu[id] = group;
3124
- }
3125
- return accu;
3126
- }, {});
3127
- const groups = res.data.reduce((accu, group) => {
3128
- accu[group] = { deviceIds: [], filters: [], total: 0, ...state[group] };
3129
- return accu;
3130
- }, dynamicGroups);
3131
- const filters = [{ key: "group", value: res.data, operator: DEVICE_FILTERING_OPTIONS.$nin.key, scope: "system" }];
3132
- return Promise.all([
3133
- dispatch(actions3.receivedGroups(groups)),
3134
- dispatch(getDevicesByStatus2({ filterSelection: filters, group: 0, page: 1, perPage: 1, status: void 0 }))
3135
- ]).then((promises) => {
3136
- const devicesRetrieval = promises[promises.length - 1] || [];
3137
- const { payload } = devicesRetrieval || {};
3138
- const result = payload[payload.length - 1] || {};
3139
- if (!result.total) {
3140
- return Promise.resolve();
3141
- }
3142
- return Promise.resolve(
3143
- dispatch(
3144
- actions3.addGroup({
3145
- groupName: UNGROUPED_GROUP.id,
3146
- group: { filters: [{ key: "group", value: res.data, operator: DEVICE_FILTERING_OPTIONS.$nin.key, scope: "system" }] }
3147
- })
3148
- )
3149
- );
3150
- });
3151
- })
3152
- );
3153
- var addDevicesToGroup = (0, import_toolkit19.createAsyncThunk)(
3154
- `${sliceName3}/addDevicesToGroup`,
3155
- ({ group, deviceIds, isCreation }, { dispatch }) => general_api_default.patch(`${inventoryApiUrl}/groups/${group}/devices`, deviceIds).then(() => dispatch(actions3.addToGroup({ group, deviceIds }))).finally(() => isCreation ? Promise.resolve(dispatch(getGroups2())) : {})
3147
+ var cutoffLength = 75;
3148
+ var ellipsis = "...";
3149
+ var longTextTrimmer = (text) => text.length >= cutoffLength + ellipsis.length ? `${text.substring(0, cutoffLength + ellipsis.length)}${ellipsis}` : text;
3150
+ var sanitizeDeviceAlerts = (alerts) => alerts.map((alert) => ({ ...alert, fullName: alert.name, name: longTextTrimmer(alert.name) }));
3151
+ var getDeviceAlerts = (0, import_toolkit19.createAsyncThunk)(`${sliceName4}/getDeviceAlerts`, ({ id, config = {} }, { dispatch }) => {
3152
+ const { page = defaultPage2, perPage = defaultPerPage2, issuedBefore, issuedAfter, sortAscending = false } = config;
3153
+ const issued_after = issuedAfter ? `&issued_after=${issuedAfter}` : "";
3154
+ const issued_before = issuedBefore ? `&issued_before=${issuedBefore}` : "";
3155
+ return general_api_default.get(`${monitorApiUrlv1}/devices/${id}/alerts?page=${page}&per_page=${perPage}${issued_after}${issued_before}&sort_ascending=${sortAscending}`).catch((err) => commonErrorHandler(err, `Retrieving device alerts for device ${id} failed:`, dispatch)).then(
3156
+ (res) => Promise.all([
3157
+ dispatch(actions4.receiveDeviceAlerts({ deviceId: id, alerts: sanitizeDeviceAlerts(res.data) })),
3158
+ dispatch(actions4.setAlertListState({ total: Number(res.headers[headerNames.total]) }))
3159
+ ])
3160
+ );
3161
+ });
3162
+ var getLatestDeviceAlerts = (0, import_toolkit19.createAsyncThunk)(`${sliceName4}/getLatestDeviceAlerts`, ({ id, config = {} }, { dispatch }) => {
3163
+ const { page = defaultPage2, perPage = 10 } = config;
3164
+ return general_api_default.get(`${monitorApiUrlv1}/devices/${id}/alerts/latest?page=${page}&per_page=${perPage}`).catch((err) => commonErrorHandler(err, `Retrieving device alerts for device ${id} failed:`, dispatch)).then((res) => Promise.resolve(dispatch(actions4.receiveLatestDeviceAlerts({ deviceId: id, alerts: sanitizeDeviceAlerts(res.data) }))));
3165
+ });
3166
+ var getIssueCountsByType2 = (0, import_toolkit19.createAsyncThunk)(`${sliceName4}/getIssueCountsByType`, ({ type, options = {} }, { dispatch, getState }) => {
3167
+ const state = getState();
3168
+ const { filters = getDeviceFilters(state), group, status, ...remainder } = options;
3169
+ const { applicableFilters: nonMonitorFilters, filterTerms } = convertDeviceListStateToFilters({
3170
+ ...remainder,
3171
+ filters,
3172
+ group,
3173
+ offlineThreshold: state.app.offlineThreshold,
3174
+ selectedIssues: [type],
3175
+ status
3176
+ });
3177
+ return general_api_default.post(getSearchEndpoint(getState()), {
3178
+ page: 1,
3179
+ per_page: 1,
3180
+ filters: filterTerms,
3181
+ attributes: [{ scope: "identity", attribute: "status" }]
3182
+ }).catch((err) => commonErrorHandler(err, `Retrieving issue counts failed:`, dispatch, commonErrorFallback)).then((res) => {
3183
+ const total = nonMonitorFilters.length ? state.monitor.issueCounts.byType[type].total : Number(res.headers[headerNames.total]);
3184
+ const filtered = nonMonitorFilters.length ? Number(res.headers[headerNames.total]) : total;
3185
+ if (total === state.monitor.issueCounts.byType[type].total && filtered === state.monitor.issueCounts.byType[type].filtered) {
3186
+ return Promise.resolve();
3187
+ }
3188
+ return Promise.resolve(dispatch(actions4.receiveDeviceIssueCounts({ counts: { filtered, total }, issueType: type })));
3189
+ });
3190
+ });
3191
+ var getDeviceMonitorConfig = (0, import_toolkit19.createAsyncThunk)(
3192
+ `${sliceName4}/getDeviceMonitorConfig`,
3193
+ (id, { dispatch }) => general_api_default.get(`${monitorApiUrlv1}/devices/${id}/config`).catch((err) => commonErrorHandler(err, `Retrieving device monitor config for device ${id} failed:`, dispatch)).then(({ data }) => Promise.all([dispatch(actions_default.receivedDevice({ id, monitors: data }), Promise.resolve(data))]))
3156
3194
  );
3157
- var removeDevicesFromGroup = (0, import_toolkit19.createAsyncThunk)(
3158
- `${sliceName3}/removeDevicesFromGroup`,
3159
- ({ group, deviceIds }, { dispatch }) => general_api_default.delete(`${inventoryApiUrl}/groups/${group}/devices`, deviceIds).then(
3195
+ var changeNotificationSetting = (0, import_toolkit19.createAsyncThunk)(
3196
+ `${sliceName4}/changeNotificationSetting`,
3197
+ ({ enabled, channel = alertChannels.email }, { dispatch }) => general_api_default.put(`${monitorApiUrlv1}/settings/global/channel/alerts/${channel}/status`, { enabled }).catch((err) => commonErrorHandler(err, `${enabled ? "En" : "Dis"}abling ${channel} alerts failed:`, dispatch)).then(
3160
3198
  () => Promise.all([
3161
- dispatch(actions3.removeFromGroup({ group, deviceIds })),
3162
- dispatch(setSnackbar3(`The ${(0, import_pluralize.default)("devices", deviceIds.length)} ${(0, import_pluralize.default)("were", deviceIds.length)} removed from the group`, TIMEOUTS.fiveSeconds))
3199
+ dispatch(actions4.changeAlertChannel({ channel, enabled })),
3200
+ dispatch(actions_default.setSnackbar(`Successfully ${enabled ? "en" : "dis"}abled ${channel} alerts`, TIMEOUTS.fiveSeconds))
3163
3201
  ])
3164
3202
  )
3165
3203
  );
3166
- var getGroupNotification = (newGroup, selectedGroup) => {
3167
- const successMessage = "The group was updated successfully";
3168
- if (newGroup === selectedGroup) {
3169
- return [successMessage, TIMEOUTS.fiveSeconds];
3170
- }
3171
- return [
3172
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
3173
- successMessage,
3174
- " - ",
3175
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_router_dom.Link, { to: `/devices?inventory=group:eq:${newGroup}`, children: "click here" }),
3176
- " to see it."
3177
- ] }),
3178
- 5e3,
3179
- void 0,
3180
- void 0,
3181
- () => {
3204
+
3205
+ // src/usersSlice/thunks.ts
3206
+ var import_helptips = require("@northern.tech/common-ui/helptips");
3207
+
3208
+ // src/api/users-api.ts
3209
+ var import_axios2 = __toESM(require("axios"), 1);
3210
+ var Api2 = {
3211
+ postLogin: (url, { email: username, password, ...body }) => import_axios2.default.post(url, body, { ...commonRequestConfig, auth: { username, password } }).then((res) => ({ text: res.data, code: res.status, contentType: res.headers?.["content-type"] })),
3212
+ putVerifyTFA: (url, userData) => {
3213
+ let body = {};
3214
+ if (userData.hasOwnProperty("token2fa")) {
3215
+ body = { token2fa: userData.token2fa };
3182
3216
  }
3183
- ];
3217
+ return import_axios2.default.put(url, body, { ...commonRequestConfig, headers: { ...commonRequestConfig.headers, Authorization: `Bearer ${getToken()}` } });
3218
+ }
3184
3219
  };
3185
- var addStaticGroup = (0, import_toolkit19.createAsyncThunk)(
3186
- `${sliceName3}/addStaticGroup`,
3187
- ({ group, devices }, { dispatch, getState }) => Promise.resolve(dispatch(addDevicesToGroup({ group, deviceIds: devices.map(({ id }) => id), isCreation: true }))).then(
3188
- () => Promise.resolve(
3189
- dispatch(
3190
- actions3.addGroup({
3191
- group: { deviceIds: [], total: 0, filters: [], ...getState().devices.groups.byId[group] },
3192
- groupName: group
3193
- })
3194
- )
3195
- ).then(
3196
- () => Promise.all([
3197
- dispatch(setDeviceListState({ setOnly: true })),
3198
- dispatch(getGroups2()),
3199
- dispatch(setSnackbar3(...getGroupNotification(group, getState().devices.groups.selectedGroup)))
3200
- ])
3201
- )
3202
- ).catch((err) => commonErrorHandler(err, `Group could not be updated:`, dispatch))
3220
+ var users_api_default = Api2;
3221
+
3222
+ // src/usersSlice/thunks.ts
3223
+ var import_helpers9 = require("@northern.tech/utils/helpers");
3224
+ var import_retrytimer = require("@northern.tech/utils/retrytimer");
3225
+ var import_toolkit20 = require("@reduxjs/toolkit");
3226
+ var import_md5 = __toESM(require("md5"), 1);
3227
+ var import_universal_cookie3 = __toESM(require("universal-cookie"), 1);
3228
+ var cookies3 = new import_universal_cookie3.default();
3229
+ var { setAnnouncement, setSnackbar: setSnackbar3 } = actions_default;
3230
+ var handleLoginError = (err, { token2fa: has2FA, password }, rejectWithValue) => (dispatch) => {
3231
+ const errorText = (0, import_helpers9.extractErrorMessage)(err);
3232
+ const is2FABackend = errorText.includes("2fa");
3233
+ if (is2FABackend && !has2FA) {
3234
+ return rejectWithValue({ error: "2fa code missing" });
3235
+ }
3236
+ if (password === void 0) {
3237
+ return Promise.reject();
3238
+ }
3239
+ const twoFAError = is2FABackend ? " and verification code" : "";
3240
+ const errorMessage = `There was a problem logging in. Please check your email${twoFAError ? "," : " and"} password${twoFAError}. If you still have problems, contact an administrator.`;
3241
+ return Promise.reject(dispatch(setSnackbar3({ message: (0, import_helpers9.preformatWithRequestID)(err.response, errorMessage), action: "Copy to clipboard" })));
3242
+ };
3243
+ var loginUser = (0, import_toolkit20.createAsyncThunk)(
3244
+ `${sliceName8}/loginUser`,
3245
+ ({ stayLoggedIn, ...userData }, { dispatch, rejectWithValue }) => users_api_default.postLogin(`${useradmApiUrlv1}/auth/login`, { ...userData, no_expiry: stayLoggedIn }).catch((err) => {
3246
+ cleanUp();
3247
+ return Promise.reject(dispatch(handleLoginError(err, userData, rejectWithValue)));
3248
+ }).then(({ text: response, contentType }) => {
3249
+ if (contentType.includes(APPLICATION_JSON_CONTENT_TYPE)) {
3250
+ const { id, kind } = response;
3251
+ const type = kind.split("/")[1];
3252
+ const ssoLoginUrl = SSO_TYPES[type].getStartUrl(id);
3253
+ window.location.replace(ssoLoginUrl);
3254
+ return;
3255
+ }
3256
+ const token = response;
3257
+ if (contentType !== APPLICATION_JWT_CONTENT_TYPE || !token) {
3258
+ return;
3259
+ }
3260
+ let now = /* @__PURE__ */ new Date();
3261
+ now.setSeconds(now.getSeconds() + maxSessionAge);
3262
+ const expiresAt = stayLoggedIn ? void 0 : now.toISOString();
3263
+ setSessionInfo({ token, expiresAt });
3264
+ cookies3.remove("JWT", { path: "/" });
3265
+ return dispatch(getUser(OWN_USER_ID)).unwrap().catch((e) => {
3266
+ cleanUp();
3267
+ return Promise.reject(dispatch(setSnackbar3((0, import_helpers9.extractErrorMessage)(e))));
3268
+ }).then(() => {
3269
+ window.sessionStorage.removeItem("pendings-redirect");
3270
+ if (window.location.pathname !== "/ui/") {
3271
+ window.location.replace("/ui/");
3272
+ }
3273
+ return Promise.resolve(dispatch(actions8.successfullyLoggedIn({ expiresAt, token })));
3274
+ });
3275
+ })
3203
3276
  );
3204
- var removeStaticGroup = (0, import_toolkit19.createAsyncThunk)(
3205
- `${sliceName3}/removeStaticGroup`,
3206
- (groupName, { dispatch }) => general_api_default.delete(`${inventoryApiUrl}/groups/${groupName}`).then(
3207
- () => Promise.all([
3208
- dispatch(actions3.removeGroup(groupName)),
3209
- dispatch(getGroups2()),
3210
- dispatch(setSnackbar3("Group was removed successfully", TIMEOUTS.fiveSeconds))
3211
- ])
3277
+ var logoutUser = (0, import_toolkit20.createAsyncThunk)(`${sliceName8}/logoutUser`, (_, { dispatch, getState }) => {
3278
+ if (Object.keys(getState().app.uploadsById).length) {
3279
+ return Promise.reject();
3280
+ }
3281
+ return general_api_default.post(`${useradmApiUrlv1}/auth/logout`).finally(() => {
3282
+ cleanUp();
3283
+ (0, import_retrytimer.clearAllRetryTimers)(setSnackbar3);
3284
+ return Promise.resolve(dispatch({ type: USER_LOGOUT }));
3285
+ });
3286
+ });
3287
+ var switchUserOrganization = (0, import_toolkit20.createAsyncThunk)(`${sliceName8}/switchUserOrganization`, (tenantId, { getState }) => {
3288
+ if (Object.keys(getState().app.uploadsById).length) {
3289
+ return Promise.reject();
3290
+ }
3291
+ return general_api_default.get(`${useradmApiUrlv1}/users/tenants/${tenantId}/token`).then(({ data: token }) => {
3292
+ window.sessionStorage.setItem("tenantChanged", "true");
3293
+ setSessionInfo({ ...getSessionInfo(), token });
3294
+ window.location.reload();
3295
+ });
3296
+ });
3297
+ var passwordResetStart = (0, import_toolkit20.createAsyncThunk)(
3298
+ `${sliceName8}/passwordResetStart`,
3299
+ (email, { dispatch }) => general_api_default.post(`${useradmApiUrlv1}/auth/password-reset/start`, { email }).catch(
3300
+ (err) => commonErrorHandler(err, `The password reset request cannot be processed:`, dispatch, void 0, true)
3212
3301
  )
3213
3302
  );
3214
- var getDynamicGroups = (0, import_toolkit19.createAsyncThunk)(
3215
- `${sliceName3}/getDynamicGroups`,
3216
- (_, { dispatch, getState }) => general_api_default.get(`${inventoryApiUrlV2}/filters?per_page=${MAX_PAGE_SIZE}`).then(({ data: filters }) => {
3217
- const state = getGroupsById(getState());
3218
- const staticGroups = Object.entries(state).reduce((accu, [id, group]) => {
3219
- if (!(group.id || group.filters?.length)) {
3220
- accu[id] = group;
3221
- }
3222
- return accu;
3223
- }, {});
3224
- const groups = (filters || []).reduce((accu, filter) => {
3225
- accu[filter.name] = {
3226
- deviceIds: [],
3227
- total: 0,
3228
- ...state[filter.name],
3229
- id: filter.id,
3230
- filters: mapTermsToFilters(filter.terms)
3231
- };
3232
- return accu;
3233
- }, staticGroups);
3234
- return Promise.resolve(dispatch(actions3.receivedGroups(groups)));
3235
- }).catch(() => console.log("Dynamic group retrieval failed - likely accessing a non-enterprise backend"))
3303
+ var passwordResetComplete = (0, import_toolkit20.createAsyncThunk)(
3304
+ `${sliceName8}/passwordResetComplete`,
3305
+ ({ secretHash, newPassword }, { dispatch }) => general_api_default.post(`${useradmApiUrlv1}/auth/password-reset/complete`, { secret_hash: secretHash, password: newPassword }).catch((err = {}) => {
3306
+ const { error, response = {} } = err;
3307
+ let errorMsg = "";
3308
+ if (response.status == 400) {
3309
+ errorMsg = "the link you are using expired or the request is not valid, please try again.";
3310
+ } else {
3311
+ errorMsg = error;
3312
+ }
3313
+ dispatch(setSnackbar3("The password reset request cannot be processed: " + errorMsg));
3314
+ return Promise.reject(err);
3315
+ })
3236
3316
  );
3237
- var addDynamicGroup = (0, import_toolkit19.createAsyncThunk)(
3238
- `${sliceName3}/addDynamicGroup`,
3239
- ({ groupName, filterPredicates }, { dispatch, getState }) => general_api_default.post(`${inventoryApiUrlV2}/filters`, { name: groupName, terms: mapFiltersToTerms(filterPredicates) }).then(
3240
- (res) => Promise.resolve(
3241
- dispatch(
3242
- actions3.addGroup({
3243
- groupName,
3244
- group: {
3245
- id: res.headers[headerNames.location].substring(res.headers[headerNames.location].lastIndexOf("/") + 1),
3246
- filters: filterPredicates
3247
- }
3248
- })
3249
- )
3250
- ).then(() => {
3251
- const { cleanedFilters } = getGroupFilters(groupName, getState().devices.groups);
3252
- return Promise.all([
3253
- dispatch(actions3.setDeviceFilters(cleanedFilters)),
3254
- dispatch(setSnackbar3(...getGroupNotification(groupName, getState().devices.groups.selectedGroup))),
3255
- dispatch(getDynamicGroups())
3256
- ]);
3257
- })
3258
- ).catch((err) => commonErrorHandler(err, `Group could not be updated:`, dispatch))
3317
+ var verifyEmailStart = (0, import_toolkit20.createAsyncThunk)(
3318
+ `${sliceName8}/verifyEmailStart`,
3319
+ (_, { dispatch, getState }) => general_api_default.post(`${useradmApiUrlv1}/auth/verify-email/start`, { email: getCurrentUser(getState()).email }).catch((err) => commonErrorHandler(err, "An error occured starting the email verification process:", dispatch)).finally(() => Promise.resolve(dispatch(getUser(OWN_USER_ID))))
3259
3320
  );
3260
- var updateDynamicGroup = (0, import_toolkit19.createAsyncThunk)(`${sliceName3}/updateDynamicGroup`, ({ groupName, filterPredicates }, { dispatch, getState }) => {
3261
- const filterId = getState().devices.groups.byId[groupName].id;
3262
- return general_api_default.delete(`${inventoryApiUrlV2}/filters/${filterId}`).then(() => Promise.resolve(dispatch(addDynamicGroup({ groupName, filterPredicates }))));
3263
- });
3264
- var removeDynamicGroup = (0, import_toolkit19.createAsyncThunk)(`${sliceName3}/removeDynamicGroup`, (groupName, { dispatch, getState }) => {
3265
- const filterId = getState().devices.groups.byId[groupName].id;
3266
- return general_api_default.delete(`${inventoryApiUrlV2}/filters/${filterId}`).then(
3267
- () => Promise.all([dispatch(actions3.removeGroup(groupName)), dispatch(setSnackbar3("Group was removed successfully", TIMEOUTS.fiveSeconds))])
3268
- );
3269
- });
3270
- var getGroupFilters = (group, groupsState, filters = []) => {
3271
- const groupName = group === UNGROUPED_GROUP.id || group === UNGROUPED_GROUP.name ? UNGROUPED_GROUP.id : group;
3272
- const selectedGroup = groupsState.byId[groupName];
3273
- const groupFilterLength = selectedGroup?.filters?.length || 0;
3274
- const cleanedFilters = groupFilterLength ? [...filters, ...selectedGroup.filters].filter(filtersFilter) : filters;
3275
- return { cleanedFilters, groupName, selectedGroup, groupFilterLength };
3276
- };
3277
- var selectGroup = (0, import_toolkit19.createAsyncThunk)(`${sliceName3}/selectGroup`, ({ group, filters = [] }, { dispatch, getState }) => {
3278
- const { cleanedFilters, groupName, selectedGroup, groupFilterLength } = getGroupFilters(group, getState().devices.groups, filters);
3279
- if (getSelectedGroup(getState()) === groupName && (filters.length === 0 && !groupFilterLength || filters.length === cleanedFilters.length)) {
3280
- return Promise.resolve();
3281
- }
3282
- let tasks = [];
3283
- if (groupFilterLength) {
3284
- tasks.push(dispatch(actions3.setDeviceFilters(cleanedFilters)));
3321
+ var verifyEmailComplete = (0, import_toolkit20.createAsyncThunk)(
3322
+ `${sliceName8}/verifyEmailComplete`,
3323
+ (secret_hash, { dispatch }) => general_api_default.post(`${useradmApiUrlv1}/auth/verify-email/complete`, { secret_hash }).catch((err) => commonErrorHandler(err, "An error occured completing the email verification process:", dispatch)).finally(() => Promise.resolve(dispatch(getUser(OWN_USER_ID))))
3324
+ );
3325
+ var verify2FA = (0, import_toolkit20.createAsyncThunk)(
3326
+ `${sliceName8}/verify2FA`,
3327
+ (tfaData, { dispatch }) => users_api_default.putVerifyTFA(`${useradmApiUrlv1}/2faverify`, tfaData).then(() => Promise.resolve(dispatch(getUser(OWN_USER_ID)))).catch(
3328
+ (err) => commonErrorHandler(err, "An error occured validating the verification code: failed to verify token, please try again.", dispatch, void 0, true)
3329
+ )
3330
+ );
3331
+ var getUserList = (0, import_toolkit20.createAsyncThunk)(
3332
+ `${sliceName8}/getUserList`,
3333
+ (_, { dispatch, getState }) => general_api_default.get(`${useradmApiUrlv1}/users`).then((res) => {
3334
+ const currentUsersById = getUsersById(getState());
3335
+ const users = res.data.reduce(
3336
+ (accu, item) => {
3337
+ accu[item.id] = {
3338
+ ...accu[item.id],
3339
+ ...item
3340
+ };
3341
+ return accu;
3342
+ },
3343
+ { ...currentUsersById }
3344
+ );
3345
+ return dispatch(actions8.receivedUserList(users));
3346
+ }).catch((err) => commonErrorHandler(err, `Users couldn't be loaded.`, dispatch, commonErrorFallback))
3347
+ );
3348
+ var getUser = (0, import_toolkit20.createAsyncThunk)(
3349
+ `${sliceName8}/getUser`,
3350
+ (id, { dispatch, rejectWithValue }) => general_api_default.get(`${useradmApiUrlv1}/users/${id}`).then(
3351
+ ({ data: user }) => Promise.all([
3352
+ dispatch(actions8.receivedUser(user)),
3353
+ dispatch(setHideAnnouncement({ shouldHide: false, userId: user.id })),
3354
+ dispatch(updateUserColumnSettings({ currentUserId: user.id })),
3355
+ user
3356
+ ])
3357
+ ).catch((e) => rejectWithValue(e))
3358
+ );
3359
+ var initializeSelf = (0, import_toolkit20.createAsyncThunk)(`${sliceName8}/initializeSelf`, (_, { dispatch }) => dispatch(getUser(OWN_USER_ID)));
3360
+ var updateUserColumnSettings = (0, import_toolkit20.createAsyncThunk)(`${sliceName8}/updateUserColumnSettings`, ({ columns, currentUserId }, { dispatch, getState }) => {
3361
+ const userId = currentUserId ?? getCurrentUser(getState()).id;
3362
+ const storageKey = `${userId}-column-widths`;
3363
+ let customColumns = [];
3364
+ if (!columns) {
3365
+ try {
3366
+ customColumns = JSON.parse(window.localStorage.getItem(storageKey)) || customColumns;
3367
+ } catch {
3368
+ }
3285
3369
  } else {
3286
- tasks.push(dispatch(actions3.setDeviceFilters(filters)));
3287
- tasks.push(dispatch(getGroupDevices({ group: groupName, perPage: 1, shouldIncludeAllStates: true })));
3370
+ customColumns = columns;
3288
3371
  }
3289
- const selectedGroupName = selectedGroup || !Object.keys(getGroupsById(getState())).length ? groupName : void 0;
3290
- tasks.push(dispatch(actions3.selectGroup(selectedGroupName)));
3291
- return Promise.all(tasks);
3372
+ window.localStorage.setItem(storageKey, JSON.stringify(customColumns));
3373
+ return Promise.resolve(dispatch(actions8.setCustomColumns(customColumns)));
3292
3374
  });
3293
- var getEarliestTs = (dateA = "", dateB = "") => !dateA || !dateB ? dateA || dateB : dateA < dateB ? dateA : dateB;
3294
- var reduceReceivedDevices = (devices, ids, state, status) => devices.reduce(
3295
- (accu, device) => {
3296
- const stateDevice = getDeviceById(state, device.id);
3297
- const {
3298
- attributes: storedAttributes = {},
3299
- identity_data: storedIdentity = {},
3300
- monitor: storedMonitor = {},
3301
- tags: storedTags = {},
3302
- group: storedGroup
3303
- } = stateDevice;
3304
- const { identity, inventory, monitor, system = {}, tags } = mapDeviceAttributes(device.attributes);
3305
- device.tags = { ...storedTags, ...tags };
3306
- device.group = system.group ?? storedGroup;
3307
- device.monitor = { ...storedMonitor, ...monitor };
3308
- device.identity_data = { ...storedIdentity, ...identity, ...device.identity_data ? device.identity_data : {} };
3309
- device.status = status ? status : device.status || identity.status;
3310
- device.check_in_time_rounded = system.check_in_time ?? stateDevice.check_in_time_rounded;
3311
- device.check_in_time_exact = device.check_in_time ?? stateDevice.check_in_time_exact;
3312
- device.created_ts = getEarliestTs(getEarliestTs(system.created_ts, device.created_ts), stateDevice.created_ts);
3313
- device.updated_ts = device.attributes ? device.updated_ts : stateDevice.updated_ts;
3314
- device.isNew = new Date(device.created_ts) > new Date(state.app.newThreshold);
3315
- device.isOffline = new Date(device.check_in_time_rounded) < new Date(state.app.offlineThreshold) || device.check_in_time_rounded === void 0;
3316
- device.attributes = device.attributes ? { ...storedAttributes, ...inventory } : storedAttributes;
3317
- accu.devicesById[device.id] = { ...stateDevice, ...device };
3318
- accu.ids.push(device.id);
3319
- return accu;
3375
+ var userActions = {
3376
+ add: {
3377
+ successMessage: "The user was added successfully.",
3378
+ errorMessage: "adding"
3320
3379
  },
3321
- { ids, devicesById: {} }
3322
- );
3323
- var getGroupDevices = (0, import_toolkit19.createAsyncThunk)(`${sliceName3}/getGroupDevices`, (options, { dispatch, getState }) => {
3324
- const { group, shouldIncludeAllStates, ...remainder } = options;
3325
- const { cleanedFilters: filterSelection } = getGroupFilters(group, getState().devices.groups);
3326
- return Promise.resolve(
3327
- dispatch(getDevicesByStatus2({ ...remainder, filterSelection, group, status: shouldIncludeAllStates ? void 0 : DEVICE_STATES.accepted }))
3328
- ).unwrap().then((results) => {
3329
- if (!group) {
3330
- return Promise.resolve();
3331
- }
3332
- const { deviceAccu, total } = results[results.length - 1];
3333
- const stateGroup = getState().devices.groups.byId[group];
3334
- if (!stateGroup && !total && !deviceAccu.ids.length) {
3335
- return Promise.resolve();
3336
- }
3337
- return Promise.resolve(
3338
- dispatch(
3339
- actions3.addGroup({
3340
- group: {
3341
- deviceIds: deviceAccu.ids.length === total || deviceAccu.ids.length > stateGroup?.deviceIds ? deviceAccu.ids : stateGroup.deviceIds,
3342
- total
3343
- },
3344
- groupName: group
3345
- })
3346
- )
3347
- );
3348
- });
3349
- });
3350
- var getAllGroupDevices = (0, import_toolkit19.createAsyncThunk)(`${sliceName3}/getAllGroupDevices`, (group, { dispatch, getState }) => {
3351
- if (!group || !!group && (!getGroupsById(getState())[group] || getGroupsById(getState())[group].filters.length)) {
3352
- return Promise.resolve();
3380
+ create: {
3381
+ successMessage: "The user was created successfully.",
3382
+ errorMessage: "creating"
3383
+ },
3384
+ edit: {
3385
+ successMessage: "The user has been updated.",
3386
+ errorMessage: "editing"
3387
+ },
3388
+ remove: {
3389
+ successMessage: "The user was removed from the system.",
3390
+ errorMessage: "removing"
3353
3391
  }
3354
- const { attributes, filterTerms } = prepareSearchArguments({
3355
- filters: [],
3356
- group,
3357
- state: getState(),
3358
- status: DEVICE_STATES.accepted
3359
- });
3360
- const getAllDevices = (perPage = MAX_PAGE_SIZE, page = defaultPage2, devices = []) => general_api_default.post(getSearchEndpoint(getState()), {
3361
- page,
3362
- per_page: perPage,
3363
- filters: filterTerms,
3364
- attributes
3365
- }).then((res) => {
3366
- const state = getState();
3367
- const deviceAccu = reduceReceivedDevices(res.data, devices, state);
3368
- dispatch(actions3.receivedDevices(deviceAccu.devicesById));
3369
- const total = Number(res.headers[headerNames.total]);
3370
- if (total > perPage * page) {
3371
- return getAllDevices(perPage, page + 1, deviceAccu.ids);
3372
- }
3373
- return Promise.resolve(dispatch(actions3.addGroup({ group: { deviceIds: deviceAccu.ids, total: deviceAccu.ids.length }, groupName: group })));
3374
- });
3375
- return getAllDevices();
3392
+ };
3393
+ var userActionErrorHandler = (err, type, dispatch) => commonErrorHandler(err, `There was an error ${userActions[type].errorMessage} the user.`, dispatch);
3394
+ var createUser = (0, import_toolkit20.createAsyncThunk)(
3395
+ `${sliceName8}/createUser`,
3396
+ ({ shouldResetPassword, ...userData }, { dispatch }) => general_api_default.post(`${useradmApiUrlv1}/users`, { ...userData, send_reset_password: shouldResetPassword }).then(() => Promise.all([dispatch(actions8.createdUser(userData)), dispatch(getUserList()), dispatch(setSnackbar3(userActions.create.successMessage))])).catch((err) => userActionErrorHandler(err, "create", dispatch))
3397
+ );
3398
+ var removeUser = (0, import_toolkit20.createAsyncThunk)(
3399
+ `${sliceName8}/removeUser`,
3400
+ (userId, { dispatch }) => general_api_default.delete(`${useradmApiUrlv1}/users/${userId}`).then(() => Promise.all([dispatch(actions8.removedUser(userId)), dispatch(getUserList()), dispatch(setSnackbar3(userActions.remove.successMessage))])).catch((err) => userActionErrorHandler(err, "remove", dispatch))
3401
+ );
3402
+ var editUser = (0, import_toolkit20.createAsyncThunk)(
3403
+ `${sliceName8}/editUser`,
3404
+ ({ id, ...userData }, { dispatch, getState }) => general_api_default.put(`${useradmApiUrlv1}/users/${id}`, userData).then(
3405
+ () => Promise.all([
3406
+ dispatch(actions8.updatedUser({ ...userData, id: id === OWN_USER_ID ? getCurrentUser(getState()).id : id })),
3407
+ dispatch(setSnackbar3(userActions.edit.successMessage))
3408
+ ])
3409
+ )
3410
+ );
3411
+ var addUserToCurrentTenant = (0, import_toolkit20.createAsyncThunk)(`${sliceName8}/addUserToTenant`, (userId, { dispatch, getState }) => {
3412
+ const { id } = getOrganization(getState());
3413
+ return general_api_default.post(`${useradmApiUrlv1}/users/${userId}/assign`, { tenant_ids: [id] }).catch((err) => commonErrorHandler(err, `There was an error adding the user to your organization:`, dispatch)).then(() => Promise.all([dispatch(setSnackbar3(userActions.add.successMessage)), dispatch(getUserList())]));
3376
3414
  });
3377
- var getAllDynamicGroupDevices = (0, import_toolkit19.createAsyncThunk)(`${sliceName3}/getAllDynamicGroupDevices`, (group, { dispatch, getState }) => {
3378
- if (!!group && (!getGroupsById(getState())[group] || !getGroupsById(getState())[group].filters.length)) {
3379
- return Promise.resolve();
3380
- }
3381
- const { attributes, filterTerms: filters } = prepareSearchArguments({
3382
- filters: getState().devices.groups.byId[group].filters,
3383
- state: getState(),
3384
- status: DEVICE_STATES.accepted
3385
- });
3386
- const getAllDevices = (perPage = MAX_PAGE_SIZE, page = defaultPage2, devices = []) => general_api_default.post(getSearchEndpoint(getState()), { page, per_page: perPage, filters, attributes }).then((res) => {
3387
- const state = getState();
3388
- const deviceAccu = reduceReceivedDevices(res.data, devices, state);
3389
- dispatch(actions3.receivedDevices(deviceAccu.devicesById));
3390
- const total = Number(res.headers[headerNames.total]);
3391
- if (total > deviceAccu.ids.length) {
3392
- return getAllDevices(perPage, page + 1, deviceAccu.ids);
3415
+ var enableUser2fa = (0, import_toolkit20.createAsyncThunk)(
3416
+ `${sliceName8}/enableUser2fa`,
3417
+ (userId = OWN_USER_ID, { dispatch }) => general_api_default.post(`${useradmApiUrlv1}/users/${userId}/2fa/enable`).catch((err) => commonErrorHandler(err, `There was an error enabling Two Factor authentication for the user.`, dispatch)).then(() => Promise.resolve(dispatch(getUser(userId))))
3418
+ );
3419
+ var disableUser2fa = (0, import_toolkit20.createAsyncThunk)(
3420
+ `${sliceName8}/disableUser2fa`,
3421
+ (userId = OWN_USER_ID, { dispatch }) => general_api_default.post(`${useradmApiUrlv1}/users/${userId}/2fa/disable`).catch((err) => commonErrorHandler(err, `There was an error disabling Two Factor authentication for the user.`, dispatch)).then(() => Promise.all([dispatch(getUser(userId)), dispatch(actions8.receivedQrCode(null))]))
3422
+ );
3423
+ var mapHttpPermission = (permission) => Object.entries(uiPermissionsByArea).reduce(
3424
+ (accu, [area, definition]) => {
3425
+ const endpointMatches = definition.endpoints.filter(
3426
+ (endpoint) => endpoint.path.test(permission.value) && (endpoint.types.includes(permission.type) || permission.type === PermissionTypes.Any)
3427
+ );
3428
+ if (permission.value === PermissionTypes.Any || permission.value.includes(apiRoot) && endpointMatches.length) {
3429
+ const endpointUiPermission = endpointMatches.reduce((endpointAccu, endpoint) => [...endpointAccu, ...endpoint.uiPermissions], []);
3430
+ const collector = (endpointUiPermission || definition.uiPermissions).reduce((permissionsAccu, uiPermission) => {
3431
+ if (permission.type === PermissionTypes.Any || !endpointMatches.length && uiPermission.verbs.some((verb) => verb === permission.type)) {
3432
+ permissionsAccu.push(uiPermission.value);
3433
+ }
3434
+ return permissionsAccu;
3435
+ }, []).filter(import_helpers9.duplicateFilter);
3436
+ if (Array.isArray(accu[area])) {
3437
+ accu[area] = [...accu[area], ...collector].filter(import_helpers9.duplicateFilter);
3438
+ } else {
3439
+ accu[area] = mergePermissions(accu[area], { [scopedPermissionAreas[area].excessiveAccessSelector]: collector });
3440
+ }
3393
3441
  }
3394
- return Promise.resolve(dispatch(actions3.addGroup({ group: { deviceIds: deviceAccu.ids, total }, groupName: group })));
3395
- });
3396
- return getAllDevices();
3397
- });
3398
- var getDeviceById2 = (0, import_toolkit19.createAsyncThunk)(
3399
- `${sliceName3}/getDeviceById`,
3400
- (id, { dispatch, getState }) => general_api_default.get(`${inventoryApiUrl}/devices/${id}`).then((res) => {
3401
- const device = reduceReceivedDevices([res.data], [], getState()).devicesById[id];
3402
- device.etag = res.headers.etag;
3403
- dispatch(actions3.receivedDevice(device));
3404
- return Promise.resolve(device);
3405
- }).catch((err) => {
3406
- const errMsg = (0, import_helpers9.extractErrorMessage)(err);
3407
- if (errMsg.includes("Not Found")) {
3408
- console.log(`${id} does not have any inventory information`);
3409
- const device = reduceReceivedDevices(
3410
- [
3411
- {
3412
- id,
3413
- attributes: [
3414
- { name: "status", value: "decomissioned", scope: "identity" },
3415
- { name: "decomissioned", value: "true", scope: "inventory" }
3416
- ]
3417
- }
3418
- ],
3419
- [],
3420
- getState()
3421
- ).devicesById[id];
3422
- dispatch(actions3.receivedDevice(device));
3423
- }
3424
- })
3442
+ return accu;
3443
+ },
3444
+ { ...emptyUiPermissions }
3425
3445
  );
3426
- var getDeviceInfo = (0, import_toolkit19.createAsyncThunk)(`${sliceName3}/getDeviceInfo`, (deviceId, { dispatch, getState }) => {
3427
- const device = getDeviceById(getState(), deviceId);
3428
- const { hasDeviceConfig, hasDeviceConnect, hasMonitor } = getTenantCapabilities(getState());
3429
- const { canConfigure } = getUserCapabilities(getState());
3430
- const integrations = getDeviceTwinIntegrations(getState());
3431
- let tasks = [dispatch(getDeviceAuth(deviceId)), ...integrations.map((integration) => dispatch(getDeviceTwin({ deviceId, integration })))];
3432
- if (hasDeviceConfig && canConfigure && [DEVICE_STATES.accepted, DEVICE_STATES.preauth].includes(device.status)) {
3433
- tasks.push(dispatch(getDeviceConfig(deviceId)));
3434
- }
3435
- if (device.status === DEVICE_STATES.accepted) {
3436
- tasks.push(dispatch(getDeviceById2(deviceId)));
3437
- if (hasDeviceConnect) {
3438
- tasks.push(dispatch(getDeviceConnect(deviceId)));
3439
- }
3440
- if (hasMonitor) {
3441
- tasks.push(dispatch(getLatestDeviceAlerts({ id: deviceId })));
3442
- tasks.push(dispatch(getDeviceMonitorConfig(deviceId)));
3443
- }
3446
+ var permissionActionTypes = {
3447
+ any: mapHttpPermission,
3448
+ CREATE_DEPLOYMENT: (permission) => permission.type === PermissionTypes.DeviceGroup ? {
3449
+ deployments: [uiPermissionsById.deploy.value],
3450
+ groups: { [permission.value]: [uiPermissionsById.deploy.value] }
3451
+ } : {},
3452
+ http: mapHttpPermission,
3453
+ REMOTE_TERMINAL: (permission) => permission.type === PermissionTypes.DeviceGroup ? {
3454
+ groups: { [permission.value]: [uiPermissionsById.connect.value] }
3455
+ } : {},
3456
+ VIEW_DEVICE: (permission) => permission.type === PermissionTypes.DeviceGroup ? {
3457
+ groups: { [permission.value]: [uiPermissionsById.read.value] }
3458
+ } : {}
3459
+ };
3460
+ var combinePermissions = (existingPermissions, additionalPermissions = {}) => Object.entries(additionalPermissions).reduce((accu, [name, permissions]) => {
3461
+ let maybeExistingPermissions = accu[name] || [];
3462
+ accu[name] = [...permissions, ...maybeExistingPermissions].filter(import_helpers9.duplicateFilter);
3463
+ return accu;
3464
+ }, existingPermissions);
3465
+ var tryParseCustomPermission = (permission) => {
3466
+ const uiPermissions = permissionActionTypes[permission.action](permission.object);
3467
+ const result = mergePermissions({ ...emptyUiPermissions }, uiPermissions);
3468
+ return { isCustom: true, permission, result };
3469
+ };
3470
+ var customPermissionHandler = (accu, permission) => {
3471
+ let processor = tryParseCustomPermission(permission);
3472
+ return {
3473
+ ...accu,
3474
+ isCustom: accu.isCustom || processor.isCustom,
3475
+ uiPermissions: mergePermissions(accu.uiPermissions, processor.result)
3476
+ };
3477
+ };
3478
+ var mapPermissionSet = (permissionSetName, names, scope, existingGroupsPermissions = {}) => {
3479
+ const permission = Object.values(uiPermissionsById).find((permission2) => permission2.permissionSets[scope] === permissionSetName).value;
3480
+ const scopedPermissions = names.reduce((accu, name) => combinePermissions(accu, { [name]: [permission] }), existingGroupsPermissions);
3481
+ return Object.entries(scopedPermissions).reduce((accu, [key, permissions]) => ({ ...accu, [key]: deriveImpliedAreaPermissions(scope, permissions) }), {});
3482
+ };
3483
+ var isEmptyPermissionSet = (permissionSet) => !Object.values(permissionSet).reduce((accu, permissions) => {
3484
+ if (Array.isArray(permissions)) {
3485
+ return accu || !!permissions.length;
3444
3486
  }
3445
- return Promise.all(tasks);
3446
- });
3447
- var deriveInactiveDevices = (0, import_toolkit19.createAsyncThunk)(`${sliceName3}/deriveInactiveDevices`, (deviceIds, { dispatch, getState }) => {
3448
- const yesterday = /* @__PURE__ */ new Date();
3449
- yesterday.setDate(yesterday.getDate() - 1);
3450
- const yesterdaysIsoString = yesterday.toISOString();
3451
- const devices = deviceIds.reduce(
3452
- (accu, id) => {
3453
- const device = getDeviceById(getState(), id);
3454
- if (device && device.updated_ts > yesterdaysIsoString) {
3455
- accu.active.push(id);
3456
- } else {
3457
- accu.inactive.push(id);
3487
+ return accu || !(0, import_helpers9.isEmpty)(permissions);
3488
+ }, false);
3489
+ var parseRolePermissions = ({ permission_sets_with_scope = [], permissions = [] }, permissionSets) => {
3490
+ const preliminaryResult = permission_sets_with_scope.reduce(
3491
+ (accu, permissionSet) => {
3492
+ let processor = permissionSets[permissionSet.name];
3493
+ if (!processor) {
3494
+ return accu;
3458
3495
  }
3459
- return accu;
3496
+ const scope = Object.keys(scopedPermissionAreas).find((scope2) => uiPermissionsByArea[scope2].scope === permissionSet.scope?.type);
3497
+ if (scope) {
3498
+ const result = mapPermissionSet(permissionSet.name, permissionSet.scope.value, scope, accu.uiPermissions[scope]);
3499
+ return { ...accu, uiPermissions: { ...accu.uiPermissions, [scope]: result } };
3500
+ } else if (isEmptyPermissionSet(processor.result)) {
3501
+ return processor.permissions.reduce(customPermissionHandler, accu);
3502
+ }
3503
+ return {
3504
+ ...accu,
3505
+ isCustom: accu.isCustom || processor.isCustom,
3506
+ uiPermissions: mergePermissions(accu.uiPermissions, processor.result)
3507
+ };
3460
3508
  },
3461
- { active: [], inactive: [] }
3509
+ { isCustom: false, uiPermissions: { ...emptyUiPermissions, groups: {}, releases: {} } }
3462
3510
  );
3463
- return dispatch(actions3.setInactiveDevices({ activeDeviceTotal: devices.active.length, inactiveDeviceTotal: devices.inactive.length }));
3464
- });
3465
- var getDeviceCount = (0, import_toolkit19.createAsyncThunk)(
3466
- `${sliceName3}/getDeviceCount`,
3467
- (status, { dispatch, getState }) => general_api_default.post(getSearchEndpoint(getState()), {
3468
- page: 1,
3469
- per_page: 1,
3470
- filters: mapFiltersToTerms([{ key: "status", value: status, operator: DEVICE_FILTERING_OPTIONS.$eq.key, scope: "identity" }]),
3471
- attributes: defaultAttributes
3472
- }).then((response) => {
3473
- const count = Number(response.headers[headerNames.total]);
3474
- if (status) {
3475
- return dispatch(actions3.setDevicesCountByStatus({ count, status }));
3511
+ return permissions.reduce(customPermissionHandler, preliminaryResult);
3512
+ };
3513
+ var normalizeRbacRoles = (roles, rolesById2, permissionSets) => roles.reduce(
3514
+ (accu, role) => {
3515
+ let normalizedPermissions;
3516
+ let isCustom = false;
3517
+ if (rolesById2[role.name]) {
3518
+ normalizedPermissions = {
3519
+ ...rolesById2[role.name].uiPermissions,
3520
+ groups: { ...rolesById2[role.name].uiPermissions.groups },
3521
+ releases: { ...rolesById2[role.name].uiPermissions.releases }
3522
+ };
3523
+ } else {
3524
+ const result = parseRolePermissions(role, permissionSets);
3525
+ normalizedPermissions = result.uiPermissions;
3526
+ isCustom = result.isCustom;
3476
3527
  }
3477
- return dispatch(actions3.setTotalDevices(count));
3478
- })
3479
- );
3480
- var getAllDeviceCounts = (0, import_toolkit19.createAsyncThunk)(
3481
- `${sliceName3}/getAllDeviceCounts`,
3482
- (_, { dispatch }) => Promise.all([DEVICE_STATES.accepted, DEVICE_STATES.pending].map((status) => dispatch(getDeviceCount(status))))
3528
+ const roleState = accu[role.name] ?? { ...emptyRole };
3529
+ accu[role.name] = {
3530
+ ...roleState,
3531
+ ...role,
3532
+ description: roleState.description ? roleState.description : role.description,
3533
+ editable: !rolesById[role.name] && !isCustom && (typeof roleState.editable !== "undefined" ? roleState.editable : true),
3534
+ isCustom,
3535
+ name: roleState.name ? roleState.name : role.name,
3536
+ uiPermissions: normalizedPermissions
3537
+ };
3538
+ return accu;
3539
+ },
3540
+ { ...rolesById2 }
3483
3541
  );
3484
- var getDeviceLimit2 = (0, import_toolkit19.createAsyncThunk)(
3485
- `${sliceName3}/getDeviceLimit`,
3486
- (_, { dispatch }) => general_api_default.get(`${deviceAuthV2}/limits/max_devices`).then((res) => dispatch(actions3.setDeviceLimit(res.data.limit)))
3542
+ var getPermissionSets = (0, import_toolkit20.createAsyncThunk)(
3543
+ `${sliceName8}/getPermissionSets`,
3544
+ (_, { dispatch, getState }) => general_api_default.get(`${useradmApiUrlv2}/permission_sets?per_page=500`).then(({ data }) => {
3545
+ const permissionSets = data.reduce(
3546
+ (accu, permissionSet) => {
3547
+ const permissionSetState = accu[permissionSet.name] ?? {};
3548
+ let permissionSetObject = { ...permissionSetState, ...permissionSet };
3549
+ permissionSetObject.result = Object.values(uiPermissionsById).reduce(
3550
+ (accu2, item) => Object.entries(item.permissionSets).reduce((collector, [area, permissionSet2]) => {
3551
+ if (scopedPermissionAreas[area]) {
3552
+ return collector;
3553
+ }
3554
+ if (permissionSet2 === permissionSetObject.name) {
3555
+ collector[area] = [...collector[area], item.value].filter(import_helpers9.duplicateFilter);
3556
+ }
3557
+ return collector;
3558
+ }, accu2),
3559
+ { ...emptyUiPermissions, ...permissionSetObject.result ?? {} }
3560
+ );
3561
+ const scopes = Object.values(scopedPermissionAreas).reduce((accu2, { key, scopeType }) => {
3562
+ if (permissionSetObject.supported_scope_types?.includes(key) || permissionSetObject.supported_scope_types?.includes(scopeType)) {
3563
+ accu2.push(key);
3564
+ }
3565
+ return accu2;
3566
+ }, []);
3567
+ permissionSetObject = scopes.reduce((accu2, scope) => {
3568
+ accu2.result[scope] = mapPermissionSet(permissionSetObject.name, [scopedPermissionAreas[scope].excessiveAccessSelector], scope);
3569
+ return accu2;
3570
+ }, permissionSetObject);
3571
+ accu[permissionSet.name] = permissionSetObject;
3572
+ return accu;
3573
+ },
3574
+ { ...getState().users.permissionSetsById }
3575
+ );
3576
+ return Promise.all([dispatch(actions8.receivedPermissionSets(permissionSets)), permissionSets]);
3577
+ }).catch(() => console.log("Permission set retrieval failed - likely accessing a non-RBAC backend"))
3487
3578
  );
3488
- var setDeviceListState = (0, import_toolkit19.createAsyncThunk)(
3489
- `${sliceName3}/setDeviceListState`,
3490
- ({ shouldSelectDevices = true, forceRefresh, fetchAuth = true, ...selectionState }, { dispatch, getState }) => {
3491
- const currentState = getDeviceListState(getState());
3492
- const refreshTrigger = forceRefresh ? !currentState.refreshTrigger : selectionState.refreshTrigger;
3493
- let nextState = {
3494
- ...currentState,
3495
- setOnly: false,
3496
- refreshTrigger,
3497
- ...selectionState,
3498
- sort: { ...currentState.sort, ...selectionState.sort }
3499
- };
3500
- let tasks = [];
3501
- const { isLoading: currentLoading, deviceIds: currentDevices, selection: currentSelection, ...currentRequestState } = currentState;
3502
- const { isLoading: nextLoading, deviceIds: nextDevices, selection: nextSelection, ...nextRequestState } = nextState;
3503
- if (!nextState.setOnly && !(0, import_helpers9.deepCompare)(currentRequestState, nextRequestState)) {
3504
- const { direction: sortDown = SORTING_OPTIONS.desc, key: sortCol, scope: sortScope } = nextState.sort ?? {};
3505
- const sortBy = sortCol ? [{ attribute: sortCol, order: sortDown, scope: sortScope }] : void 0;
3506
- const applicableSelectedState = nextState.state === ALL_DEVICE_STATES ? void 0 : nextState.state;
3507
- nextState.isLoading = true;
3508
- tasks.push(
3509
- dispatch(getDevicesByStatus2({ ...nextState, status: applicableSelectedState, sortOptions: sortBy, fetchAuth })).unwrap().then((results) => {
3510
- const { deviceAccu, total } = results[results.length - 1];
3511
- const devicesState = shouldSelectDevices ? { deviceIds: deviceAccu.ids, total, isLoading: false } : { isLoading: false };
3512
- return Promise.resolve(dispatch(actions3.setDeviceListState(devicesState)));
3513
- }).catch(() => Promise.resolve({ isLoading: false }))
3514
- );
3579
+ var getRoles = (0, import_toolkit20.createAsyncThunk)(
3580
+ `${sliceName8}/getRoles`,
3581
+ (_, { dispatch, getState }) => Promise.all([general_api_default.get(`${useradmApiUrlv2}/roles?per_page=500`), dispatch(getPermissionSets())]).then((results) => {
3582
+ if (!results) {
3583
+ return Promise.resolve();
3515
3584
  }
3516
- tasks.push(dispatch(actions3.setDeviceListState(nextState)));
3517
- return Promise.all(tasks);
3518
- }
3585
+ const [{ data: roles }, { payload: permissionSetTasks }] = results;
3586
+ const rolesById2 = normalizeRbacRoles(roles, getRolesById(getState()), permissionSetTasks[permissionSetTasks.length - 1]);
3587
+ return Promise.resolve(dispatch(actions8.receivedRoles(rolesById2)));
3588
+ }).catch(() => console.log("Role retrieval failed - likely accessing a non-RBAC backend"))
3519
3589
  );
3520
- var getDevicesByStatus2 = (0, import_toolkit19.createAsyncThunk)(`${sliceName3}/getDevicesByStatus`, (options, { dispatch, getState }) => {
3521
- const {
3522
- status,
3523
- fetchAuth = true,
3524
- filterSelection,
3525
- group,
3526
- selectedIssues = [],
3527
- page = defaultPage2,
3528
- perPage = defaultPerPage2,
3529
- sortOptions = [],
3530
- selectedAttributes = []
3531
- } = options;
3532
- const state = getState();
3533
- const { applicableFilters, filterTerms } = convertDeviceListStateToFilters({
3534
- filters: filterSelection ?? getDeviceFilters(state),
3535
- group: group ?? getSelectedGroup(state),
3536
- groups: state.devices.groups,
3537
- offlineThreshold: state.app.offlineThreshold,
3538
- selectedIssues,
3539
- status
3540
- });
3541
- const attributes = [...defaultAttributes, getIdAttribute(getState()), ...selectedAttributes];
3542
- return general_api_default.post(getSearchEndpoint(getState()), {
3543
- page,
3544
- per_page: perPage,
3545
- filters: filterTerms,
3546
- sort: sortOptions,
3547
- attributes
3548
- }).then((response) => {
3549
- const state2 = getState();
3550
- const deviceAccu = reduceReceivedDevices(response.data, [], state2, status);
3551
- let total = !applicableFilters.length ? Number(response.headers[headerNames.total]) : null;
3552
- if (status && state2.devices.byStatus[status].total === deviceAccu.ids.length) {
3553
- total = deviceAccu.ids.length;
3554
- }
3555
- let tasks = [dispatch(actions3.receivedDevices(deviceAccu.devicesById))];
3556
- if (status) {
3557
- tasks.push(dispatch(actions3.setDevicesByStatus({ deviceIds: deviceAccu.ids, status, total })));
3558
- }
3559
- const receivedDevices = Object.values(deviceAccu.devicesById);
3560
- if (receivedDevices.length && fetchAuth) {
3561
- tasks.push(dispatch(getDevicesWithAuth(receivedDevices)));
3562
- }
3563
- tasks.push(Promise.resolve({ deviceAccu, total: Number(response.headers[headerNames.total]) }));
3564
- return Promise.all(tasks);
3565
- }).catch((err) => commonErrorHandler(err, `${status} devices couldn't be loaded.`, dispatch, commonErrorFallback));
3566
- });
3567
- var getAllDevicesByStatus = (0, import_toolkit19.createAsyncThunk)(`${sliceName3}/getAllDevicesByStatus`, (status, { dispatch, getState }) => {
3568
- const attributes = [...defaultAttributes, getIdAttribute(getState())];
3569
- const getAllDevices = (perPage = MAX_PAGE_SIZE, page = 1, devices = []) => general_api_default.post(getSearchEndpoint(getState()), {
3570
- page,
3571
- per_page: perPage,
3572
- filters: mapFiltersToTerms([{ key: "status", value: status, operator: DEVICE_FILTERING_OPTIONS.$eq.key, scope: "identity" }]),
3573
- attributes
3574
- }).then((res) => {
3575
- const state = getState();
3576
- const deviceAccu = reduceReceivedDevices(res.data, devices, state, status);
3577
- dispatch(actions3.receivedDevices(deviceAccu.devicesById));
3578
- const total = Number(res.headers[headerNames.total]);
3579
- if (total > state.deployments.deploymentDeviceLimit) {
3580
- return Promise.resolve();
3581
- }
3582
- if (total > perPage * page) {
3583
- return getAllDevices(perPage, page + 1, deviceAccu.ids);
3590
+ var deriveImpliedAreaPermissions = (area, areaPermissions, skipPermissions = []) => {
3591
+ const highestAreaPermissionLevelSelected = areaPermissions.reduce(
3592
+ (highest, current) => uiPermissionsById[current].permissionLevel > highest ? uiPermissionsById[current].permissionLevel : highest,
3593
+ 1
3594
+ );
3595
+ return uiPermissionsByArea[area].uiPermissions.reduce((permissions, current) => {
3596
+ if ((current.permissionLevel < highestAreaPermissionLevelSelected || areaPermissions.includes(current.value)) && !skipPermissions.includes(current.value)) {
3597
+ permissions.push(current.value);
3584
3598
  }
3585
- let tasks = [dispatch(actions3.setDevicesByStatus({ deviceIds: deviceAccu.ids, forceUpdate: true, status, total: deviceAccu.ids.length }))];
3586
- if (status === DEVICE_STATES.accepted && deviceAccu.ids.length === total) {
3587
- tasks.push(dispatch(deriveInactiveDevices(deviceAccu.ids)));
3588
- tasks.push(dispatch(deriveReportsData()));
3599
+ return permissions;
3600
+ }, []);
3601
+ };
3602
+ var transformAreaRoleDataToScopedPermissionsSets = (area, areaPermissions, excessiveAccessSelector) => {
3603
+ const permissionSetObject = areaPermissions.reduce((accu, { item, uiPermissions }) => {
3604
+ const skipPermissions = scopedPermissionAreas.releases.key === area && item !== ALL_RELEASES ? [uiPermissionsById.upload.value] : [];
3605
+ const impliedPermissions = deriveImpliedAreaPermissions(area, uiPermissions, skipPermissions);
3606
+ accu = impliedPermissions.reduce((itemPermissionAccu, impliedPermission) => {
3607
+ const permissionSetState = itemPermissionAccu[uiPermissionsById[impliedPermission].permissionSets[area]] ?? {
3608
+ type: uiPermissionsByArea[area].scope,
3609
+ value: []
3610
+ };
3611
+ itemPermissionAccu[uiPermissionsById[impliedPermission].permissionSets[area]] = {
3612
+ ...permissionSetState,
3613
+ value: [...permissionSetState.value, item]
3614
+ };
3615
+ return itemPermissionAccu;
3616
+ }, accu);
3617
+ return accu;
3618
+ }, {});
3619
+ return Object.entries(permissionSetObject).map(([name, { value, ...scope }]) => {
3620
+ if (value.includes(excessiveAccessSelector)) {
3621
+ return { name };
3589
3622
  }
3590
- return Promise.all(tasks);
3623
+ return { name, scope: { ...scope, value: value.filter(import_helpers9.duplicateFilter) } };
3591
3624
  });
3592
- return getAllDevices();
3593
- });
3594
- var searchDevices = (0, import_toolkit19.createAsyncThunk)(`${sliceName3}/searchDevices`, (passedOptions = {}, { dispatch, getState }) => {
3595
- const state = getState();
3596
- let options = { ...state.app.searchState, ...passedOptions };
3597
- const { page = defaultPage2, searchTerm, sortOptions = [] } = options;
3598
- const { columnSelection = [] } = getUserSettings(state);
3599
- const selectedAttributes = columnSelection.map((column) => ({ attribute: column.key, scope: column.scope }));
3600
- const attributes = (0, import_helpers9.attributeDuplicateFilter)([...defaultAttributes, getIdAttribute(state), ...selectedAttributes], "attribute");
3601
- return general_api_default.post(getSearchEndpoint(getState()), {
3602
- page,
3603
- per_page: 10,
3604
- filters: [],
3605
- sort: sortOptions,
3606
- text: searchTerm,
3607
- attributes
3608
- }).then((response) => {
3609
- const deviceAccu = reduceReceivedDevices(response.data, [], getState());
3610
- return Promise.all([
3611
- dispatch(actions3.receivedDevices(deviceAccu.devicesById)),
3612
- Promise.resolve({ deviceIds: deviceAccu.ids, searchTotal: Number(response.headers[headerNames.total]) })
3613
- ]);
3614
- }).catch((err) => commonErrorHandler(err, `devices couldn't be searched.`, dispatch, commonErrorFallback));
3615
- });
3616
- var ATTRIBUTE_LIST_CUTOFF = 100;
3617
- var attributeReducer = (attributes = []) => attributes.slice(0, ATTRIBUTE_LIST_CUTOFF).reduce(
3618
- (accu, { name, scope }) => {
3619
- if (!accu[scope]) {
3620
- accu[scope] = [];
3625
+ };
3626
+ var transformRoleDataToRole = (roleData, roleState = {}) => {
3627
+ const role = { ...roleState, ...roleData };
3628
+ const { description = "", name, uiPermissions = emptyUiPermissions } = role;
3629
+ const { maybeUiPermissions, remainderKeys } = Object.entries(emptyUiPermissions).reduce(
3630
+ (accu, [key, emptyPermissions]) => {
3631
+ if (!scopedPermissionAreas[key]) {
3632
+ accu.remainderKeys.push(key);
3633
+ } else if (uiPermissions[key]) {
3634
+ accu.maybeUiPermissions[key] = uiPermissions[key].reduce(itemUiPermissionsReducer, emptyPermissions);
3635
+ }
3636
+ return accu;
3637
+ },
3638
+ { maybeUiPermissions: {}, remainderKeys: [] }
3639
+ );
3640
+ const { permissionSetsWithScope, roleUiPermissions } = remainderKeys.reduce(
3641
+ (accu, area) => {
3642
+ const areaPermissions = role.uiPermissions[area];
3643
+ if (!Array.isArray(areaPermissions)) {
3644
+ return accu;
3645
+ }
3646
+ const impliedPermissions = deriveImpliedAreaPermissions(area, areaPermissions);
3647
+ accu.roleUiPermissions[area] = impliedPermissions;
3648
+ const mappedPermissions = impliedPermissions.map((uiPermission) => ({ name: uiPermissionsById[uiPermission].permissionSets[area] }));
3649
+ accu.permissionSetsWithScope.push(...mappedPermissions);
3650
+ return accu;
3651
+ },
3652
+ { permissionSetsWithScope: [{ name: defaultPermissionSets.Basic.name }], roleUiPermissions: {} }
3653
+ );
3654
+ const scopedPermissionSets = Object.values(scopedPermissionAreas).reduce((accu, { key, excessiveAccessSelector }) => {
3655
+ if (!uiPermissions[key]) {
3656
+ return accu;
3621
3657
  }
3622
- accu[scope].push(name);
3658
+ accu.push(...transformAreaRoleDataToScopedPermissionsSets(key, uiPermissions[key], excessiveAccessSelector));
3623
3659
  return accu;
3660
+ }, []);
3661
+ return {
3662
+ permissionSetsWithScope: [...permissionSetsWithScope, ...scopedPermissionSets],
3663
+ role: {
3664
+ ...emptyRole,
3665
+ name,
3666
+ description: description ? description : roleState.description,
3667
+ uiPermissions: {
3668
+ ...emptyUiPermissions,
3669
+ ...roleUiPermissions,
3670
+ ...maybeUiPermissions
3671
+ }
3672
+ }
3673
+ };
3674
+ };
3675
+ var roleActions = {
3676
+ create: {
3677
+ successMessage: "The role was created successfully.",
3678
+ errorMessage: "creating"
3624
3679
  },
3625
- { identity: [], inventory: [], system: [], tags: [] }
3680
+ edit: {
3681
+ successMessage: "The role has been updated.",
3682
+ errorMessage: "editing"
3683
+ },
3684
+ remove: {
3685
+ successMessage: "The role was deleted successfully.",
3686
+ errorMessage: "removing"
3687
+ }
3688
+ };
3689
+ var roleActionErrorHandler = (err, type, dispatch) => commonErrorHandler(err, `There was an error ${roleActions[type].errorMessage} the role.`, dispatch);
3690
+ var createRole = (0, import_toolkit20.createAsyncThunk)(`${sliceName8}/createRole`, (roleData, { dispatch }) => {
3691
+ const { permissionSetsWithScope, role } = transformRoleDataToRole(roleData);
3692
+ return general_api_default.post(`${useradmApiUrlv2}/roles`, {
3693
+ name: role.name,
3694
+ description: role.description,
3695
+ permission_sets_with_scope: permissionSetsWithScope
3696
+ }).then(() => Promise.all([dispatch(actions8.createdRole(role)), dispatch(getRoles()), dispatch(setSnackbar3(roleActions.create.successMessage))])).catch((err) => roleActionErrorHandler(err, "create", dispatch));
3697
+ });
3698
+ var editRole = (0, import_toolkit20.createAsyncThunk)(`${sliceName8}/editRole`, (roleData, { dispatch, getState }) => {
3699
+ const { permissionSetsWithScope, role } = transformRoleDataToRole(roleData, getRolesById(getState())[roleData.name]);
3700
+ return general_api_default.put(`${useradmApiUrlv2}/roles/${role.name}`, {
3701
+ description: role.description,
3702
+ name: role.name,
3703
+ permission_sets_with_scope: permissionSetsWithScope
3704
+ }).then(() => Promise.all([dispatch(actions8.createdRole(role)), dispatch(getRoles()), dispatch(setSnackbar3(roleActions.edit.successMessage))])).catch((err) => roleActionErrorHandler(err, "edit", dispatch));
3705
+ });
3706
+ var removeRole = (0, import_toolkit20.createAsyncThunk)(
3707
+ `${sliceName8}/removeRole`,
3708
+ (roleId, { dispatch }) => general_api_default.delete(`${useradmApiUrlv2}/roles/${roleId}`).then(() => Promise.all([dispatch(actions8.removedRole(roleId)), dispatch(getRoles()), dispatch(setSnackbar3(roleActions.remove.successMessage))])).catch((err) => roleActionErrorHandler(err, "remove", dispatch))
3626
3709
  );
3627
- var getDeviceAttributes = (0, import_toolkit19.createAsyncThunk)(
3628
- `${sliceName3}/getDeviceAttributes`,
3629
- (_, { dispatch, getState }) => general_api_default.get(getAttrsEndpoint(getState())).then(({ data }) => {
3630
- const { identity: identityAttributes, inventory: inventoryAttributes, system: systemAttributes, tags: tagAttributes } = attributeReducer(data || []);
3631
- return dispatch(actions3.setFilterAttributes({ identityAttributes, inventoryAttributes, systemAttributes, tagAttributes }));
3710
+ var getGlobalSettings2 = (0, import_toolkit20.createAsyncThunk)(
3711
+ `${sliceName8}/getGlobalSettings`,
3712
+ (_, { dispatch }) => general_api_default.get(`${useradmApiUrlv1}/settings`).then(({ data: settings, headers: { etag } }) => {
3713
+ window.sessionStorage.setItem(settingsKeys.initialized, true);
3714
+ return Promise.all([dispatch(actions8.setGlobalSettings(settings)), dispatch(setOfflineThreshold()), etag]);
3632
3715
  })
3633
3716
  );
3634
- var getReportingLimits = (0, import_toolkit19.createAsyncThunk)(
3635
- `${sliceName3}/getReportingLimits`,
3636
- (_, { dispatch }) => general_api_default.get(`${reportingApiUrl}/devices/attributes`).catch((err) => commonErrorHandler(err, `filterable attributes limit & usage could not be retrieved.`, dispatch, commonErrorFallback)).then(({ data }) => {
3637
- const { attributes, count, limit } = data;
3638
- const groupedAttributes = attributeReducer(attributes);
3639
- return Promise.resolve(dispatch(actions3.setFilterablesConfig({ count, limit, attributes: groupedAttributes })));
3717
+ var saveGlobalSettings = (0, import_toolkit20.createAsyncThunk)(
3718
+ `${sliceName8}/saveGlobalSettings`,
3719
+ ({ beOptimistic = false, notify = false, ...settings }, { dispatch, getState }) => {
3720
+ if (!window.sessionStorage.getItem(settingsKeys.initialized) && !beOptimistic) {
3721
+ return;
3722
+ }
3723
+ return dispatch(getGlobalSettings2()).unwrap().then((result) => {
3724
+ let updatedSettings = { ...getState().users.globalSettings, ...settings };
3725
+ if (getCurrentUser(getState()).verified) {
3726
+ updatedSettings["2fa"] = twoFAStates.enabled;
3727
+ } else {
3728
+ delete updatedSettings["2fa"];
3729
+ }
3730
+ let tasks = [dispatch(actions8.setGlobalSettings(updatedSettings))];
3731
+ const headers = result[result.length - 1] ? { "If-Match": result[result.length - 1] } : {};
3732
+ return general_api_default.post(`${useradmApiUrlv1}/settings`, updatedSettings, { headers }).then(() => {
3733
+ if (notify) {
3734
+ tasks.push(dispatch(setSnackbar3("Settings saved successfully")));
3735
+ }
3736
+ return Promise.all(tasks);
3737
+ }).catch((err) => {
3738
+ if (beOptimistic) {
3739
+ return Promise.all([tasks]);
3740
+ }
3741
+ console.log(err);
3742
+ return commonErrorHandler(err, `The settings couldn't be saved.`, dispatch);
3743
+ });
3744
+ });
3745
+ }
3746
+ );
3747
+ var getUserSettings2 = (0, import_toolkit20.createAsyncThunk)(
3748
+ `${sliceName8}/getUserSettings`,
3749
+ (_, { dispatch }) => general_api_default.get(`${useradmApiUrlv1}/settings/me`).then(({ data: settings, headers: { etag } }) => {
3750
+ window.sessionStorage.setItem(settingsKeys.initialized, true);
3751
+ return Promise.all([dispatch(actions8.setUserSettings(settings)), etag]);
3640
3752
  })
3641
3753
  );
3642
- var ensureVersionString = (software, fallback) => software.length && software !== "artifact_name" ? software.endsWith(".version") ? software : `${software}.version` : fallback;
3643
- var REPORT_CHART_SIZE_LIMIT = 6;
3644
- var getSingleReportData = (reportConfig, groups) => {
3645
- const { attribute, group, software = "" } = reportConfig;
3646
- const filters = [{ key: "status", scope: "identity", operator: DEVICE_FILTERING_OPTIONS.$eq.key, value: "accepted" }];
3647
- if (group) {
3648
- const staticGroupFilter = { key: "group", scope: "system", operator: DEVICE_FILTERING_OPTIONS.$eq.key, value: group };
3649
- const { cleanedFilters: groupFilters } = getGroupFilters(group, groups);
3650
- filters.push(...groupFilters.length ? groupFilters : [staticGroupFilter]);
3754
+ var saveUserSettings = (0, import_toolkit20.createAsyncThunk)(`${sliceName8}/saveUserSettings`, (settings = { onboarding: {} }, { dispatch, getState }) => {
3755
+ if (!getCurrentUser(getState()).id) {
3756
+ return Promise.resolve();
3651
3757
  }
3652
- const aggregationAttribute = ensureVersionString(software, attribute);
3653
- return general_api_default.post(`${reportingApiUrl}/devices/aggregate`, {
3654
- aggregations: [{ attribute: aggregationAttribute, name: "*", scope: "inventory", size: REPORT_CHART_SIZE_LIMIT }],
3655
- filters: mapFiltersToTerms(filters)
3656
- }).then(({ data }) => ({ data, reportConfig }));
3657
- };
3658
- var getReportsData = (0, import_toolkit19.createAsyncThunk)(`${sliceName3}/getReportsData`, (_, { dispatch, getState }) => {
3659
- const state = getState();
3660
- const currentUserId = getCurrentUser(state).id;
3661
- const reports = getUserSettings(state).reports || getGlobalSettings(state)[`${currentUserId}-reports`] || (Object.keys(getDevicesById(state)).length ? defaultReports : []);
3662
- return Promise.all(reports.map((report) => getSingleReportData(report, getState().devices.groups))).then((results) => {
3663
- const devicesState = getState().devices;
3664
- const totalDeviceCount = devicesState.byStatus.accepted.total;
3665
- const newReports = results.map(({ data, reportConfig }) => {
3666
- let { items, other_count } = data[0];
3667
- const { attribute, group, software = "" } = reportConfig;
3668
- const dataCount = items.reduce((accu, item) => accu + item.count, 0);
3669
- const otherCount = !group && (software === rootfsImageVersion || attribute === "artifact_name") ? totalDeviceCount - dataCount : other_count;
3670
- return { items, otherCount, total: otherCount + dataCount };
3671
- });
3672
- return Promise.resolve(dispatch(actions3.setDeviceReports(newReports)));
3673
- });
3674
- });
3675
- var initializeDistributionData = (report, groups, devices, totalDeviceCount) => {
3676
- const { attribute, group = "", software = "" } = report;
3677
- const effectiveAttribute = software ? software : attribute;
3678
- const { deviceIds, total = 0 } = groups[group] || {};
3679
- const relevantDevices = groups[group] ? deviceIds.map((id) => devices[id]) : Object.values(devices);
3680
- const distributionByAttribute = relevantDevices.reduce((accu, item) => {
3681
- if (!item.attributes || item.status !== DEVICE_STATES.accepted) return accu;
3682
- if (!accu[item.attributes[effectiveAttribute]]) {
3683
- accu[item.attributes[effectiveAttribute]] = 0;
3684
- }
3685
- accu[item.attributes[effectiveAttribute]] = accu[item.attributes[effectiveAttribute]] + 1;
3686
- return accu;
3687
- }, {});
3688
- const distributionByAttributeSorted = Object.entries(distributionByAttribute).sort((pairA, pairB) => pairB[1] - pairA[1]);
3689
- const items = distributionByAttributeSorted.map(([key, count]) => ({ key, count }));
3690
- const dataCount = items.reduce((accu, item) => accu + item.count, 0);
3691
- const otherCount = (groups[group] ? total : totalDeviceCount) - dataCount;
3692
- return { items, otherCount, total: otherCount + dataCount };
3693
- };
3694
- var deriveReportsData = (0, import_toolkit19.createAsyncThunk)(`${sliceName3}/deriveReportsData`, (_, { dispatch, getState }) => {
3695
- const state = getState();
3696
- const {
3697
- groups: { byId: groupsById },
3698
- byId,
3699
- byStatus: {
3700
- accepted: { total }
3701
- }
3702
- } = state.devices;
3703
- const reports = getUserSettings(state).reports || state.users.globalSettings[`${state.users.currentUser}-reports`] || (Object.keys(byId).length ? defaultReports : []);
3704
- const newReports = reports.map((report) => initializeDistributionData(report, groupsById, byId, total));
3705
- return Promise.resolve(dispatch(actions3.setDeviceReports(newReports)));
3706
- });
3707
- var getReportsDataWithoutBackendSupport = (0, import_toolkit19.createAsyncThunk)(
3708
- `${sliceName3}/getReportsDataWithoutBackendSupport`,
3709
- (_, { dispatch, getState }) => Promise.all([dispatch(getAllDevicesByStatus(DEVICE_STATES.accepted)), dispatch(getGroups2()), dispatch(getDynamicGroups())]).then(() => {
3710
- const { dynamic: dynamicGroups, static: staticGroups } = getGroups(getState());
3758
+ return dispatch(getUserSettings2()).unwrap().then((result) => {
3759
+ const userSettings = getUserSettings(getState());
3760
+ const onboardingState = getOnboardingState(getState());
3761
+ const tooltipState = getTooltipsState(getState());
3762
+ const updatedSettings = {
3763
+ ...userSettings,
3764
+ ...settings,
3765
+ onboarding: {
3766
+ ...onboardingState,
3767
+ ...settings.onboarding
3768
+ },
3769
+ tooltips: tooltipState
3770
+ };
3771
+ const headers = result[result.length - 1] ? { "If-Match": result[result.length - 1] } : {};
3711
3772
  return Promise.all([
3712
- ...staticGroups.map(({ groupId }) => dispatch(getAllGroupDevices(groupId))),
3713
- ...dynamicGroups.map(({ groupId }) => dispatch(getAllDynamicGroupDevices(groupId)))
3714
- ]).then(() => dispatch(deriveReportsData()));
3715
- })
3716
- );
3717
- var getDeviceConnect = (0, import_toolkit19.createAsyncThunk)(
3718
- `${sliceName3}/getDeviceConnect`,
3719
- (id, { dispatch }) => general_api_default.get(`${deviceConnect}/devices/${id}`).then(
3720
- ({ data }) => Promise.all([dispatch(actions3.receivedDevice({ connect_status: data.status, connect_updated_ts: data.updated_ts, id })), Promise.resolve(data)])
3721
- )
3722
- );
3723
- var getSessionDetails = (0, import_toolkit19.createAsyncThunk)(`${sliceName3}/getSessionDetails`, ({ sessionId, deviceId, userId, startDate, endDate }) => {
3724
- const { start: startUnix, end: endUnix } = (0, import_helpers9.dateRangeToUnix)(startDate, endDate);
3725
- const createdAfter = startDate ? `&created_after=${startUnix}` : "";
3726
- const createdBefore = endDate ? `&created_before=${endUnix}` : "";
3727
- const objectSearch = `&object_id=${deviceId}`;
3728
- return general_api_default.get(`${auditLogsApiUrl}/logs?per_page=500${createdAfter}${createdBefore}&actor_id=${userId}${objectSearch}`).then(
3729
- ({ data: auditLogEntries }) => {
3730
- const { start, end } = auditLogEntries.reduce(
3731
- (accu, item) => {
3732
- if (item.meta?.session_id?.includes(sessionId)) {
3733
- accu.start = new Date(item.action.startsWith("open") ? item.time : accu.start);
3734
- accu.end = new Date(item.action.startsWith("close") ? item.time : accu.end);
3735
- }
3736
- return accu;
3737
- },
3738
- { start: startDate || endDate, end: endDate || startDate }
3739
- );
3740
- return Promise.resolve({ start, end });
3741
- }
3742
- );
3773
+ Promise.resolve(dispatch(actions8.setUserSettings(updatedSettings))),
3774
+ general_api_default.post(`${useradmApiUrlv1}/settings/me`, updatedSettings, { headers })
3775
+ ]).catch(() => dispatch(actions8.setUserSettings(userSettings)));
3776
+ });
3743
3777
  });
3744
- var getDeviceFileDownloadLink = (0, import_toolkit19.createAsyncThunk)(
3745
- `${sliceName3}/getDeviceFileDownloadLink`,
3746
- ({ deviceId, path }) => Promise.resolve(`${window.location.origin}${deviceConnect}/devices/${deviceId}/download?path=${encodeURIComponent(path)}`)
3778
+ var get2FAQRCode = (0, import_toolkit20.createAsyncThunk)(
3779
+ `${sliceName8}/get2FAQRCode`,
3780
+ (_, { dispatch }) => general_api_default.get(`${useradmApiUrlv1}/2faqr`).then((res) => dispatch(actions8.receivedQrCode(res.data.qr)))
3747
3781
  );
3748
- var deviceFileUpload = (0, import_toolkit19.createAsyncThunk)(`${sliceName3}/deviceFileUpload`, ({ deviceId, path, file }, { dispatch }) => {
3749
- let formData = new FormData();
3750
- formData.append("path", path);
3751
- formData.append("file", file);
3752
- const uploadId = (0, import_uuid.v4)();
3753
- const cancelSource = new AbortController();
3754
- return Promise.all([
3755
- dispatch(setSnackbar3("Uploading file")),
3756
- dispatch(initUpload({ id: uploadId, upload: { inprogress: true, uploadProgress: 0, cancelSource } })),
3757
- general_api_default.uploadPut(
3758
- `${deviceConnect}/devices/${deviceId}/upload`,
3759
- formData,
3760
- (e) => dispatch(uploadProgress2({ id: uploadId, progress: progress(e) })),
3761
- cancelSource.signal
3762
- )
3763
- ]).then(() => Promise.resolve(dispatch(setSnackbar3("Upload successful", TIMEOUTS.fiveSeconds)))).catch((err) => {
3764
- if ((0, import_axios2.isCancel)(err)) {
3765
- return dispatch(setSnackbar3("The upload has been cancelled", TIMEOUTS.fiveSeconds));
3766
- }
3767
- return commonErrorHandler(err, `Error uploading file to device.`, dispatch);
3768
- }).finally(() => dispatch(cleanUpUpload(uploadId)));
3782
+ var setHideAnnouncement = (0, import_toolkit20.createAsyncThunk)(`${sliceName8}/setHideAnnouncement`, ({ shouldHide, userId }, { dispatch, getState }) => {
3783
+ const currentUserId = userId || getCurrentUser(getState()).id;
3784
+ const hash = getState().app.hostedAnnouncement ? (0, import_md5.default)(getState().app.hostedAnnouncement) : "";
3785
+ const announceCookie = cookies3.get(`${currentUserId}${hash}`);
3786
+ if (shouldHide || hash.length && typeof announceCookie !== "undefined") {
3787
+ cookies3.set(`${currentUserId}${hash}`, true, { maxAge: 604800 });
3788
+ return Promise.resolve(dispatch(setAnnouncement()));
3789
+ }
3790
+ return Promise.resolve();
3769
3791
  });
3770
- var getDeviceAuth = (0, import_toolkit19.createAsyncThunk)(
3771
- `${sliceName3}/getDeviceAuth`,
3772
- (id, { dispatch }) => dispatch(getDevicesWithAuth([{ id }])).unwrap().then((results) => {
3773
- if (results[results.length - 1]) {
3774
- return Promise.resolve(results[results.length - 1][0]);
3775
- }
3776
- return Promise.resolve();
3792
+ var getTokens = (0, import_toolkit20.createAsyncThunk)(
3793
+ `${sliceName8}/getTokens`,
3794
+ (_, { dispatch, getState }) => general_api_default.get(`${useradmApiUrlv1}/settings/tokens`).then(({ data: tokens }) => {
3795
+ const user = getCurrentUser(getState());
3796
+ const updatedUser = {
3797
+ ...user,
3798
+ tokens
3799
+ };
3800
+ return Promise.resolve(dispatch(actions8.updatedUser(updatedUser)));
3777
3801
  })
3778
3802
  );
3779
- var getDevicesWithAuth = (0, import_toolkit19.createAsyncThunk)(
3780
- `${sliceName3}/getDevicesWithAuth`,
3781
- (devices, { dispatch, getState }) => devices.length ? general_api_default.get(`${deviceAuthV2}/devices?id=${devices.map((device) => device.id).join("&id=")}`).then(({ data: receivedDevices }) => {
3782
- const { devicesById } = reduceReceivedDevices(receivedDevices, [], getState());
3783
- return Promise.all([dispatch(actions3.receivedDevices(devicesById)), Promise.resolve(receivedDevices)]);
3784
- }).catch((err) => commonErrorHandler(err, `Error: ${err}`, dispatch)) : Promise.resolve([[], []])
3803
+ var ONE_YEAR = 31536e3;
3804
+ var generateToken = (0, import_toolkit20.createAsyncThunk)(
3805
+ `${sliceName8}/generateToken`,
3806
+ ({ expiresIn = ONE_YEAR, name }, { dispatch }) => general_api_default.post(`${useradmApiUrlv1}/settings/tokens`, { name, expires_in: expiresIn }).then(({ data: token }) => Promise.all([dispatch(getTokens()), token])).catch((err) => commonErrorHandler(err, "There was an error creating the token:", dispatch))
3785
3807
  );
3786
- var updateDeviceAuth = (0, import_toolkit19.createAsyncThunk)(
3787
- `${sliceName3}/updateDeviceAuth`,
3788
- ({ deviceId, authId, status }, { dispatch, getState }) => general_api_default.put(`${deviceAuthV2}/devices/${deviceId}/auth/${authId}/status`, { status }).then(() => Promise.all([dispatch(getDeviceAuth(deviceId)), dispatch(setSnackbar3("Device authorization status was updated successfully"))])).catch((err) => commonErrorHandler(err, "There was a problem updating the device authorization status:", dispatch)).then(() => Promise.resolve(dispatch(actions3.maybeUpdateDevicesByStatus({ deviceId, authId })))).finally(() => dispatch(setDeviceListState({ refreshTrigger: !getDeviceListState(getState()).refreshTrigger })))
3808
+ var revokeToken = (0, import_toolkit20.createAsyncThunk)(
3809
+ `${sliceName8}/revokeToken`,
3810
+ (token, { dispatch }) => general_api_default.delete(`${useradmApiUrlv1}/settings/tokens/${token.id}`).then(() => Promise.resolve(dispatch(getTokens())))
3789
3811
  );
3790
- var updateDevicesAuth = (0, import_toolkit19.createAsyncThunk)(`${sliceName3}/updateDevicesAuth`, ({ deviceIds, status }, { dispatch, getState }) => {
3791
- let devices = getDevicesById(getState());
3792
- const deviceIdsWithoutAuth = deviceIds.reduce((accu, id) => devices[id].auth_sets ? accu : [...accu, { id }], []);
3793
- return dispatch(getDevicesWithAuth(deviceIdsWithoutAuth)).then(() => {
3794
- devices = getDevicesById(getState());
3795
- const deviceAuthUpdates = deviceIds.map((id) => {
3796
- const device = devices[id];
3797
- if (device.auth_sets.length !== 1) {
3798
- return Promise.reject();
3812
+ var setTooltipReadState = (0, import_toolkit20.createAsyncThunk)(`${sliceName8}/setTooltipReadState`, ({ persist, ...remainder }, { dispatch }) => {
3813
+ let tasks = [dispatch(actions8.setTooltipState(remainder))];
3814
+ if (persist) {
3815
+ tasks.push(dispatch(saveUserSettings()));
3816
+ }
3817
+ return Promise.all(tasks);
3818
+ });
3819
+ var setAllTooltipsReadState = (0, import_toolkit20.createAsyncThunk)(`${sliceName8}/toggleHelptips`, (readState = READ_STATES.read, { dispatch }) => {
3820
+ const updatedTips = Object.keys(import_helptips.HELPTOOLTIPS).reduce((accu, id) => ({ ...accu, [id]: { readState } }), {});
3821
+ return Promise.resolve(dispatch(actions8.setTooltipsState(updatedTips))).then(() => dispatch(saveUserSettings()));
3822
+ });
3823
+ var submitFeedback = (0, import_toolkit20.createAsyncThunk)(
3824
+ `${sliceName8}/submitFeedback`,
3825
+ ({ satisfaction, feedback, ...meta }, { dispatch }) => general_api_default.post(`${tenantadmApiUrlv2}/contact/support`, {
3826
+ subject: "feedback submission",
3827
+ body: JSON.stringify({ feedback, satisfaction, meta })
3828
+ }).then(() => {
3829
+ const today = /* @__PURE__ */ new Date();
3830
+ dispatch(saveUserSettings({ feedbackCollectedAt: today.toISOString().split("T")[0] }));
3831
+ setTimeout(() => dispatch(actions8.setShowFeedbackDialog(false)), TIMEOUTS.threeSeconds);
3832
+ })
3833
+ );
3834
+
3835
+ // src/devicesSlice/thunks.tsx
3836
+ var import_helpers10 = require("@northern.tech/utils/helpers");
3837
+ var import_toolkit21 = require("@reduxjs/toolkit");
3838
+ var import_axios3 = require("axios");
3839
+ var import_pluralize = __toESM(require("pluralize"), 1);
3840
+ var import_uuid = require("uuid");
3841
+ var import_jsx_runtime2 = require("react/jsx-runtime");
3842
+ var { cleanUpUpload, initUpload, setSnackbar: setSnackbar4, uploadProgress: uploadProgress2 } = actions_default;
3843
+ var { page: defaultPage3, perPage: defaultPerPage3 } = DEVICE_LIST_DEFAULTS;
3844
+ var defaultAttributes = [
3845
+ { scope: "identity", attribute: "status" },
3846
+ { scope: "inventory", attribute: "artifact_name" },
3847
+ { scope: "inventory", attribute: "device_type" },
3848
+ { scope: "inventory", attribute: "mender_is_gateway" },
3849
+ { scope: "inventory", attribute: "mender_gateway_system_id" },
3850
+ { scope: "inventory", attribute: rootfsImageVersion },
3851
+ { scope: "monitor", attribute: "alerts" },
3852
+ { scope: "system", attribute: "created_ts" },
3853
+ { scope: "system", attribute: "updated_ts" },
3854
+ { scope: "system", attribute: "check_in_time" },
3855
+ { scope: "system", attribute: "group" },
3856
+ { scope: "tags", attribute: "name" }
3857
+ ];
3858
+ var getGroups2 = (0, import_toolkit21.createAsyncThunk)(
3859
+ `${sliceName3}/getGroups`,
3860
+ (_, { dispatch, getState }) => general_api_default.get(`${inventoryApiUrl}/groups`).then((res) => {
3861
+ const state = getGroupsById(getState());
3862
+ const dynamicGroups = Object.entries(state).reduce((accu, [id, group]) => {
3863
+ if (group.id || group.filters?.length && id !== UNGROUPED_GROUP.id) {
3864
+ accu[id] = group;
3799
3865
  }
3800
- return dispatch(updateDeviceAuth({ authId: device.auth_sets[0].id, deviceId: device.id, status })).unwrap().catch((err) => commonErrorHandler(err, "The action was stopped as there was a problem updating a device authorization status: ", dispatch, "", false));
3801
- });
3802
- return Promise.allSettled(deviceAuthUpdates).then((results) => {
3803
- const { skipped, count } = results.reduce(
3804
- (accu, item) => {
3805
- if (item.status === "rejected") {
3806
- accu.skipped = accu.skipped + 1;
3807
- } else {
3808
- accu.count = accu.count + 1;
3809
- }
3810
- return accu;
3811
- },
3812
- { skipped: 0, count: 0 }
3866
+ return accu;
3867
+ }, {});
3868
+ const groups = res.data.reduce((accu, group) => {
3869
+ accu[group] = { deviceIds: [], filters: [], total: 0, ...state[group] };
3870
+ return accu;
3871
+ }, dynamicGroups);
3872
+ const filters = [{ key: "group", value: res.data, operator: DEVICE_FILTERING_OPTIONS.$nin.key, scope: "system" }];
3873
+ return Promise.all([
3874
+ dispatch(actions3.receivedGroups(groups)),
3875
+ dispatch(getDevicesByStatus2({ filterSelection: filters, group: 0, page: 1, perPage: 1, status: void 0 }))
3876
+ ]).then((promises) => {
3877
+ const devicesRetrieval = promises[promises.length - 1] || [];
3878
+ const { payload } = devicesRetrieval || {};
3879
+ const result = payload[payload.length - 1] || {};
3880
+ if (!result.total) {
3881
+ return Promise.resolve();
3882
+ }
3883
+ return Promise.resolve(
3884
+ dispatch(
3885
+ actions3.addGroup({
3886
+ groupName: UNGROUPED_GROUP.id,
3887
+ group: { filters: [{ key: "group", value: res.data, operator: DEVICE_FILTERING_OPTIONS.$nin.key, scope: "system" }] }
3888
+ })
3889
+ )
3813
3890
  );
3814
- const message = (0, import_helpers9.getSnackbarMessage)(skipped, count);
3815
- return dispatch(setSnackbar3(message));
3816
3891
  });
3817
- });
3818
- });
3819
- var deleteAuthset = (0, import_toolkit19.createAsyncThunk)(
3820
- `${sliceName3}/deleteAuthset`,
3821
- ({ deviceId, authId }, { dispatch, getState }) => general_api_default.delete(`${deviceAuthV2}/devices/${deviceId}/auth/${authId}`).then(() => Promise.all([dispatch(setSnackbar3("Device authorization status was updated successfully"))])).catch((err) => commonErrorHandler(err, "There was a problem updating the device authorization status:", dispatch)).then(() => Promise.resolve(dispatch(actions3.maybeUpdateDevicesByStatus({ deviceId, authId })))).finally(() => dispatch(setDeviceListState({ refreshTrigger: !getState().devices.deviceList.refreshTrigger })))
3822
- );
3823
- var preauthDevice = (0, import_toolkit19.createAsyncThunk)(
3824
- `${sliceName3}/preauthDevice`,
3825
- (authset, { dispatch }) => general_api_default.post(`${deviceAuthV2}/devices`, authset).catch((err) => {
3826
- if (err.response.status === 409) {
3827
- return Promise.reject("A device with a matching identity data set already exists");
3828
- }
3829
- return commonErrorHandler(err, "The device could not be added:", dispatch);
3830
- }).then(() => Promise.resolve(dispatch(setSnackbar3("Device was successfully added to the preauthorization list", TIMEOUTS.fiveSeconds))))
3831
- );
3832
- var decommissionDevice = (0, import_toolkit19.createAsyncThunk)(
3833
- `${sliceName3}/decommissionDevice`,
3834
- ({ deviceId, authId }, { dispatch, getState }) => general_api_default.delete(`${deviceAuthV2}/devices/${deviceId}`).then(() => Promise.resolve(dispatch(setSnackbar3("Device was decommissioned successfully")))).catch((err) => commonErrorHandler(err, "There was a problem decommissioning the device:", dispatch)).then(() => Promise.resolve(dispatch(actions3.maybeUpdateDevicesByStatus({ deviceId, authId })))).finally(() => dispatch(setDeviceListState({ refreshTrigger: !getState().devices.deviceList.refreshTrigger })))
3835
- );
3836
- var getDeviceConfig = (0, import_toolkit19.createAsyncThunk)(
3837
- `${sliceName3}/getDeviceConfig`,
3838
- (deviceId, { dispatch }) => general_api_default.get(`${deviceConfig}/${deviceId}`).then(({ data }) => Promise.all([dispatch(actions3.receivedDevice({ id: deviceId, config: data })), Promise.resolve(data)])).catch((err) => {
3839
- if (err.response?.data?.error.status_code !== 404) {
3840
- return commonErrorHandler(err, `There was an error retrieving the configuration for device ${deviceId}.`, dispatch, commonErrorFallback);
3841
- }
3842
3892
  })
3843
3893
  );
3844
- var setDeviceConfig = (0, import_toolkit19.createAsyncThunk)(
3845
- `${sliceName3}/setDeviceConfig`,
3846
- ({ deviceId, config }, { dispatch }) => general_api_default.put(`${deviceConfig}/${deviceId}`, config).catch((err) => commonErrorHandler(err, `There was an error setting the configuration for device ${deviceId}.`, dispatch, commonErrorFallback)).then(() => Promise.resolve(dispatch(getDeviceConfig(deviceId))))
3894
+ var addDevicesToGroup = (0, import_toolkit21.createAsyncThunk)(
3895
+ `${sliceName3}/addDevicesToGroup`,
3896
+ ({ group, deviceIds, isCreation }, { dispatch }) => general_api_default.patch(`${inventoryApiUrl}/groups/${group}/devices`, deviceIds).then(() => dispatch(actions3.addToGroup({ group, deviceIds }))).finally(() => isCreation ? Promise.resolve(dispatch(getGroups2())) : {})
3847
3897
  );
3848
- var applyDeviceConfig = (0, import_toolkit19.createAsyncThunk)(
3849
- `${sliceName3}/applyDeviceConfig`,
3850
- ({ deviceId, configDeploymentConfiguration, isDefault, config }, { dispatch, getState }) => general_api_default.post(`${deviceConfig}/${deviceId}/deploy`, configDeploymentConfiguration).catch((err) => commonErrorHandler(err, `There was an error deploying the configuration to device ${deviceId}.`, dispatch, commonErrorFallback)).then(({ data }) => {
3851
- const device = getDeviceById(getState(), deviceId);
3852
- const { canManageUsers } = getUserCapabilities(getState());
3853
- let tasks = [
3854
- dispatch(actions3.receivedDevice({ ...device, config: { ...device.config, deployment_id: data.deployment_id } })),
3855
- new Promise((resolve) => setTimeout(() => resolve(dispatch(getSingleDeployment(data.deployment_id))), TIMEOUTS.oneSecond))
3856
- ];
3857
- if (isDefault && canManageUsers) {
3858
- const { previous } = getGlobalSettings(getState()).defaultDeviceConfig ?? {};
3859
- tasks.push(dispatch(saveGlobalSettings({ defaultDeviceConfig: { current: config, previous } })));
3860
- }
3861
- return Promise.all(tasks);
3862
- })
3898
+ var removeDevicesFromGroup = (0, import_toolkit21.createAsyncThunk)(
3899
+ `${sliceName3}/removeDevicesFromGroup`,
3900
+ ({ group, deviceIds }, { dispatch }) => general_api_default.delete(`${inventoryApiUrl}/groups/${group}/devices`, deviceIds).then(
3901
+ () => Promise.all([
3902
+ dispatch(actions3.removeFromGroup({ group, deviceIds })),
3903
+ dispatch(setSnackbar4(`The ${(0, import_pluralize.default)("devices", deviceIds.length)} ${(0, import_pluralize.default)("were", deviceIds.length)} removed from the group`, TIMEOUTS.fiveSeconds))
3904
+ ])
3905
+ )
3863
3906
  );
3864
- var setDeviceTags = (0, import_toolkit19.createAsyncThunk)(
3865
- `${sliceName3}/setDeviceTags`,
3866
- ({ deviceId, tags }, { dispatch }) => (
3867
- // to prevent tag set failures, retrieve the device & use the freshest etag we can get
3868
- Promise.resolve(dispatch(getDeviceById2(deviceId))).then((device) => {
3869
- const headers = device.etag ? { "If-Match": device.etag } : {};
3870
- return general_api_default.put(
3871
- `${inventoryApiUrl}/devices/${deviceId}/tags`,
3872
- Object.entries(tags).map(([name, value]) => ({ name, value })),
3873
- { headers }
3874
- ).catch((err) => commonErrorHandler(err, `There was an error setting tags for device ${deviceId}.`, dispatch, "Please check your connection.")).then(() => Promise.all([dispatch(actions3.receivedDevice({ ...device, id: deviceId, tags })), dispatch(setSnackbar3("Device name changed"))]));
3875
- })
3907
+ var getGroupNotification = (newGroup, selectedGroup) => {
3908
+ const successMessage = "The group was updated successfully";
3909
+ if (newGroup === selectedGroup) {
3910
+ return [successMessage, TIMEOUTS.fiveSeconds];
3911
+ }
3912
+ return [
3913
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
3914
+ successMessage,
3915
+ " - ",
3916
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_router_dom.Link, { to: `/devices?inventory=group:eq:${newGroup}`, children: "click here" }),
3917
+ " to see it."
3918
+ ] }),
3919
+ 5e3,
3920
+ void 0,
3921
+ void 0,
3922
+ () => {
3923
+ }
3924
+ ];
3925
+ };
3926
+ var addStaticGroup = (0, import_toolkit21.createAsyncThunk)(
3927
+ `${sliceName3}/addStaticGroup`,
3928
+ ({ group, devices }, { dispatch, getState }) => Promise.resolve(dispatch(addDevicesToGroup({ group, deviceIds: devices.map(({ id }) => id), isCreation: true }))).then(
3929
+ () => Promise.resolve(
3930
+ dispatch(
3931
+ actions3.addGroup({
3932
+ group: { deviceIds: [], total: 0, filters: [], ...getState().devices.groups.byId[group] },
3933
+ groupName: group
3934
+ })
3935
+ )
3936
+ ).then(
3937
+ () => Promise.all([
3938
+ dispatch(setDeviceListState({ setOnly: true })),
3939
+ dispatch(getGroups2()),
3940
+ dispatch(setSnackbar4(...getGroupNotification(group, getState().devices.groups.selectedGroup)))
3941
+ ])
3942
+ )
3943
+ ).catch((err) => commonErrorHandler(err, `Group could not be updated:`, dispatch))
3944
+ );
3945
+ var removeStaticGroup = (0, import_toolkit21.createAsyncThunk)(
3946
+ `${sliceName3}/removeStaticGroup`,
3947
+ (groupName, { dispatch }) => general_api_default.delete(`${inventoryApiUrl}/groups/${groupName}`).then(
3948
+ () => Promise.all([
3949
+ dispatch(actions3.removeGroup(groupName)),
3950
+ dispatch(getGroups2()),
3951
+ dispatch(setSnackbar4("Group was removed successfully", TIMEOUTS.fiveSeconds))
3952
+ ])
3876
3953
  )
3877
3954
  );
3878
- var getDeviceTwin = (0, import_toolkit19.createAsyncThunk)(`${sliceName3}/getDeviceTwin`, ({ deviceId, integration }, { dispatch, getState }) => {
3879
- let providerResult = {};
3880
- return general_api_default.get(`${iotManagerBaseURL}/devices/${deviceId}/state`).then(({ data }) => {
3881
- providerResult = { ...data, twinError: "" };
3882
- }).catch((err) => {
3883
- providerResult = {
3884
- twinError: `There was an error getting the ${EXTERNAL_PROVIDER[integration.provider].twinTitle.toLowerCase()} for device ${deviceId}. ${err}`
3885
- };
3886
- }).finally(() => {
3887
- const device = getDeviceById(getState(), deviceId);
3888
- Promise.resolve(dispatch(actions3.receivedDevice({ ...device, twinsByIntegration: { ...device.twinsByIntegration, ...providerResult } })));
3889
- });
3955
+ var getDynamicGroups = (0, import_toolkit21.createAsyncThunk)(
3956
+ `${sliceName3}/getDynamicGroups`,
3957
+ (_, { dispatch, getState }) => general_api_default.get(`${inventoryApiUrlV2}/filters?per_page=${MAX_PAGE_SIZE}`).then(({ data: filters }) => {
3958
+ const state = getGroupsById(getState());
3959
+ const staticGroups = Object.entries(state).reduce((accu, [id, group]) => {
3960
+ if (!(group.id || group.filters?.length)) {
3961
+ accu[id] = group;
3962
+ }
3963
+ return accu;
3964
+ }, {});
3965
+ const groups = (filters || []).reduce((accu, filter) => {
3966
+ accu[filter.name] = {
3967
+ deviceIds: [],
3968
+ total: 0,
3969
+ ...state[filter.name],
3970
+ id: filter.id,
3971
+ filters: mapTermsToFilters(filter.terms)
3972
+ };
3973
+ return accu;
3974
+ }, staticGroups);
3975
+ return Promise.resolve(dispatch(actions3.receivedGroups(groups)));
3976
+ }).catch(() => console.log("Dynamic group retrieval failed - likely accessing a non-enterprise backend"))
3977
+ );
3978
+ var addDynamicGroup = (0, import_toolkit21.createAsyncThunk)(
3979
+ `${sliceName3}/addDynamicGroup`,
3980
+ ({ groupName, filterPredicates }, { dispatch, getState }) => general_api_default.post(`${inventoryApiUrlV2}/filters`, { name: groupName, terms: mapFiltersToTerms(filterPredicates) }).then(
3981
+ (res) => Promise.resolve(
3982
+ dispatch(
3983
+ actions3.addGroup({
3984
+ groupName,
3985
+ group: {
3986
+ id: res.headers[headerNames.location].substring(res.headers[headerNames.location].lastIndexOf("/") + 1),
3987
+ filters: filterPredicates
3988
+ }
3989
+ })
3990
+ )
3991
+ ).then(() => {
3992
+ const { cleanedFilters } = getGroupFilters(groupName, getState().devices.groups);
3993
+ return Promise.all([
3994
+ dispatch(actions3.setDeviceFilters(cleanedFilters)),
3995
+ dispatch(setSnackbar4(...getGroupNotification(groupName, getState().devices.groups.selectedGroup))),
3996
+ dispatch(getDynamicGroups())
3997
+ ]);
3998
+ })
3999
+ ).catch((err) => commonErrorHandler(err, `Group could not be updated:`, dispatch))
4000
+ );
4001
+ var updateDynamicGroup = (0, import_toolkit21.createAsyncThunk)(`${sliceName3}/updateDynamicGroup`, ({ groupName, filterPredicates }, { dispatch, getState }) => {
4002
+ const filterId = getState().devices.groups.byId[groupName].id;
4003
+ return general_api_default.delete(`${inventoryApiUrlV2}/filters/${filterId}`).then(() => Promise.resolve(dispatch(addDynamicGroup({ groupName, filterPredicates }))));
3890
4004
  });
3891
- var setDeviceTwin = (0, import_toolkit19.createAsyncThunk)(
3892
- `${sliceName3}/setDeviceTwin`,
3893
- ({ deviceId, integration, settings }, { dispatch, getState }) => general_api_default.put(`${iotManagerBaseURL}/devices/${deviceId}/state/${integration.id}`, { desired: settings }).catch(
3894
- (err) => commonErrorHandler(
3895
- err,
3896
- `There was an error updating the ${EXTERNAL_PROVIDER[integration.provider].twinTitle.toLowerCase()} for device ${deviceId}.`,
3897
- dispatch
3898
- )
3899
- ).then(() => {
3900
- const device = getDeviceById(getState(), deviceId);
3901
- const { twinsByIntegration = {} } = device;
3902
- const { [integration.id]: currentState = {} } = twinsByIntegration;
4005
+ var removeDynamicGroup = (0, import_toolkit21.createAsyncThunk)(`${sliceName3}/removeDynamicGroup`, (groupName, { dispatch, getState }) => {
4006
+ const filterId = getState().devices.groups.byId[groupName].id;
4007
+ return general_api_default.delete(`${inventoryApiUrlV2}/filters/${filterId}`).then(
4008
+ () => Promise.all([dispatch(actions3.removeGroup(groupName)), dispatch(setSnackbar4("Group was removed successfully", TIMEOUTS.fiveSeconds))])
4009
+ );
4010
+ });
4011
+ var getGroupFilters = (group, groupsState, filters = []) => {
4012
+ const groupName = group === UNGROUPED_GROUP.id || group === UNGROUPED_GROUP.name ? UNGROUPED_GROUP.id : group;
4013
+ const selectedGroup = groupsState.byId[groupName];
4014
+ const groupFilterLength = selectedGroup?.filters?.length || 0;
4015
+ const cleanedFilters = groupFilterLength ? [...filters, ...selectedGroup.filters].filter(filtersFilter) : filters;
4016
+ return { cleanedFilters, groupName, selectedGroup, groupFilterLength };
4017
+ };
4018
+ var selectGroup = (0, import_toolkit21.createAsyncThunk)(`${sliceName3}/selectGroup`, ({ group, filters = [] }, { dispatch, getState }) => {
4019
+ const { cleanedFilters, groupName, selectedGroup, groupFilterLength } = getGroupFilters(group, getState().devices.groups, filters);
4020
+ if (getSelectedGroup(getState()) === groupName && (filters.length === 0 && !groupFilterLength || filters.length === cleanedFilters.length)) {
4021
+ return Promise.resolve();
4022
+ }
4023
+ let tasks = [];
4024
+ if (groupFilterLength) {
4025
+ tasks.push(dispatch(actions3.setDeviceFilters(cleanedFilters)));
4026
+ } else {
4027
+ tasks.push(dispatch(actions3.setDeviceFilters(filters)));
4028
+ tasks.push(dispatch(getGroupDevices({ group: groupName, perPage: 1, shouldIncludeAllStates: true })));
4029
+ }
4030
+ const selectedGroupName = selectedGroup || !Object.keys(getGroupsById(getState())).length ? groupName : void 0;
4031
+ tasks.push(dispatch(actions3.selectGroup(selectedGroupName)));
4032
+ return Promise.all(tasks);
4033
+ });
4034
+ var getEarliestTs = (dateA = "", dateB = "") => !dateA || !dateB ? dateA || dateB : dateA < dateB ? dateA : dateB;
4035
+ var reduceReceivedDevices = (devices, ids, state, status) => devices.reduce(
4036
+ (accu, device) => {
4037
+ const stateDevice = getDeviceById(state, device.id);
4038
+ const {
4039
+ attributes: storedAttributes = {},
4040
+ identity_data: storedIdentity = {},
4041
+ monitor: storedMonitor = {},
4042
+ tags: storedTags = {},
4043
+ group: storedGroup
4044
+ } = stateDevice;
4045
+ const { identity, inventory, monitor, system = {}, tags } = mapDeviceAttributes(device.attributes);
4046
+ device.tags = { ...storedTags, ...tags };
4047
+ device.group = system.group ?? storedGroup;
4048
+ device.monitor = { ...storedMonitor, ...monitor };
4049
+ device.identity_data = { ...storedIdentity, ...identity, ...device.identity_data ? device.identity_data : {} };
4050
+ device.status = status ? status : device.status || identity.status;
4051
+ device.check_in_time_rounded = system.check_in_time ?? stateDevice.check_in_time_rounded;
4052
+ device.check_in_time_exact = device.check_in_time ?? stateDevice.check_in_time_exact;
4053
+ device.created_ts = getEarliestTs(getEarliestTs(system.created_ts, device.created_ts), stateDevice.created_ts);
4054
+ device.updated_ts = device.attributes ? device.updated_ts : stateDevice.updated_ts;
4055
+ device.isNew = new Date(device.created_ts) > new Date(state.app.newThreshold);
4056
+ device.isOffline = new Date(device.check_in_time_rounded) < new Date(state.app.offlineThreshold) || device.check_in_time_rounded === void 0;
4057
+ device.attributes = device.attributes ? { ...storedAttributes, ...inventory } : storedAttributes;
4058
+ accu.devicesById[device.id] = { ...stateDevice, ...device };
4059
+ accu.ids.push(device.id);
4060
+ return accu;
4061
+ },
4062
+ { ids, devicesById: {} }
4063
+ );
4064
+ var getGroupDevices = (0, import_toolkit21.createAsyncThunk)(`${sliceName3}/getGroupDevices`, (options, { dispatch, getState }) => {
4065
+ const { group, shouldIncludeAllStates, ...remainder } = options;
4066
+ const { cleanedFilters: filterSelection } = getGroupFilters(group, getState().devices.groups);
4067
+ return Promise.resolve(
4068
+ dispatch(getDevicesByStatus2({ ...remainder, filterSelection, group, status: shouldIncludeAllStates ? void 0 : DEVICE_STATES.accepted }))
4069
+ ).unwrap().then((results) => {
4070
+ if (!group) {
4071
+ return Promise.resolve();
4072
+ }
4073
+ const { deviceAccu, total } = results[results.length - 1];
4074
+ const stateGroup = getState().devices.groups.byId[group];
4075
+ if (!stateGroup && !total && !deviceAccu.ids.length) {
4076
+ return Promise.resolve();
4077
+ }
3903
4078
  return Promise.resolve(
3904
- dispatch(actions3.receivedDevice({ ...device, twinsByIntegration: { ...twinsByIntegration, [integration.id]: { ...currentState, desired: settings } } }))
4079
+ dispatch(
4080
+ actions3.addGroup({
4081
+ group: {
4082
+ deviceIds: deviceAccu.ids.length === total || deviceAccu.ids.length > stateGroup?.deviceIds ? deviceAccu.ids : stateGroup.deviceIds,
4083
+ total
4084
+ },
4085
+ groupName: group
4086
+ })
4087
+ )
3905
4088
  );
3906
- })
3907
- );
3908
- var prepareSearchArguments = ({ filters, group, state, status }) => {
3909
- const { filterTerms } = convertDeviceListStateToFilters({ filters, group, offlineThreshold: state.app.offlineThreshold, selectedIssues: [], status });
3910
- const { columnSelection = [] } = getUserSettings(state);
3911
- const selectedAttributes = columnSelection.map((column) => ({ attribute: column.key, scope: column.scope }));
3912
- const attributes = [...defaultAttributes, getIdAttribute(state), ...selectedAttributes];
3913
- return { attributes, filterTerms };
3914
- };
3915
- var getSystemDevices = (0, import_toolkit19.createAsyncThunk)(`${sliceName3}/getSystemDevices`, (options, { dispatch, getState }) => {
3916
- const { id, page = defaultPage2, perPage = defaultPerPage2, sortOptions = [] } = options;
3917
- const state = getState();
3918
- const { hasFullFiltering } = getTenantCapabilities(state);
3919
- if (!hasFullFiltering) {
4089
+ });
4090
+ });
4091
+ var getAllGroupDevices = (0, import_toolkit21.createAsyncThunk)(`${sliceName3}/getAllGroupDevices`, (group, { dispatch, getState }) => {
4092
+ if (!group || !!group && (!getGroupsById(getState())[group] || getGroupsById(getState())[group].filters.length)) {
3920
4093
  return Promise.resolve();
3921
4094
  }
3922
- const { attributes: deviceAttributes = {} } = getDeviceById(state, id);
3923
- const { mender_gateway_system_id = "" } = deviceAttributes;
3924
- const filters = [
3925
- { ...emptyFilter, key: "mender_is_gateway", operator: DEVICE_FILTERING_OPTIONS.$ne.key, value: "true", scope: "inventory" },
3926
- { ...emptyFilter, key: "mender_gateway_system_id", value: mender_gateway_system_id, scope: "inventory" }
3927
- ];
3928
- const { attributes, filterTerms } = prepareSearchArguments({ filters, state });
3929
- return general_api_default.post(getSearchEndpoint(getState()), {
4095
+ const { attributes, filterTerms } = prepareSearchArguments({
4096
+ filters: [],
4097
+ group,
4098
+ state: getState(),
4099
+ status: DEVICE_STATES.accepted
4100
+ });
4101
+ const getAllDevices = (perPage = MAX_PAGE_SIZE, page = defaultPage3, devices = []) => general_api_default.post(getSearchEndpoint(getState()), {
3930
4102
  page,
3931
4103
  per_page: perPage,
3932
4104
  filters: filterTerms,
3933
- sort: sortOptions,
3934
4105
  attributes
3935
- }).catch((err) => commonErrorHandler(err, `There was an error getting system devices device ${id}.`, dispatch, "Please check your connection.")).then(({ data, headers }) => {
3936
- const state2 = getState();
3937
- const { devicesById, ids } = reduceReceivedDevices(data, [], state2);
3938
- const device = {
3939
- ...getDeviceById(state2, id),
3940
- systemDeviceIds: ids,
3941
- systemDeviceTotal: Number(headers[headerNames.total])
3942
- };
3943
- return Promise.resolve(dispatch(actions3.receivedDevices({ ...devicesById, [id]: device })));
4106
+ }).then((res) => {
4107
+ const state = getState();
4108
+ const deviceAccu = reduceReceivedDevices(res.data, devices, state);
4109
+ dispatch(actions3.receivedDevices(deviceAccu.devicesById));
4110
+ const total = Number(res.headers[headerNames.total]);
4111
+ if (total > perPage * page) {
4112
+ return getAllDevices(perPage, page + 1, deviceAccu.ids);
4113
+ }
4114
+ return Promise.resolve(dispatch(actions3.addGroup({ group: { deviceIds: deviceAccu.ids, total: deviceAccu.ids.length }, groupName: group })));
3944
4115
  });
4116
+ return getAllDevices();
3945
4117
  });
3946
- var getGatewayDevices = (0, import_toolkit19.createAsyncThunk)(`${sliceName3}/getGatewayDevices`, (deviceId, { dispatch, getState }) => {
3947
- const state = getState();
3948
- const { attributes = {} } = getDeviceById(state, deviceId);
3949
- const { mender_gateway_system_id = "" } = attributes;
3950
- const filters = [
3951
- { ...emptyFilter, key: "id", operator: DEVICE_FILTERING_OPTIONS.$ne.key, value: deviceId, scope: "identity" },
3952
- { ...emptyFilter, key: "mender_is_gateway", value: "true", scope: "inventory" },
3953
- { ...emptyFilter, key: "mender_gateway_system_id", value: mender_gateway_system_id, scope: "inventory" }
3954
- ];
3955
- const { attributes: attributeSelection, filterTerms } = prepareSearchArguments({ filters, state });
3956
- return general_api_default.post(getSearchEndpoint(getState()), {
3957
- page: 1,
3958
- per_page: MAX_PAGE_SIZE,
3959
- filters: filterTerms,
3960
- attributes: attributeSelection
3961
- }).then(({ data }) => {
3962
- const { ids } = reduceReceivedDevices(data, [], getState());
3963
- let tasks = ids.map((deviceId2) => dispatch(getDeviceInfo(deviceId2)));
3964
- tasks.push(dispatch(actions3.receivedDevice({ id: deviceId, gatewayIds: ids })));
3965
- return Promise.all(tasks);
3966
- });
3967
- });
3968
- var getDevicesInBounds = (0, import_toolkit19.createAsyncThunk)(`${sliceName3}/getDevicesInBounds`, ({ bounds, group }, { dispatch, getState }) => {
3969
- const state = getState();
3970
- const { filterTerms } = convertDeviceListStateToFilters({
3971
- group: group === ALL_DEVICES ? void 0 : group,
3972
- groups: state.devices.groups,
4118
+ var getAllDynamicGroupDevices = (0, import_toolkit21.createAsyncThunk)(`${sliceName3}/getAllDynamicGroupDevices`, (group, { dispatch, getState }) => {
4119
+ if (!!group && (!getGroupsById(getState())[group] || !getGroupsById(getState())[group].filters.length)) {
4120
+ return Promise.resolve();
4121
+ }
4122
+ const { attributes, filterTerms: filters } = prepareSearchArguments({
4123
+ filters: getState().devices.groups.byId[group].filters,
4124
+ state: getState(),
3973
4125
  status: DEVICE_STATES.accepted
3974
4126
  });
3975
- return general_api_default.post(getSearchEndpoint(getState()), {
3976
- page: 1,
3977
- per_page: MAX_PAGE_SIZE,
3978
- filters: filterTerms,
3979
- attributes: geoAttributes,
3980
- geo_bounding_box_filter: {
3981
- geo_bounding_box: {
3982
- location: {
3983
- top_left: { lat: bounds._northEast.lat, lon: bounds._southWest.lng },
3984
- bottom_right: { lat: bounds._southWest.lat, lon: bounds._northEast.lng }
3985
- }
3986
- }
4127
+ const getAllDevices = (perPage = MAX_PAGE_SIZE, page = defaultPage3, devices = []) => general_api_default.post(getSearchEndpoint(getState()), { page, per_page: perPage, filters, attributes }).then((res) => {
4128
+ const state = getState();
4129
+ const deviceAccu = reduceReceivedDevices(res.data, devices, state);
4130
+ dispatch(actions3.receivedDevices(deviceAccu.devicesById));
4131
+ const total = Number(res.headers[headerNames.total]);
4132
+ if (total > deviceAccu.ids.length) {
4133
+ return getAllDevices(perPage, page + 1, deviceAccu.ids);
3987
4134
  }
3988
- }).then(({ data }) => {
3989
- const { devicesById } = reduceReceivedDevices(data, [], getState());
3990
- return Promise.resolve(dispatch(actions3.receivedDevices(devicesById)));
4135
+ return Promise.resolve(dispatch(actions3.addGroup({ group: { deviceIds: deviceAccu.ids, total }, groupName: group })));
3991
4136
  });
4137
+ return getAllDevices();
3992
4138
  });
3993
-
3994
- // src/monitorSlice/thunks.ts
3995
- var import_toolkit20 = require("@reduxjs/toolkit");
3996
- var { page: defaultPage3, perPage: defaultPerPage3 } = DEVICE_LIST_DEFAULTS;
3997
- var cutoffLength = 75;
3998
- var ellipsis = "...";
3999
- var longTextTrimmer = (text) => text.length >= cutoffLength + ellipsis.length ? `${text.substring(0, cutoffLength + ellipsis.length)}${ellipsis}` : text;
4000
- var sanitizeDeviceAlerts = (alerts) => alerts.map((alert) => ({ ...alert, fullName: alert.name, name: longTextTrimmer(alert.name) }));
4001
- var getDeviceAlerts = (0, import_toolkit20.createAsyncThunk)(`${sliceName4}/getDeviceAlerts`, ({ id, config = {} }, { dispatch }) => {
4002
- const { page = defaultPage3, perPage = defaultPerPage3, issuedBefore, issuedAfter, sortAscending = false } = config;
4003
- const issued_after = issuedAfter ? `&issued_after=${issuedAfter}` : "";
4004
- const issued_before = issuedBefore ? `&issued_before=${issuedBefore}` : "";
4005
- return general_api_default.get(`${monitorApiUrlv1}/devices/${id}/alerts?page=${page}&per_page=${perPage}${issued_after}${issued_before}&sort_ascending=${sortAscending}`).catch((err) => commonErrorHandler(err, `Retrieving device alerts for device ${id} failed:`, dispatch)).then(
4006
- (res) => Promise.all([
4007
- dispatch(actions4.receiveDeviceAlerts({ deviceId: id, alerts: sanitizeDeviceAlerts(res.data) })),
4008
- dispatch(actions4.setAlertListState({ total: Number(res.headers[headerNames.total]) }))
4009
- ])
4010
- );
4011
- });
4012
- var getLatestDeviceAlerts = (0, import_toolkit20.createAsyncThunk)(`${sliceName4}/getLatestDeviceAlerts`, ({ id, config = {} }, { dispatch }) => {
4013
- const { page = defaultPage3, perPage = 10 } = config;
4014
- return general_api_default.get(`${monitorApiUrlv1}/devices/${id}/alerts/latest?page=${page}&per_page=${perPage}`).catch((err) => commonErrorHandler(err, `Retrieving device alerts for device ${id} failed:`, dispatch)).then((res) => Promise.resolve(dispatch(actions4.receiveLatestDeviceAlerts({ deviceId: id, alerts: sanitizeDeviceAlerts(res.data) }))));
4015
- });
4016
- var getIssueCountsByType2 = (0, import_toolkit20.createAsyncThunk)(`${sliceName4}/getIssueCountsByType`, ({ type, options = {} }, { dispatch, getState }) => {
4017
- const state = getState();
4018
- const { filters = getDeviceFilters(state), group, status, ...remainder } = options;
4019
- const { applicableFilters: nonMonitorFilters, filterTerms } = convertDeviceListStateToFilters({
4020
- ...remainder,
4021
- filters,
4022
- group,
4023
- offlineThreshold: state.app.offlineThreshold,
4024
- selectedIssues: [type],
4025
- status
4026
- });
4027
- return general_api_default.post(getSearchEndpoint(getState()), {
4028
- page: 1,
4029
- per_page: 1,
4030
- filters: filterTerms,
4031
- attributes: [{ scope: "identity", attribute: "status" }]
4032
- }).catch((err) => commonErrorHandler(err, `Retrieving issue counts failed:`, dispatch, commonErrorFallback)).then((res) => {
4033
- const total = nonMonitorFilters.length ? state.monitor.issueCounts.byType[type].total : Number(res.headers[headerNames.total]);
4034
- const filtered = nonMonitorFilters.length ? Number(res.headers[headerNames.total]) : total;
4035
- if (total === state.monitor.issueCounts.byType[type].total && filtered === state.monitor.issueCounts.byType[type].filtered) {
4036
- return Promise.resolve();
4139
+ var getDeviceById2 = (0, import_toolkit21.createAsyncThunk)(
4140
+ `${sliceName3}/getDeviceById`,
4141
+ (id, { dispatch, getState }) => general_api_default.get(`${inventoryApiUrl}/devices/${id}`).then((res) => {
4142
+ const device = reduceReceivedDevices([res.data], [], getState()).devicesById[id];
4143
+ device.etag = res.headers.etag;
4144
+ dispatch(actions3.receivedDevice(device));
4145
+ return Promise.resolve(device);
4146
+ }).catch((err) => {
4147
+ const errMsg = (0, import_helpers10.extractErrorMessage)(err);
4148
+ if (errMsg.includes("Not Found")) {
4149
+ console.log(`${id} does not have any inventory information`);
4150
+ const device = reduceReceivedDevices(
4151
+ [
4152
+ {
4153
+ id,
4154
+ attributes: [
4155
+ { name: "status", value: "decomissioned", scope: "identity" },
4156
+ { name: "decomissioned", value: "true", scope: "inventory" }
4157
+ ]
4158
+ }
4159
+ ],
4160
+ [],
4161
+ getState()
4162
+ ).devicesById[id];
4163
+ dispatch(actions3.receivedDevice(device));
4037
4164
  }
4038
- return Promise.resolve(dispatch(actions4.receiveDeviceIssueCounts({ counts: { filtered, total }, issueType: type })));
4039
- });
4040
- });
4041
- var getDeviceMonitorConfig = (0, import_toolkit20.createAsyncThunk)(
4042
- `${sliceName4}/getDeviceMonitorConfig`,
4043
- (id, { dispatch }) => general_api_default.get(`${monitorApiUrlv1}/devices/${id}/config`).catch((err) => commonErrorHandler(err, `Retrieving device monitor config for device ${id} failed:`, dispatch)).then(({ data }) => Promise.all([dispatch(actions_default.receivedDevice({ id, monitors: data }), Promise.resolve(data))]))
4044
- );
4045
- var changeNotificationSetting = (0, import_toolkit20.createAsyncThunk)(
4046
- `${sliceName4}/changeNotificationSetting`,
4047
- ({ enabled, channel = alertChannels.email }, { dispatch }) => {
4048
- return general_api_default.put(`${monitorApiUrlv1}/settings/global/channel/alerts/${channel}/status`, { enabled }).catch((err) => commonErrorHandler(err, `${enabled ? "En" : "Dis"}abling ${channel} alerts failed:`, dispatch)).then(
4049
- () => Promise.all([
4050
- dispatch(actions4.changeAlertChannel({ channel, enabled })),
4051
- dispatch(actions_default.setSnackbar(`Successfully ${enabled ? "en" : "dis"}abled ${channel} alerts`, TIMEOUTS.fiveSeconds))
4052
- ])
4053
- );
4054
- }
4165
+ })
4055
4166
  );
4056
-
4057
- // src/api/users-api.ts
4058
- var import_axios3 = __toESM(require("axios"), 1);
4059
- var Api2 = {
4060
- postLogin: (url, { email: username, password, ...body }) => import_axios3.default.post(url, body, { ...commonRequestConfig, auth: { username, password } }).then((res) => ({ text: res.data, code: res.status, contentType: res.headers?.["content-type"] })),
4061
- putVerifyTFA: (url, userData) => {
4062
- let body = {};
4063
- if (userData.hasOwnProperty("token2fa")) {
4064
- body = { token2fa: userData.token2fa };
4065
- }
4066
- return import_axios3.default.put(url, body, { ...commonRequestConfig, headers: { ...commonRequestConfig.headers, Authorization: `Bearer ${getToken()}` } });
4067
- }
4068
- };
4069
- var users_api_default = Api2;
4070
-
4071
- // src/usersSlice/thunks.ts
4072
- var import_helpers10 = require("@northern.tech/utils/helpers");
4073
- var import_retrytimer = require("@northern.tech/utils/retrytimer");
4074
- var import_toolkit21 = require("@reduxjs/toolkit");
4075
- var import_md5 = __toESM(require("md5"), 1);
4076
- var import_universal_cookie3 = __toESM(require("universal-cookie"), 1);
4077
- var cookies3 = new import_universal_cookie3.default();
4078
- var { setAnnouncement, setSnackbar: setSnackbar4 } = actions_default;
4079
- var handleLoginError = (err, { token2fa: has2FA, password }, rejectWithValue) => (dispatch) => {
4080
- const errorText = (0, import_helpers10.extractErrorMessage)(err);
4081
- const is2FABackend = errorText.includes("2fa");
4082
- if (is2FABackend && !has2FA) {
4083
- return rejectWithValue({ error: "2fa code missing" });
4084
- }
4085
- if (password === void 0) {
4086
- return Promise.reject();
4167
+ var getDeviceInfo = (0, import_toolkit21.createAsyncThunk)(`${sliceName3}/getDeviceInfo`, (deviceId, { dispatch, getState }) => {
4168
+ const device = getDeviceById(getState(), deviceId);
4169
+ const { hasDeviceConfig, hasDeviceConnect, hasMonitor } = getTenantCapabilities(getState());
4170
+ const { canConfigure } = getUserCapabilities(getState());
4171
+ const integrations = getDeviceTwinIntegrations(getState());
4172
+ let tasks = [dispatch(getDeviceAuth(deviceId)), ...integrations.map((integration) => dispatch(getDeviceTwin({ deviceId, integration })))];
4173
+ if (hasDeviceConfig && canConfigure && [DEVICE_STATES.accepted, DEVICE_STATES.preauth].includes(device.status)) {
4174
+ tasks.push(dispatch(getDeviceConfig(deviceId)));
4087
4175
  }
4088
- const twoFAError = is2FABackend ? " and verification code" : "";
4089
- const errorMessage = `There was a problem logging in. Please check your email${twoFAError ? "," : " and"} password${twoFAError}. If you still have problems, contact an administrator.`;
4090
- return Promise.reject(dispatch(setSnackbar4((0, import_helpers10.preformatWithRequestID)(err.response, errorMessage), null, "Copy to clipboard")));
4091
- };
4092
- var loginUser = (0, import_toolkit21.createAsyncThunk)(
4093
- `${sliceName8}/loginUser`,
4094
- ({ stayLoggedIn, ...userData }, { dispatch, rejectWithValue }) => users_api_default.postLogin(`${useradmApiUrlv1}/auth/login`, { ...userData, no_expiry: stayLoggedIn }).catch((err) => {
4095
- cleanUp();
4096
- return Promise.reject(dispatch(handleLoginError(err, userData, rejectWithValue)));
4097
- }).then(({ text: response, contentType }) => {
4098
- if (contentType.includes(APPLICATION_JSON_CONTENT_TYPE)) {
4099
- const { id, kind } = response;
4100
- const type = kind.split("/")[1];
4101
- const ssoLoginUrl = SSO_TYPES[type].getStartUrl(id);
4102
- window.location.replace(ssoLoginUrl);
4103
- return;
4176
+ if (device.status === DEVICE_STATES.accepted) {
4177
+ tasks.push(dispatch(getDeviceById2(deviceId)));
4178
+ if (hasDeviceConnect) {
4179
+ tasks.push(dispatch(getDeviceConnect(deviceId)));
4104
4180
  }
4105
- const token = response;
4106
- if (contentType !== APPLICATION_JWT_CONTENT_TYPE || !token) {
4107
- return;
4181
+ if (hasMonitor) {
4182
+ tasks.push(dispatch(getLatestDeviceAlerts({ id: deviceId })));
4183
+ tasks.push(dispatch(getDeviceMonitorConfig(deviceId)));
4108
4184
  }
4109
- let now = /* @__PURE__ */ new Date();
4110
- now.setSeconds(now.getSeconds() + maxSessionAge);
4111
- const expiresAt = stayLoggedIn ? void 0 : now.toISOString();
4112
- setSessionInfo({ token, expiresAt });
4113
- cookies3.remove("JWT", { path: "/" });
4114
- return (
4115
- // @ts-ignore
4116
- Promise.resolve(dispatch(getUser(OWN_USER_ID))).unwrap().catch((e) => {
4117
- cleanUp();
4118
- return Promise.reject(dispatch(setSnackbar4((0, import_helpers10.extractErrorMessage)(e))));
4119
- }).then(() => {
4120
- window.sessionStorage.removeItem("pendings-redirect");
4121
- if (window.location.pathname !== "/ui/") {
4122
- window.location.replace("/ui/");
4123
- }
4124
- return Promise.resolve(dispatch(actions8.successfullyLoggedIn({ expiresAt, token })));
4125
- })
4126
- );
4127
- })
4128
- );
4129
- var logoutUser = (0, import_toolkit21.createAsyncThunk)(`${sliceName8}/logoutUser`, (_, { dispatch, getState }) => {
4130
- if (Object.keys(getState().app.uploadsById).length) {
4131
- return Promise.reject();
4132
4185
  }
4133
- return general_api_default.post(`${useradmApiUrlv1}/auth/logout`).finally(() => {
4134
- cleanUp();
4135
- (0, import_retrytimer.clearAllRetryTimers)(setSnackbar4);
4136
- return Promise.resolve(dispatch({ type: USER_LOGOUT }));
4137
- });
4186
+ return Promise.all(tasks);
4138
4187
  });
4139
- var switchUserOrganization = (0, import_toolkit21.createAsyncThunk)(`${sliceName8}/switchUserOrganization`, (tenantId, { getState }) => {
4140
- if (Object.keys(getState().app.uploadsById).length) {
4141
- return Promise.reject();
4142
- }
4143
- return general_api_default.get(`${useradmApiUrlv1}/users/tenants/${tenantId}/token`).then(({ data: token }) => {
4144
- setSessionInfo({ ...getSessionInfo(), token });
4145
- window.location.reload();
4146
- });
4188
+ var deriveInactiveDevices = (0, import_toolkit21.createAsyncThunk)(`${sliceName3}/deriveInactiveDevices`, (deviceIds, { dispatch, getState }) => {
4189
+ const yesterday = /* @__PURE__ */ new Date();
4190
+ yesterday.setDate(yesterday.getDate() - 1);
4191
+ const yesterdaysIsoString = yesterday.toISOString();
4192
+ const devices = deviceIds.reduce(
4193
+ (accu, id) => {
4194
+ const device = getDeviceById(getState(), id);
4195
+ if (device && device.updated_ts > yesterdaysIsoString) {
4196
+ accu.active.push(id);
4197
+ } else {
4198
+ accu.inactive.push(id);
4199
+ }
4200
+ return accu;
4201
+ },
4202
+ { active: [], inactive: [] }
4203
+ );
4204
+ return dispatch(actions3.setInactiveDevices({ activeDeviceTotal: devices.active.length, inactiveDeviceTotal: devices.inactive.length }));
4147
4205
  });
4148
- var passwordResetStart = (0, import_toolkit21.createAsyncThunk)(
4149
- `${sliceName8}/passwordResetStart`,
4150
- (email, { dispatch }) => general_api_default.post(`${useradmApiUrlv1}/auth/password-reset/start`, { email }).catch(
4151
- (err) => commonErrorHandler(err, `The password reset request cannot be processed:`, dispatch, void 0, true)
4152
- )
4153
- );
4154
- var passwordResetComplete = (0, import_toolkit21.createAsyncThunk)(
4155
- `${sliceName8}/passwordResetComplete`,
4156
- ({ secretHash, newPassword }, { dispatch }) => general_api_default.post(`${useradmApiUrlv1}/auth/password-reset/complete`, { secret_hash: secretHash, password: newPassword }).catch((err = {}) => {
4157
- const { error, response = {} } = err;
4158
- let errorMsg = "";
4159
- if (response.status == 400) {
4160
- errorMsg = "the link you are using expired or the request is not valid, please try again.";
4161
- } else {
4162
- errorMsg = error;
4206
+ var getDeviceCount = (0, import_toolkit21.createAsyncThunk)(
4207
+ `${sliceName3}/getDeviceCount`,
4208
+ (status, { dispatch, getState }) => general_api_default.post(getSearchEndpoint(getState()), {
4209
+ page: 1,
4210
+ per_page: 1,
4211
+ filters: mapFiltersToTerms([{ key: "status", value: status, operator: DEVICE_FILTERING_OPTIONS.$eq.key, scope: "identity" }]),
4212
+ attributes: defaultAttributes
4213
+ }).then((response) => {
4214
+ const count = Number(response.headers[headerNames.total]);
4215
+ if (status) {
4216
+ return dispatch(actions3.setDevicesCountByStatus({ count, status }));
4163
4217
  }
4164
- dispatch(setSnackbar4("The password reset request cannot be processed: " + errorMsg));
4165
- return Promise.reject(err);
4218
+ return dispatch(actions3.setTotalDevices(count));
4166
4219
  })
4167
4220
  );
4168
- var verifyEmailStart = (0, import_toolkit21.createAsyncThunk)(
4169
- `${sliceName8}/verifyEmailStart`,
4170
- (_, { dispatch, getState }) => general_api_default.post(`${useradmApiUrlv1}/auth/verify-email/start`, { email: getCurrentUser(getState()).email }).catch((err) => commonErrorHandler(err, "An error occured starting the email verification process:", dispatch)).finally(() => Promise.resolve(dispatch(getUser(OWN_USER_ID))))
4171
- );
4172
- var verifyEmailComplete = (0, import_toolkit21.createAsyncThunk)(
4173
- `${sliceName8}/verifyEmailComplete`,
4174
- (secret_hash, { dispatch }) => general_api_default.post(`${useradmApiUrlv1}/auth/verify-email/complete`, { secret_hash }).catch((err) => commonErrorHandler(err, "An error occured completing the email verification process:", dispatch)).finally(() => Promise.resolve(dispatch(getUser(OWN_USER_ID))))
4221
+ var getAllDeviceCounts = (0, import_toolkit21.createAsyncThunk)(
4222
+ `${sliceName3}/getAllDeviceCounts`,
4223
+ (_, { dispatch }) => Promise.all([DEVICE_STATES.accepted, DEVICE_STATES.pending].map((status) => dispatch(getDeviceCount(status))))
4175
4224
  );
4176
- var verify2FA = (0, import_toolkit21.createAsyncThunk)(
4177
- `${sliceName8}/verify2FA`,
4178
- (tfaData, { dispatch }) => users_api_default.putVerifyTFA(`${useradmApiUrlv1}/2faverify`, tfaData).then(() => Promise.resolve(dispatch(getUser(OWN_USER_ID)))).catch(
4179
- (err) => commonErrorHandler(err, "An error occured validating the verification code: failed to verify token, please try again.", dispatch, void 0, true)
4180
- )
4225
+ var getDeviceLimit2 = (0, import_toolkit21.createAsyncThunk)(
4226
+ `${sliceName3}/getDeviceLimit`,
4227
+ (_, { dispatch }) => general_api_default.get(`${deviceAuthV2}/limits/max_devices`).then((res) => dispatch(actions3.setDeviceLimit(res.data.limit)))
4181
4228
  );
4182
- var getUserList = (0, import_toolkit21.createAsyncThunk)(
4183
- `${sliceName8}/getUserList`,
4184
- (_, { dispatch }) => general_api_default.get(`${useradmApiUrlv1}/users`).then((res) => {
4185
- const users = res.data.reduce((accu, item) => {
4186
- accu[item.id] = item;
4187
- return accu;
4188
- }, {});
4189
- return dispatch(actions8.receivedUserList(users));
4190
- }).catch((err) => commonErrorHandler(err, `Users couldn't be loaded.`, dispatch, commonErrorFallback))
4191
- );
4192
- var getUser = (0, import_toolkit21.createAsyncThunk)(
4193
- `${sliceName8}/getUser`,
4194
- (id, { dispatch, rejectWithValue }) => general_api_default.get(`${useradmApiUrlv1}/users/${id}`).then(
4195
- ({ data: user }) => Promise.all([
4196
- dispatch(actions8.receivedUser(user)),
4197
- // @ts-ignore
4198
- dispatch(setHideAnnouncement({ shouldHide: false, userId: user.id })),
4199
- // @ts-ignore
4200
- dispatch(updateUserColumnSettings({ currentUserId: user.id })),
4201
- user
4202
- ])
4203
- ).catch((e) => rejectWithValue(e))
4204
- );
4205
- var initializeSelf = (0, import_toolkit21.createAsyncThunk)(`${sliceName8}/initializeSelf`, (_, { dispatch }) => dispatch(getUser(OWN_USER_ID)));
4206
- var updateUserColumnSettings = (0, import_toolkit21.createAsyncThunk)(`${sliceName8}/updateUserColumnSettings`, ({ columns, currentUserId }, { dispatch, getState }) => {
4207
- const userId = currentUserId ?? getCurrentUser(getState()).id;
4208
- const storageKey = `${userId}-column-widths`;
4209
- let customColumns = [];
4210
- if (!columns) {
4211
- try {
4212
- customColumns = JSON.parse(window.localStorage.getItem(storageKey)) || customColumns;
4213
- } catch {
4229
+ var setDeviceListState = (0, import_toolkit21.createAsyncThunk)(
4230
+ `${sliceName3}/setDeviceListState`,
4231
+ ({ shouldSelectDevices = true, forceRefresh, fetchAuth = true, ...selectionState }, { dispatch, getState }) => {
4232
+ const currentState = getDeviceListState(getState());
4233
+ const refreshTrigger = forceRefresh ? !currentState.refreshTrigger : selectionState.refreshTrigger;
4234
+ let nextState = {
4235
+ ...currentState,
4236
+ setOnly: false,
4237
+ refreshTrigger,
4238
+ ...selectionState,
4239
+ sort: { ...currentState.sort, ...selectionState.sort }
4240
+ };
4241
+ let tasks = [];
4242
+ const { isLoading: currentLoading, deviceIds: currentDevices, selection: currentSelection, ...currentRequestState } = currentState;
4243
+ const { isLoading: nextLoading, deviceIds: nextDevices, selection: nextSelection, ...nextRequestState } = nextState;
4244
+ if (!nextState.setOnly && !(0, import_helpers10.deepCompare)(currentRequestState, nextRequestState)) {
4245
+ const { direction: sortDown = SORTING_OPTIONS.desc, key: sortCol, scope: sortScope } = nextState.sort ?? {};
4246
+ const sortBy = sortCol ? [{ attribute: sortCol, order: sortDown, scope: sortScope }] : void 0;
4247
+ const applicableSelectedState = nextState.state === ALL_DEVICE_STATES ? void 0 : nextState.state;
4248
+ nextState.isLoading = true;
4249
+ tasks.push(
4250
+ dispatch(getDevicesByStatus2({ ...nextState, status: applicableSelectedState, sortOptions: sortBy, fetchAuth })).unwrap().then((results) => {
4251
+ const { deviceAccu, total } = results[results.length - 1];
4252
+ const devicesState = shouldSelectDevices ? { deviceIds: deviceAccu.ids, total, isLoading: false } : { isLoading: false };
4253
+ return Promise.resolve(dispatch(actions3.setDeviceListState(devicesState)));
4254
+ }).catch(() => Promise.resolve({ isLoading: false }))
4255
+ );
4214
4256
  }
4215
- } else {
4216
- customColumns = columns;
4257
+ tasks.push(dispatch(actions3.setDeviceListState(nextState)));
4258
+ return Promise.all(tasks);
4217
4259
  }
4218
- window.localStorage.setItem(storageKey, JSON.stringify(customColumns));
4219
- return Promise.resolve(dispatch(actions8.setCustomColumns(customColumns)));
4260
+ );
4261
+ var getDevicesByStatus2 = (0, import_toolkit21.createAsyncThunk)(`${sliceName3}/getDevicesByStatus`, (options, { dispatch, getState }) => {
4262
+ const {
4263
+ status,
4264
+ fetchAuth = true,
4265
+ filterSelection,
4266
+ group,
4267
+ selectedIssues = [],
4268
+ page = defaultPage3,
4269
+ perPage = defaultPerPage3,
4270
+ sortOptions = [],
4271
+ selectedAttributes = getSelectedDeviceAttribute(getState())
4272
+ } = options;
4273
+ const state = getState();
4274
+ const { applicableFilters, filterTerms } = convertDeviceListStateToFilters({
4275
+ filters: filterSelection ?? getDeviceFilters(state),
4276
+ group: group ?? getSelectedGroup(state),
4277
+ groups: state.devices.groups,
4278
+ offlineThreshold: state.app.offlineThreshold,
4279
+ selectedIssues,
4280
+ status
4281
+ });
4282
+ const attributes = [...defaultAttributes, getIdAttribute(getState()), ...selectedAttributes];
4283
+ return general_api_default.post(getSearchEndpoint(getState()), {
4284
+ page,
4285
+ per_page: perPage,
4286
+ filters: filterTerms,
4287
+ sort: sortOptions,
4288
+ attributes
4289
+ }).then((response) => {
4290
+ const state2 = getState();
4291
+ const deviceAccu = reduceReceivedDevices(response.data, [], state2, status);
4292
+ let total = !applicableFilters.length ? Number(response.headers[headerNames.total]) : null;
4293
+ if (status && state2.devices.byStatus[status].total === deviceAccu.ids.length) {
4294
+ total = deviceAccu.ids.length;
4295
+ }
4296
+ let tasks = [dispatch(actions3.receivedDevices(deviceAccu.devicesById))];
4297
+ if (status) {
4298
+ tasks.push(dispatch(actions3.setDevicesByStatus({ deviceIds: deviceAccu.ids, status, total })));
4299
+ }
4300
+ const receivedDevices = Object.values(deviceAccu.devicesById);
4301
+ if (receivedDevices.length && fetchAuth) {
4302
+ tasks.push(dispatch(getDevicesWithAuth(receivedDevices)));
4303
+ }
4304
+ tasks.push(Promise.resolve({ deviceAccu, total: Number(response.headers[headerNames.total]) }));
4305
+ return Promise.all(tasks);
4306
+ }).catch((err) => commonErrorHandler(err, `${status} devices couldn't be loaded.`, dispatch, commonErrorFallback));
4220
4307
  });
4221
- var userActions = {
4222
- add: {
4223
- successMessage: "The user was added successfully.",
4224
- errorMessage: "adding"
4225
- },
4226
- create: {
4227
- successMessage: "The user was created successfully.",
4228
- errorMessage: "creating"
4229
- },
4230
- edit: {
4231
- successMessage: "The user has been updated.",
4232
- errorMessage: "editing"
4308
+ var getAllDevicesByStatus = (0, import_toolkit21.createAsyncThunk)(`${sliceName3}/getAllDevicesByStatus`, (status, { dispatch, getState }) => {
4309
+ const attributes = [...defaultAttributes, getIdAttribute(getState())];
4310
+ const getAllDevices = (perPage = MAX_PAGE_SIZE, page = 1, devices = []) => general_api_default.post(getSearchEndpoint(getState()), {
4311
+ page,
4312
+ per_page: perPage,
4313
+ filters: mapFiltersToTerms([{ key: "status", value: status, operator: DEVICE_FILTERING_OPTIONS.$eq.key, scope: "identity" }]),
4314
+ attributes
4315
+ }).then((res) => {
4316
+ const state = getState();
4317
+ const deviceAccu = reduceReceivedDevices(res.data, devices, state, status);
4318
+ dispatch(actions3.receivedDevices(deviceAccu.devicesById));
4319
+ const total = Number(res.headers[headerNames.total]);
4320
+ if (total > state.deployments.deploymentDeviceLimit) {
4321
+ return Promise.resolve();
4322
+ }
4323
+ if (total > perPage * page) {
4324
+ return getAllDevices(perPage, page + 1, deviceAccu.ids);
4325
+ }
4326
+ let tasks = [dispatch(actions3.setDevicesByStatus({ deviceIds: deviceAccu.ids, forceUpdate: true, status, total: deviceAccu.ids.length }))];
4327
+ if (status === DEVICE_STATES.accepted && deviceAccu.ids.length === total) {
4328
+ tasks.push(dispatch(deriveInactiveDevices(deviceAccu.ids)));
4329
+ tasks.push(dispatch(deriveReportsData()));
4330
+ }
4331
+ return Promise.all(tasks);
4332
+ });
4333
+ return getAllDevices();
4334
+ });
4335
+ var searchDevices = (0, import_toolkit21.createAsyncThunk)(`${sliceName3}/searchDevices`, (passedOptions = {}, { dispatch, getState }) => {
4336
+ const state = getState();
4337
+ let options = { ...state.app.searchState, ...passedOptions };
4338
+ const { page = defaultPage3, searchTerm, sortOptions = [] } = options;
4339
+ const { columnSelection = [] } = getUserSettings(state);
4340
+ const selectedAttributes = columnSelection.map((column) => ({ attribute: column.key, scope: column.scope }));
4341
+ const attributes = (0, import_helpers10.attributeDuplicateFilter)([...defaultAttributes, getIdAttribute(state), ...selectedAttributes], "attribute");
4342
+ return general_api_default.post(getSearchEndpoint(getState()), {
4343
+ page,
4344
+ per_page: 10,
4345
+ filters: [],
4346
+ sort: sortOptions,
4347
+ text: searchTerm,
4348
+ attributes
4349
+ }).then((response) => {
4350
+ const deviceAccu = reduceReceivedDevices(response.data, [], getState());
4351
+ return Promise.all([
4352
+ dispatch(actions3.receivedDevices(deviceAccu.devicesById)),
4353
+ Promise.resolve({ deviceIds: deviceAccu.ids, searchTotal: Number(response.headers[headerNames.total]) })
4354
+ ]);
4355
+ }).catch((err) => commonErrorHandler(err, `devices couldn't be searched.`, dispatch, commonErrorFallback));
4356
+ });
4357
+ var ATTRIBUTE_LIST_CUTOFF = 100;
4358
+ var attributeReducer = (attributes = []) => attributes.slice(0, ATTRIBUTE_LIST_CUTOFF).reduce(
4359
+ (accu, { name, scope }) => {
4360
+ if (!accu[scope]) {
4361
+ accu[scope] = [];
4362
+ }
4363
+ accu[scope].push(name);
4364
+ return accu;
4233
4365
  },
4234
- remove: {
4235
- successMessage: "The user was removed from the system.",
4236
- errorMessage: "removing"
4366
+ { identity: [], inventory: [], system: [], tags: [] }
4367
+ );
4368
+ var getDeviceAttributes = (0, import_toolkit21.createAsyncThunk)(
4369
+ `${sliceName3}/getDeviceAttributes`,
4370
+ (_, { dispatch, getState }) => general_api_default.get(getAttrsEndpoint(getState())).then(({ data }) => {
4371
+ const { identity: identityAttributes, inventory: inventoryAttributes, system: systemAttributes, tags: tagAttributes } = attributeReducer(data || []);
4372
+ return dispatch(actions3.setFilterAttributes({ identityAttributes, inventoryAttributes, systemAttributes, tagAttributes }));
4373
+ })
4374
+ );
4375
+ var getReportingLimits = (0, import_toolkit21.createAsyncThunk)(
4376
+ `${sliceName3}/getReportingLimits`,
4377
+ (_, { dispatch }) => general_api_default.get(`${reportingApiUrl}/devices/attributes`).catch((err) => commonErrorHandler(err, `filterable attributes limit & usage could not be retrieved.`, dispatch, commonErrorFallback)).then(({ data }) => {
4378
+ const { attributes, count, limit } = data;
4379
+ const groupedAttributes = attributeReducer(attributes);
4380
+ return Promise.resolve(dispatch(actions3.setFilterablesConfig({ count, limit, attributes: groupedAttributes })));
4381
+ })
4382
+ );
4383
+ var ensureVersionString = (software, fallback) => software.length && software !== "artifact_name" ? software.endsWith(".version") ? software : `${software}.version` : fallback;
4384
+ var getSingleReportData = (reportConfig, groups) => {
4385
+ const { attribute, group, software = "" } = reportConfig;
4386
+ const filters = [{ key: "status", scope: "identity", operator: DEVICE_FILTERING_OPTIONS.$eq.key, value: "accepted" }];
4387
+ if (group) {
4388
+ const staticGroupFilter = { key: "group", scope: "system", operator: DEVICE_FILTERING_OPTIONS.$eq.key, value: group };
4389
+ const { cleanedFilters: groupFilters } = getGroupFilters(group, groups);
4390
+ filters.push(...groupFilters.length ? groupFilters : [staticGroupFilter]);
4237
4391
  }
4392
+ const aggregationAttribute = ensureVersionString(software, attribute);
4393
+ return general_api_default.post(`${reportingApiUrl}/devices/aggregate`, {
4394
+ aggregations: [{ attribute: aggregationAttribute, name: "*", scope: "inventory", size: REPORT_CHART_SIZE_LIMIT }],
4395
+ filters: mapFiltersToTerms(filters)
4396
+ }).then(({ data }) => ({ data, reportConfig }));
4238
4397
  };
4239
- var userActionErrorHandler = (err, type, dispatch) => commonErrorHandler(err, `There was an error ${userActions[type].errorMessage} the user.`, dispatch);
4240
- var createUser = (0, import_toolkit21.createAsyncThunk)(
4241
- `${sliceName8}/createUser`,
4242
- ({ shouldResetPassword, ...userData }, { dispatch }) => general_api_default.post(`${useradmApiUrlv1}/users`, { ...userData, send_reset_password: shouldResetPassword }).then(() => Promise.all([dispatch(actions8.createdUser(userData)), dispatch(getUserList()), dispatch(setSnackbar4(userActions.create.successMessage))])).catch((err) => userActionErrorHandler(err, "create", dispatch))
4398
+ var getReportsData = (0, import_toolkit21.createAsyncThunk)(`${sliceName3}/getReportsData`, (_, { dispatch, getState }) => {
4399
+ const state = getState();
4400
+ const currentUserId = getCurrentUser(state).id;
4401
+ const reports = getUserSettings(state).reports || getGlobalSettings(state)[`${currentUserId}-reports`] || (Object.keys(getDevicesById(state)).length ? defaultReports : []);
4402
+ return Promise.all(reports.map((report) => getSingleReportData(report, getState().devices.groups))).then((results) => {
4403
+ const devicesState = getState().devices;
4404
+ const totalDeviceCount = devicesState.byStatus.accepted.total;
4405
+ const newReports = results.map(({ data, reportConfig }) => {
4406
+ let { items, other_count } = data[0];
4407
+ const { attribute, group, software = "" } = reportConfig;
4408
+ const dataCount = items.reduce((accu, item) => accu + item.count, 0);
4409
+ const otherCount = !group && (software === rootfsImageVersion || attribute === "artifact_name") ? totalDeviceCount - dataCount : other_count;
4410
+ return { items, otherCount, total: otherCount + dataCount };
4411
+ });
4412
+ return Promise.resolve(dispatch(actions3.setDeviceReports(newReports)));
4413
+ });
4414
+ });
4415
+ var initializeDistributionData = (report, groups, devices, totalDeviceCount) => {
4416
+ const { attribute, group = "", software = "" } = report;
4417
+ const effectiveAttribute = software ? software : attribute;
4418
+ const { deviceIds, total = 0 } = groups[group] || {};
4419
+ const relevantDevices = groups[group] ? deviceIds.map((id) => devices[id]) : Object.values(devices);
4420
+ const distributionByAttribute = relevantDevices.reduce((accu, item) => {
4421
+ if (!item.attributes || item.status !== DEVICE_STATES.accepted) return accu;
4422
+ if (!accu[item.attributes[effectiveAttribute]]) {
4423
+ accu[item.attributes[effectiveAttribute]] = 0;
4424
+ }
4425
+ accu[item.attributes[effectiveAttribute]] = accu[item.attributes[effectiveAttribute]] + 1;
4426
+ return accu;
4427
+ }, {});
4428
+ const distributionByAttributeSorted = Object.entries(distributionByAttribute).sort((pairA, pairB) => pairB[1] - pairA[1]);
4429
+ const items = distributionByAttributeSorted.map(([key, count]) => ({ key, count }));
4430
+ const dataCount = items.reduce((accu, item) => accu + item.count, 0);
4431
+ const otherCount = (groups[group] ? total : totalDeviceCount) - dataCount;
4432
+ return { items, otherCount, total: otherCount + dataCount };
4433
+ };
4434
+ var deriveReportsData = (0, import_toolkit21.createAsyncThunk)(`${sliceName3}/deriveReportsData`, (_, { dispatch, getState }) => {
4435
+ const state = getState();
4436
+ const {
4437
+ groups: { byId: groupsById },
4438
+ byId,
4439
+ byStatus: {
4440
+ accepted: { total }
4441
+ }
4442
+ } = state.devices;
4443
+ const reports = getUserSettings(state).reports || state.users.globalSettings[`${state.users.currentUser}-reports`] || (Object.keys(byId).length ? defaultReports : []);
4444
+ const newReports = reports.map((report) => initializeDistributionData(report, groupsById, byId, total));
4445
+ return Promise.resolve(dispatch(actions3.setDeviceReports(newReports)));
4446
+ });
4447
+ var getReportsDataWithoutBackendSupport = (0, import_toolkit21.createAsyncThunk)(
4448
+ `${sliceName3}/getReportsDataWithoutBackendSupport`,
4449
+ (_, { dispatch, getState }) => Promise.all([dispatch(getAllDevicesByStatus(DEVICE_STATES.accepted)), dispatch(getGroups2()), dispatch(getDynamicGroups())]).then(() => {
4450
+ const { dynamic: dynamicGroups, static: staticGroups } = getGroups(getState());
4451
+ return Promise.all([
4452
+ ...staticGroups.map(({ groupId }) => dispatch(getAllGroupDevices(groupId))),
4453
+ ...dynamicGroups.map(({ groupId }) => dispatch(getAllDynamicGroupDevices(groupId)))
4454
+ ]).then(() => dispatch(deriveReportsData()));
4455
+ })
4243
4456
  );
4244
- var removeUser = (0, import_toolkit21.createAsyncThunk)(
4245
- `${sliceName8}/removeUser`,
4246
- (userId, { dispatch }) => (
4247
- // @ts-ignore
4248
- general_api_default.delete(`${useradmApiUrlv1}/users/${userId}`).then(() => Promise.all([dispatch(actions8.removedUser(userId)), dispatch(getUserList()), dispatch(setSnackbar4(userActions.remove.successMessage))])).catch((err) => userActionErrorHandler(err, "remove", dispatch))
4457
+ var getDeviceConnect = (0, import_toolkit21.createAsyncThunk)(
4458
+ `${sliceName3}/getDeviceConnect`,
4459
+ (id, { dispatch }) => general_api_default.get(`${deviceConnect}/devices/${id}`).then(
4460
+ ({ data }) => Promise.all([dispatch(actions3.receivedDevice({ connect_status: data.status, connect_updated_ts: data.updated_ts, id })), Promise.resolve(data)])
4249
4461
  )
4250
4462
  );
4251
- var editUser = (0, import_toolkit21.createAsyncThunk)(
4252
- `${sliceName8}/editUser`,
4253
- ({ id, ...userData }, { dispatch, getState }) => general_api_default.put(`${useradmApiUrlv1}/users/${id}`, userData).then(
4254
- () => Promise.all([
4255
- dispatch(actions8.updatedUser({ ...userData, id: id === OWN_USER_ID ? getCurrentUser(getState()).id : id })),
4256
- dispatch(setSnackbar4(userActions.edit.successMessage))
4257
- ])
4463
+ var updateTypeMap = { deploymentUpdate: "check-update", inventoryUpdate: "send-inventory" };
4464
+ var triggerDeviceUpdate = (0, import_toolkit21.createAsyncThunk)(
4465
+ `${sliceName3}/triggerDeviceUpdate`,
4466
+ ({ id, type }, { dispatch }) => general_api_default.post(`${deviceConnect}/devices/${id}/${updateTypeMap[type] ?? updateTypeMap.deploymentUpdate}`).then(
4467
+ () => new Promise((resolve) => setTimeout(() => resolve(dispatch(getDeviceById2(id))), TIMEOUTS.threeSeconds))
4258
4468
  )
4259
4469
  );
4260
- var addUserToCurrentTenant = (0, import_toolkit21.createAsyncThunk)(`${sliceName8}/addUserToTenant`, (userId, { dispatch, getState }) => {
4261
- const { id } = getOrganization(getState());
4262
- return general_api_default.post(`${useradmApiUrlv1}/users/${userId}/assign`, { tenant_ids: [id] }).catch((err) => commonErrorHandler(err, `There was an error adding the user to your organization:`, dispatch)).then(() => Promise.all([dispatch(setSnackbar4(userActions.add.successMessage)), dispatch(getUserList())]));
4470
+ var getSessionDetails = (0, import_toolkit21.createAsyncThunk)(`${sliceName3}/getSessionDetails`, ({ sessionId, deviceId, userId, startDate, endDate }) => {
4471
+ const { start: startUnix, end: endUnix } = (0, import_helpers10.dateRangeToUnix)(startDate, endDate);
4472
+ const createdAfter = startDate ? `&created_after=${startUnix}` : "";
4473
+ const createdBefore = endDate ? `&created_before=${endUnix}` : "";
4474
+ const objectSearch = `&object_id=${deviceId}`;
4475
+ return general_api_default.get(`${auditLogsApiUrl}/logs?per_page=500${createdAfter}${createdBefore}&actor_id=${userId}${objectSearch}`).then(
4476
+ ({ data: auditLogEntries }) => {
4477
+ const { start, end } = auditLogEntries.reduce(
4478
+ (accu, item) => {
4479
+ if (item.meta?.session_id?.includes(sessionId)) {
4480
+ accu.start = new Date(item.action.startsWith("open") ? item.time : accu.start);
4481
+ accu.end = new Date(item.action.startsWith("close") ? item.time : accu.end);
4482
+ }
4483
+ return accu;
4484
+ },
4485
+ { start: startDate || endDate, end: endDate || startDate }
4486
+ );
4487
+ return Promise.resolve({ start, end });
4488
+ }
4489
+ );
4263
4490
  });
4264
- var enableUser2fa = (0, import_toolkit21.createAsyncThunk)(
4265
- `${sliceName8}/enableUser2fa`,
4266
- (userId = OWN_USER_ID, { dispatch }) => general_api_default.post(`${useradmApiUrlv1}/users/${userId}/2fa/enable`).catch((err) => commonErrorHandler(err, `There was an error enabling Two Factor authentication for the user.`, dispatch)).then(() => Promise.resolve(dispatch(getUser(userId))))
4267
- );
4268
- var disableUser2fa = (0, import_toolkit21.createAsyncThunk)(
4269
- `${sliceName8}/disableUser2fa`,
4270
- (userId = OWN_USER_ID, { dispatch }) => general_api_default.post(`${useradmApiUrlv1}/users/${userId}/2fa/disable`).catch((err) => commonErrorHandler(err, `There was an error disabling Two Factor authentication for the user.`, dispatch)).then(() => Promise.resolve(dispatch(getUser(userId))))
4491
+ var getDeviceFileDownloadLink = (0, import_toolkit21.createAsyncThunk)(
4492
+ `${sliceName3}/getDeviceFileDownloadLink`,
4493
+ ({ deviceId, path }) => Promise.resolve(`${window.location.origin}${deviceConnect}/devices/${deviceId}/download?path=${encodeURIComponent(path)}`)
4271
4494
  );
4272
- var mapHttpPermission = (permission) => Object.entries(uiPermissionsByArea).reduce(
4273
- (accu, [area, definition]) => {
4274
- const endpointMatches = definition.endpoints.filter(
4275
- (endpoint) => endpoint.path.test(permission.value) && (endpoint.types.includes(permission.type) || permission.type === PermissionTypes.Any)
4276
- );
4277
- if (permission.value === PermissionTypes.Any || permission.value.includes(apiRoot) && endpointMatches.length) {
4278
- const endpointUiPermission = endpointMatches.reduce((endpointAccu, endpoint) => [...endpointAccu, ...endpoint.uiPermissions], []);
4279
- const collector = (endpointUiPermission || definition.uiPermissions).reduce((permissionsAccu, uiPermission) => {
4280
- if (permission.type === PermissionTypes.Any || !endpointMatches.length && uiPermission.verbs.some((verb) => verb === permission.type)) {
4281
- permissionsAccu.push(uiPermission.value);
4282
- }
4283
- return permissionsAccu;
4284
- }, []).filter(import_helpers10.duplicateFilter);
4285
- if (Array.isArray(accu[area])) {
4286
- accu[area] = [...accu[area], ...collector].filter(import_helpers10.duplicateFilter);
4287
- } else {
4288
- accu[area] = mergePermissions(accu[area], { [scopedPermissionAreas[area].excessiveAccessSelector]: collector });
4289
- }
4495
+ var deviceFileUpload = (0, import_toolkit21.createAsyncThunk)(`${sliceName3}/deviceFileUpload`, ({ deviceId, path, file }, { dispatch }) => {
4496
+ let formData = new FormData();
4497
+ formData.append("path", path);
4498
+ formData.append("file", file);
4499
+ const uploadId = (0, import_uuid.v4)();
4500
+ const cancelSource = new AbortController();
4501
+ return Promise.all([
4502
+ dispatch(setSnackbar4("Uploading file")),
4503
+ dispatch(initUpload({ id: uploadId, upload: { inprogress: true, uploadProgress: 0, cancelSource } })),
4504
+ general_api_default.uploadPut(
4505
+ `${deviceConnect}/devices/${deviceId}/upload`,
4506
+ formData,
4507
+ (e) => dispatch(uploadProgress2({ id: uploadId, progress: progress(e) })),
4508
+ cancelSource.signal
4509
+ )
4510
+ ]).then(() => Promise.resolve(dispatch(setSnackbar4("Upload successful", TIMEOUTS.fiveSeconds)))).catch((err) => {
4511
+ if ((0, import_axios3.isCancel)(err)) {
4512
+ return dispatch(setSnackbar4("The upload has been cancelled", TIMEOUTS.fiveSeconds));
4290
4513
  }
4291
- return accu;
4292
- },
4293
- { ...emptyUiPermissions }
4294
- );
4295
- var permissionActionTypes = {
4296
- any: mapHttpPermission,
4297
- CREATE_DEPLOYMENT: (permission) => permission.type === PermissionTypes.DeviceGroup ? {
4298
- deployments: [uiPermissionsById.deploy.value],
4299
- groups: { [permission.value]: [uiPermissionsById.deploy.value] }
4300
- } : {},
4301
- http: mapHttpPermission,
4302
- REMOTE_TERMINAL: (permission) => permission.type === PermissionTypes.DeviceGroup ? {
4303
- groups: { [permission.value]: [uiPermissionsById.connect.value] }
4304
- } : {},
4305
- VIEW_DEVICE: (permission) => permission.type === PermissionTypes.DeviceGroup ? {
4306
- groups: { [permission.value]: [uiPermissionsById.read.value] }
4307
- } : {}
4308
- };
4309
- var combinePermissions = (existingPermissions, additionalPermissions = {}) => Object.entries(additionalPermissions).reduce((accu, [name, permissions]) => {
4310
- let maybeExistingPermissions = accu[name] || [];
4311
- accu[name] = [...permissions, ...maybeExistingPermissions].filter(import_helpers10.duplicateFilter);
4312
- return accu;
4313
- }, existingPermissions);
4314
- var tryParseCustomPermission = (permission) => {
4315
- const uiPermissions = permissionActionTypes[permission.action](permission.object);
4316
- const result = mergePermissions({ ...emptyUiPermissions }, uiPermissions);
4317
- return { isCustom: true, permission, result };
4318
- };
4319
- var customPermissionHandler = (accu, permission) => {
4320
- let processor = tryParseCustomPermission(permission);
4321
- return {
4322
- ...accu,
4323
- isCustom: accu.isCustom || processor.isCustom,
4324
- uiPermissions: mergePermissions(accu.uiPermissions, processor.result)
4325
- };
4326
- };
4327
- var mapPermissionSet = (permissionSetName, names, scope, existingGroupsPermissions = {}) => {
4328
- const permission = Object.values(uiPermissionsById).find((permission2) => permission2.permissionSets[scope] === permissionSetName).value;
4329
- const scopedPermissions = names.reduce((accu, name) => combinePermissions(accu, { [name]: [permission] }), existingGroupsPermissions);
4330
- return Object.entries(scopedPermissions).reduce((accu, [key, permissions]) => ({ ...accu, [key]: deriveImpliedAreaPermissions(scope, permissions) }), {});
4331
- };
4332
- var isEmptyPermissionSet = (permissionSet) => !Object.values(permissionSet).reduce((accu, permissions) => {
4333
- if (Array.isArray(permissions)) {
4334
- return accu || !!permissions.length;
4335
- }
4336
- return accu || !(0, import_helpers10.isEmpty)(permissions);
4337
- }, false);
4338
- var parseRolePermissions = ({ permission_sets_with_scope = [], permissions = [] }, permissionSets) => {
4339
- const preliminaryResult = permission_sets_with_scope.reduce(
4340
- (accu, permissionSet) => {
4341
- let processor = permissionSets[permissionSet.name];
4342
- if (!processor) {
4343
- return accu;
4344
- }
4345
- const scope = Object.keys(scopedPermissionAreas).find((scope2) => uiPermissionsByArea[scope2].scope === permissionSet.scope?.type);
4346
- if (scope) {
4347
- const result = mapPermissionSet(permissionSet.name, permissionSet.scope.value, scope, accu.uiPermissions[scope]);
4348
- return { ...accu, uiPermissions: { ...accu.uiPermissions, [scope]: result } };
4349
- } else if (isEmptyPermissionSet(processor.result)) {
4350
- return processor.permissions.reduce(customPermissionHandler, accu);
4351
- }
4352
- return {
4353
- ...accu,
4354
- isCustom: accu.isCustom || processor.isCustom,
4355
- uiPermissions: mergePermissions(accu.uiPermissions, processor.result)
4356
- };
4357
- },
4358
- { isCustom: false, uiPermissions: { ...emptyUiPermissions, groups: {}, releases: {} } }
4359
- );
4360
- return permissions.reduce(customPermissionHandler, preliminaryResult);
4361
- };
4362
- var normalizeRbacRoles = (roles, rolesById2, permissionSets) => roles.reduce(
4363
- (accu, role) => {
4364
- let normalizedPermissions;
4365
- let isCustom = false;
4366
- if (rolesById2[role.name]) {
4367
- normalizedPermissions = {
4368
- ...rolesById2[role.name].uiPermissions,
4369
- groups: { ...rolesById2[role.name].uiPermissions.groups },
4370
- releases: { ...rolesById2[role.name].uiPermissions.releases }
4371
- };
4372
- } else {
4373
- const result = parseRolePermissions(role, permissionSets);
4374
- normalizedPermissions = result.uiPermissions;
4375
- isCustom = result.isCustom;
4514
+ return commonErrorHandler(err, `Error uploading file to device.`, dispatch);
4515
+ }).finally(() => dispatch(cleanUpUpload(uploadId)));
4516
+ });
4517
+ var getDeviceAuth = (0, import_toolkit21.createAsyncThunk)(
4518
+ `${sliceName3}/getDeviceAuth`,
4519
+ (id, { dispatch }) => dispatch(getDevicesWithAuth([{ id }])).unwrap().then((results) => {
4520
+ if (results[results.length - 1]) {
4521
+ return Promise.resolve(results[results.length - 1][0]);
4376
4522
  }
4377
- const roleState = accu[role.name] ?? { ...emptyRole };
4378
- accu[role.name] = {
4379
- ...roleState,
4380
- ...role,
4381
- description: roleState.description ? roleState.description : role.description,
4382
- editable: !rolesById[role.name] && !isCustom && (typeof roleState.editable !== "undefined" ? roleState.editable : true),
4383
- isCustom,
4384
- name: roleState.name ? roleState.name : role.name,
4385
- uiPermissions: normalizedPermissions
4386
- };
4387
- return accu;
4388
- },
4389
- { ...rolesById2 }
4523
+ return Promise.resolve();
4524
+ })
4390
4525
  );
4391
- var getPermissionSets = (0, import_toolkit21.createAsyncThunk)(
4392
- `${sliceName8}/getPermissionSets`,
4393
- (_, { dispatch, getState }) => general_api_default.get(`${useradmApiUrlv2}/permission_sets?per_page=500`).then(({ data }) => {
4394
- const permissionSets = data.reduce(
4395
- (accu, permissionSet) => {
4396
- const permissionSetState = accu[permissionSet.name] ?? {};
4397
- let permissionSetObject = { ...permissionSetState, ...permissionSet };
4398
- permissionSetObject.result = Object.values(uiPermissionsById).reduce(
4399
- (accu2, item) => Object.entries(item.permissionSets).reduce((collector, [area, permissionSet2]) => {
4400
- if (scopedPermissionAreas[area]) {
4401
- return collector;
4402
- }
4403
- if (permissionSet2 === permissionSetObject.name) {
4404
- collector[area] = [...collector[area], item.value].filter(import_helpers10.duplicateFilter);
4405
- }
4406
- return collector;
4407
- }, accu2),
4408
- { ...emptyUiPermissions, ...permissionSetObject.result ?? {} }
4409
- );
4410
- const scopes = Object.values(scopedPermissionAreas).reduce((accu2, { key, scopeType }) => {
4411
- if (permissionSetObject.supported_scope_types?.includes(key) || permissionSetObject.supported_scope_types?.includes(scopeType)) {
4412
- accu2.push(key);
4413
- }
4414
- return accu2;
4415
- }, []);
4416
- permissionSetObject = scopes.reduce((accu2, scope) => {
4417
- accu2.result[scope] = mapPermissionSet(permissionSetObject.name, [scopedPermissionAreas[scope].excessiveAccessSelector], scope);
4418
- return accu2;
4419
- }, permissionSetObject);
4420
- accu[permissionSet.name] = permissionSetObject;
4421
- return accu;
4422
- },
4423
- // @ts-ignore
4424
- { ...getState().users.permissionSetsById }
4425
- );
4426
- return Promise.all([dispatch(actions8.receivedPermissionSets(permissionSets)), permissionSets]);
4427
- }).catch(() => console.log("Permission set retrieval failed - likely accessing a non-RBAC backend"))
4526
+ var getDevicesWithAuth = (0, import_toolkit21.createAsyncThunk)(
4527
+ `${sliceName3}/getDevicesWithAuth`,
4528
+ (devices, { dispatch, getState }) => devices.length ? general_api_default.get(`${deviceAuthV2}/devices?id=${devices.map((device) => device.id).join("&id=")}`).then(({ data: receivedDevices }) => {
4529
+ const { devicesById } = reduceReceivedDevices(receivedDevices, [], getState());
4530
+ return Promise.all([dispatch(actions3.receivedDevices(devicesById)), Promise.resolve(receivedDevices)]);
4531
+ }).catch((err) => commonErrorHandler(err, `Error: ${err}`, dispatch)) : Promise.resolve([[], []])
4428
4532
  );
4429
- var getRoles = (0, import_toolkit21.createAsyncThunk)(
4430
- `${sliceName8}/getRoles`,
4431
- (_, { dispatch, getState }) => Promise.all([general_api_default.get(`${useradmApiUrlv2}/roles?per_page=500`), dispatch(getPermissionSets())]).then((results) => {
4432
- if (!results) {
4433
- return Promise.resolve();
4434
- }
4435
- const [{ data: roles }, { payload: permissionSetTasks }] = results;
4436
- const rolesById2 = normalizeRbacRoles(roles, getRolesById(getState()), permissionSetTasks[permissionSetTasks.length - 1]);
4437
- return Promise.resolve(dispatch(actions8.receivedRoles(rolesById2)));
4438
- }).catch(() => console.log("Role retrieval failed - likely accessing a non-RBAC backend"))
4533
+ var updateDeviceAuth = (0, import_toolkit21.createAsyncThunk)(
4534
+ `${sliceName3}/updateDeviceAuth`,
4535
+ ({ deviceId, authId, status }, { dispatch, getState }) => general_api_default.put(`${deviceAuthV2}/devices/${deviceId}/auth/${authId}/status`, { status }).then(() => Promise.all([dispatch(getDeviceAuth(deviceId)), dispatch(setSnackbar4("Device authorization status was updated successfully"))])).catch((err) => commonErrorHandler(err, "There was a problem updating the device authorization status:", dispatch)).then(() => Promise.resolve(dispatch(actions3.maybeUpdateDevicesByStatus({ deviceId, authId })))).finally(() => dispatch(setDeviceListState({ refreshTrigger: !getDeviceListState(getState()).refreshTrigger })))
4439
4536
  );
4440
- var deriveImpliedAreaPermissions = (area, areaPermissions, skipPermissions = []) => {
4441
- const highestAreaPermissionLevelSelected = areaPermissions.reduce(
4442
- (highest, current) => uiPermissionsById[current].permissionLevel > highest ? uiPermissionsById[current].permissionLevel : highest,
4443
- 1
4444
- );
4445
- return uiPermissionsByArea[area].uiPermissions.reduce((permissions, current) => {
4446
- if ((current.permissionLevel < highestAreaPermissionLevelSelected || areaPermissions.includes(current.value)) && !skipPermissions.includes(current.value)) {
4447
- permissions.push(current.value);
4448
- }
4449
- return permissions;
4450
- }, []);
4451
- };
4452
- var transformAreaRoleDataToScopedPermissionsSets = (area, areaPermissions, excessiveAccessSelector) => {
4453
- const permissionSetObject = areaPermissions.reduce((accu, { item, uiPermissions }) => {
4454
- const skipPermissions = scopedPermissionAreas.releases.key === area && item !== ALL_RELEASES ? [uiPermissionsById.upload.value] : [];
4455
- const impliedPermissions = deriveImpliedAreaPermissions(area, uiPermissions, skipPermissions);
4456
- accu = impliedPermissions.reduce((itemPermissionAccu, impliedPermission) => {
4457
- const permissionSetState = itemPermissionAccu[uiPermissionsById[impliedPermission].permissionSets[area]] ?? {
4458
- type: uiPermissionsByArea[area].scope,
4459
- value: []
4460
- };
4461
- itemPermissionAccu[uiPermissionsById[impliedPermission].permissionSets[area]] = {
4462
- ...permissionSetState,
4463
- value: [...permissionSetState.value, item]
4464
- };
4465
- return itemPermissionAccu;
4466
- }, accu);
4467
- return accu;
4468
- }, {});
4469
- return Object.entries(permissionSetObject).map(([name, { value, ...scope }]) => {
4470
- if (value.includes(excessiveAccessSelector)) {
4471
- return { name };
4472
- }
4473
- return { name, scope: { ...scope, value: value.filter(import_helpers10.duplicateFilter) } };
4474
- });
4475
- };
4476
- var transformRoleDataToRole = (roleData, roleState = {}) => {
4477
- const role = { ...roleState, ...roleData };
4478
- const { description = "", name, uiPermissions = emptyUiPermissions } = role;
4479
- const { maybeUiPermissions, remainderKeys } = Object.entries(emptyUiPermissions).reduce(
4480
- (accu, [key, emptyPermissions]) => {
4481
- if (!scopedPermissionAreas[key]) {
4482
- accu.remainderKeys.push(key);
4483
- } else if (uiPermissions[key]) {
4484
- accu.maybeUiPermissions[key] = uiPermissions[key].reduce(itemUiPermissionsReducer, emptyPermissions);
4485
- }
4486
- return accu;
4487
- },
4488
- { maybeUiPermissions: {}, remainderKeys: [] }
4489
- );
4490
- const { permissionSetsWithScope, roleUiPermissions } = remainderKeys.reduce(
4491
- (accu, area) => {
4492
- const areaPermissions = role.uiPermissions[area];
4493
- if (!Array.isArray(areaPermissions)) {
4494
- return accu;
4495
- }
4496
- const impliedPermissions = deriveImpliedAreaPermissions(area, areaPermissions);
4497
- accu.roleUiPermissions[area] = impliedPermissions;
4498
- const mappedPermissions = impliedPermissions.map((uiPermission) => ({ name: uiPermissionsById[uiPermission].permissionSets[area] }));
4499
- accu.permissionSetsWithScope.push(...mappedPermissions);
4500
- return accu;
4501
- },
4502
- { permissionSetsWithScope: [{ name: defaultPermissionSets.Basic.name }], roleUiPermissions: {} }
4503
- );
4504
- const scopedPermissionSets = Object.values(scopedPermissionAreas).reduce((accu, { key, excessiveAccessSelector }) => {
4505
- if (!uiPermissions[key]) {
4506
- return accu;
4507
- }
4508
- accu.push(...transformAreaRoleDataToScopedPermissionsSets(key, uiPermissions[key], excessiveAccessSelector));
4509
- return accu;
4510
- }, []);
4511
- return {
4512
- permissionSetsWithScope: [...permissionSetsWithScope, ...scopedPermissionSets],
4513
- role: {
4514
- ...emptyRole,
4515
- name,
4516
- // @ts-ignore
4517
- description: description ? description : roleState.description,
4518
- uiPermissions: {
4519
- ...emptyUiPermissions,
4520
- ...roleUiPermissions,
4521
- ...maybeUiPermissions
4537
+ var updateDevicesAuth = (0, import_toolkit21.createAsyncThunk)(`${sliceName3}/updateDevicesAuth`, ({ deviceIds, status }, { dispatch, getState }) => {
4538
+ let devices = getDevicesById(getState());
4539
+ const deviceIdsWithoutAuth = deviceIds.reduce((accu, id) => devices[id].auth_sets ? accu : [...accu, { id }], []);
4540
+ return dispatch(getDevicesWithAuth(deviceIdsWithoutAuth)).then(() => {
4541
+ devices = getDevicesById(getState());
4542
+ const deviceAuthUpdates = deviceIds.map((id) => {
4543
+ const device = devices[id];
4544
+ if (device.auth_sets.length !== 1) {
4545
+ return Promise.reject();
4522
4546
  }
4523
- }
4524
- };
4525
- };
4526
- var roleActions = {
4527
- create: {
4528
- successMessage: "The role was created successfully.",
4529
- errorMessage: "creating"
4530
- },
4531
- edit: {
4532
- successMessage: "The role has been updated.",
4533
- errorMessage: "editing"
4534
- },
4535
- remove: {
4536
- successMessage: "The role was deleted successfully.",
4537
- errorMessage: "removing"
4538
- }
4539
- };
4540
- var roleActionErrorHandler = (err, type, dispatch) => commonErrorHandler(err, `There was an error ${roleActions[type].errorMessage} the role.`, dispatch);
4541
- var createRole = (0, import_toolkit21.createAsyncThunk)(`${sliceName8}/createRole`, (roleData, { dispatch }) => {
4542
- const { permissionSetsWithScope, role } = transformRoleDataToRole(roleData);
4543
- return general_api_default.post(`${useradmApiUrlv2}/roles`, {
4544
- name: role.name,
4545
- description: role.description,
4546
- permission_sets_with_scope: permissionSetsWithScope
4547
- }).then(() => Promise.all([dispatch(actions8.createdRole(role)), dispatch(getRoles()), dispatch(setSnackbar4(roleActions.create.successMessage))])).catch((err) => roleActionErrorHandler(err, "create", dispatch));
4548
- });
4549
- var editRole = (0, import_toolkit21.createAsyncThunk)(`${sliceName8}/editRole`, (roleData, { dispatch, getState }) => {
4550
- const { permissionSetsWithScope, role } = transformRoleDataToRole(roleData, getRolesById(getState())[roleData.name]);
4551
- return general_api_default.put(`${useradmApiUrlv2}/roles/${role.name}`, {
4552
- description: role.description,
4553
- name: role.name,
4554
- permission_sets_with_scope: permissionSetsWithScope
4555
- }).then(() => Promise.all([dispatch(actions8.createdRole(role)), dispatch(getRoles()), dispatch(setSnackbar4(roleActions.edit.successMessage))])).catch((err) => roleActionErrorHandler(err, "edit", dispatch));
4547
+ return dispatch(updateDeviceAuth({ authId: device.auth_sets[0].id, deviceId: device.id, status })).unwrap().catch((err) => commonErrorHandler(err, "The action was stopped as there was a problem updating a device authorization status: ", dispatch, "", false));
4548
+ });
4549
+ return Promise.allSettled(deviceAuthUpdates).then((results) => {
4550
+ const { skipped, count } = results.reduce(
4551
+ (accu, item) => {
4552
+ if (item.status === "rejected") {
4553
+ accu.skipped = accu.skipped + 1;
4554
+ } else {
4555
+ accu.count = accu.count + 1;
4556
+ }
4557
+ return accu;
4558
+ },
4559
+ { skipped: 0, count: 0 }
4560
+ );
4561
+ const message = (0, import_helpers10.getSnackbarMessage)(skipped, count);
4562
+ return dispatch(setSnackbar4(message));
4563
+ });
4564
+ });
4556
4565
  });
4557
- var removeRole = (0, import_toolkit21.createAsyncThunk)(
4558
- `${sliceName8}/removeRole`,
4559
- (roleId, { dispatch }) => (
4560
- // @ts-ignore
4561
- general_api_default.delete(`${useradmApiUrlv2}/roles/${roleId}`).then(() => Promise.all([dispatch(actions8.removedRole(roleId)), dispatch(getRoles()), dispatch(setSnackbar4(roleActions.remove.successMessage))])).catch((err) => roleActionErrorHandler(err, "remove", dispatch))
4562
- )
4566
+ var deleteAuthset = (0, import_toolkit21.createAsyncThunk)(
4567
+ `${sliceName3}/deleteAuthset`,
4568
+ ({ deviceId, authId }, { dispatch, getState }) => general_api_default.delete(`${deviceAuthV2}/devices/${deviceId}/auth/${authId}`).then(() => Promise.all([dispatch(setSnackbar4("Device authorization status was updated successfully"))])).catch((err) => commonErrorHandler(err, "There was a problem updating the device authorization status:", dispatch)).then(() => Promise.resolve(dispatch(actions3.maybeUpdateDevicesByStatus({ deviceId, authId })))).finally(() => dispatch(setDeviceListState({ refreshTrigger: !getState().devices.deviceList.refreshTrigger })))
4563
4569
  );
4564
- var getGlobalSettings2 = (0, import_toolkit21.createAsyncThunk)(
4565
- `${sliceName8}/getGlobalSettings`,
4566
- (_, { dispatch }) => general_api_default.get(`${useradmApiUrlv1}/settings`).then(({ data: settings, headers: { etag } }) => {
4567
- window.sessionStorage.setItem(settingsKeys.initialized, true);
4568
- return Promise.all([dispatch(actions8.setGlobalSettings(settings)), dispatch(setOfflineThreshold()), etag]);
4570
+ var preauthDevice = (0, import_toolkit21.createAsyncThunk)(
4571
+ `${sliceName3}/preauthDevice`,
4572
+ (authset, { dispatch, rejectWithValue }) => general_api_default.post(`${deviceAuthV2}/devices`, authset).then(() => Promise.resolve(dispatch(setSnackbar4("Device was successfully added to the preauthorization list", TIMEOUTS.fiveSeconds)))).catch((err) => {
4573
+ if (err.response.status === 409) {
4574
+ return rejectWithValue("A device with a matching identity data set already exists");
4575
+ }
4576
+ return commonErrorHandler(err, "The device could not be added:", dispatch);
4569
4577
  })
4570
4578
  );
4571
- var saveGlobalSettings = (0, import_toolkit21.createAsyncThunk)(
4572
- `${sliceName8}/saveGlobalSettings`,
4573
- // @ts-ignore
4574
- ({ beOptimistic = false, notify = false, ...settings }, { dispatch, getState }) => {
4575
- if (!window.sessionStorage.getItem(settingsKeys.initialized) && !beOptimistic) {
4576
- return;
4579
+ var decommissionDevice = (0, import_toolkit21.createAsyncThunk)(
4580
+ `${sliceName3}/decommissionDevice`,
4581
+ ({ deviceId, authId }, { dispatch, getState }) => general_api_default.delete(`${deviceAuthV2}/devices/${deviceId}`).then(() => Promise.resolve(dispatch(setSnackbar4("Device was decommissioned successfully")))).catch((err) => commonErrorHandler(err, "There was a problem decommissioning the device:", dispatch)).then(() => Promise.resolve(dispatch(actions3.maybeUpdateDevicesByStatus({ deviceId, authId })))).finally(() => dispatch(setDeviceListState({ refreshTrigger: !getState().devices.deviceList.refreshTrigger })))
4582
+ );
4583
+ var getDeviceConfig = (0, import_toolkit21.createAsyncThunk)(
4584
+ `${sliceName3}/getDeviceConfig`,
4585
+ (deviceId, { dispatch }) => general_api_default.get(`${deviceConfig}/${deviceId}`).then(({ data }) => Promise.all([dispatch(actions3.receivedDevice({ id: deviceId, config: data })), Promise.resolve(data)])).catch((err) => {
4586
+ if (err.response?.data?.error.status_code !== 404) {
4587
+ return commonErrorHandler(err, `There was an error retrieving the configuration for device ${deviceId}.`, dispatch, commonErrorFallback);
4577
4588
  }
4578
- return dispatch(getGlobalSettings2()).unwrap().then((result) => {
4579
- let updatedSettings = { ...getState().users.globalSettings, ...settings };
4580
- if (getCurrentUser(getState()).verified) {
4581
- updatedSettings["2fa"] = twoFAStates.enabled;
4582
- } else {
4583
- delete updatedSettings["2fa"];
4584
- }
4585
- let tasks = [dispatch(actions8.setGlobalSettings(updatedSettings))];
4586
- const headers = result[result.length - 1] ? { "If-Match": result[result.length - 1] } : {};
4587
- return general_api_default.post(`${useradmApiUrlv1}/settings`, updatedSettings, { headers }).then(() => {
4588
- if (notify) {
4589
- tasks.push(dispatch(setSnackbar4("Settings saved successfully")));
4590
- }
4591
- return Promise.all(tasks);
4592
- }).catch((err) => {
4593
- if (beOptimistic) {
4594
- return Promise.all([tasks]);
4595
- }
4596
- console.log(err);
4597
- return commonErrorHandler(err, `The settings couldn't be saved.`, dispatch);
4598
- });
4599
- });
4600
- }
4589
+ })
4601
4590
  );
4602
- var getUserSettings2 = (0, import_toolkit21.createAsyncThunk)(
4603
- `${sliceName8}/getUserSettings`,
4604
- (_, { dispatch }) => general_api_default.get(`${useradmApiUrlv1}/settings/me`).then(({ data: settings, headers: { etag } }) => {
4605
- window.sessionStorage.setItem(settingsKeys.initialized, true);
4606
- return Promise.all([dispatch(actions8.setUserSettings(settings)), etag]);
4591
+ var setDeviceConfig = (0, import_toolkit21.createAsyncThunk)(
4592
+ `${sliceName3}/setDeviceConfig`,
4593
+ ({ deviceId, config }, { dispatch }) => general_api_default.put(`${deviceConfig}/${deviceId}`, config).catch((err) => commonErrorHandler(err, `There was an error setting the configuration for device ${deviceId}.`, dispatch, commonErrorFallback)).then(() => Promise.resolve(dispatch(getDeviceConfig(deviceId))))
4594
+ );
4595
+ var applyDeviceConfig = (0, import_toolkit21.createAsyncThunk)(
4596
+ `${sliceName3}/applyDeviceConfig`,
4597
+ ({ deviceId, configDeploymentConfiguration, isDefault, config }, { dispatch, getState }) => general_api_default.post(`${deviceConfig}/${deviceId}/deploy`, configDeploymentConfiguration).catch((err) => commonErrorHandler(err, `There was an error deploying the configuration to device ${deviceId}.`, dispatch, commonErrorFallback)).then(({ data }) => {
4598
+ const device = getDeviceById(getState(), deviceId);
4599
+ const { canManageUsers } = getUserCapabilities(getState());
4600
+ let tasks = [
4601
+ dispatch(actions3.receivedDevice({ ...device, config: { ...device.config, deployment_id: data.deployment_id } })),
4602
+ new Promise((resolve) => setTimeout(() => resolve(dispatch(getSingleDeployment(data.deployment_id))), TIMEOUTS.oneSecond))
4603
+ ];
4604
+ if (isDefault && canManageUsers) {
4605
+ const { previous } = getGlobalSettings(getState()).defaultDeviceConfig ?? {};
4606
+ tasks.push(dispatch(saveGlobalSettings({ defaultDeviceConfig: { current: config, previous } })));
4607
+ }
4608
+ return Promise.all(tasks);
4607
4609
  })
4608
4610
  );
4609
- var saveUserSettings = (0, import_toolkit21.createAsyncThunk)(`${sliceName8}/saveUserSettings`, (settings = { onboarding: {} }, { dispatch, getState }) => {
4610
- if (!getCurrentUser(getState()).id) {
4611
- return Promise.resolve();
4612
- }
4613
- return dispatch(getUserSettings2()).unwrap().then((result) => {
4614
- const userSettings = getUserSettings(getState());
4615
- const onboardingState = getOnboardingState(getState());
4616
- const tooltipState = getTooltipsState(getState());
4617
- const updatedSettings = {
4618
- ...userSettings,
4619
- // @ts-ignore
4620
- ...settings,
4621
- onboarding: {
4622
- ...onboardingState,
4623
- // @ts-ignore
4624
- ...settings.onboarding
4625
- },
4626
- tooltips: tooltipState
4611
+ var setDeviceTags = (0, import_toolkit21.createAsyncThunk)(
4612
+ `${sliceName3}/setDeviceTags`,
4613
+ ({ deviceId, tags }, { dispatch }) => (
4614
+ // to prevent tag set failures, retrieve the device & use the freshest etag we can get
4615
+ Promise.resolve(dispatch(getDeviceById2(deviceId))).then((device) => {
4616
+ const headers = device.etag ? { "If-Match": device.etag } : {};
4617
+ return general_api_default.put(
4618
+ `${inventoryApiUrl}/devices/${deviceId}/tags`,
4619
+ Object.entries(tags).map(([name, value]) => ({ name, value })),
4620
+ { headers }
4621
+ ).catch((err) => commonErrorHandler(err, `There was an error setting tags for device ${deviceId}.`, dispatch, "Please check your connection.")).then(() => Promise.all([dispatch(actions3.receivedDevice({ ...device, id: deviceId, tags })), dispatch(setSnackbar4("Device name changed"))]));
4622
+ })
4623
+ )
4624
+ );
4625
+ var getDeviceTwin = (0, import_toolkit21.createAsyncThunk)(`${sliceName3}/getDeviceTwin`, ({ deviceId, integration }, { dispatch, getState }) => {
4626
+ let providerResult = {};
4627
+ return general_api_default.get(`${iotManagerBaseURL}/devices/${deviceId}/state`).then(({ data }) => {
4628
+ providerResult = { ...data, twinError: "" };
4629
+ }).catch((err) => {
4630
+ providerResult = {
4631
+ twinError: `There was an error getting the ${EXTERNAL_PROVIDER[integration.provider].twinTitle.toLowerCase()} for device ${deviceId}. ${err}`
4627
4632
  };
4628
- const headers = result[result.length - 1] ? { "If-Match": result[result.length - 1] } : {};
4629
- return Promise.all([
4630
- Promise.resolve(dispatch(actions8.setUserSettings(updatedSettings))),
4631
- general_api_default.post(`${useradmApiUrlv1}/settings/me`, updatedSettings, { headers })
4632
- ]).catch(() => dispatch(actions8.setUserSettings(userSettings)));
4633
+ }).finally(() => {
4634
+ const device = getDeviceById(getState(), deviceId);
4635
+ Promise.resolve(dispatch(actions3.receivedDevice({ ...device, twinsByIntegration: { ...device.twinsByIntegration, ...providerResult } })));
4633
4636
  });
4634
4637
  });
4635
- var get2FAQRCode = (0, import_toolkit21.createAsyncThunk)(
4636
- `${sliceName8}/get2FAQRCode`,
4637
- (_, { dispatch }) => general_api_default.get(`${useradmApiUrlv1}/2faqr`).then((res) => dispatch(actions8.receivedQrCode(res.data.qr)))
4638
- );
4639
- var setHideAnnouncement = (0, import_toolkit21.createAsyncThunk)(`${sliceName8}/setHideAnnouncement`, ({ shouldHide, userId }, { dispatch, getState }) => {
4640
- const currentUserId = userId || getCurrentUser(getState()).id;
4641
- const hash = getState().app.hostedAnnouncement ? (0, import_md5.default)(getState().app.hostedAnnouncement) : "";
4642
- const announceCookie = cookies3.get(`${currentUserId}${hash}`);
4643
- if (shouldHide || hash.length && typeof announceCookie !== "undefined") {
4644
- cookies3.set(`${currentUserId}${hash}`, true, { maxAge: 604800 });
4645
- return Promise.resolve(dispatch(setAnnouncement()));
4646
- }
4647
- return Promise.resolve();
4648
- });
4649
- var getTokens = (0, import_toolkit21.createAsyncThunk)(
4650
- `${sliceName8}/getTokens`,
4651
- (_, { dispatch, getState }) => general_api_default.get(`${useradmApiUrlv1}/settings/tokens`).then(({ data: tokens }) => {
4652
- const user = getCurrentUser(getState());
4653
- const updatedUser = {
4654
- ...user,
4655
- tokens
4656
- };
4657
- return Promise.resolve(dispatch(actions8.updatedUser(updatedUser)));
4638
+ var setDeviceTwin = (0, import_toolkit21.createAsyncThunk)(
4639
+ `${sliceName3}/setDeviceTwin`,
4640
+ ({ deviceId, integration, settings }, { dispatch, getState }) => general_api_default.put(`${iotManagerBaseURL}/devices/${deviceId}/state/${integration.id}`, { desired: settings }).catch(
4641
+ (err) => commonErrorHandler(
4642
+ err,
4643
+ `There was an error updating the ${EXTERNAL_PROVIDER[integration.provider].twinTitle.toLowerCase()} for device ${deviceId}.`,
4644
+ dispatch
4645
+ )
4646
+ ).then(() => {
4647
+ const device = getDeviceById(getState(), deviceId);
4648
+ const { twinsByIntegration = {} } = device;
4649
+ const { [integration.id]: currentState = {} } = twinsByIntegration;
4650
+ return Promise.resolve(
4651
+ dispatch(actions3.receivedDevice({ ...device, twinsByIntegration: { ...twinsByIntegration, [integration.id]: { ...currentState, desired: settings } } }))
4652
+ );
4658
4653
  })
4659
4654
  );
4660
- var ONE_YEAR = 31536e3;
4661
- var generateToken = (0, import_toolkit21.createAsyncThunk)(
4662
- `${sliceName8}/generateToken`,
4663
- ({ expiresIn = ONE_YEAR, name }, { dispatch }) => general_api_default.post(`${useradmApiUrlv1}/settings/tokens`, { name, expires_in: expiresIn }).then(({ data: token }) => Promise.all([dispatch(getTokens()), token])).catch((err) => commonErrorHandler(err, "There was an error creating the token:", dispatch))
4664
- );
4665
- var revokeToken = (0, import_toolkit21.createAsyncThunk)(
4666
- `${sliceName8}/revokeToken`,
4667
- (token, { dispatch }) => (
4668
- // @ts-ignore
4669
- general_api_default.delete(`${useradmApiUrlv1}/settings/tokens/${token.id}`).then(() => Promise.resolve(dispatch(getTokens())))
4670
- )
4671
- );
4672
- var setTooltipReadState = (0, import_toolkit21.createAsyncThunk)(`${sliceName8}/setTooltipReadState`, ({ persist, ...remainder }, { dispatch }) => {
4673
- let tasks = [dispatch(actions8.setTooltipState(remainder))];
4674
- if (persist) {
4675
- tasks.push(dispatch(saveUserSettings()));
4655
+ var prepareSearchArguments = ({ filters, group, state, status }) => {
4656
+ const { filterTerms } = convertDeviceListStateToFilters({ filters, group, offlineThreshold: state.app.offlineThreshold, selectedIssues: [], status });
4657
+ const { columnSelection = [] } = getUserSettings(state);
4658
+ const selectedAttributes = columnSelection.map((column) => ({ attribute: column.key, scope: column.scope }));
4659
+ const attributes = [...defaultAttributes, getIdAttribute(state), ...selectedAttributes];
4660
+ return { attributes, filterTerms };
4661
+ };
4662
+ var getSystemDevices = (0, import_toolkit21.createAsyncThunk)(`${sliceName3}/getSystemDevices`, (options, { dispatch, getState }) => {
4663
+ const { id, page = defaultPage3, perPage = defaultPerPage3, sortOptions = [] } = options;
4664
+ const state = getState();
4665
+ const { hasFullFiltering } = getTenantCapabilities(state);
4666
+ if (!hasFullFiltering) {
4667
+ return Promise.resolve();
4676
4668
  }
4677
- return Promise.all(tasks);
4669
+ const { attributes: deviceAttributes = {} } = getDeviceById(state, id);
4670
+ const { mender_gateway_system_id = "" } = deviceAttributes;
4671
+ const filters = [
4672
+ { ...emptyFilter, key: "mender_is_gateway", operator: DEVICE_FILTERING_OPTIONS.$ne.key, value: "true", scope: "inventory" },
4673
+ { ...emptyFilter, key: "mender_gateway_system_id", value: mender_gateway_system_id, scope: "inventory" }
4674
+ ];
4675
+ const { attributes, filterTerms } = prepareSearchArguments({ filters, state });
4676
+ return general_api_default.post(getSearchEndpoint(getState()), {
4677
+ page,
4678
+ per_page: perPage,
4679
+ filters: filterTerms,
4680
+ sort: sortOptions,
4681
+ attributes
4682
+ }).catch((err) => commonErrorHandler(err, `There was an error getting system devices device ${id}.`, dispatch, "Please check your connection.")).then(({ data, headers }) => {
4683
+ const state2 = getState();
4684
+ const { devicesById, ids } = reduceReceivedDevices(data, [], state2);
4685
+ const device = {
4686
+ ...getDeviceById(state2, id),
4687
+ systemDeviceIds: ids,
4688
+ systemDeviceTotal: Number(headers[headerNames.total])
4689
+ };
4690
+ return Promise.resolve(dispatch(actions3.receivedDevices({ ...devicesById, [id]: device })));
4691
+ });
4678
4692
  });
4679
- var setAllTooltipsReadState = (0, import_toolkit21.createAsyncThunk)(`${sliceName8}/toggleHelptips`, ({ readState = READ_STATES.read, tooltips }, { dispatch }) => {
4680
- const updatedTips = tooltips.reduce((accu, id) => ({ ...accu, [id]: { readState } }), {});
4681
- return Promise.resolve(dispatch(actions8.setTooltipsState(updatedTips))).then(() => dispatch(saveUserSettings()));
4693
+ var getGatewayDevices = (0, import_toolkit21.createAsyncThunk)(`${sliceName3}/getGatewayDevices`, (deviceId, { dispatch, getState }) => {
4694
+ const state = getState();
4695
+ const { attributes = {} } = getDeviceById(state, deviceId);
4696
+ const { mender_gateway_system_id = "" } = attributes;
4697
+ const filters = [
4698
+ { ...emptyFilter, key: "id", operator: DEVICE_FILTERING_OPTIONS.$ne.key, value: deviceId, scope: "identity" },
4699
+ { ...emptyFilter, key: "mender_is_gateway", value: "true", scope: "inventory" },
4700
+ { ...emptyFilter, key: "mender_gateway_system_id", value: mender_gateway_system_id, scope: "inventory" }
4701
+ ];
4702
+ const { attributes: attributeSelection, filterTerms } = prepareSearchArguments({ filters, state });
4703
+ return general_api_default.post(getSearchEndpoint(getState()), {
4704
+ page: 1,
4705
+ per_page: MAX_PAGE_SIZE,
4706
+ filters: filterTerms,
4707
+ attributes: attributeSelection
4708
+ }).then(({ data }) => {
4709
+ const { ids } = reduceReceivedDevices(data, [], getState());
4710
+ let tasks = ids.map((deviceId2) => dispatch(getDeviceInfo(deviceId2)));
4711
+ tasks.push(dispatch(actions3.receivedDevice({ id: deviceId, gatewayIds: ids })));
4712
+ return Promise.all(tasks);
4713
+ });
4714
+ });
4715
+ var getDevicesInBounds = (0, import_toolkit21.createAsyncThunk)(`${sliceName3}/getDevicesInBounds`, ({ bounds, group }, { dispatch, getState }) => {
4716
+ const state = getState();
4717
+ const { filterTerms } = convertDeviceListStateToFilters({
4718
+ group: group === ALL_DEVICES ? void 0 : group,
4719
+ groups: state.devices.groups,
4720
+ status: DEVICE_STATES.accepted
4721
+ });
4722
+ return general_api_default.post(getSearchEndpoint(getState()), {
4723
+ page: 1,
4724
+ per_page: MAX_PAGE_SIZE,
4725
+ filters: filterTerms,
4726
+ attributes: geoAttributes,
4727
+ geo_bounding_box_filter: {
4728
+ geo_bounding_box: {
4729
+ location: {
4730
+ top_left: { lat: bounds._northEast.lat, lon: bounds._southWest.lng },
4731
+ bottom_right: { lat: bounds._southWest.lat, lon: bounds._northEast.lng }
4732
+ }
4733
+ }
4734
+ }
4735
+ }).then(({ data }) => {
4736
+ const { devicesById } = reduceReceivedDevices(data, [], getState());
4737
+ return Promise.resolve(dispatch(actions3.receivedDevices(devicesById)));
4738
+ });
4682
4739
  });
4683
- var submitFeedback = (0, import_toolkit21.createAsyncThunk)(
4684
- `${sliceName8}/submitFeedback`,
4685
- // @ts-ignore
4686
- ({ satisfaction, feedback, ...meta }, { dispatch }) => {
4687
- return general_api_default.post(`${tenantadmApiUrlv2}/contact/support`, {
4688
- subject: "feedback submission",
4689
- body: JSON.stringify({ feedback, satisfaction, meta })
4690
- }).then(() => {
4691
- const today = /* @__PURE__ */ new Date();
4692
- dispatch(saveUserSettings({ feedbackCollectedAt: today.toISOString().split("T")[0] }));
4693
- setTimeout(() => dispatch(actions8.setShowFeedbackDialog(false)), TIMEOUTS.threeSeconds);
4694
- });
4695
- }
4696
- );
4697
4740
 
4698
4741
  // src/organizationSlice/thunks.ts
4699
4742
  var import_helpers11 = require("@northern.tech/utils/helpers");
@@ -4770,7 +4813,7 @@ var startUpgrade = (0, import_toolkit22.createAsyncThunk)(
4770
4813
  var cancelUpgrade = (0, import_toolkit22.createAsyncThunk)(`${sliceName6}/cancelUpgrade`, (tenantId) => general_api_default.post(`${tenantadmApiUrlv2}/tenants/${tenantId}/upgrade/cancel`));
4771
4814
  var completeUpgrade = (0, import_toolkit22.createAsyncThunk)(
4772
4815
  `${sliceName6}/completeUpgrade`,
4773
- ({ tenantId, plan }, { dispatch }) => general_api_default.post(`${tenantadmApiUrlv2}/tenants/${tenantId}/upgrade/complete`, { plan }).catch((err) => commonErrorHandler(err, `There was an error upgrading your account:`, dispatch)).then(() => Promise.resolve(dispatch(getUserOrganization())))
4816
+ ({ tenantId, plan, billing_profile }, { dispatch }) => general_api_default.post(`${tenantadmApiUrlv2}/tenants/${tenantId}/upgrade/complete`, { plan, billing_profile }).catch((err) => commonErrorHandler(err, `There was an error upgrading your account:`, dispatch)).then(() => Promise.all([dispatch(getDeviceLimit2()), dispatch(getUserOrganization())]))
4774
4817
  );
4775
4818
  var prepareAuditlogQuery = ({ startDate, endDate, user: userFilter, type, detail: detailFilter, sort = {} }) => {
4776
4819
  const userId = userFilter?.id || userFilter;
@@ -4818,9 +4861,15 @@ var setAuditlogsState = (0, import_toolkit22.createAsyncThunk)(`${sliceName6}/se
4818
4861
  return Promise.all(tasks);
4819
4862
  });
4820
4863
  var tenantDataDivergedMessage = "The system detected there is a change in your plan or purchased add-ons. Please log out and log in again";
4821
- var addTenant = (0, import_toolkit22.createAsyncThunk)(`${sliceName6}/createTenant`, (selectionState, { dispatch }) => {
4822
- return general_api_default.post(`${tenantadmApiUrlv2}/tenants`, selectionState).then(() => Promise.all([dispatch(getTenants()), dispatch(setSnackbar5("Tenant was created successfully."))])).catch((err) => commonErrorHandler(err, "There was an error creating tenant", dispatch, commonErrorFallback));
4823
- });
4864
+ var addTenant = (0, import_toolkit22.createAsyncThunk)(
4865
+ `${sliceName6}/createTenant`,
4866
+ (selectionState, { dispatch }) => general_api_default.post(`${tenantadmApiUrlv2}/tenants`, selectionState).then(
4867
+ () => Promise.all([
4868
+ dispatch(setSnackbar5("Tenant was created successfully.")),
4869
+ new Promise((resolve) => setTimeout(() => resolve(dispatch(getTenants())), TIMEOUTS.oneSecond))
4870
+ ])
4871
+ ).catch((err) => commonErrorHandler(err, "There was an error creating tenant", dispatch, commonErrorFallback))
4872
+ );
4824
4873
  var tenantListRetrieval = async (config) => {
4825
4874
  const { page, perPage } = config;
4826
4875
  const params = new URLSearchParams({ page, per_page: perPage }).toString();
@@ -4845,21 +4894,29 @@ var setTenantsListState = (0, import_toolkit22.createAsyncThunk)(`${sliceName6}/
4845
4894
  }
4846
4895
  return dispatch(actions6.setTenantListState({ ...nextState }));
4847
4896
  });
4848
- var editTenantDeviceLimit = (0, import_toolkit22.createAsyncThunk)(`${sliceName6}/editDeviceLimit`, ({ newLimit, id, name }, { dispatch }) => {
4849
- return general_api_default.put(`${tenantadmApiUrlv2}/tenants/${id}/child`, { device_limit: newLimit, name }).catch((err) => commonErrorHandler(err, `Device Limit cannot be changed`, dispatch)).then(() => {
4850
- const tasks = [Promise.resolve(dispatch(setSnackbar5("Device Limit was changed successfully")))];
4851
- tasks.push(dispatch(getTenants()));
4852
- tasks.push(dispatch(getUserOrganization()));
4853
- return Promise.all(tasks);
4854
- });
4855
- });
4856
- var removeTenant = (0, import_toolkit22.createAsyncThunk)(`${sliceName6}/editDeviceLimit`, ({ id }, { dispatch }) => {
4857
- return general_api_default.post(`${tenantadmApiUrlv2}/tenants/${id}/remove/start`).catch((err) => commonErrorHandler(err, `There was an error removing the tenant`, dispatch)).then(
4858
- () => Promise.all([Promise.resolve(dispatch(setSnackbar5("Device Limit was changed successfully"))), dispatch(getTenants()), dispatch(getUserOrganization())])
4859
- );
4860
- });
4861
- var getUserOrganization = (0, import_toolkit22.createAsyncThunk)(`${sliceName6}/getUserOrganization`, (_, { dispatch, getState }) => {
4862
- return general_api_default.get(`${tenantadmApiUrlv1}/user/tenant`).then((res) => {
4897
+ var editTenantDeviceLimit = (0, import_toolkit22.createAsyncThunk)(
4898
+ `${sliceName6}/editDeviceLimit`,
4899
+ ({ newLimit, id, name }, { dispatch }) => general_api_default.put(`${tenantadmApiUrlv2}/tenants/${id}/child`, { device_limit: newLimit, name }).catch((err) => commonErrorHandler(err, `Device Limit cannot be changed`, dispatch)).then(
4900
+ () => Promise.all([
4901
+ dispatch(setSnackbar5("Device Limit was changed successfully")),
4902
+ dispatch(getUserOrganization()),
4903
+ new Promise((resolve) => setTimeout(() => resolve(dispatch(getTenants())), TIMEOUTS.oneSecond))
4904
+ ])
4905
+ )
4906
+ );
4907
+ var removeTenant = (0, import_toolkit22.createAsyncThunk)(
4908
+ `${sliceName6}/editDeviceLimit`,
4909
+ ({ id }, { dispatch }) => general_api_default.post(`${tenantadmApiUrlv2}/tenants/${id}/remove/start`).catch((err) => commonErrorHandler(err, `There was an error removing the tenant`, dispatch)).then(
4910
+ () => Promise.all([
4911
+ dispatch(setSnackbar5("The tenant was removed successfully")),
4912
+ dispatch(getUserOrganization()),
4913
+ new Promise((resolve) => setTimeout(() => resolve(dispatch(getTenants())), TIMEOUTS.oneSecond))
4914
+ ])
4915
+ )
4916
+ );
4917
+ var getUserOrganization = (0, import_toolkit22.createAsyncThunk)(
4918
+ `${sliceName6}/getUserOrganization`,
4919
+ (_, { dispatch, getState }) => general_api_default.get(`${tenantadmApiUrlv1}/user/tenant`).then((res) => {
4863
4920
  let tasks = [dispatch(actions6.setOrganization(res.data))];
4864
4921
  const { addons, plan, trial } = res.data;
4865
4922
  const { token } = getCurrentSession(getState());
@@ -4871,15 +4928,18 @@ var getUserOrganization = (0, import_toolkit22.createAsyncThunk)(`${sliceName6}/
4871
4928
  tasks.push(dispatch(setAnnouncement2(tenantDataDivergedMessage)));
4872
4929
  }
4873
4930
  return Promise.all(tasks);
4874
- });
4875
- });
4931
+ })
4932
+ );
4876
4933
  var sendSupportMessage = (0, import_toolkit22.createAsyncThunk)(
4877
4934
  `${sliceName6}/sendSupportMessage`,
4878
4935
  (content, { dispatch }) => general_api_default.post(`${tenantadmApiUrlv2}/contact/support`, content).catch((err) => commonErrorHandler(err, "There was an error sending your request", dispatch, commonErrorFallback)).then(() => Promise.resolve(dispatch(setSnackbar5({ message: "Your request was sent successfully", autoHideDuration: TIMEOUTS.fiveSeconds }))))
4879
4936
  );
4880
4937
  var requestPlanChange = (0, import_toolkit22.createAsyncThunk)(
4881
4938
  `${sliceName6}/requestPlanChange`,
4882
- ({ content, tenantId }, { dispatch }) => general_api_default.post(`${tenantadmApiUrlv2}/tenants/${tenantId}/plan`, content).catch((err) => commonErrorHandler(err, "There was an error sending your request", dispatch, commonErrorFallback)).then(() => Promise.resolve(dispatch(setSnackbar5({ message: "Your request was sent successfully", autoHideDuration: TIMEOUTS.fiveSeconds }))))
4939
+ ({ content, tenantId }, { dispatch, rejectWithValue }) => general_api_default.post(`${tenantadmApiUrlv2}/tenants/${tenantId}/plan`, content).catch(async (err) => {
4940
+ await commonErrorHandler(err, "There was an error sending your request", dispatch, commonErrorFallback);
4941
+ rejectWithValue(err);
4942
+ }).then(() => Promise.resolve(dispatch(setSnackbar5({ message: "Your request was sent successfully", autoHideDuration: TIMEOUTS.fiveSeconds }))))
4883
4943
  );
4884
4944
  var downloadLicenseReport = (0, import_toolkit22.createAsyncThunk)(
4885
4945
  `${sliceName6}/downloadLicenseReport`,