@verdaccio/ui-components 5.0.0-next-9.19 → 5.0.0-next-9.21

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 (312) hide show
  1. package/build/api/use-data-mutation.js +1 -4
  2. package/build/api/use-data-mutation.js.map +1 -1
  3. package/build/api/use-data-mutation.mjs +1 -4
  4. package/build/api/use-data-mutation.mjs.map +1 -1
  5. package/build/api/use-data.d.ts +1 -0
  6. package/build/api/use-data.js +3 -2
  7. package/build/api/use-data.js.map +1 -1
  8. package/build/api/use-data.mjs +3 -3
  9. package/build/api/use-data.mjs.map +1 -1
  10. package/build/components/ActionBar/ActionBar.js +4 -2
  11. package/build/components/ActionBar/ActionBar.js.map +1 -1
  12. package/build/components/ActionBar/ActionBar.mjs +4 -2
  13. package/build/components/ActionBar/ActionBar.mjs.map +1 -1
  14. package/build/components/ActionBar/ActionBarAction.js +1 -1
  15. package/build/components/ActionBar/ActionBarAction.mjs +1 -1
  16. package/build/components/AppRoute/AppRoute.js +13 -0
  17. package/build/components/AppRoute/AppRoute.js.map +1 -1
  18. package/build/components/AppRoute/AppRoute.mjs +13 -0
  19. package/build/components/AppRoute/AppRoute.mjs.map +1 -1
  20. package/build/components/Author/Author.js +1 -1
  21. package/build/components/Author/Author.mjs +1 -1
  22. package/build/components/CopyClipboard/CopyToClipBoard.js +5 -0
  23. package/build/components/CopyClipboard/CopyToClipBoard.js.map +1 -1
  24. package/build/components/CopyClipboard/CopyToClipBoard.mjs +5 -0
  25. package/build/components/CopyClipboard/CopyToClipBoard.mjs.map +1 -1
  26. package/build/components/CopyClipboard/utils.js +14 -1
  27. package/build/components/CopyClipboard/utils.js.map +1 -1
  28. package/build/components/CopyClipboard/utils.mjs +14 -1
  29. package/build/components/CopyClipboard/utils.mjs.map +1 -1
  30. package/build/components/Dependencies/Dependencies.js +2 -1
  31. package/build/components/Dependencies/Dependencies.js.map +1 -1
  32. package/build/components/Dependencies/Dependencies.mjs +2 -1
  33. package/build/components/Dependencies/Dependencies.mjs.map +1 -1
  34. package/build/components/Dependencies/DependencyBlock.js +1 -1
  35. package/build/components/Dependencies/DependencyBlock.mjs +1 -1
  36. package/build/components/Developers/Title.js +1 -1
  37. package/build/components/Developers/Title.mjs +1 -1
  38. package/build/components/Developers/get-unique-developer-values.js +2 -1
  39. package/build/components/Developers/get-unique-developer-values.js.map +1 -1
  40. package/build/components/Developers/get-unique-developer-values.mjs +2 -1
  41. package/build/components/Developers/get-unique-developer-values.mjs.map +1 -1
  42. package/build/components/Distribution/Dist.js +3 -3
  43. package/build/components/Distribution/Dist.js.map +1 -1
  44. package/build/components/Distribution/Dist.mjs +3 -3
  45. package/build/components/Distribution/Dist.mjs.map +1 -1
  46. package/build/components/Engines/Engines.js +1 -1
  47. package/build/components/Engines/Engines.mjs +1 -1
  48. package/build/components/Forbidden/Forbidden.js +1 -1
  49. package/build/components/Forbidden/Forbidden.mjs +1 -1
  50. package/build/components/FundButton/FundButton.js +4 -3
  51. package/build/components/FundButton/FundButton.js.map +1 -1
  52. package/build/components/FundButton/FundButton.mjs +4 -3
  53. package/build/components/FundButton/FundButton.mjs.map +1 -1
  54. package/build/components/GenericError/GenericError.d.ts +3 -0
  55. package/build/components/GenericError/GenericError.js +60 -0
  56. package/build/components/GenericError/GenericError.js.map +1 -0
  57. package/build/components/GenericError/GenericError.mjs +54 -0
  58. package/build/components/GenericError/GenericError.mjs.map +1 -0
  59. package/build/components/GenericError/index.d.ts +1 -0
  60. package/build/components/GenericError/index.js +2 -0
  61. package/build/components/GenericError/index.mjs +2 -0
  62. package/build/components/Help/Help.js +1 -1
  63. package/build/components/Help/Help.mjs +1 -1
  64. package/build/components/Install/Install.js +1 -1
  65. package/build/components/Install/Install.mjs +1 -1
  66. package/build/components/Install/InstallListItem.js +2 -2
  67. package/build/components/Install/InstallListItem.js.map +1 -1
  68. package/build/components/Install/InstallListItem.mjs +2 -2
  69. package/build/components/Install/InstallListItem.mjs.map +1 -1
  70. package/build/components/Keywords/KeywordListItems.js +1 -1
  71. package/build/components/Keywords/KeywordListItems.js.map +1 -1
  72. package/build/components/Keywords/KeywordListItems.mjs +1 -1
  73. package/build/components/Keywords/KeywordListItems.mjs.map +1 -1
  74. package/build/components/Keywords/Keywords.js +2 -2
  75. package/build/components/Keywords/Keywords.js.map +1 -1
  76. package/build/components/Keywords/Keywords.mjs +2 -2
  77. package/build/components/Keywords/Keywords.mjs.map +1 -1
  78. package/build/components/LoginDialog/LoginDialogCloseButton.js +1 -1
  79. package/build/components/LoginDialog/LoginDialogCloseButton.mjs +1 -1
  80. package/build/components/LoginDialog/LoginDialogForm.js +2 -1
  81. package/build/components/LoginDialog/LoginDialogForm.js.map +1 -1
  82. package/build/components/LoginDialog/LoginDialogForm.mjs +2 -1
  83. package/build/components/LoginDialog/LoginDialogForm.mjs.map +1 -1
  84. package/build/components/LoginForm/Login.d.ts +1 -0
  85. package/build/components/LoginForm/Login.js +6 -4
  86. package/build/components/LoginForm/Login.js.map +1 -1
  87. package/build/components/LoginForm/Login.mjs +9 -7
  88. package/build/components/LoginForm/Login.mjs.map +1 -1
  89. package/build/components/LoginForm/PasswordField.js +4 -6
  90. package/build/components/LoginForm/PasswordField.js.map +1 -1
  91. package/build/components/LoginForm/PasswordField.mjs +4 -6
  92. package/build/components/LoginForm/PasswordField.mjs.map +1 -1
  93. package/build/components/LoginForm/UsernameField.js +4 -6
  94. package/build/components/LoginForm/UsernameField.js.map +1 -1
  95. package/build/components/LoginForm/UsernameField.mjs +4 -6
  96. package/build/components/LoginForm/UsernameField.mjs.map +1 -1
  97. package/build/components/LoginForm/styles.js +1 -1
  98. package/build/components/LoginForm/styles.mjs +1 -1
  99. package/build/components/LoginForm/useLoginForm.js +13 -3
  100. package/build/components/LoginForm/useLoginForm.js.map +1 -1
  101. package/build/components/LoginForm/useLoginForm.mjs +14 -4
  102. package/build/components/LoginForm/useLoginForm.mjs.map +1 -1
  103. package/build/components/NoItems/NoItems.js +2 -2
  104. package/build/components/NoItems/NoItems.mjs +1 -1
  105. package/build/components/NotFound/NotFound.js +1 -1
  106. package/build/components/NotFound/NotFound.mjs +1 -1
  107. package/build/components/Package/Package.d.ts +1 -1
  108. package/build/components/Package/Package.js +28 -29
  109. package/build/components/Package/Package.js.map +1 -1
  110. package/build/components/Package/Package.mjs +29 -30
  111. package/build/components/Package/Package.mjs.map +1 -1
  112. package/build/components/Person/Person.js +1 -1
  113. package/build/components/Person/Person.js.map +1 -1
  114. package/build/components/Person/Person.mjs +1 -1
  115. package/build/components/Person/Person.mjs.map +1 -1
  116. package/build/components/RawViewer/RawViewer.js +1 -1
  117. package/build/components/RawViewer/RawViewer.mjs +1 -1
  118. package/build/components/RegistryInfoDialog/RegistryInfoDialog.js +1 -1
  119. package/build/components/RegistryInfoDialog/RegistryInfoDialog.mjs +1 -1
  120. package/build/components/Repository/Repository.js +5 -8
  121. package/build/components/Repository/Repository.js.map +1 -1
  122. package/build/components/Repository/Repository.mjs +5 -8
  123. package/build/components/Repository/Repository.mjs.map +1 -1
  124. package/build/components/Search/AutoComplete/AutoComplete.d.ts +1 -0
  125. package/build/components/Search/AutoComplete/AutoComplete.js +4 -4
  126. package/build/components/Search/AutoComplete/AutoComplete.js.map +1 -1
  127. package/build/components/Search/AutoComplete/AutoComplete.mjs +4 -4
  128. package/build/components/Search/AutoComplete/AutoComplete.mjs.map +1 -1
  129. package/build/components/Search/Search.js +12 -4
  130. package/build/components/Search/Search.js.map +1 -1
  131. package/build/components/Search/Search.mjs +13 -5
  132. package/build/components/Search/Search.mjs.map +1 -1
  133. package/build/components/Search/SearchItem.js +1 -1
  134. package/build/components/Search/SearchItem.mjs +1 -1
  135. package/build/components/SettingsMenu/SettingsMenu.js +1 -1
  136. package/build/components/SettingsMenu/SettingsMenu.mjs +1 -1
  137. package/build/components/SideBarTitle/SideBarTitle.js +2 -2
  138. package/build/components/SideBarTitle/SideBarTitle.js.map +1 -1
  139. package/build/components/SideBarTitle/SideBarTitle.mjs +2 -2
  140. package/build/components/SideBarTitle/SideBarTitle.mjs.map +1 -1
  141. package/build/components/UpLinks/UpLinks.js +1 -1
  142. package/build/components/UpLinks/UpLinks.mjs +1 -1
  143. package/build/components/Versions/HistoryList.js +2 -2
  144. package/build/components/Versions/HistoryList.js.map +1 -1
  145. package/build/components/Versions/HistoryList.mjs +2 -2
  146. package/build/components/Versions/HistoryList.mjs.map +1 -1
  147. package/build/components/Versions/Versions.js +22 -21
  148. package/build/components/Versions/Versions.js.map +1 -1
  149. package/build/components/Versions/Versions.mjs +22 -21
  150. package/build/components/Versions/Versions.mjs.map +1 -1
  151. package/build/index.d.ts +1 -0
  152. package/build/index.js +4 -0
  153. package/build/index.mjs +4 -2
  154. package/build/pages/Stage/StageDetail.d.ts +2 -0
  155. package/build/pages/Stage/StageDetail.js +8 -0
  156. package/build/pages/Stage/StageDetail.js.map +1 -0
  157. package/build/pages/Stage/StageDetail.mjs +8 -0
  158. package/build/pages/Stage/StageDetail.mjs.map +1 -0
  159. package/build/pages/Stage/StageList.d.ts +2 -0
  160. package/build/pages/Stage/StageList.js +8 -0
  161. package/build/pages/Stage/StageList.js.map +1 -0
  162. package/build/pages/Stage/StageList.mjs +8 -0
  163. package/build/pages/Stage/StageList.mjs.map +1 -0
  164. package/build/pages/Stage/index.d.ts +2 -0
  165. package/build/pages/Version/Version.js +4 -1
  166. package/build/pages/Version/Version.js.map +1 -1
  167. package/build/pages/Version/Version.mjs +4 -1
  168. package/build/pages/Version/Version.mjs.map +1 -1
  169. package/build/providers/AuthProvider/AuthProvider.js +9 -7
  170. package/build/providers/AuthProvider/AuthProvider.js.map +1 -1
  171. package/build/providers/AuthProvider/AuthProvider.mjs +10 -8
  172. package/build/providers/AuthProvider/AuthProvider.mjs.map +1 -1
  173. package/build/providers/AuthProvider/utils.d.ts +12 -0
  174. package/build/providers/AuthProvider/utils.js +22 -0
  175. package/build/providers/AuthProvider/utils.js.map +1 -1
  176. package/build/providers/AuthProvider/utils.mjs +21 -2
  177. package/build/providers/AuthProvider/utils.mjs.map +1 -1
  178. package/build/providers/DownloadProvider/DownloadProvider.d.ts +1 -0
  179. package/build/providers/DownloadProvider/DownloadProvider.js +27 -4
  180. package/build/providers/DownloadProvider/DownloadProvider.js.map +1 -1
  181. package/build/providers/DownloadProvider/DownloadProvider.mjs +27 -6
  182. package/build/providers/DownloadProvider/DownloadProvider.mjs.map +1 -1
  183. package/build/providers/ManifestsProvider/ManifestsProvider.js +1 -1
  184. package/build/providers/ManifestsProvider/ManifestsProvider.js.map +1 -1
  185. package/build/providers/ManifestsProvider/ManifestsProvider.mjs +1 -1
  186. package/build/providers/ManifestsProvider/ManifestsProvider.mjs.map +1 -1
  187. package/build/providers/SearchProvider/SearchProvider.d.ts +1 -0
  188. package/build/providers/SearchProvider/SearchProvider.js +8 -6
  189. package/build/providers/SearchProvider/SearchProvider.js.map +1 -1
  190. package/build/providers/SearchProvider/SearchProvider.mjs +8 -6
  191. package/build/providers/SearchProvider/SearchProvider.mjs.map +1 -1
  192. package/build/providers/TranslatorProvider/TranslatorProvider.js +5 -3
  193. package/build/providers/TranslatorProvider/TranslatorProvider.js.map +1 -1
  194. package/build/providers/TranslatorProvider/TranslatorProvider.mjs +5 -3
  195. package/build/providers/TranslatorProvider/TranslatorProvider.mjs.map +1 -1
  196. package/build/providers/VersionProvider/VersionProvider.js +3 -3
  197. package/build/providers/VersionProvider/VersionProvider.js.map +1 -1
  198. package/build/providers/VersionProvider/VersionProvider.mjs +3 -3
  199. package/build/providers/VersionProvider/VersionProvider.mjs.map +1 -1
  200. package/build/sections/Detail/Tabs.js +1 -1
  201. package/build/sections/Detail/Tabs.mjs +1 -1
  202. package/build/sections/Footer/Footer.js +1 -1
  203. package/build/sections/Footer/Footer.mjs +1 -1
  204. package/build/sections/Header/Header.d.ts +0 -1
  205. package/build/sections/Header/Header.js +16 -14
  206. package/build/sections/Header/Header.js.map +1 -1
  207. package/build/sections/Header/Header.mjs +17 -15
  208. package/build/sections/Header/Header.mjs.map +1 -1
  209. package/build/sections/Header/HeaderGreetings.js +1 -1
  210. package/build/sections/Header/HeaderGreetings.mjs +1 -1
  211. package/build/sections/Header/HeaderMenu.js +26 -7
  212. package/build/sections/Header/HeaderMenu.js.map +1 -1
  213. package/build/sections/Header/HeaderMenu.mjs +26 -7
  214. package/build/sections/Header/HeaderMenu.mjs.map +1 -1
  215. package/build/sections/Header/HeaderRight.js +1 -1
  216. package/build/sections/Header/HeaderRight.mjs +1 -1
  217. package/build/sections/Header/HeaderSettingsDialog.js +1 -1
  218. package/build/sections/Header/HeaderSettingsDialog.mjs +1 -1
  219. package/build/sections/Header/LanguageSwitch.js +1 -1
  220. package/build/sections/Header/LanguageSwitch.mjs +1 -1
  221. package/build/sections/Header/RegistryInfoContent/RegistryInfoContent.js +1 -1
  222. package/build/sections/Header/RegistryInfoContent/RegistryInfoContent.mjs +1 -1
  223. package/build/sections/Home/Home.js +4 -3
  224. package/build/sections/Home/Home.js.map +1 -1
  225. package/build/sections/Home/Home.mjs +5 -4
  226. package/build/sections/Home/Home.mjs.map +1 -1
  227. package/build/sections/Security/AddUser.js +33 -18
  228. package/build/sections/Security/AddUser.js.map +1 -1
  229. package/build/sections/Security/AddUser.mjs +37 -22
  230. package/build/sections/Security/AddUser.mjs.map +1 -1
  231. package/build/sections/Security/ChangePassword.js +17 -15
  232. package/build/sections/Security/ChangePassword.js.map +1 -1
  233. package/build/sections/Security/ChangePassword.mjs +19 -17
  234. package/build/sections/Security/ChangePassword.mjs.map +1 -1
  235. package/build/sections/Security/Login.js +51 -35
  236. package/build/sections/Security/Login.js.map +1 -1
  237. package/build/sections/Security/Login.mjs +54 -38
  238. package/build/sections/Security/Login.mjs.map +1 -1
  239. package/build/sections/Security/Success.js +28 -24
  240. package/build/sections/Security/Success.js.map +1 -1
  241. package/build/sections/Security/Success.mjs +29 -25
  242. package/build/sections/Security/Success.mjs.map +1 -1
  243. package/build/sections/Stage/StageActions.d.ts +15 -0
  244. package/build/sections/Stage/StageActions.js +101 -0
  245. package/build/sections/Stage/StageActions.js.map +1 -0
  246. package/build/sections/Stage/StageActions.mjs +99 -0
  247. package/build/sections/Stage/StageActions.mjs.map +1 -0
  248. package/build/sections/Stage/StageDetail.d.ts +3 -0
  249. package/build/sections/Stage/StageDetail.js +110 -0
  250. package/build/sections/Stage/StageDetail.js.map +1 -0
  251. package/build/sections/Stage/StageDetail.mjs +108 -0
  252. package/build/sections/Stage/StageDetail.mjs.map +1 -0
  253. package/build/sections/Stage/StageList.d.ts +3 -0
  254. package/build/sections/Stage/StageList.js +153 -0
  255. package/build/sections/Stage/StageList.js.map +1 -0
  256. package/build/sections/Stage/StageList.mjs +151 -0
  257. package/build/sections/Stage/StageList.mjs.map +1 -0
  258. package/build/sections/Stage/index.d.ts +6 -0
  259. package/build/sections/Stage/index.js +13 -0
  260. package/build/sections/Stage/index.mjs +6 -0
  261. package/build/sections/Stage/types.d.ts +22 -0
  262. package/build/sections/Stage/useRequireSession.d.ts +14 -0
  263. package/build/sections/Stage/useRequireSession.js +33 -0
  264. package/build/sections/Stage/useRequireSession.js.map +1 -0
  265. package/build/sections/Stage/useRequireSession.mjs +33 -0
  266. package/build/sections/Stage/useRequireSession.mjs.map +1 -0
  267. package/build/sections/Stage/useStage.d.ts +34 -0
  268. package/build/sections/Stage/useStage.js +71 -0
  269. package/build/sections/Stage/useStage.js.map +1 -0
  270. package/build/sections/Stage/useStage.mjs +65 -0
  271. package/build/sections/Stage/useStage.mjs.map +1 -0
  272. package/build/store/api.js +7 -4
  273. package/build/store/api.js.map +1 -1
  274. package/build/store/api.mjs +7 -4
  275. package/build/store/api.mjs.map +1 -1
  276. package/build/types/packageMeta.d.ts +3 -2
  277. package/build/utils/cli-utils.js +2 -2
  278. package/build/utils/cli-utils.js.map +1 -1
  279. package/build/utils/cli-utils.mjs +2 -2
  280. package/build/utils/cli-utils.mjs.map +1 -1
  281. package/build/utils/index.js +1 -0
  282. package/build/utils/index.mjs +2 -2
  283. package/build/utils/routes.d.ts +5 -1
  284. package/build/utils/routes.js +4 -0
  285. package/build/utils/routes.js.map +1 -1
  286. package/build/utils/routes.mjs +4 -0
  287. package/build/utils/routes.mjs.map +1 -1
  288. package/build/utils/schemas.d.ts +1 -0
  289. package/build/utils/schemas.js +4 -4
  290. package/build/utils/schemas.js.map +1 -1
  291. package/build/utils/schemas.mjs +4 -4
  292. package/build/utils/schemas.mjs.map +1 -1
  293. package/build/utils/session-id.d.ts +8 -0
  294. package/build/utils/session-id.js +26 -0
  295. package/build/utils/session-id.js.map +1 -0
  296. package/build/utils/session-id.mjs +26 -0
  297. package/build/utils/session-id.mjs.map +1 -0
  298. package/build/utils/token.d.ts +1 -0
  299. package/build/utils/token.js +12 -8
  300. package/build/utils/token.js.map +1 -1
  301. package/build/utils/token.mjs +12 -9
  302. package/build/utils/token.mjs.map +1 -1
  303. package/build/utils/url.js +1 -1
  304. package/build/utils/url.js.map +1 -1
  305. package/build/utils/url.mjs +1 -1
  306. package/build/utils/url.mjs.map +1 -1
  307. package/build/utils/utils.d.ts +10 -0
  308. package/build/utils/utils.js +26 -0
  309. package/build/utils/utils.js.map +1 -1
  310. package/build/utils/utils.mjs +25 -1
  311. package/build/utils/utils.mjs.map +1 -1
  312. package/package.json +6 -6
@@ -1,17 +1,18 @@
1
1
  import { useManifests } from "../../providers/ManifestsProvider/ManifestsProvider.mjs";
2
+ import GenericError from "../../components/GenericError/GenericError.mjs";
2
3
  import Loading from "../../components/Loading/Loading.mjs";
3
4
  import PackageList from "../../components/PackageList/PackageList.mjs";
4
5
  import "../../index.mjs";
5
6
  import "react";
6
- import { jsx, jsxs } from "react/jsx-runtime";
7
+ import { jsx } from "react/jsx-runtime";
7
8
  //#region src/sections/Home/Home.tsx
8
9
  var Home = () => {
9
10
  const manifests = useManifests();
10
- if (manifests.isError) return /* @__PURE__ */ jsx("div", { children: "Error loading manifests" });
11
- return /* @__PURE__ */ jsxs("div", {
11
+ if (manifests.isError) return /* @__PURE__ */ jsx(GenericError, {});
12
+ return /* @__PURE__ */ jsx("div", {
12
13
  className: "container content",
13
14
  "data-testid": "home-page-container",
14
- children: [manifests.isLoading ? /* @__PURE__ */ jsx(Loading, {}) : /* @__PURE__ */ jsx(PackageList, { packages: manifests.manifests }), manifests.isError && /* @__PURE__ */ jsx("div", { children: "Error loading manifests" })]
15
+ children: manifests.isLoading ? /* @__PURE__ */ jsx(Loading, {}) : /* @__PURE__ */ jsx(PackageList, { packages: manifests.manifests })
15
16
  });
16
17
  };
17
18
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"Home.mjs","names":[],"sources":["../../../src/sections/Home/Home.tsx"],"sourcesContent":["import React from 'react';\n\nimport { Loading, PackageList, useManifests } from '../..';\nimport type { ManifestWeb } from '../../providers/ManifestsProvider/ManifestsProvider';\n\nconst Home: React.FC = () => {\n const manifests = useManifests();\n\n if (manifests.isError) {\n return <div>Error loading manifests</div>;\n }\n\n return (\n <div className=\"container content\" data-testid=\"home-page-container\">\n {manifests.isLoading ? (\n <Loading />\n ) : (\n <PackageList packages={manifests.manifests as ManifestWeb[]} />\n )}\n {manifests.isError && <div>{'Error loading manifests'}</div>}\n </div>\n );\n};\n\nexport default Home;\n"],"mappings":";;;;;;;AAKA,IAAM,aAAuB;CAC3B,MAAM,YAAY,aAAa;CAE/B,IAAI,UAAU,SACZ,OAAO,oBAAC,OAAD,EAAA,UAAK,0BAA4B,CAAA;CAG1C,OACE,qBAAC,OAAD;EAAK,WAAU;EAAoB,eAAY;EAA/C,UAAA,CACG,UAAU,YACT,oBAAC,SAAD,CAAU,CAAA,IAEV,oBAAC,aAAD,EAAa,UAAU,UAAU,UAA6B,CAAA,GAE/D,UAAU,WAAW,oBAAC,OAAD,EAAA,UAAM,0BAA+B,CAAA,CACxD;;AAET"}
1
+ {"version":3,"file":"Home.mjs","names":[],"sources":["../../../src/sections/Home/Home.tsx"],"sourcesContent":["import React from 'react';\n\nimport { GenericError, Loading, PackageList, useManifests } from '../..';\nimport type { ManifestWeb } from '../../providers/ManifestsProvider/ManifestsProvider';\n\nconst Home: React.FC = () => {\n const manifests = useManifests();\n\n if (manifests.isError) {\n return <GenericError />;\n }\n\n return (\n <div className=\"container content\" data-testid=\"home-page-container\">\n {manifests.isLoading ? (\n <Loading />\n ) : (\n <PackageList packages={manifests.manifests as ManifestWeb[]} />\n )}\n </div>\n );\n};\n\nexport default Home;\n"],"mappings":";;;;;;;;AAKA,IAAM,aAAuB;CAC3B,MAAM,YAAY,aAAa;CAE/B,IAAI,UAAU,SACZ,OAAO,oBAAC,cAAD,CAAe,CAAA;CAGxB,OACE,oBAAC,OAAD;EAAK,WAAU;EAAoB,eAAY;EAC5C,UAAA,UAAU,YACT,oBAAC,SAAD,CAAU,CAAA,IAEV,oBAAC,aAAD,EAAa,UAAU,UAAU,UAA6B,CAAA;CAE7D,CAAA;AAET"}
@@ -1,22 +1,25 @@
1
1
  const require_runtime = require("../../_virtual/_rolldown/runtime.js");
2
2
  const require_routes = require("../../utils/routes.js");
3
3
  require("../../utils/index.js");
4
+ const require_storage = require("../../store/storage.js");
4
5
  const require_configuration = require("../../configuration.js");
5
6
  const require_utils = require("../../store/utils.js");
6
7
  const require_use_data_mutation = require("../../api/use-data-mutation.js");
7
8
  const require_utils$1 = require("../../providers/AuthProvider/utils.js");
9
+ const require_AuthProvider = require("../../providers/AuthProvider/AuthProvider.js");
8
10
  const require_LoginDialogFormError = require("../../components/LoginDialog/LoginDialogFormError.js");
11
+ const require_schemas = require("../../utils/schemas.js");
9
12
  const require_PasswordField = require("../../components/LoginForm/PasswordField.js");
10
13
  const require_UsernameField = require("../../components/LoginForm/UsernameField.js");
11
- const require_schemas = require("../../utils/schemas.js");
12
14
  const require_Dialog = require("../../layouts/Security/Dialog.js");
13
15
  const require_styles = require("./styles.js");
14
16
  const require_Success = require("./Success.js");
15
17
  const require_utils$2 = require("./utils.js");
18
+ const require_session_id = require("../../utils/session-id.js");
16
19
  let react = require("react");
17
20
  react = require_runtime.__toESM(react);
18
- let react_jsx_runtime = require("react/jsx-runtime");
19
21
  let react_i18next = require("react-i18next");
22
+ let react_jsx_runtime = require("react/jsx-runtime");
20
23
  let react_router = require("react-router");
21
24
  let _mui_material = require("@mui/material");
22
25
  let _hookform_resolvers_yup = require("@hookform/resolvers/yup");
@@ -26,12 +29,13 @@ var AddUser = () => {
26
29
  const { t } = (0, react_i18next.useTranslation)();
27
30
  const location = (0, react_router.useLocation)();
28
31
  const navigate = (0, react_router.useNavigate)();
32
+ const { setUserState } = require_AuthProvider.useAuth();
29
33
  const configuration = require_configuration.getConfiguration();
30
34
  const basePath = require_utils.stripTrailingSlash(configuration.base);
31
35
  const { next, user } = require_utils$2.getSecurityUrlParams(location);
32
36
  const loginLink = require_routes.Route.LOGIN + (next ? `?next=${encodeURIComponent(next)}` : "");
33
37
  const createUserEnabled = configuration?.flags?.createUser;
34
- const { setError, handleSubmit, register, watch, formState: { isValid, errors } } = (0, react_hook_form.useForm)({
38
+ const { setError, handleSubmit, register, formState: { isValid, isSubmitting, errors } } = (0, react_hook_form.useForm)({
35
39
  mode: "onChange",
36
40
  defaultValues: {
37
41
  username: typeof user === "string" ? user : "",
@@ -40,34 +44,42 @@ var AddUser = () => {
40
44
  },
41
45
  resolver: (0, _hookform_resolvers_yup.yupResolver)(require_schemas.addUserSchema)
42
46
  });
43
- const username = watch("username");
44
- const addUserLink = `${require_routes.Route.ADD_USER}:${encodeURIComponent(username)}`;
45
- const { trigger } = require_use_data_mutation.useDataMutation(basePath, addUserLink, "PUT");
47
+ const { trigger } = require_use_data_mutation.useDataMutation(basePath, require_routes.APIRoute.SIGNUP, "PUT");
46
48
  const handleAddUser = (0, react.useCallback)(async (body) => {
47
- try {
48
- await trigger(body);
49
- } catch (err) {
50
- throw require_utils$1.normalizeAuthError(err);
51
- }
49
+ return await trigger(body);
52
50
  }, [trigger]);
51
+ const inFlight = (0, react.useRef)(false);
53
52
  const onSubmit = (0, react.useCallback)(async (data) => {
53
+ if (inFlight.current) return;
54
+ inFlight.current = true;
54
55
  try {
55
- await handleAddUser({
56
+ const result = await handleAddUser({
56
57
  name: data.username,
57
58
  password: data.password,
58
- email: data.email
59
+ email: data.email,
60
+ sessionId: require_session_id.generateSessionId()
61
+ });
62
+ if (!result || !result.username || !result.token) throw new Error("signup response is missing the token");
63
+ require_storage.saveAuth(result.username, result.token);
64
+ setUserState?.({
65
+ username: result.username,
66
+ token: result.token
59
67
  });
60
68
  navigate(`${require_routes.Route.SUCCESS}?messageType=${require_Success.MessageType.AddUser}`);
61
- } catch {
69
+ } catch (err) {
62
70
  setError("root", {
63
71
  type: "server",
64
- message: "Failed to create user"
72
+ message: require_utils$1.authErrorMessage(err, t("security.error.unable-to-add-user"))
65
73
  });
74
+ } finally {
75
+ inFlight.current = false;
66
76
  }
67
77
  }, [
68
78
  handleAddUser,
69
79
  setError,
70
- navigate
80
+ setUserState,
81
+ navigate,
82
+ t
71
83
  ]);
72
84
  (0, react.useEffect)(() => {
73
85
  if (!createUserEnabled) navigate("/");
@@ -91,6 +103,8 @@ var AddUser = () => {
91
103
  register
92
104
  }),
93
105
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_styles.SecurityTextField, {
106
+ error: !!errors.email,
107
+ helperText: errors.email?.message ? t(errors.email.message) : void 0,
94
108
  label: t("security.addUser.email"),
95
109
  type: "email",
96
110
  ...register("email")
@@ -105,7 +119,7 @@ var AddUser = () => {
105
119
  errors.root && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_LoginDialogFormError.default, { error: errors.root }),
106
120
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material.Button, {
107
121
  color: "primary",
108
- disabled: !isValid,
122
+ disabled: !isValid || isSubmitting,
109
123
  fullWidth: true,
110
124
  sx: { mt: 2 },
111
125
  type: "submit",
@@ -120,8 +134,9 @@ var AddUser = () => {
120
134
  },
121
135
  variant: "body2",
122
136
  children: [t("security.addUser.alreadyUserQuestion"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material.Link, {
123
- href: loginLink,
137
+ component: react_router.Link,
124
138
  sx: { ml: 1 },
139
+ to: loginLink,
125
140
  children: t("security.addUser.login")
126
141
  })]
127
142
  })
@@ -1 +1 @@
1
- {"version":3,"file":"AddUser.js","names":[],"sources":["../../../src/sections/Security/AddUser.tsx"],"sourcesContent":["import { yupResolver } from '@hookform/resolvers/yup';\nimport { Button, Link, Typography } from '@mui/material';\nimport React, { useCallback, useEffect } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { useTranslation } from 'react-i18next';\nimport { useLocation, useNavigate } from 'react-router';\n\nimport { useDataMutation } from '../../api/use-data-mutation';\nimport LoginDialogFormError from '../../components/LoginDialog/LoginDialogFormError';\nimport PasswordField from '../../components/LoginForm/PasswordField';\nimport UsernameField from '../../components/LoginForm/UsernameField';\nimport { getConfiguration } from '../../configuration';\nimport SecurityLayout from '../../layouts/Security/Dialog';\nimport { normalizeAuthError } from '../../providers/AuthProvider/utils';\nimport { stripTrailingSlash } from '../../store/utils';\nimport { Route } from '../../utils';\nimport type { AddUserFormValues } from '../../utils/schemas';\nimport { addUserSchema } from '../../utils/schemas';\nimport { MessageType } from './Success';\nimport { SecurityContainer, SecurityForm, SecurityTextField } from './styles';\nimport { getSecurityUrlParams } from './utils';\n\ntype AddUserBody = {\n name: string;\n password: string;\n email?: string;\n};\n\nconst AddUser: React.FC = () => {\n const { t } = useTranslation();\n const location = useLocation();\n const navigate = useNavigate();\n const configuration = getConfiguration();\n const basePath = stripTrailingSlash(configuration.base);\n const { next, user } = getSecurityUrlParams(location);\n const loginLink = Route.LOGIN + (next ? `?next=${encodeURIComponent(next)}` : '');\n const createUserEnabled = configuration?.flags?.createUser;\n const form = useForm<AddUserFormValues>({\n mode: 'onChange',\n defaultValues: {\n username: typeof user === 'string' ? user : '',\n password: '',\n email: '',\n },\n resolver: yupResolver(addUserSchema),\n });\n\n const {\n setError,\n handleSubmit,\n register,\n watch,\n formState: { isValid, errors },\n } = form;\n\n const username = watch('username');\n\n const addUserLink = `${Route.ADD_USER}:${encodeURIComponent(username)}`;\n\n const { trigger } = useDataMutation<{ ok: string; token: string }>(basePath, addUserLink, 'PUT');\n\n const handleAddUser = useCallback(\n async (body: AddUserBody) => {\n try {\n await trigger(body);\n } catch (err) {\n throw normalizeAuthError(err);\n }\n },\n [trigger]\n );\n\n const onSubmit = useCallback(\n async (data: AddUserFormValues) => {\n try {\n await handleAddUser({\n name: data.username,\n password: data.password,\n email: data.email,\n });\n navigate(`${Route.SUCCESS}?messageType=${MessageType.AddUser}`);\n } catch {\n setError('root', {\n type: 'server',\n // TODO: add translation key\n message: 'Failed to create user',\n });\n }\n },\n [handleAddUser, setError, navigate]\n );\n\n useEffect(() => {\n if (!createUserEnabled) {\n navigate('/');\n }\n }, [createUserEnabled, navigate]);\n\n return createUserEnabled ? (\n <SecurityLayout>\n <SecurityContainer>\n <SecurityForm onSubmit={handleSubmit(onSubmit)}>\n <Typography align=\"center\" component=\"h1\" gutterBottom={true} variant=\"h4\">\n {t('security.addUser.title')}\n </Typography>\n <UsernameField errors={errors} register={register} />\n <PasswordField errors={errors} register={register} />\n\n <SecurityTextField\n label={t('security.addUser.email')}\n type=\"email\"\n {...register('email')}\n />\n\n <Typography color=\"text.secondary\" paragraph={true} sx={{ fontSize: 12 }} variant=\"body2\">\n {t('security.addUser.emailDescription')}\n </Typography>\n {errors.root && <LoginDialogFormError error={errors.root} />}\n <Button\n color=\"primary\"\n disabled={!isValid}\n fullWidth={true}\n sx={{ mt: 2 }}\n type=\"submit\"\n variant=\"contained\"\n >\n {t('security.addUser.submit')}\n </Button>\n <Typography align=\"center\" sx={{ mt: 2, fontSize: 12 }} variant=\"body2\">\n {t('security.addUser.alreadyUserQuestion')}\n <Link href={loginLink} sx={{ ml: 1 }}>\n {t('security.addUser.login')}\n </Link>\n </Typography>\n </SecurityForm>\n </SecurityContainer>\n </SecurityLayout>\n ) : null;\n};\n\nexport default AddUser;\n"],"mappings":"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"}
1
+ {"version":3,"file":"AddUser.js","names":[],"sources":["../../../src/sections/Security/AddUser.tsx"],"sourcesContent":["import { yupResolver } from '@hookform/resolvers/yup';\nimport { Button, Link, Typography } from '@mui/material';\nimport React, { useCallback, useEffect, useRef } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { useTranslation } from 'react-i18next';\nimport { Link as RouterLink, useLocation, useNavigate } from 'react-router';\n\nimport { useDataMutation } from '../../api/use-data-mutation';\nimport LoginDialogFormError from '../../components/LoginDialog/LoginDialogFormError';\nimport PasswordField from '../../components/LoginForm/PasswordField';\nimport UsernameField from '../../components/LoginForm/UsernameField';\nimport { getConfiguration } from '../../configuration';\nimport SecurityLayout from '../../layouts/Security/Dialog';\nimport { useAuth } from '../../providers/AuthProvider/AuthProvider';\nimport { authErrorMessage } from '../../providers/AuthProvider/utils';\nimport { saveAuth } from '../../store/storage';\nimport { stripTrailingSlash } from '../../store/utils';\nimport { Route } from '../../utils';\nimport { APIRoute } from '../../utils/routes';\nimport { generateSessionId } from '../../utils/session-id';\nimport type { AddUserFormValues } from '../../utils/schemas';\nimport { addUserSchema } from '../../utils/schemas';\nimport { MessageType } from './Success';\nimport { SecurityContainer, SecurityForm, SecurityTextField } from './styles';\nimport { getSecurityUrlParams } from './utils';\n\ntype AddUserBody = {\n name: string;\n password: string;\n email?: string;\n // the signup endpoint rejects requests without a 36-char session id\n sessionId: string;\n};\n\nconst AddUser: React.FC = () => {\n const { t } = useTranslation();\n const location = useLocation();\n const navigate = useNavigate();\n const { setUserState } = useAuth();\n const configuration = getConfiguration();\n const basePath = stripTrailingSlash(configuration.base);\n const { next, user } = getSecurityUrlParams(location);\n const loginLink = Route.LOGIN + (next ? `?next=${encodeURIComponent(next)}` : '');\n const createUserEnabled = configuration?.flags?.createUser;\n const form = useForm<AddUserFormValues>({\n mode: 'onChange',\n defaultValues: {\n username: typeof user === 'string' ? user : '',\n password: '',\n email: '',\n },\n resolver: yupResolver(addUserSchema),\n });\n\n const {\n setError,\n handleSubmit,\n register,\n formState: { isValid, isSubmitting, errors },\n } = form;\n\n const { trigger } = useDataMutation<{ token?: string; username?: string }>(\n basePath,\n APIRoute.SIGNUP,\n 'PUT'\n );\n\n const handleAddUser = useCallback(\n async (body: AddUserBody) => {\n return await trigger(body);\n },\n [trigger]\n );\n\n // `disabled={isSubmitting}` only applies after a re-render; clicks landing in\n // the same React batch would still fire duplicate requests\n const inFlight = useRef(false);\n\n const onSubmit = useCallback(\n async (data: AddUserFormValues) => {\n if (inFlight.current) {\n return;\n }\n inFlight.current = true;\n try {\n const result = await handleAddUser({\n name: data.username,\n password: data.password,\n email: data.email,\n sessionId: generateSessionId(),\n });\n if (!result || !result.username || !result.token) {\n // a 2xx with an unexpected body must not pass as a successful signup\n throw new Error('signup response is missing the token');\n }\n saveAuth(result.username, result.token);\n // AuthProvider reads storage only once, so the header needs the state update\n setUserState?.({ username: result.username, token: result.token });\n navigate(`${Route.SUCCESS}?messageType=${MessageType.AddUser}`);\n } catch (err) {\n setError('root', {\n type: 'server',\n message: authErrorMessage(err, t('security.error.unable-to-add-user')),\n });\n } finally {\n inFlight.current = false;\n }\n },\n [handleAddUser, setError, setUserState, navigate, t]\n );\n\n useEffect(() => {\n if (!createUserEnabled) {\n navigate('/');\n }\n }, [createUserEnabled, navigate]);\n\n return createUserEnabled ? (\n <SecurityLayout>\n <SecurityContainer>\n <SecurityForm onSubmit={handleSubmit(onSubmit)}>\n <Typography align=\"center\" component=\"h1\" gutterBottom={true} variant=\"h4\">\n {t('security.addUser.title')}\n </Typography>\n <UsernameField errors={errors} register={register} />\n <PasswordField errors={errors} register={register} />\n\n <SecurityTextField\n error={!!errors.email}\n // without this the submit button silently stays disabled on an\n // invalid email, with no visible reason\n helperText={errors.email?.message ? t(errors.email.message) : undefined}\n label={t('security.addUser.email')}\n type=\"email\"\n {...register('email')}\n />\n\n <Typography color=\"text.secondary\" paragraph={true} sx={{ fontSize: 12 }} variant=\"body2\">\n {t('security.addUser.emailDescription')}\n </Typography>\n {errors.root && <LoginDialogFormError error={errors.root} />}\n <Button\n color=\"primary\"\n disabled={!isValid || isSubmitting}\n fullWidth={true}\n sx={{ mt: 2 }}\n type=\"submit\"\n variant=\"contained\"\n >\n {t('security.addUser.submit')}\n </Button>\n <Typography align=\"center\" sx={{ mt: 2, fontSize: 12 }} variant=\"body2\">\n {t('security.addUser.alreadyUserQuestion')}\n <Link component={RouterLink} sx={{ ml: 1 }} to={loginLink}>\n {t('security.addUser.login')}\n </Link>\n </Typography>\n </SecurityForm>\n </SecurityContainer>\n </SecurityLayout>\n ) : null;\n};\n\nexport default AddUser;\n"],"mappings":"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"}
@@ -1,21 +1,24 @@
1
- import { Route as Route$1 } from "../../utils/routes.mjs";
1
+ import { APIRoute, Route as Route$1 } from "../../utils/routes.mjs";
2
2
  import "../../utils/index.mjs";
3
+ import { saveAuth } from "../../store/storage.mjs";
3
4
  import { getConfiguration } from "../../configuration.mjs";
4
5
  import { stripTrailingSlash } from "../../store/utils.mjs";
5
6
  import { useDataMutation } from "../../api/use-data-mutation.mjs";
6
- import { normalizeAuthError } from "../../providers/AuthProvider/utils.mjs";
7
+ import { authErrorMessage } from "../../providers/AuthProvider/utils.mjs";
8
+ import { useAuth } from "../../providers/AuthProvider/AuthProvider.mjs";
7
9
  import LoginDialogFormError from "../../components/LoginDialog/LoginDialogFormError.mjs";
10
+ import { addUserSchema } from "../../utils/schemas.mjs";
8
11
  import PasswordField from "../../components/LoginForm/PasswordField.mjs";
9
12
  import UsernameField from "../../components/LoginForm/UsernameField.mjs";
10
- import { addUserSchema } from "../../utils/schemas.mjs";
11
13
  import SecurityLayout from "../../layouts/Security/Dialog.mjs";
12
14
  import { SecurityContainer, SecurityForm, SecurityTextField } from "./styles.mjs";
13
15
  import { MessageType } from "./Success.mjs";
14
16
  import { getSecurityUrlParams } from "./utils.mjs";
15
- import { useCallback, useEffect } from "react";
16
- import { jsx, jsxs } from "react/jsx-runtime";
17
+ import { generateSessionId } from "../../utils/session-id.mjs";
18
+ import { useCallback, useEffect, useRef } from "react";
17
19
  import { useTranslation } from "react-i18next";
18
- import { useLocation, useNavigate } from "react-router";
20
+ import { jsx, jsxs } from "react/jsx-runtime";
21
+ import { Link, useLocation, useNavigate } from "react-router";
19
22
  import { Button, Link as Link$1, Typography } from "@mui/material";
20
23
  import { yupResolver } from "@hookform/resolvers/yup";
21
24
  import { useForm } from "react-hook-form";
@@ -24,12 +27,13 @@ var AddUser = () => {
24
27
  const { t } = useTranslation();
25
28
  const location = useLocation();
26
29
  const navigate = useNavigate();
30
+ const { setUserState } = useAuth();
27
31
  const configuration = getConfiguration();
28
32
  const basePath = stripTrailingSlash(configuration.base);
29
33
  const { next, user } = getSecurityUrlParams(location);
30
34
  const loginLink = Route$1.LOGIN + (next ? `?next=${encodeURIComponent(next)}` : "");
31
35
  const createUserEnabled = configuration?.flags?.createUser;
32
- const { setError, handleSubmit, register, watch, formState: { isValid, errors } } = useForm({
36
+ const { setError, handleSubmit, register, formState: { isValid, isSubmitting, errors } } = useForm({
33
37
  mode: "onChange",
34
38
  defaultValues: {
35
39
  username: typeof user === "string" ? user : "",
@@ -38,34 +42,42 @@ var AddUser = () => {
38
42
  },
39
43
  resolver: yupResolver(addUserSchema)
40
44
  });
41
- const username = watch("username");
42
- const addUserLink = `${Route$1.ADD_USER}:${encodeURIComponent(username)}`;
43
- const { trigger } = useDataMutation(basePath, addUserLink, "PUT");
45
+ const { trigger } = useDataMutation(basePath, APIRoute.SIGNUP, "PUT");
44
46
  const handleAddUser = useCallback(async (body) => {
45
- try {
46
- await trigger(body);
47
- } catch (err) {
48
- throw normalizeAuthError(err);
49
- }
47
+ return await trigger(body);
50
48
  }, [trigger]);
49
+ const inFlight = useRef(false);
51
50
  const onSubmit = useCallback(async (data) => {
51
+ if (inFlight.current) return;
52
+ inFlight.current = true;
52
53
  try {
53
- await handleAddUser({
54
+ const result = await handleAddUser({
54
55
  name: data.username,
55
56
  password: data.password,
56
- email: data.email
57
+ email: data.email,
58
+ sessionId: generateSessionId()
59
+ });
60
+ if (!result || !result.username || !result.token) throw new Error("signup response is missing the token");
61
+ saveAuth(result.username, result.token);
62
+ setUserState?.({
63
+ username: result.username,
64
+ token: result.token
57
65
  });
58
66
  navigate(`${Route$1.SUCCESS}?messageType=${MessageType.AddUser}`);
59
- } catch {
67
+ } catch (err) {
60
68
  setError("root", {
61
69
  type: "server",
62
- message: "Failed to create user"
70
+ message: authErrorMessage(err, t("security.error.unable-to-add-user"))
63
71
  });
72
+ } finally {
73
+ inFlight.current = false;
64
74
  }
65
75
  }, [
66
76
  handleAddUser,
67
77
  setError,
68
- navigate
78
+ setUserState,
79
+ navigate,
80
+ t
69
81
  ]);
70
82
  useEffect(() => {
71
83
  if (!createUserEnabled) navigate("/");
@@ -89,6 +101,8 @@ var AddUser = () => {
89
101
  register
90
102
  }),
91
103
  /* @__PURE__ */ jsx(SecurityTextField, {
104
+ error: !!errors.email,
105
+ helperText: errors.email?.message ? t(errors.email.message) : void 0,
92
106
  label: t("security.addUser.email"),
93
107
  type: "email",
94
108
  ...register("email")
@@ -103,7 +117,7 @@ var AddUser = () => {
103
117
  errors.root && /* @__PURE__ */ jsx(LoginDialogFormError, { error: errors.root }),
104
118
  /* @__PURE__ */ jsx(Button, {
105
119
  color: "primary",
106
- disabled: !isValid,
120
+ disabled: !isValid || isSubmitting,
107
121
  fullWidth: true,
108
122
  sx: { mt: 2 },
109
123
  type: "submit",
@@ -118,8 +132,9 @@ var AddUser = () => {
118
132
  },
119
133
  variant: "body2",
120
134
  children: [t("security.addUser.alreadyUserQuestion"), /* @__PURE__ */ jsx(Link$1, {
121
- href: loginLink,
135
+ component: Link,
122
136
  sx: { ml: 1 },
137
+ to: loginLink,
123
138
  children: t("security.addUser.login")
124
139
  })]
125
140
  })
@@ -1 +1 @@
1
- {"version":3,"file":"AddUser.mjs","names":[],"sources":["../../../src/sections/Security/AddUser.tsx"],"sourcesContent":["import { yupResolver } from '@hookform/resolvers/yup';\nimport { Button, Link, Typography } from '@mui/material';\nimport React, { useCallback, useEffect } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { useTranslation } from 'react-i18next';\nimport { useLocation, useNavigate } from 'react-router';\n\nimport { useDataMutation } from '../../api/use-data-mutation';\nimport LoginDialogFormError from '../../components/LoginDialog/LoginDialogFormError';\nimport PasswordField from '../../components/LoginForm/PasswordField';\nimport UsernameField from '../../components/LoginForm/UsernameField';\nimport { getConfiguration } from '../../configuration';\nimport SecurityLayout from '../../layouts/Security/Dialog';\nimport { normalizeAuthError } from '../../providers/AuthProvider/utils';\nimport { stripTrailingSlash } from '../../store/utils';\nimport { Route } from '../../utils';\nimport type { AddUserFormValues } from '../../utils/schemas';\nimport { addUserSchema } from '../../utils/schemas';\nimport { MessageType } from './Success';\nimport { SecurityContainer, SecurityForm, SecurityTextField } from './styles';\nimport { getSecurityUrlParams } from './utils';\n\ntype AddUserBody = {\n name: string;\n password: string;\n email?: string;\n};\n\nconst AddUser: React.FC = () => {\n const { t } = useTranslation();\n const location = useLocation();\n const navigate = useNavigate();\n const configuration = getConfiguration();\n const basePath = stripTrailingSlash(configuration.base);\n const { next, user } = getSecurityUrlParams(location);\n const loginLink = Route.LOGIN + (next ? `?next=${encodeURIComponent(next)}` : '');\n const createUserEnabled = configuration?.flags?.createUser;\n const form = useForm<AddUserFormValues>({\n mode: 'onChange',\n defaultValues: {\n username: typeof user === 'string' ? user : '',\n password: '',\n email: '',\n },\n resolver: yupResolver(addUserSchema),\n });\n\n const {\n setError,\n handleSubmit,\n register,\n watch,\n formState: { isValid, errors },\n } = form;\n\n const username = watch('username');\n\n const addUserLink = `${Route.ADD_USER}:${encodeURIComponent(username)}`;\n\n const { trigger } = useDataMutation<{ ok: string; token: string }>(basePath, addUserLink, 'PUT');\n\n const handleAddUser = useCallback(\n async (body: AddUserBody) => {\n try {\n await trigger(body);\n } catch (err) {\n throw normalizeAuthError(err);\n }\n },\n [trigger]\n );\n\n const onSubmit = useCallback(\n async (data: AddUserFormValues) => {\n try {\n await handleAddUser({\n name: data.username,\n password: data.password,\n email: data.email,\n });\n navigate(`${Route.SUCCESS}?messageType=${MessageType.AddUser}`);\n } catch {\n setError('root', {\n type: 'server',\n // TODO: add translation key\n message: 'Failed to create user',\n });\n }\n },\n [handleAddUser, setError, navigate]\n );\n\n useEffect(() => {\n if (!createUserEnabled) {\n navigate('/');\n }\n }, [createUserEnabled, navigate]);\n\n return createUserEnabled ? (\n <SecurityLayout>\n <SecurityContainer>\n <SecurityForm onSubmit={handleSubmit(onSubmit)}>\n <Typography align=\"center\" component=\"h1\" gutterBottom={true} variant=\"h4\">\n {t('security.addUser.title')}\n </Typography>\n <UsernameField errors={errors} register={register} />\n <PasswordField errors={errors} register={register} />\n\n <SecurityTextField\n label={t('security.addUser.email')}\n type=\"email\"\n {...register('email')}\n />\n\n <Typography color=\"text.secondary\" paragraph={true} sx={{ fontSize: 12 }} variant=\"body2\">\n {t('security.addUser.emailDescription')}\n </Typography>\n {errors.root && <LoginDialogFormError error={errors.root} />}\n <Button\n color=\"primary\"\n disabled={!isValid}\n fullWidth={true}\n sx={{ mt: 2 }}\n type=\"submit\"\n variant=\"contained\"\n >\n {t('security.addUser.submit')}\n </Button>\n <Typography align=\"center\" sx={{ mt: 2, fontSize: 12 }} variant=\"body2\">\n {t('security.addUser.alreadyUserQuestion')}\n <Link href={loginLink} sx={{ ml: 1 }}>\n {t('security.addUser.login')}\n </Link>\n </Typography>\n </SecurityForm>\n </SecurityContainer>\n </SecurityLayout>\n ) : null;\n};\n\nexport default AddUser;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA4BA,IAAM,gBAA0B;CAC9B,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,WAAW,YAAY;CAC7B,MAAM,WAAW,YAAY;CAC7B,MAAM,gBAAgB,iBAAiB;CACvC,MAAM,WAAW,mBAAmB,cAAc,IAAI;CACtD,MAAM,EAAE,MAAM,SAAS,qBAAqB,QAAQ;CACpD,MAAM,YAAY,QAAM,SAAS,OAAO,SAAS,mBAAmB,IAAI,MAAM;CAC9E,MAAM,oBAAoB,eAAe,OAAO;CAWhD,MAAM,EACJ,UACA,cACA,UACA,OACA,WAAW,EAAE,SAAS,aAfX,QAA2B;EACtC,MAAM;EACN,eAAe;GACb,UAAU,OAAO,SAAS,WAAW,OAAO;GAC5C,UAAU;GACV,OAAO;EACT;EACA,UAAU,YAAY,aAAa;CACrC,CAQI;CAEJ,MAAM,WAAW,MAAM,UAAU;CAEjC,MAAM,cAAc,GAAG,QAAM,SAAS,GAAG,mBAAmB,QAAQ;CAEpE,MAAM,EAAE,YAAY,gBAA+C,UAAU,aAAa,KAAK;CAE/F,MAAM,gBAAgB,YACpB,OAAO,SAAsB;EAC3B,IAAI;GACF,MAAM,QAAQ,IAAI;EACpB,SAAS,KAAK;GACZ,MAAM,mBAAmB,GAAG;EAC9B;CACF,GACA,CAAC,OAAO,CACV;CAEA,MAAM,WAAW,YACf,OAAO,SAA4B;EACjC,IAAI;GACF,MAAM,cAAc;IAClB,MAAM,KAAK;IACX,UAAU,KAAK;IACf,OAAO,KAAK;GACd,CAAC;GACD,SAAS,GAAG,QAAM,QAAQ,eAAe,YAAY,SAAS;EAChE,QAAQ;GACN,SAAS,QAAQ;IACf,MAAM;IAEN,SAAS;GACX,CAAC;EACH;CACF,GACA;EAAC;EAAe;EAAU;CAAQ,CACpC;CAEA,gBAAgB;EACd,IAAI,CAAC,mBACH,SAAS,GAAG;CAEhB,GAAG,CAAC,mBAAmB,QAAQ,CAAC;CAEhC,OAAO,oBACL,oBAAC,gBAAD,EAAA,UACE,oBAAC,mBAAD,EAAA,UACE,qBAAC,cAAD;EAAc,UAAU,aAAa,QAAQ;EAA7C,UAAA;GACE,oBAAC,YAAD;IAAY,OAAM;IAAS,WAAU;IAAK,cAAc;IAAM,SAAQ;IACnE,UAAA,EAAE,wBAAwB;GACjB,CAAA;GACZ,oBAAC,eAAD;IAAuB;IAAkB;GAAW,CAAA;GACpD,oBAAC,eAAD;IAAuB;IAAkB;GAAW,CAAA;GAEpD,oBAAC,mBAAD;IACE,OAAO,EAAE,wBAAwB;IACjC,MAAK;IACL,GAAI,SAAS,OAAO;GACrB,CAAA;GAED,oBAAC,YAAD;IAAY,OAAM;IAAiB,WAAW;IAAM,IAAI,EAAE,UAAU,GAAG;IAAG,SAAQ;IAC/E,UAAA,EAAE,mCAAmC;GAC5B,CAAA;GACX,OAAO,QAAQ,oBAAC,sBAAD,EAAsB,OAAO,OAAO,KAAO,CAAA;GAC3D,oBAAC,QAAD;IACE,OAAM;IACN,UAAU,CAAC;IACX,WAAW;IACX,IAAI,EAAE,IAAI,EAAE;IACZ,MAAK;IACL,SAAQ;IAEP,UAAA,EAAE,yBAAyB;GACtB,CAAA;GACR,qBAAC,YAAD;IAAY,OAAM;IAAS,IAAI;KAAE,IAAI;KAAG,UAAU;IAAG;IAAG,SAAQ;IAAhE,UAAA,CACG,EAAE,sCAAsC,GACzC,oBAAC,QAAD;KAAM,MAAM;KAAW,IAAI,EAAE,IAAI,EAAE;KAChC,UAAA,EAAE,wBAAwB;IACvB,CAAA,CACI;;EACA;CACG,CAAA,EAAA,CAAA,EACL,CAAA,IACd;AACN"}
1
+ {"version":3,"file":"AddUser.mjs","names":[],"sources":["../../../src/sections/Security/AddUser.tsx"],"sourcesContent":["import { yupResolver } from '@hookform/resolvers/yup';\nimport { Button, Link, Typography } from '@mui/material';\nimport React, { useCallback, useEffect, useRef } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { useTranslation } from 'react-i18next';\nimport { Link as RouterLink, useLocation, useNavigate } from 'react-router';\n\nimport { useDataMutation } from '../../api/use-data-mutation';\nimport LoginDialogFormError from '../../components/LoginDialog/LoginDialogFormError';\nimport PasswordField from '../../components/LoginForm/PasswordField';\nimport UsernameField from '../../components/LoginForm/UsernameField';\nimport { getConfiguration } from '../../configuration';\nimport SecurityLayout from '../../layouts/Security/Dialog';\nimport { useAuth } from '../../providers/AuthProvider/AuthProvider';\nimport { authErrorMessage } from '../../providers/AuthProvider/utils';\nimport { saveAuth } from '../../store/storage';\nimport { stripTrailingSlash } from '../../store/utils';\nimport { Route } from '../../utils';\nimport { APIRoute } from '../../utils/routes';\nimport { generateSessionId } from '../../utils/session-id';\nimport type { AddUserFormValues } from '../../utils/schemas';\nimport { addUserSchema } from '../../utils/schemas';\nimport { MessageType } from './Success';\nimport { SecurityContainer, SecurityForm, SecurityTextField } from './styles';\nimport { getSecurityUrlParams } from './utils';\n\ntype AddUserBody = {\n name: string;\n password: string;\n email?: string;\n // the signup endpoint rejects requests without a 36-char session id\n sessionId: string;\n};\n\nconst AddUser: React.FC = () => {\n const { t } = useTranslation();\n const location = useLocation();\n const navigate = useNavigate();\n const { setUserState } = useAuth();\n const configuration = getConfiguration();\n const basePath = stripTrailingSlash(configuration.base);\n const { next, user } = getSecurityUrlParams(location);\n const loginLink = Route.LOGIN + (next ? `?next=${encodeURIComponent(next)}` : '');\n const createUserEnabled = configuration?.flags?.createUser;\n const form = useForm<AddUserFormValues>({\n mode: 'onChange',\n defaultValues: {\n username: typeof user === 'string' ? user : '',\n password: '',\n email: '',\n },\n resolver: yupResolver(addUserSchema),\n });\n\n const {\n setError,\n handleSubmit,\n register,\n formState: { isValid, isSubmitting, errors },\n } = form;\n\n const { trigger } = useDataMutation<{ token?: string; username?: string }>(\n basePath,\n APIRoute.SIGNUP,\n 'PUT'\n );\n\n const handleAddUser = useCallback(\n async (body: AddUserBody) => {\n return await trigger(body);\n },\n [trigger]\n );\n\n // `disabled={isSubmitting}` only applies after a re-render; clicks landing in\n // the same React batch would still fire duplicate requests\n const inFlight = useRef(false);\n\n const onSubmit = useCallback(\n async (data: AddUserFormValues) => {\n if (inFlight.current) {\n return;\n }\n inFlight.current = true;\n try {\n const result = await handleAddUser({\n name: data.username,\n password: data.password,\n email: data.email,\n sessionId: generateSessionId(),\n });\n if (!result || !result.username || !result.token) {\n // a 2xx with an unexpected body must not pass as a successful signup\n throw new Error('signup response is missing the token');\n }\n saveAuth(result.username, result.token);\n // AuthProvider reads storage only once, so the header needs the state update\n setUserState?.({ username: result.username, token: result.token });\n navigate(`${Route.SUCCESS}?messageType=${MessageType.AddUser}`);\n } catch (err) {\n setError('root', {\n type: 'server',\n message: authErrorMessage(err, t('security.error.unable-to-add-user')),\n });\n } finally {\n inFlight.current = false;\n }\n },\n [handleAddUser, setError, setUserState, navigate, t]\n );\n\n useEffect(() => {\n if (!createUserEnabled) {\n navigate('/');\n }\n }, [createUserEnabled, navigate]);\n\n return createUserEnabled ? (\n <SecurityLayout>\n <SecurityContainer>\n <SecurityForm onSubmit={handleSubmit(onSubmit)}>\n <Typography align=\"center\" component=\"h1\" gutterBottom={true} variant=\"h4\">\n {t('security.addUser.title')}\n </Typography>\n <UsernameField errors={errors} register={register} />\n <PasswordField errors={errors} register={register} />\n\n <SecurityTextField\n error={!!errors.email}\n // without this the submit button silently stays disabled on an\n // invalid email, with no visible reason\n helperText={errors.email?.message ? t(errors.email.message) : undefined}\n label={t('security.addUser.email')}\n type=\"email\"\n {...register('email')}\n />\n\n <Typography color=\"text.secondary\" paragraph={true} sx={{ fontSize: 12 }} variant=\"body2\">\n {t('security.addUser.emailDescription')}\n </Typography>\n {errors.root && <LoginDialogFormError error={errors.root} />}\n <Button\n color=\"primary\"\n disabled={!isValid || isSubmitting}\n fullWidth={true}\n sx={{ mt: 2 }}\n type=\"submit\"\n variant=\"contained\"\n >\n {t('security.addUser.submit')}\n </Button>\n <Typography align=\"center\" sx={{ mt: 2, fontSize: 12 }} variant=\"body2\">\n {t('security.addUser.alreadyUserQuestion')}\n <Link component={RouterLink} sx={{ ml: 1 }} to={loginLink}>\n {t('security.addUser.login')}\n </Link>\n </Typography>\n </SecurityForm>\n </SecurityContainer>\n </SecurityLayout>\n ) : null;\n};\n\nexport default AddUser;\n"],"mappings":"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"}
@@ -12,8 +12,8 @@ const require_styles = require("./styles.js");
12
12
  const require_Success = require("./Success.js");
13
13
  let react = require("react");
14
14
  react = require_runtime.__toESM(react);
15
- let react_jsx_runtime = require("react/jsx-runtime");
16
15
  let react_i18next = require("react-i18next");
16
+ let react_jsx_runtime = require("react/jsx-runtime");
17
17
  let react_router = require("react-router");
18
18
  let _mui_material = require("@mui/material");
19
19
  let _hookform_resolvers_yup = require("@hookform/resolvers/yup");
@@ -25,7 +25,7 @@ var ChangePassword = () => {
25
25
  const configuration = require_configuration.getConfiguration();
26
26
  const basePath = require_utils.stripTrailingSlash(configuration.base);
27
27
  const changePasswordEnabled = configuration?.flags?.changePassword;
28
- const { setError, handleSubmit, register, formState: { isValid, errors } } = (0, react_hook_form.useForm)({
28
+ const { setError, handleSubmit, register, formState: { isValid, isSubmitting, errors } } = (0, react_hook_form.useForm)({
29
29
  mode: "onChange",
30
30
  defaultValues: {
31
31
  username: "",
@@ -37,29 +37,31 @@ var ChangePassword = () => {
37
37
  });
38
38
  const { trigger } = require_use_data_mutation.useDataMutation(basePath, require_routes.APIRoute.RESET_PASSWORD, "PUT");
39
39
  const handleChangePassword = (0, react.useCallback)(async (body) => {
40
- try {
41
- await trigger(body);
42
- } catch (err) {
43
- throw require_utils$1.normalizeAuthError(err);
44
- }
40
+ await trigger(body);
45
41
  }, [trigger]);
42
+ const inFlight = (0, react.useRef)(false);
46
43
  const onSubmit = (0, react.useCallback)(async (data) => {
44
+ if (inFlight.current) return;
45
+ inFlight.current = true;
47
46
  try {
48
47
  await handleChangePassword({ password: {
49
48
  old: data.oldPassword,
50
49
  new: data.newPassword
51
50
  } });
52
51
  navigate(`${require_routes.Route.SUCCESS}?messageType=${require_Success.MessageType.ChangePassword}`);
53
- } catch {
52
+ } catch (err) {
54
53
  setError("root", {
55
54
  type: "server",
56
- message: "Failed to change password"
55
+ message: require_utils$1.authErrorMessage(err, t("security.error.unable-to-change-password"))
57
56
  });
57
+ } finally {
58
+ inFlight.current = false;
58
59
  }
59
60
  }, [
60
61
  handleChangePassword,
61
62
  setError,
62
- navigate
63
+ navigate,
64
+ t
63
65
  ]);
64
66
  (0, react.useEffect)(() => {
65
67
  if (!changePasswordEnabled) navigate("/");
@@ -76,14 +78,14 @@ var ChangePassword = () => {
76
78
  }),
77
79
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_styles.SecurityTextField, {
78
80
  error: !!errors.username,
79
- helperText: errors.username?.message,
81
+ helperText: errors.username?.message ? t(errors.username.message, { length: 2 }) : void 0,
80
82
  label: t("security.changePassword.username"),
81
83
  ...register("username"),
82
84
  required: true
83
85
  }),
84
86
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_styles.SecurityTextField, {
85
87
  error: !!errors.oldPassword,
86
- helperText: errors.oldPassword?.message,
88
+ helperText: errors.oldPassword?.message ? t(errors.oldPassword.message, { length: 2 }) : void 0,
87
89
  label: t("security.changePassword.oldPassword"),
88
90
  ...register("oldPassword"),
89
91
  required: true,
@@ -91,7 +93,7 @@ var ChangePassword = () => {
91
93
  }),
92
94
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_styles.SecurityTextField, {
93
95
  error: !!errors.newPassword,
94
- helperText: errors.newPassword?.message,
96
+ helperText: errors.newPassword?.message ? t(errors.newPassword.message, { length: 2 }) : void 0,
95
97
  label: t("security.changePassword.newPassword"),
96
98
  ...register("newPassword"),
97
99
  required: true,
@@ -99,7 +101,7 @@ var ChangePassword = () => {
99
101
  }),
100
102
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_styles.SecurityTextField, {
101
103
  error: !!errors.confirmPassword,
102
- helperText: errors.confirmPassword?.message,
104
+ helperText: errors.confirmPassword?.message ? t(errors.confirmPassword.message) : void 0,
103
105
  label: t("security.changePassword.confirmPassword"),
104
106
  ...register("confirmPassword"),
105
107
  required: true,
@@ -108,7 +110,7 @@ var ChangePassword = () => {
108
110
  errors.root && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_LoginDialogFormError.default, { error: errors.root }),
109
111
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material.Button, {
110
112
  color: "primary",
111
- disabled: !isValid,
113
+ disabled: !isValid || isSubmitting,
112
114
  fullWidth: true,
113
115
  sx: { mt: 2 },
114
116
  type: "submit",
@@ -1 +1 @@
1
- {"version":3,"file":"ChangePassword.js","names":[],"sources":["../../../src/sections/Security/ChangePassword.tsx"],"sourcesContent":["import { yupResolver } from '@hookform/resolvers/yup';\nimport { Button, Typography } from '@mui/material';\nimport React, { useCallback, useEffect } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { useTranslation } from 'react-i18next';\nimport { useNavigate } from 'react-router';\n\nimport { useDataMutation } from '../../api/use-data-mutation';\nimport LoginDialogFormError from '../../components/LoginDialog/LoginDialogFormError';\nimport { getConfiguration } from '../../configuration';\nimport SecurityLayout from '../../layouts/Security/Dialog';\nimport { normalizeAuthError } from '../../providers/AuthProvider/utils';\nimport { stripTrailingSlash } from '../../store/utils';\nimport { Route } from '../../utils';\nimport { APIRoute } from '../../utils/routes';\nimport type { ChangePasswordFormValues } from '../../utils/schemas';\nimport { changePasswordSchema } from '../../utils/schemas';\nimport { MessageType } from './Success';\nimport { SecurityContainer, SecurityForm, SecurityTextField } from './styles';\n\nconst ChangePassword: React.FC = () => {\n const { t } = useTranslation();\n const navigate = useNavigate();\n const configuration = getConfiguration();\n const basePath = stripTrailingSlash(configuration.base);\n const changePasswordEnabled = configuration?.flags?.changePassword;\n\n const form = useForm<ChangePasswordFormValues>({\n mode: 'onChange',\n defaultValues: {\n username: '',\n oldPassword: '',\n newPassword: '',\n confirmPassword: '',\n },\n resolver: yupResolver(changePasswordSchema),\n });\n\n const {\n setError,\n handleSubmit,\n register,\n formState: { isValid, errors },\n } = form;\n\n const { trigger } = useDataMutation<{ ok: string }>(basePath, APIRoute.RESET_PASSWORD, 'PUT');\n\n const handleChangePassword = useCallback(\n async (body: { password: { old: string; new: string } }) => {\n try {\n await trigger(body);\n } catch (err) {\n throw normalizeAuthError(err);\n }\n },\n [trigger]\n );\n\n const onSubmit = useCallback(\n async (data: ChangePasswordFormValues) => {\n try {\n await handleChangePassword({\n password: {\n old: data.oldPassword,\n new: data.newPassword,\n },\n });\n navigate(`${Route.SUCCESS}?messageType=${MessageType.ChangePassword}`);\n } catch {\n setError('root', {\n type: 'server',\n message: 'Failed to change password',\n });\n }\n },\n [handleChangePassword, setError, navigate]\n );\n\n useEffect(() => {\n if (!changePasswordEnabled) {\n navigate('/');\n }\n }, [changePasswordEnabled, navigate]);\n\n return changePasswordEnabled ? (\n <SecurityLayout>\n <SecurityContainer>\n <SecurityForm onSubmit={handleSubmit(onSubmit)}>\n <Typography align=\"center\" component=\"h1\" gutterBottom={true} variant=\"h4\">\n {t('security.changePassword.title')}\n </Typography>\n <SecurityTextField\n error={!!errors.username}\n helperText={errors.username?.message}\n label={t('security.changePassword.username')}\n {...register('username')}\n required={true}\n />\n <SecurityTextField\n error={!!errors.oldPassword}\n helperText={errors.oldPassword?.message}\n label={t('security.changePassword.oldPassword')}\n {...register('oldPassword')}\n required={true}\n type=\"password\"\n />\n <SecurityTextField\n error={!!errors.newPassword}\n helperText={errors.newPassword?.message}\n label={t('security.changePassword.newPassword')}\n {...register('newPassword')}\n required={true}\n type=\"password\"\n />\n <SecurityTextField\n error={!!errors.confirmPassword}\n helperText={errors.confirmPassword?.message}\n label={t('security.changePassword.confirmPassword')}\n {...register('confirmPassword')}\n required={true}\n type=\"password\"\n />\n {errors.root && <LoginDialogFormError error={errors.root} />}\n <Button\n color=\"primary\"\n disabled={!isValid}\n fullWidth={true}\n sx={{ mt: 2 }}\n type=\"submit\"\n variant=\"contained\"\n >\n {t('security.changePassword.submit')}\n </Button>\n </SecurityForm>\n </SecurityContainer>\n </SecurityLayout>\n ) : null;\n};\n\nexport default ChangePassword;\n"],"mappings":"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"}
1
+ {"version":3,"file":"ChangePassword.js","names":[],"sources":["../../../src/sections/Security/ChangePassword.tsx"],"sourcesContent":["import { yupResolver } from '@hookform/resolvers/yup';\nimport { Button, Typography } from '@mui/material';\nimport React, { useCallback, useEffect, useRef } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { useTranslation } from 'react-i18next';\nimport { useNavigate } from 'react-router';\n\nimport { useDataMutation } from '../../api/use-data-mutation';\nimport LoginDialogFormError from '../../components/LoginDialog/LoginDialogFormError';\nimport { getConfiguration } from '../../configuration';\nimport SecurityLayout from '../../layouts/Security/Dialog';\nimport { authErrorMessage } from '../../providers/AuthProvider/utils';\nimport { stripTrailingSlash } from '../../store/utils';\nimport { Route } from '../../utils';\nimport { APIRoute } from '../../utils/routes';\nimport type { ChangePasswordFormValues } from '../../utils/schemas';\nimport {\n PASSWORD_MIN_LENGTH,\n USERNAME_MIN_LENGTH,\n changePasswordSchema,\n} from '../../utils/schemas';\nimport { MessageType } from './Success';\nimport { SecurityContainer, SecurityForm, SecurityTextField } from './styles';\n\nconst ChangePassword: React.FC = () => {\n const { t } = useTranslation();\n const navigate = useNavigate();\n const configuration = getConfiguration();\n const basePath = stripTrailingSlash(configuration.base);\n const changePasswordEnabled = configuration?.flags?.changePassword;\n\n const form = useForm<ChangePasswordFormValues>({\n mode: 'onChange',\n defaultValues: {\n username: '',\n oldPassword: '',\n newPassword: '',\n confirmPassword: '',\n },\n resolver: yupResolver(changePasswordSchema),\n });\n\n const {\n setError,\n handleSubmit,\n register,\n formState: { isValid, isSubmitting, errors },\n } = form;\n\n const { trigger } = useDataMutation<{ ok: string }>(basePath, APIRoute.RESET_PASSWORD, 'PUT');\n\n const handleChangePassword = useCallback(\n async (body: { password: { old: string; new: string } }) => {\n await trigger(body);\n },\n [trigger]\n );\n\n // `disabled={isSubmitting}` only applies after a re-render; clicks landing in\n // the same React batch would still fire duplicate requests\n const inFlight = useRef(false);\n\n const onSubmit = useCallback(\n async (data: ChangePasswordFormValues) => {\n if (inFlight.current) {\n return;\n }\n inFlight.current = true;\n try {\n await handleChangePassword({\n password: {\n old: data.oldPassword,\n new: data.newPassword,\n },\n });\n navigate(`${Route.SUCCESS}?messageType=${MessageType.ChangePassword}`);\n } catch (err) {\n setError('root', {\n type: 'server',\n message: authErrorMessage(err, t('security.error.unable-to-change-password')),\n });\n } finally {\n inFlight.current = false;\n }\n },\n [handleChangePassword, setError, navigate, t]\n );\n\n useEffect(() => {\n if (!changePasswordEnabled) {\n navigate('/');\n }\n }, [changePasswordEnabled, navigate]);\n\n return changePasswordEnabled ? (\n <SecurityLayout>\n <SecurityContainer>\n <SecurityForm onSubmit={handleSubmit(onSubmit)}>\n <Typography align=\"center\" component=\"h1\" gutterBottom={true} variant=\"h4\">\n {t('security.changePassword.title')}\n </Typography>\n <SecurityTextField\n error={!!errors.username}\n helperText={\n errors.username?.message\n ? t(errors.username.message, { length: USERNAME_MIN_LENGTH })\n : undefined\n }\n label={t('security.changePassword.username')}\n {...register('username')}\n required={true}\n />\n <SecurityTextField\n error={!!errors.oldPassword}\n helperText={\n errors.oldPassword?.message\n ? t(errors.oldPassword.message, { length: PASSWORD_MIN_LENGTH })\n : undefined\n }\n label={t('security.changePassword.oldPassword')}\n {...register('oldPassword')}\n required={true}\n type=\"password\"\n />\n <SecurityTextField\n error={!!errors.newPassword}\n helperText={\n errors.newPassword?.message\n ? t(errors.newPassword.message, { length: PASSWORD_MIN_LENGTH })\n : undefined\n }\n label={t('security.changePassword.newPassword')}\n {...register('newPassword')}\n required={true}\n type=\"password\"\n />\n <SecurityTextField\n error={!!errors.confirmPassword}\n helperText={\n errors.confirmPassword?.message ? t(errors.confirmPassword.message) : undefined\n }\n label={t('security.changePassword.confirmPassword')}\n {...register('confirmPassword')}\n required={true}\n type=\"password\"\n />\n {errors.root && <LoginDialogFormError error={errors.root} />}\n <Button\n color=\"primary\"\n disabled={!isValid || isSubmitting}\n fullWidth={true}\n sx={{ mt: 2 }}\n type=\"submit\"\n variant=\"contained\"\n >\n {t('security.changePassword.submit')}\n </Button>\n </SecurityForm>\n </SecurityContainer>\n </SecurityLayout>\n ) : null;\n};\n\nexport default ChangePassword;\n"],"mappings":"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"}
@@ -3,15 +3,15 @@ import "../../utils/index.mjs";
3
3
  import { getConfiguration } from "../../configuration.mjs";
4
4
  import { stripTrailingSlash } from "../../store/utils.mjs";
5
5
  import { useDataMutation } from "../../api/use-data-mutation.mjs";
6
- import { normalizeAuthError } from "../../providers/AuthProvider/utils.mjs";
6
+ import { authErrorMessage } from "../../providers/AuthProvider/utils.mjs";
7
7
  import LoginDialogFormError from "../../components/LoginDialog/LoginDialogFormError.mjs";
8
8
  import { changePasswordSchema } from "../../utils/schemas.mjs";
9
9
  import SecurityLayout from "../../layouts/Security/Dialog.mjs";
10
10
  import { SecurityContainer, SecurityForm, SecurityTextField } from "./styles.mjs";
11
11
  import { MessageType } from "./Success.mjs";
12
- import { useCallback, useEffect } from "react";
13
- import { jsx, jsxs } from "react/jsx-runtime";
12
+ import { useCallback, useEffect, useRef } from "react";
14
13
  import { useTranslation } from "react-i18next";
14
+ import { jsx, jsxs } from "react/jsx-runtime";
15
15
  import { useNavigate } from "react-router";
16
16
  import { Button, Typography } from "@mui/material";
17
17
  import { yupResolver } from "@hookform/resolvers/yup";
@@ -23,7 +23,7 @@ var ChangePassword = () => {
23
23
  const configuration = getConfiguration();
24
24
  const basePath = stripTrailingSlash(configuration.base);
25
25
  const changePasswordEnabled = configuration?.flags?.changePassword;
26
- const { setError, handleSubmit, register, formState: { isValid, errors } } = useForm({
26
+ const { setError, handleSubmit, register, formState: { isValid, isSubmitting, errors } } = useForm({
27
27
  mode: "onChange",
28
28
  defaultValues: {
29
29
  username: "",
@@ -35,29 +35,31 @@ var ChangePassword = () => {
35
35
  });
36
36
  const { trigger } = useDataMutation(basePath, APIRoute.RESET_PASSWORD, "PUT");
37
37
  const handleChangePassword = useCallback(async (body) => {
38
- try {
39
- await trigger(body);
40
- } catch (err) {
41
- throw normalizeAuthError(err);
42
- }
38
+ await trigger(body);
43
39
  }, [trigger]);
40
+ const inFlight = useRef(false);
44
41
  const onSubmit = useCallback(async (data) => {
42
+ if (inFlight.current) return;
43
+ inFlight.current = true;
45
44
  try {
46
45
  await handleChangePassword({ password: {
47
46
  old: data.oldPassword,
48
47
  new: data.newPassword
49
48
  } });
50
49
  navigate(`${Route$1.SUCCESS}?messageType=${MessageType.ChangePassword}`);
51
- } catch {
50
+ } catch (err) {
52
51
  setError("root", {
53
52
  type: "server",
54
- message: "Failed to change password"
53
+ message: authErrorMessage(err, t("security.error.unable-to-change-password"))
55
54
  });
55
+ } finally {
56
+ inFlight.current = false;
56
57
  }
57
58
  }, [
58
59
  handleChangePassword,
59
60
  setError,
60
- navigate
61
+ navigate,
62
+ t
61
63
  ]);
62
64
  useEffect(() => {
63
65
  if (!changePasswordEnabled) navigate("/");
@@ -74,14 +76,14 @@ var ChangePassword = () => {
74
76
  }),
75
77
  /* @__PURE__ */ jsx(SecurityTextField, {
76
78
  error: !!errors.username,
77
- helperText: errors.username?.message,
79
+ helperText: errors.username?.message ? t(errors.username.message, { length: 2 }) : void 0,
78
80
  label: t("security.changePassword.username"),
79
81
  ...register("username"),
80
82
  required: true
81
83
  }),
82
84
  /* @__PURE__ */ jsx(SecurityTextField, {
83
85
  error: !!errors.oldPassword,
84
- helperText: errors.oldPassword?.message,
86
+ helperText: errors.oldPassword?.message ? t(errors.oldPassword.message, { length: 2 }) : void 0,
85
87
  label: t("security.changePassword.oldPassword"),
86
88
  ...register("oldPassword"),
87
89
  required: true,
@@ -89,7 +91,7 @@ var ChangePassword = () => {
89
91
  }),
90
92
  /* @__PURE__ */ jsx(SecurityTextField, {
91
93
  error: !!errors.newPassword,
92
- helperText: errors.newPassword?.message,
94
+ helperText: errors.newPassword?.message ? t(errors.newPassword.message, { length: 2 }) : void 0,
93
95
  label: t("security.changePassword.newPassword"),
94
96
  ...register("newPassword"),
95
97
  required: true,
@@ -97,7 +99,7 @@ var ChangePassword = () => {
97
99
  }),
98
100
  /* @__PURE__ */ jsx(SecurityTextField, {
99
101
  error: !!errors.confirmPassword,
100
- helperText: errors.confirmPassword?.message,
102
+ helperText: errors.confirmPassword?.message ? t(errors.confirmPassword.message) : void 0,
101
103
  label: t("security.changePassword.confirmPassword"),
102
104
  ...register("confirmPassword"),
103
105
  required: true,
@@ -106,7 +108,7 @@ var ChangePassword = () => {
106
108
  errors.root && /* @__PURE__ */ jsx(LoginDialogFormError, { error: errors.root }),
107
109
  /* @__PURE__ */ jsx(Button, {
108
110
  color: "primary",
109
- disabled: !isValid,
111
+ disabled: !isValid || isSubmitting,
110
112
  fullWidth: true,
111
113
  sx: { mt: 2 },
112
114
  type: "submit",