@verdaccio/ui-components 5.0.0-next-9.20 → 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 (274) 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/Author/Author.js +1 -1
  17. package/build/components/Author/Author.mjs +1 -1
  18. package/build/components/CopyClipboard/CopyToClipBoard.js +5 -0
  19. package/build/components/CopyClipboard/CopyToClipBoard.js.map +1 -1
  20. package/build/components/CopyClipboard/CopyToClipBoard.mjs +5 -0
  21. package/build/components/CopyClipboard/CopyToClipBoard.mjs.map +1 -1
  22. package/build/components/CopyClipboard/utils.js +14 -1
  23. package/build/components/CopyClipboard/utils.js.map +1 -1
  24. package/build/components/CopyClipboard/utils.mjs +14 -1
  25. package/build/components/CopyClipboard/utils.mjs.map +1 -1
  26. package/build/components/Dependencies/Dependencies.js +2 -1
  27. package/build/components/Dependencies/Dependencies.js.map +1 -1
  28. package/build/components/Dependencies/Dependencies.mjs +2 -1
  29. package/build/components/Dependencies/Dependencies.mjs.map +1 -1
  30. package/build/components/Dependencies/DependencyBlock.js +1 -1
  31. package/build/components/Dependencies/DependencyBlock.mjs +1 -1
  32. package/build/components/Developers/Title.js +1 -1
  33. package/build/components/Developers/Title.mjs +1 -1
  34. package/build/components/Developers/get-unique-developer-values.js +2 -1
  35. package/build/components/Developers/get-unique-developer-values.js.map +1 -1
  36. package/build/components/Developers/get-unique-developer-values.mjs +2 -1
  37. package/build/components/Developers/get-unique-developer-values.mjs.map +1 -1
  38. package/build/components/Distribution/Dist.js +3 -3
  39. package/build/components/Distribution/Dist.js.map +1 -1
  40. package/build/components/Distribution/Dist.mjs +3 -3
  41. package/build/components/Distribution/Dist.mjs.map +1 -1
  42. package/build/components/Engines/Engines.js +1 -1
  43. package/build/components/Engines/Engines.mjs +1 -1
  44. package/build/components/Forbidden/Forbidden.js +1 -1
  45. package/build/components/Forbidden/Forbidden.mjs +1 -1
  46. package/build/components/FundButton/FundButton.js +4 -3
  47. package/build/components/FundButton/FundButton.js.map +1 -1
  48. package/build/components/FundButton/FundButton.mjs +4 -3
  49. package/build/components/FundButton/FundButton.mjs.map +1 -1
  50. package/build/components/GenericError/GenericError.d.ts +3 -0
  51. package/build/components/GenericError/GenericError.js +60 -0
  52. package/build/components/GenericError/GenericError.js.map +1 -0
  53. package/build/components/GenericError/GenericError.mjs +54 -0
  54. package/build/components/GenericError/GenericError.mjs.map +1 -0
  55. package/build/components/GenericError/index.d.ts +1 -0
  56. package/build/components/GenericError/index.js +2 -0
  57. package/build/components/GenericError/index.mjs +2 -0
  58. package/build/components/Help/Help.js +1 -1
  59. package/build/components/Help/Help.mjs +1 -1
  60. package/build/components/Install/Install.js +1 -1
  61. package/build/components/Install/Install.mjs +1 -1
  62. package/build/components/Install/InstallListItem.js +2 -2
  63. package/build/components/Install/InstallListItem.js.map +1 -1
  64. package/build/components/Install/InstallListItem.mjs +2 -2
  65. package/build/components/Install/InstallListItem.mjs.map +1 -1
  66. package/build/components/Keywords/KeywordListItems.js +1 -1
  67. package/build/components/Keywords/KeywordListItems.js.map +1 -1
  68. package/build/components/Keywords/KeywordListItems.mjs +1 -1
  69. package/build/components/Keywords/KeywordListItems.mjs.map +1 -1
  70. package/build/components/Keywords/Keywords.js +2 -2
  71. package/build/components/Keywords/Keywords.js.map +1 -1
  72. package/build/components/Keywords/Keywords.mjs +2 -2
  73. package/build/components/Keywords/Keywords.mjs.map +1 -1
  74. package/build/components/LoginDialog/LoginDialogCloseButton.js +1 -1
  75. package/build/components/LoginDialog/LoginDialogCloseButton.mjs +1 -1
  76. package/build/components/LoginDialog/LoginDialogForm.js +2 -1
  77. package/build/components/LoginDialog/LoginDialogForm.js.map +1 -1
  78. package/build/components/LoginDialog/LoginDialogForm.mjs +2 -1
  79. package/build/components/LoginDialog/LoginDialogForm.mjs.map +1 -1
  80. package/build/components/LoginForm/Login.d.ts +1 -0
  81. package/build/components/LoginForm/Login.js +6 -4
  82. package/build/components/LoginForm/Login.js.map +1 -1
  83. package/build/components/LoginForm/Login.mjs +9 -7
  84. package/build/components/LoginForm/Login.mjs.map +1 -1
  85. package/build/components/LoginForm/PasswordField.js +4 -6
  86. package/build/components/LoginForm/PasswordField.js.map +1 -1
  87. package/build/components/LoginForm/PasswordField.mjs +4 -6
  88. package/build/components/LoginForm/PasswordField.mjs.map +1 -1
  89. package/build/components/LoginForm/UsernameField.js +4 -6
  90. package/build/components/LoginForm/UsernameField.js.map +1 -1
  91. package/build/components/LoginForm/UsernameField.mjs +4 -6
  92. package/build/components/LoginForm/UsernameField.mjs.map +1 -1
  93. package/build/components/LoginForm/styles.js +1 -1
  94. package/build/components/LoginForm/styles.mjs +1 -1
  95. package/build/components/LoginForm/useLoginForm.js +13 -3
  96. package/build/components/LoginForm/useLoginForm.js.map +1 -1
  97. package/build/components/LoginForm/useLoginForm.mjs +14 -4
  98. package/build/components/LoginForm/useLoginForm.mjs.map +1 -1
  99. package/build/components/NoItems/NoItems.js +2 -2
  100. package/build/components/NoItems/NoItems.mjs +1 -1
  101. package/build/components/NotFound/NotFound.js +1 -1
  102. package/build/components/NotFound/NotFound.mjs +1 -1
  103. package/build/components/Package/Package.d.ts +1 -1
  104. package/build/components/Package/Package.js +28 -29
  105. package/build/components/Package/Package.js.map +1 -1
  106. package/build/components/Package/Package.mjs +29 -30
  107. package/build/components/Package/Package.mjs.map +1 -1
  108. package/build/components/Person/Person.js +1 -1
  109. package/build/components/Person/Person.js.map +1 -1
  110. package/build/components/Person/Person.mjs +1 -1
  111. package/build/components/Person/Person.mjs.map +1 -1
  112. package/build/components/RawViewer/RawViewer.js +1 -1
  113. package/build/components/RawViewer/RawViewer.mjs +1 -1
  114. package/build/components/RegistryInfoDialog/RegistryInfoDialog.js +1 -1
  115. package/build/components/RegistryInfoDialog/RegistryInfoDialog.mjs +1 -1
  116. package/build/components/Repository/Repository.js +5 -8
  117. package/build/components/Repository/Repository.js.map +1 -1
  118. package/build/components/Repository/Repository.mjs +5 -8
  119. package/build/components/Repository/Repository.mjs.map +1 -1
  120. package/build/components/Search/AutoComplete/AutoComplete.d.ts +1 -0
  121. package/build/components/Search/AutoComplete/AutoComplete.js +4 -4
  122. package/build/components/Search/AutoComplete/AutoComplete.js.map +1 -1
  123. package/build/components/Search/AutoComplete/AutoComplete.mjs +4 -4
  124. package/build/components/Search/AutoComplete/AutoComplete.mjs.map +1 -1
  125. package/build/components/Search/Search.js +12 -4
  126. package/build/components/Search/Search.js.map +1 -1
  127. package/build/components/Search/Search.mjs +13 -5
  128. package/build/components/Search/Search.mjs.map +1 -1
  129. package/build/components/Search/SearchItem.js +1 -1
  130. package/build/components/Search/SearchItem.mjs +1 -1
  131. package/build/components/SettingsMenu/SettingsMenu.js +1 -1
  132. package/build/components/SettingsMenu/SettingsMenu.mjs +1 -1
  133. package/build/components/SideBarTitle/SideBarTitle.js +2 -2
  134. package/build/components/SideBarTitle/SideBarTitle.js.map +1 -1
  135. package/build/components/SideBarTitle/SideBarTitle.mjs +2 -2
  136. package/build/components/SideBarTitle/SideBarTitle.mjs.map +1 -1
  137. package/build/components/UpLinks/UpLinks.js +1 -1
  138. package/build/components/UpLinks/UpLinks.mjs +1 -1
  139. package/build/components/Versions/HistoryList.js +2 -2
  140. package/build/components/Versions/HistoryList.js.map +1 -1
  141. package/build/components/Versions/HistoryList.mjs +2 -2
  142. package/build/components/Versions/HistoryList.mjs.map +1 -1
  143. package/build/components/Versions/Versions.js +22 -21
  144. package/build/components/Versions/Versions.js.map +1 -1
  145. package/build/components/Versions/Versions.mjs +22 -21
  146. package/build/components/Versions/Versions.mjs.map +1 -1
  147. package/build/index.d.ts +1 -0
  148. package/build/index.js +4 -0
  149. package/build/index.mjs +4 -2
  150. package/build/pages/Version/Version.js +4 -1
  151. package/build/pages/Version/Version.js.map +1 -1
  152. package/build/pages/Version/Version.mjs +4 -1
  153. package/build/pages/Version/Version.mjs.map +1 -1
  154. package/build/providers/AuthProvider/AuthProvider.js +9 -7
  155. package/build/providers/AuthProvider/AuthProvider.js.map +1 -1
  156. package/build/providers/AuthProvider/AuthProvider.mjs +10 -8
  157. package/build/providers/AuthProvider/AuthProvider.mjs.map +1 -1
  158. package/build/providers/AuthProvider/utils.d.ts +12 -0
  159. package/build/providers/AuthProvider/utils.js +22 -0
  160. package/build/providers/AuthProvider/utils.js.map +1 -1
  161. package/build/providers/AuthProvider/utils.mjs +21 -2
  162. package/build/providers/AuthProvider/utils.mjs.map +1 -1
  163. package/build/providers/DownloadProvider/DownloadProvider.d.ts +1 -0
  164. package/build/providers/DownloadProvider/DownloadProvider.js +27 -4
  165. package/build/providers/DownloadProvider/DownloadProvider.js.map +1 -1
  166. package/build/providers/DownloadProvider/DownloadProvider.mjs +27 -6
  167. package/build/providers/DownloadProvider/DownloadProvider.mjs.map +1 -1
  168. package/build/providers/ManifestsProvider/ManifestsProvider.js +1 -1
  169. package/build/providers/ManifestsProvider/ManifestsProvider.js.map +1 -1
  170. package/build/providers/ManifestsProvider/ManifestsProvider.mjs +1 -1
  171. package/build/providers/ManifestsProvider/ManifestsProvider.mjs.map +1 -1
  172. package/build/providers/SearchProvider/SearchProvider.d.ts +1 -0
  173. package/build/providers/SearchProvider/SearchProvider.js +8 -6
  174. package/build/providers/SearchProvider/SearchProvider.js.map +1 -1
  175. package/build/providers/SearchProvider/SearchProvider.mjs +8 -6
  176. package/build/providers/SearchProvider/SearchProvider.mjs.map +1 -1
  177. package/build/providers/TranslatorProvider/TranslatorProvider.js +5 -3
  178. package/build/providers/TranslatorProvider/TranslatorProvider.js.map +1 -1
  179. package/build/providers/TranslatorProvider/TranslatorProvider.mjs +5 -3
  180. package/build/providers/TranslatorProvider/TranslatorProvider.mjs.map +1 -1
  181. package/build/providers/VersionProvider/VersionProvider.js +3 -3
  182. package/build/providers/VersionProvider/VersionProvider.js.map +1 -1
  183. package/build/providers/VersionProvider/VersionProvider.mjs +3 -3
  184. package/build/providers/VersionProvider/VersionProvider.mjs.map +1 -1
  185. package/build/sections/Detail/Tabs.js +1 -1
  186. package/build/sections/Detail/Tabs.mjs +1 -1
  187. package/build/sections/Footer/Footer.js +1 -1
  188. package/build/sections/Footer/Footer.mjs +1 -1
  189. package/build/sections/Header/Header.d.ts +0 -1
  190. package/build/sections/Header/Header.js +16 -14
  191. package/build/sections/Header/Header.js.map +1 -1
  192. package/build/sections/Header/Header.mjs +17 -15
  193. package/build/sections/Header/Header.mjs.map +1 -1
  194. package/build/sections/Header/HeaderGreetings.js +1 -1
  195. package/build/sections/Header/HeaderGreetings.mjs +1 -1
  196. package/build/sections/Header/HeaderMenu.js +1 -1
  197. package/build/sections/Header/HeaderMenu.mjs +1 -1
  198. package/build/sections/Header/HeaderRight.js +1 -1
  199. package/build/sections/Header/HeaderRight.mjs +1 -1
  200. package/build/sections/Header/HeaderSettingsDialog.js +1 -1
  201. package/build/sections/Header/HeaderSettingsDialog.mjs +1 -1
  202. package/build/sections/Header/LanguageSwitch.js +1 -1
  203. package/build/sections/Header/LanguageSwitch.mjs +1 -1
  204. package/build/sections/Header/RegistryInfoContent/RegistryInfoContent.js +1 -1
  205. package/build/sections/Header/RegistryInfoContent/RegistryInfoContent.mjs +1 -1
  206. package/build/sections/Home/Home.js +4 -3
  207. package/build/sections/Home/Home.js.map +1 -1
  208. package/build/sections/Home/Home.mjs +5 -4
  209. package/build/sections/Home/Home.mjs.map +1 -1
  210. package/build/sections/Security/AddUser.js +33 -18
  211. package/build/sections/Security/AddUser.js.map +1 -1
  212. package/build/sections/Security/AddUser.mjs +37 -22
  213. package/build/sections/Security/AddUser.mjs.map +1 -1
  214. package/build/sections/Security/ChangePassword.js +17 -15
  215. package/build/sections/Security/ChangePassword.js.map +1 -1
  216. package/build/sections/Security/ChangePassword.mjs +19 -17
  217. package/build/sections/Security/ChangePassword.mjs.map +1 -1
  218. package/build/sections/Security/Login.js +51 -35
  219. package/build/sections/Security/Login.js.map +1 -1
  220. package/build/sections/Security/Login.mjs +54 -38
  221. package/build/sections/Security/Login.mjs.map +1 -1
  222. package/build/sections/Security/Success.js +28 -24
  223. package/build/sections/Security/Success.js.map +1 -1
  224. package/build/sections/Security/Success.mjs +29 -25
  225. package/build/sections/Security/Success.mjs.map +1 -1
  226. package/build/sections/Stage/StageActions.js +1 -1
  227. package/build/sections/Stage/StageActions.mjs +1 -1
  228. package/build/sections/Stage/StageDetail.js +1 -1
  229. package/build/sections/Stage/StageDetail.mjs +1 -1
  230. package/build/sections/Stage/StageList.js +15 -2
  231. package/build/sections/Stage/StageList.js.map +1 -1
  232. package/build/sections/Stage/StageList.mjs +15 -2
  233. package/build/sections/Stage/StageList.mjs.map +1 -1
  234. package/build/store/api.js +7 -4
  235. package/build/store/api.js.map +1 -1
  236. package/build/store/api.mjs +7 -4
  237. package/build/store/api.mjs.map +1 -1
  238. package/build/types/packageMeta.d.ts +3 -2
  239. package/build/utils/cli-utils.js +2 -2
  240. package/build/utils/cli-utils.js.map +1 -1
  241. package/build/utils/cli-utils.mjs +2 -2
  242. package/build/utils/cli-utils.mjs.map +1 -1
  243. package/build/utils/index.js +1 -0
  244. package/build/utils/index.mjs +2 -2
  245. package/build/utils/routes.d.ts +1 -0
  246. package/build/utils/routes.js +1 -0
  247. package/build/utils/routes.js.map +1 -1
  248. package/build/utils/routes.mjs +1 -0
  249. package/build/utils/routes.mjs.map +1 -1
  250. package/build/utils/schemas.d.ts +1 -0
  251. package/build/utils/schemas.js +4 -4
  252. package/build/utils/schemas.js.map +1 -1
  253. package/build/utils/schemas.mjs +4 -4
  254. package/build/utils/schemas.mjs.map +1 -1
  255. package/build/utils/session-id.d.ts +8 -0
  256. package/build/utils/session-id.js +26 -0
  257. package/build/utils/session-id.js.map +1 -0
  258. package/build/utils/session-id.mjs +26 -0
  259. package/build/utils/session-id.mjs.map +1 -0
  260. package/build/utils/token.d.ts +1 -0
  261. package/build/utils/token.js +12 -8
  262. package/build/utils/token.js.map +1 -1
  263. package/build/utils/token.mjs +12 -9
  264. package/build/utils/token.mjs.map +1 -1
  265. package/build/utils/url.js +1 -1
  266. package/build/utils/url.js.map +1 -1
  267. package/build/utils/url.mjs +1 -1
  268. package/build/utils/url.mjs.map +1 -1
  269. package/build/utils/utils.d.ts +10 -0
  270. package/build/utils/utils.js +26 -0
  271. package/build/utils/utils.js.map +1 -1
  272. package/build/utils/utils.mjs +25 -1
  273. package/build/utils/utils.mjs.map +1 -1
  274. package/package.json +6 -6
@@ -1,4 +1,4 @@
1
- import { isTokenExpire } from "../../utils/token.mjs";
1
+ import { tokenExpireInMs } from "../../utils/token.mjs";
2
2
  import { useConfig } from "../../providers/AppConfigurationProvider/AppConfigurationProvider.mjs";
3
3
  import { useAuth } from "../../providers/AuthProvider/AuthProvider.mjs";
4
4
  import LoginDialog from "../../components/LoginDialog/LoginDialog.mjs";
@@ -9,11 +9,11 @@ import HeaderRight from "./HeaderRight.mjs";
9
9
  import HeaderSettingsDialog from "./HeaderSettingsDialog.mjs";
10
10
  import "../../index.mjs";
11
11
  import { useEffect, useRef, useState } from "react";
12
- import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
13
12
  import { useTranslation } from "react-i18next";
13
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
14
14
  import Button from "@mui/material/Button";
15
15
  //#region src/sections/Header/Header.tsx
16
- var Header = ({ HeaderInfoDialog, isPlainHeader, tokenCheckIntervalMs = 36e5 }) => {
16
+ var Header = ({ HeaderInfoDialog, isPlainHeader }) => {
17
17
  const { t } = useTranslation();
18
18
  const [isInfoDialogOpen, setOpenInfoDialog] = useState(false);
19
19
  const [isSettingsDialogOpen, setSettingsDialogOpen] = useState(false);
@@ -21,23 +21,25 @@ var Header = ({ HeaderInfoDialog, isPlainHeader, tokenCheckIntervalMs = 36e5 })
21
21
  const [showLoginModal, setShowLoginModal] = useState(false);
22
22
  const { configOptions } = useConfig();
23
23
  const { userState, logOutUser } = useAuth();
24
- const tokenRef = useRef(userState?.token);
25
24
  const logOutUserRef = useRef(logOutUser);
26
- useEffect(() => {
27
- tokenRef.current = userState?.token;
28
- }, [userState?.token]);
29
25
  useEffect(() => {
30
26
  logOutUserRef.current = logOutUser;
31
27
  }, [logOutUser]);
32
28
  useEffect(() => {
33
- function checkToken() {
34
- const token = tokenRef.current;
35
- if (token && isTokenExpire(token)) logOutUserRef.current?.();
36
- }
37
- checkToken();
38
- const interval = setInterval(checkToken, tokenCheckIntervalMs);
39
- return () => clearInterval(interval);
40
- }, [tokenCheckIntervalMs]);
29
+ const token = userState?.token;
30
+ if (!token) return;
31
+ let timer;
32
+ const arm = () => {
33
+ const remaining = tokenExpireInMs(token);
34
+ if (remaining === null || remaining <= 0) {
35
+ logOutUserRef.current?.();
36
+ return;
37
+ }
38
+ timer = setTimeout(arm, Math.min(remaining, 2 ** 31 - 1));
39
+ };
40
+ arm();
41
+ return () => clearTimeout(timer);
42
+ }, [userState?.token]);
41
43
  const handleLogout = () => {
42
44
  logOutUser?.();
43
45
  setShowLoginModal(false);
@@ -1 +1 @@
1
- {"version":3,"file":"Header.mjs","names":[],"sources":["../../../src/sections/Header/Header.tsx"],"sourcesContent":["import Button from '@mui/material/Button';\nimport React, { useEffect, useRef, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\n\nimport { LoginDialog, Search, useAuth, useConfig } from '../../';\nimport { isTokenExpire } from '../../utils/token';\nimport HeaderLeft from './HeaderLeft';\nimport HeaderRight from './HeaderRight';\nimport HeaderSettingsDialog from './HeaderSettingsDialog';\nimport { InnerMobileNavBar, InnerNavBar, MobileNavBar, NavBar } from './styles';\n\ntype Props = {\n HeaderInfoDialog?: React.FC<any>;\n isPlainHeader?: boolean;\n tokenCheckIntervalMs?: number;\n};\n\n// Session timeout default is 1 hour\nconst Header: React.FC<Props> = ({\n HeaderInfoDialog,\n isPlainHeader,\n tokenCheckIntervalMs = 60 * 60 * 1000,\n}) => {\n const { t } = useTranslation();\n const [isInfoDialogOpen, setOpenInfoDialog] = useState<boolean>(false);\n const [isSettingsDialogOpen, setSettingsDialogOpen] = useState<boolean>(false);\n const [showMobileNavBar, setShowMobileNavBar] = useState<boolean>(false);\n const [showLoginModal, setShowLoginModal] = useState<boolean>(false);\n const { configOptions } = useConfig();\n const { userState, logOutUser } = useAuth();\n\n // Use refs to always have the latest token/logout in the interval callback\n const tokenRef = useRef(userState?.token);\n const logOutUserRef = useRef(logOutUser);\n useEffect(() => {\n tokenRef.current = userState?.token;\n }, [userState?.token]);\n useEffect(() => {\n logOutUserRef.current = logOutUser;\n }, [logOutUser]);\n\n useEffect(() => {\n function checkToken() {\n const token = tokenRef.current;\n if (token && isTokenExpire(token)) {\n logOutUserRef.current?.();\n }\n }\n checkToken();\n const interval = setInterval(checkToken, tokenCheckIntervalMs);\n return () => clearInterval(interval);\n }, [tokenCheckIntervalMs]);\n\n const handleLogout = () => {\n logOutUser?.();\n setShowLoginModal(false);\n };\n if (isPlainHeader) {\n return (\n <NavBar data-testid=\"header\" position=\"static\">\n <InnerNavBar data-testid=\"inner-nav-bar\">\n <HeaderLeft showSearch={false} />\n <HeaderRight\n hasLogin={false}\n onLogout={() => {}}\n onOpenRegistryInfoDialog={() => {}}\n onOpenSettingsDialog={() => {}}\n onToggleLogin={() => {}}\n onToggleMobileNav={() => {}}\n showInfo={false}\n showSearch={false}\n showSettings={false}\n showThemeSwitch={false}\n username={''}\n />\n </InnerNavBar>\n </NavBar>\n );\n }\n\n return (\n <>\n <NavBar data-testid=\"header\" position=\"static\">\n <InnerNavBar data-testid=\"inner-nav-bar\">\n <HeaderLeft showSearch={configOptions.showSearch} />\n <HeaderRight\n hasLogin={configOptions?.login}\n onLogout={handleLogout}\n onOpenRegistryInfoDialog={() => setOpenInfoDialog(true)}\n onOpenSettingsDialog={() => setSettingsDialogOpen(true)}\n onToggleLogin={() => setShowLoginModal(!showLoginModal)}\n onToggleMobileNav={() => setShowMobileNavBar(!showMobileNavBar)}\n showInfo={configOptions.showInfo}\n showSearch={configOptions.showSearch}\n showSettings={configOptions.showSettings}\n showThemeSwitch={configOptions.showThemeSwitch}\n username={userState?.username}\n />\n </InnerNavBar>\n <HeaderSettingsDialog\n isOpen={isSettingsDialogOpen}\n onCloseDialog={() => setSettingsDialogOpen(false)}\n />\n {HeaderInfoDialog ? (\n <HeaderInfoDialog\n dialogTitle={t('dialog.registry-info.title')}\n isOpen={isInfoDialogOpen}\n onCloseDialog={() => setOpenInfoDialog(false)}\n />\n ) : null}\n </NavBar>\n {showMobileNavBar && (\n <MobileNavBar data-testid=\"mobile-nav-bar\">\n <InnerMobileNavBar>\n <Search />\n </InnerMobileNavBar>\n <Button color=\"inherit\" onClick={() => setShowMobileNavBar(false)}>\n {t('button.cancel')}\n </Button>\n </MobileNavBar>\n )}\n {!userState?.username && (\n <LoginDialog onClose={() => setShowLoginModal(false)} open={showLoginModal} />\n )}\n </>\n );\n};\n\nexport default Header;\n"],"mappings":";;;;;;;;;;;;;;;AAkBA,IAAM,UAA2B,EAC/B,kBACA,eACA,uBAAuB,WACnB;CACJ,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,CAAC,kBAAkB,qBAAqB,SAAkB,KAAK;CACrE,MAAM,CAAC,sBAAsB,yBAAyB,SAAkB,KAAK;CAC7E,MAAM,CAAC,kBAAkB,uBAAuB,SAAkB,KAAK;CACvE,MAAM,CAAC,gBAAgB,qBAAqB,SAAkB,KAAK;CACnE,MAAM,EAAE,kBAAkB,UAAU;CACpC,MAAM,EAAE,WAAW,eAAe,QAAQ;CAG1C,MAAM,WAAW,OAAO,WAAW,KAAK;CACxC,MAAM,gBAAgB,OAAO,UAAU;CACvC,gBAAgB;EACd,SAAS,UAAU,WAAW;CAChC,GAAG,CAAC,WAAW,KAAK,CAAC;CACrB,gBAAgB;EACd,cAAc,UAAU;CAC1B,GAAG,CAAC,UAAU,CAAC;CAEf,gBAAgB;EACd,SAAS,aAAa;GACpB,MAAM,QAAQ,SAAS;GACvB,IAAI,SAAS,cAAc,KAAK,GAC9B,cAAc,UAAU;EAE5B;EACA,WAAW;EACX,MAAM,WAAW,YAAY,YAAY,oBAAoB;EAC7D,aAAa,cAAc,QAAQ;CACrC,GAAG,CAAC,oBAAoB,CAAC;CAEzB,MAAM,qBAAqB;EACzB,aAAa;EACb,kBAAkB,KAAK;CACzB;CACA,IAAI,eACF,OACE,oBAAC,QAAD;EAAQ,eAAY;EAAS,UAAS;EACpC,UAAA,qBAAC,aAAD;GAAa,eAAY;GAAzB,UAAA,CACE,oBAAC,YAAD,EAAY,YAAY,MAAQ,CAAA,GAChC,oBAAC,aAAD;IACE,UAAU;IACV,gBAAgB,CAAC;IACjB,gCAAgC,CAAC;IACjC,4BAA4B,CAAC;IAC7B,qBAAqB,CAAC;IACtB,yBAAyB,CAAC;IAC1B,UAAU;IACV,YAAY;IACZ,cAAc;IACd,iBAAiB;IACjB,UAAU;GACX,CAAA,CACU;;CACP,CAAA;CAIZ,OACE,qBAAA,YAAA,EAAA,UAAA;EACE,qBAAC,QAAD;GAAQ,eAAY;GAAS,UAAS;GAAtC,UAAA;IACE,qBAAC,aAAD;KAAa,eAAY;KAAzB,UAAA,CACE,oBAAC,YAAD,EAAY,YAAY,cAAc,WAAa,CAAA,GACnD,oBAAC,aAAD;MACE,UAAU,eAAe;MACzB,UAAU;MACV,gCAAgC,kBAAkB,IAAI;MACtD,4BAA4B,sBAAsB,IAAI;MACtD,qBAAqB,kBAAkB,CAAC,cAAc;MACtD,yBAAyB,oBAAoB,CAAC,gBAAgB;MAC9D,UAAU,cAAc;MACxB,YAAY,cAAc;MAC1B,cAAc,cAAc;MAC5B,iBAAiB,cAAc;MAC/B,UAAU,WAAW;KACtB,CAAA,CACU;;IACb,oBAAC,sBAAD;KACE,QAAQ;KACR,qBAAqB,sBAAsB,KAAK;IACjD,CAAA;IACA,mBACC,oBAAC,kBAAD;KACE,aAAa,EAAE,4BAA4B;KAC3C,QAAQ;KACR,qBAAqB,kBAAkB,KAAK;IAC7C,CAAA,IACC;GACE;;EACP,oBACC,qBAAC,cAAD;GAAc,eAAY;GAA1B,UAAA,CACE,oBAAC,mBAAD,EAAA,UACE,oBAAC,QAAD,CAAS,CAAA,EACQ,CAAA,GACnB,oBAAC,QAAD;IAAQ,OAAM;IAAU,eAAe,oBAAoB,KAAK;IAC7D,UAAA,EAAE,eAAe;GACZ,CAAA,CACI;;EAEf,CAAC,WAAW,YACX,oBAAC,aAAD;GAAa,eAAe,kBAAkB,KAAK;GAAG,MAAM;EAAiB,CAAA;CAE/E,EAAA,CAAA;AAEN"}
1
+ {"version":3,"file":"Header.mjs","names":[],"sources":["../../../src/sections/Header/Header.tsx"],"sourcesContent":["import Button from '@mui/material/Button';\nimport React, { useEffect, useRef, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\n\nimport { LoginDialog, Search, useAuth, useConfig } from '../../';\nimport { tokenExpireInMs } from '../../utils/token';\nimport HeaderLeft from './HeaderLeft';\nimport HeaderRight from './HeaderRight';\nimport HeaderSettingsDialog from './HeaderSettingsDialog';\nimport { InnerMobileNavBar, InnerNavBar, MobileNavBar, NavBar } from './styles';\n\ntype Props = {\n HeaderInfoDialog?: React.FC<any>;\n isPlainHeader?: boolean;\n};\n\nconst Header: React.FC<Props> = ({ HeaderInfoDialog, isPlainHeader }) => {\n const { t } = useTranslation();\n const [isInfoDialogOpen, setOpenInfoDialog] = useState<boolean>(false);\n const [isSettingsDialogOpen, setSettingsDialogOpen] = useState<boolean>(false);\n const [showMobileNavBar, setShowMobileNavBar] = useState<boolean>(false);\n const [showLoginModal, setShowLoginModal] = useState<boolean>(false);\n const { configOptions } = useConfig();\n const { userState, logOutUser } = useAuth();\n\n // Use a ref to always have the latest logout in the timer callback\n const logOutUserRef = useRef(logOutUser);\n useEffect(() => {\n logOutUserRef.current = logOutUser;\n }, [logOutUser]);\n\n // log out exactly when the token expires; polling reloaded the page at an\n // arbitrary moment up to a minute later, mid-interaction\n useEffect(() => {\n const token = userState?.token;\n if (!token) {\n return;\n }\n let timer: ReturnType<typeof setTimeout> | undefined;\n const arm = () => {\n const remaining = tokenExpireInMs(token);\n if (remaining === null || remaining <= 0) {\n logOutUserRef.current?.();\n return;\n }\n // setTimeout overflows above 2^31-1 ms; re-arm for far-away expiries\n timer = setTimeout(arm, Math.min(remaining, 2 ** 31 - 1));\n };\n arm();\n return () => clearTimeout(timer);\n }, [userState?.token]);\n\n const handleLogout = () => {\n logOutUser?.();\n setShowLoginModal(false);\n };\n if (isPlainHeader) {\n return (\n <NavBar data-testid=\"header\" position=\"static\">\n <InnerNavBar data-testid=\"inner-nav-bar\">\n <HeaderLeft showSearch={false} />\n <HeaderRight\n hasLogin={false}\n onLogout={() => {}}\n onOpenRegistryInfoDialog={() => {}}\n onOpenSettingsDialog={() => {}}\n onToggleLogin={() => {}}\n onToggleMobileNav={() => {}}\n showInfo={false}\n showSearch={false}\n showSettings={false}\n showThemeSwitch={false}\n username={''}\n />\n </InnerNavBar>\n </NavBar>\n );\n }\n\n return (\n <>\n <NavBar data-testid=\"header\" position=\"static\">\n <InnerNavBar data-testid=\"inner-nav-bar\">\n <HeaderLeft showSearch={configOptions.showSearch} />\n <HeaderRight\n hasLogin={configOptions?.login}\n onLogout={handleLogout}\n onOpenRegistryInfoDialog={() => setOpenInfoDialog(true)}\n onOpenSettingsDialog={() => setSettingsDialogOpen(true)}\n onToggleLogin={() => setShowLoginModal(!showLoginModal)}\n onToggleMobileNav={() => setShowMobileNavBar(!showMobileNavBar)}\n showInfo={configOptions.showInfo}\n showSearch={configOptions.showSearch}\n showSettings={configOptions.showSettings}\n showThemeSwitch={configOptions.showThemeSwitch}\n username={userState?.username}\n />\n </InnerNavBar>\n <HeaderSettingsDialog\n isOpen={isSettingsDialogOpen}\n onCloseDialog={() => setSettingsDialogOpen(false)}\n />\n {HeaderInfoDialog ? (\n <HeaderInfoDialog\n dialogTitle={t('dialog.registry-info.title')}\n isOpen={isInfoDialogOpen}\n onCloseDialog={() => setOpenInfoDialog(false)}\n />\n ) : null}\n </NavBar>\n {showMobileNavBar && (\n <MobileNavBar data-testid=\"mobile-nav-bar\">\n <InnerMobileNavBar>\n <Search />\n </InnerMobileNavBar>\n <Button color=\"inherit\" onClick={() => setShowMobileNavBar(false)}>\n {t('button.cancel')}\n </Button>\n </MobileNavBar>\n )}\n {!userState?.username && (\n <LoginDialog onClose={() => setShowLoginModal(false)} open={showLoginModal} />\n )}\n </>\n );\n};\n\nexport default Header;\n"],"mappings":";;;;;;;;;;;;;;;AAgBA,IAAM,UAA2B,EAAE,kBAAkB,oBAAoB;CACvE,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,CAAC,kBAAkB,qBAAqB,SAAkB,KAAK;CACrE,MAAM,CAAC,sBAAsB,yBAAyB,SAAkB,KAAK;CAC7E,MAAM,CAAC,kBAAkB,uBAAuB,SAAkB,KAAK;CACvE,MAAM,CAAC,gBAAgB,qBAAqB,SAAkB,KAAK;CACnE,MAAM,EAAE,kBAAkB,UAAU;CACpC,MAAM,EAAE,WAAW,eAAe,QAAQ;CAG1C,MAAM,gBAAgB,OAAO,UAAU;CACvC,gBAAgB;EACd,cAAc,UAAU;CAC1B,GAAG,CAAC,UAAU,CAAC;CAIf,gBAAgB;EACd,MAAM,QAAQ,WAAW;EACzB,IAAI,CAAC,OACH;EAEF,IAAI;EACJ,MAAM,YAAY;GAChB,MAAM,YAAY,gBAAgB,KAAK;GACvC,IAAI,cAAc,QAAQ,aAAa,GAAG;IACxC,cAAc,UAAU;IACxB;GACF;GAEA,QAAQ,WAAW,KAAK,KAAK,IAAI,WAAW,KAAK,KAAK,CAAC,CAAC;EAC1D;EACA,IAAI;EACJ,aAAa,aAAa,KAAK;CACjC,GAAG,CAAC,WAAW,KAAK,CAAC;CAErB,MAAM,qBAAqB;EACzB,aAAa;EACb,kBAAkB,KAAK;CACzB;CACA,IAAI,eACF,OACE,oBAAC,QAAD;EAAQ,eAAY;EAAS,UAAS;EACpC,UAAA,qBAAC,aAAD;GAAa,eAAY;GAAzB,UAAA,CACE,oBAAC,YAAD,EAAY,YAAY,MAAQ,CAAA,GAChC,oBAAC,aAAD;IACE,UAAU;IACV,gBAAgB,CAAC;IACjB,gCAAgC,CAAC;IACjC,4BAA4B,CAAC;IAC7B,qBAAqB,CAAC;IACtB,yBAAyB,CAAC;IAC1B,UAAU;IACV,YAAY;IACZ,cAAc;IACd,iBAAiB;IACjB,UAAU;GACX,CAAA,CACU;;CACP,CAAA;CAIZ,OACE,qBAAA,YAAA,EAAA,UAAA;EACE,qBAAC,QAAD;GAAQ,eAAY;GAAS,UAAS;GAAtC,UAAA;IACE,qBAAC,aAAD;KAAa,eAAY;KAAzB,UAAA,CACE,oBAAC,YAAD,EAAY,YAAY,cAAc,WAAa,CAAA,GACnD,oBAAC,aAAD;MACE,UAAU,eAAe;MACzB,UAAU;MACV,gCAAgC,kBAAkB,IAAI;MACtD,4BAA4B,sBAAsB,IAAI;MACtD,qBAAqB,kBAAkB,CAAC,cAAc;MACtD,yBAAyB,oBAAoB,CAAC,gBAAgB;MAC9D,UAAU,cAAc;MACxB,YAAY,cAAc;MAC1B,cAAc,cAAc;MAC5B,iBAAiB,cAAc;MAC/B,UAAU,WAAW;KACtB,CAAA,CACU;;IACb,oBAAC,sBAAD;KACE,QAAQ;KACR,qBAAqB,sBAAsB,KAAK;IACjD,CAAA;IACA,mBACC,oBAAC,kBAAD;KACE,aAAa,EAAE,4BAA4B;KAC3C,QAAQ;KACR,qBAAqB,kBAAkB,KAAK;IAC7C,CAAA,IACC;GACE;;EACP,oBACC,qBAAC,cAAD;GAAc,eAAY;GAA1B,UAAA,CACE,oBAAC,mBAAD,EAAA,UACE,oBAAC,QAAD,CAAS,CAAA,EACQ,CAAA,GACnB,oBAAC,QAAD;IAAQ,OAAM;IAAU,eAAe,oBAAoB,KAAK;IAC7D,UAAA,EAAE,eAAe;GACZ,CAAA,CACI;;EAEf,CAAC,WAAW,YACX,oBAAC,aAAD;GAAa,eAAe,kBAAkB,KAAK;GAAG,MAAM;EAAiB,CAAA;CAE/E,EAAA,CAAA;AAEN"}
@@ -4,8 +4,8 @@ const require_styles = require("./styles.js");
4
4
  require("../../index.js");
5
5
  let react = require("react");
6
6
  react = require_runtime.__toESM(react);
7
- let react_jsx_runtime = require("react/jsx-runtime");
8
7
  let react_i18next = require("react-i18next");
8
+ let react_jsx_runtime = require("react/jsx-runtime");
9
9
  //#region src/sections/Header/HeaderGreetings.tsx
10
10
  var HeaderGreetings = ({ username }) => {
11
11
  const { t } = (0, react_i18next.useTranslation)();
@@ -2,8 +2,8 @@ import Label from "../../components/Label/Label.mjs";
2
2
  import { Greetings } from "./styles.mjs";
3
3
  import "../../index.mjs";
4
4
  import "react";
5
- import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
6
5
  import { useTranslation } from "react-i18next";
6
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
7
7
  //#region src/sections/Header/HeaderGreetings.tsx
8
8
  var HeaderGreetings = ({ username }) => {
9
9
  const { t } = useTranslation();
@@ -9,8 +9,8 @@ let _mui_material_IconButton = require("@mui/material/IconButton");
9
9
  _mui_material_IconButton = require_runtime.__toESM(_mui_material_IconButton);
10
10
  let react = require("react");
11
11
  react = require_runtime.__toESM(react);
12
- let react_jsx_runtime = require("react/jsx-runtime");
13
12
  let react_i18next = require("react-i18next");
13
+ let react_jsx_runtime = require("react/jsx-runtime");
14
14
  let react_router = require("react-router");
15
15
  let _mui_material_Menu = require("@mui/material/Menu");
16
16
  _mui_material_Menu = require_runtime.__toESM(_mui_material_Menu);
@@ -6,8 +6,8 @@ import HeaderGreetings from "./HeaderGreetings.mjs";
6
6
  import "../../index.mjs";
7
7
  import IconButton from "@mui/material/IconButton";
8
8
  import "react";
9
- import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
10
9
  import { useTranslation } from "react-i18next";
10
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
11
11
  import { useNavigate } from "react-router";
12
12
  import Menu from "@mui/material/Menu";
13
13
  import AccountCircle from "@mui/icons-material/AccountCircle";
@@ -5,8 +5,8 @@ const require_ThemeProvider = require("../../Theme/ThemeProvider.js");
5
5
  require("../../index.js");
6
6
  let react = require("react");
7
7
  react = require_runtime.__toESM(react);
8
- let react_jsx_runtime = require("react/jsx-runtime");
9
8
  let react_i18next = require("react-i18next");
9
+ let react_jsx_runtime = require("react/jsx-runtime");
10
10
  let _mui_material_Button = require("@mui/material/Button");
11
11
  _mui_material_Button = require_runtime.__toESM(_mui_material_Button);
12
12
  let _mui_material_Toolbar = require("@mui/material/Toolbar");
@@ -3,8 +3,8 @@ import HeaderToolTip from "./HeaderToolTip.mjs";
3
3
  import { useCustomTheme } from "../../Theme/ThemeProvider.mjs";
4
4
  import "../../index.mjs";
5
5
  import { useEffect, useState } from "react";
6
- import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
7
6
  import { useTranslation } from "react-i18next";
7
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
8
  import Button from "@mui/material/Button";
9
9
  import Toolbar from "@mui/material/Toolbar";
10
10
  //#region src/sections/Header/HeaderRight.tsx
@@ -9,10 +9,10 @@ let _emotion_styled = require("@emotion/styled");
9
9
  _emotion_styled = require_runtime.__toESM(_emotion_styled);
10
10
  let react = require("react");
11
11
  react = require_runtime.__toESM(react);
12
+ let react_i18next = require("react-i18next");
12
13
  let react_jsx_runtime = require("react/jsx-runtime");
13
14
  let _mui_material_Box = require("@mui/material/Box");
14
15
  _mui_material_Box = require_runtime.__toESM(_mui_material_Box);
15
- let react_i18next = require("react-i18next");
16
16
  let _mui_material_Tab = require("@mui/material/Tab");
17
17
  _mui_material_Tab = require_runtime.__toESM(_mui_material_Tab);
18
18
  let _mui_material_Tabs = require("@mui/material/Tabs");
@@ -6,9 +6,9 @@ import RegistryInfoContent from "./RegistryInfoContent/RegistryInfoContent.mjs";
6
6
  import "./RegistryInfoContent/index.mjs";
7
7
  import styled from "@emotion/styled";
8
8
  import React from "react";
9
+ import { useTranslation } from "react-i18next";
9
10
  import { jsx, jsxs } from "react/jsx-runtime";
10
11
  import Box from "@mui/material/Box";
11
- import { useTranslation } from "react-i18next";
12
12
  import Tab from "@mui/material/Tab";
13
13
  import Tabs from "@mui/material/Tabs";
14
14
  import ReactMarkdown from "react-markdown";
@@ -5,10 +5,10 @@ let _emotion_styled = require("@emotion/styled");
5
5
  _emotion_styled = require_runtime.__toESM(_emotion_styled);
6
6
  let react = require("react");
7
7
  react = require_runtime.__toESM(react);
8
+ let react_i18next = require("react-i18next");
8
9
  let react_jsx_runtime = require("react/jsx-runtime");
9
10
  let i18next = require("i18next");
10
11
  i18next = require_runtime.__toESM(i18next);
11
- let react_i18next = require("react-i18next");
12
12
  let _mui_material_Typography = require("@mui/material/Typography");
13
13
  _mui_material_Typography = require_runtime.__toESM(_mui_material_Typography);
14
14
  let _mui_material_Card = require("@mui/material/Card");
@@ -2,9 +2,9 @@ import { useLanguage } from "../../providers/TranslatorProvider/TranslatorProvid
2
2
  import "../../index.mjs";
3
3
  import styled from "@emotion/styled";
4
4
  import { useCallback, useState } from "react";
5
+ import { useTranslation } from "react-i18next";
5
6
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
6
7
  import i18next from "i18next";
7
- import { useTranslation } from "react-i18next";
8
8
  import Typography from "@mui/material/Typography";
9
9
  import Card from "@mui/material/Card";
10
10
  import CardContent from "@mui/material/CardContent";
@@ -8,10 +8,10 @@ let _emotion_styled = require("@emotion/styled");
8
8
  _emotion_styled = require_runtime.__toESM(_emotion_styled);
9
9
  let react = require("react");
10
10
  react = require_runtime.__toESM(react);
11
+ let react_i18next = require("react-i18next");
11
12
  let react_jsx_runtime = require("react/jsx-runtime");
12
13
  let _mui_material_Box = require("@mui/material/Box");
13
14
  _mui_material_Box = require_runtime.__toESM(_mui_material_Box);
14
- let react_i18next = require("react-i18next");
15
15
  let _mui_material_Link = require("@mui/material/Link");
16
16
  _mui_material_Link = require_runtime.__toESM(_mui_material_Link);
17
17
  let _mui_material_Typography = require("@mui/material/Typography");
@@ -5,9 +5,9 @@ import { Description, TextContent } from "./styles.mjs";
5
5
  import "../../../index.mjs";
6
6
  import styled from "@emotion/styled";
7
7
  import "react";
8
+ import { useTranslation } from "react-i18next";
8
9
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
9
10
  import Box from "@mui/material/Box";
10
- import { useTranslation } from "react-i18next";
11
11
  import Link from "@mui/material/Link";
12
12
  import Typography from "@mui/material/Typography";
13
13
  import ReactMarkdown from "react-markdown";
@@ -1,5 +1,6 @@
1
1
  const require_runtime = require("../../_virtual/_rolldown/runtime.js");
2
2
  const require_ManifestsProvider = require("../../providers/ManifestsProvider/ManifestsProvider.js");
3
+ const require_GenericError = require("../../components/GenericError/GenericError.js");
3
4
  const require_Loading = require("../../components/Loading/Loading.js");
4
5
  const require_PackageList = require("../../components/PackageList/PackageList.js");
5
6
  require("../../index.js");
@@ -9,11 +10,11 @@ let react_jsx_runtime = require("react/jsx-runtime");
9
10
  //#region src/sections/Home/Home.tsx
10
11
  var Home = () => {
11
12
  const manifests = require_ManifestsProvider.useManifests();
12
- if (manifests.isError) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: "Error loading manifests" });
13
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
13
+ if (manifests.isError) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_GenericError.default, {});
14
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
14
15
  className: "container content",
15
16
  "data-testid": "home-page-container",
16
- children: [manifests.isLoading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Loading.default, {}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_PackageList.default, { packages: manifests.manifests }), manifests.isError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: "Error loading manifests" })]
17
+ children: manifests.isLoading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Loading.default, {}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_PackageList.default, { packages: manifests.manifests })
17
18
  });
18
19
  };
19
20
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"Home.js","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,0BAAA,aAAa;CAE/B,IAAI,UAAU,SACZ,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD,EAAA,UAAK,0BAA4B,CAAA;CAG1C,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;EAAK,WAAU;EAAoB,eAAY;EAA/C,UAAA,CACG,UAAU,YACT,iBAAA,GAAA,kBAAA,IAAA,CAAC,gBAAA,SAAD,CAAU,CAAA,IAEV,iBAAA,GAAA,kBAAA,IAAA,CAAC,oBAAA,SAAD,EAAa,UAAU,UAAU,UAA6B,CAAA,GAE/D,UAAU,WAAW,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD,EAAA,UAAM,0BAA+B,CAAA,CACxD;;AAET"}
1
+ {"version":3,"file":"Home.js","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,0BAAA,aAAa;CAE/B,IAAI,UAAU,SACZ,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,qBAAA,SAAD,CAAe,CAAA;CAGxB,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;EAAK,WAAU;EAAoB,eAAY;EAC5C,UAAA,UAAU,YACT,iBAAA,GAAA,kBAAA,IAAA,CAAC,gBAAA,SAAD,CAAU,CAAA,IAEV,iBAAA,GAAA,kBAAA,IAAA,CAAC,oBAAA,SAAD,EAAa,UAAU,UAAU,UAA6B,CAAA;CAE7D,CAAA;AAET"}
@@ -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
  })