@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 +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":";;;;;;;;;;;;;;;;;;;;;AAoBA,IAAM,uBAAiC;CACrC,MAAM,EAAE,OAAA,GAAM,cAAA,eAAA,CAAe;CAC7B,MAAM,YAAA,GAAW,aAAA,YAAA,CAAY;CAC7B,MAAM,gBAAgB,sBAAA,iBAAiB;CACvC,MAAM,WAAW,cAAA,mBAAmB,cAAc,IAAI;CACtD,MAAM,wBAAwB,eAAe,OAAO;CAapD,MAAM,EACJ,UACA,cACA,UACA,WAAW,EAAE,SAAS,cAAA,GAfX,gBAAA,QAAA,CAAkC;EAC7C,MAAM;EACN,eAAe;GACb,UAAU;GACV,aAAa;GACb,aAAa;GACb,iBAAiB;EACnB;EACA,WAAA,GAAU,wBAAA,YAAA,CAAY,gBAAA,oBAAoB;CAC5C,CAOI;CAEJ,MAAM,EAAE,YAAY,0BAAA,gBAAgC,UAAU,eAAA,SAAS,gBAAgB,KAAK;CAE5F,MAAM,wBAAA,GAAuB,MAAA,YAAA,CAC3B,OAAO,SAAqD;EAC1D,IAAI;GACF,MAAM,QAAQ,IAAI;EACpB,SAAS,KAAK;GACZ,MAAM,gBAAA,mBAAmB,GAAG;EAC9B;CACF,GACA,CAAC,OAAO,CACV;CAEA,MAAM,YAAA,GAAW,MAAA,YAAA,CACf,OAAO,SAAmC;EACxC,IAAI;GACF,MAAM,qBAAqB,EACzB,UAAU;IACR,KAAK,KAAK;IACV,KAAK,KAAK;GACZ,EACF,CAAC;GACD,SAAS,GAAG,eAAA,MAAM,QAAQ,eAAe,gBAAA,YAAY,gBAAgB;EACvE,QAAQ;GACN,SAAS,QAAQ;IACf,MAAM;IACN,SAAS;GACX,CAAC;EACH;CACF,GACA;EAAC;EAAsB;EAAU;CAAQ,CAC3C;CAEA,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,IAAI,CAAC,uBACH,SAAS,GAAG;CAEhB,GAAG,CAAC,uBAAuB,QAAQ,CAAC;CAEpC,OAAO,wBACL,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAA,SAAD,EAAA,UACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAA,mBAAD,EAAA,UACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,eAAA,cAAD;EAAc,UAAU,aAAa,QAAQ;EAA7C,UAAA;GACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAA,YAAD;IAAY,OAAM;IAAS,WAAU;IAAK,cAAc;IAAM,SAAQ;IACnE,UAAA,EAAE,+BAA+B;GACxB,CAAA;GACZ,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAA,mBAAD;IACE,OAAO,CAAC,CAAC,OAAO;IAChB,YAAY,OAAO,UAAU;IAC7B,OAAO,EAAE,kCAAkC;IAC3C,GAAI,SAAS,UAAU;IACvB,UAAU;GACX,CAAA;GACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAA,mBAAD;IACE,OAAO,CAAC,CAAC,OAAO;IAChB,YAAY,OAAO,aAAa;IAChC,OAAO,EAAE,qCAAqC;IAC9C,GAAI,SAAS,aAAa;IAC1B,UAAU;IACV,MAAK;GACN,CAAA;GACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAA,mBAAD;IACE,OAAO,CAAC,CAAC,OAAO;IAChB,YAAY,OAAO,aAAa;IAChC,OAAO,EAAE,qCAAqC;IAC9C,GAAI,SAAS,aAAa;IAC1B,UAAU;IACV,MAAK;GACN,CAAA;GACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAA,mBAAD;IACE,OAAO,CAAC,CAAC,OAAO;IAChB,YAAY,OAAO,iBAAiB;IACpC,OAAO,EAAE,yCAAyC;IAClD,GAAI,SAAS,iBAAiB;IAC9B,UAAU;IACV,MAAK;GACN,CAAA;GACA,OAAO,QAAQ,iBAAA,GAAA,kBAAA,IAAA,CAAC,6BAAA,SAAD,EAAsB,OAAO,OAAO,KAAO,CAAA;GAC3D,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAA,QAAD;IACE,OAAM;IACN,UAAU,CAAC;IACX,WAAW;IACX,IAAI,EAAE,IAAI,EAAE;IACZ,MAAK;IACL,SAAQ;IAEP,UAAA,EAAE,gCAAgC;GAC7B,CAAA;EACI;CACG,CAAA,EAAA,CAAA,EACL,CAAA,IACd;AACN"}
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":";;;;;;;;;;;;;;;;;;;;;AAwBA,IAAM,uBAAiC;CACrC,MAAM,EAAE,OAAA,GAAM,cAAA,eAAA,CAAe;CAC7B,MAAM,YAAA,GAAW,aAAA,YAAA,CAAY;CAC7B,MAAM,gBAAgB,sBAAA,iBAAiB;CACvC,MAAM,WAAW,cAAA,mBAAmB,cAAc,IAAI;CACtD,MAAM,wBAAwB,eAAe,OAAO;CAapD,MAAM,EACJ,UACA,cACA,UACA,WAAW,EAAE,SAAS,cAAc,cAAA,GAfzB,gBAAA,QAAA,CAAkC;EAC7C,MAAM;EACN,eAAe;GACb,UAAU;GACV,aAAa;GACb,aAAa;GACb,iBAAiB;EACnB;EACA,WAAA,GAAU,wBAAA,YAAA,CAAY,gBAAA,oBAAoB;CAC5C,CAOI;CAEJ,MAAM,EAAE,YAAY,0BAAA,gBAAgC,UAAU,eAAA,SAAS,gBAAgB,KAAK;CAE5F,MAAM,wBAAA,GAAuB,MAAA,YAAA,CAC3B,OAAO,SAAqD;EAC1D,MAAM,QAAQ,IAAI;CACpB,GACA,CAAC,OAAO,CACV;CAIA,MAAM,YAAA,GAAW,MAAA,OAAA,CAAO,KAAK;CAE7B,MAAM,YAAA,GAAW,MAAA,YAAA,CACf,OAAO,SAAmC;EACxC,IAAI,SAAS,SACX;EAEF,SAAS,UAAU;EACnB,IAAI;GACF,MAAM,qBAAqB,EACzB,UAAU;IACR,KAAK,KAAK;IACV,KAAK,KAAK;GACZ,EACF,CAAC;GACD,SAAS,GAAG,eAAA,MAAM,QAAQ,eAAe,gBAAA,YAAY,gBAAgB;EACvE,SAAS,KAAK;GACZ,SAAS,QAAQ;IACf,MAAM;IACN,SAAS,gBAAA,iBAAiB,KAAK,EAAE,0CAA0C,CAAC;GAC9E,CAAC;EACH,UAAU;GACR,SAAS,UAAU;EACrB;CACF,GACA;EAAC;EAAsB;EAAU;EAAU;CAAC,CAC9C;CAEA,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,IAAI,CAAC,uBACH,SAAS,GAAG;CAEhB,GAAG,CAAC,uBAAuB,QAAQ,CAAC;CAEpC,OAAO,wBACL,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAA,SAAD,EAAA,UACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAA,mBAAD,EAAA,UACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,eAAA,cAAD;EAAc,UAAU,aAAa,QAAQ;EAA7C,UAAA;GACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAA,YAAD;IAAY,OAAM;IAAS,WAAU;IAAK,cAAc;IAAM,SAAQ;IACnE,UAAA,EAAE,+BAA+B;GACxB,CAAA;GACZ,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAA,mBAAD;IACE,OAAO,CAAC,CAAC,OAAO;IAChB,YACE,OAAO,UAAU,UACb,EAAE,OAAO,SAAS,SAAS,EAAE,QAAA,EAA4B,CAAC,IAC1D,KAAA;IAEN,OAAO,EAAE,kCAAkC;IAC3C,GAAI,SAAS,UAAU;IACvB,UAAU;GACX,CAAA;GACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAA,mBAAD;IACE,OAAO,CAAC,CAAC,OAAO;IAChB,YACE,OAAO,aAAa,UAChB,EAAE,OAAO,YAAY,SAAS,EAAE,QAAA,EAA4B,CAAC,IAC7D,KAAA;IAEN,OAAO,EAAE,qCAAqC;IAC9C,GAAI,SAAS,aAAa;IAC1B,UAAU;IACV,MAAK;GACN,CAAA;GACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAA,mBAAD;IACE,OAAO,CAAC,CAAC,OAAO;IAChB,YACE,OAAO,aAAa,UAChB,EAAE,OAAO,YAAY,SAAS,EAAE,QAAA,EAA4B,CAAC,IAC7D,KAAA;IAEN,OAAO,EAAE,qCAAqC;IAC9C,GAAI,SAAS,aAAa;IAC1B,UAAU;IACV,MAAK;GACN,CAAA;GACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAA,mBAAD;IACE,OAAO,CAAC,CAAC,OAAO;IAChB,YACE,OAAO,iBAAiB,UAAU,EAAE,OAAO,gBAAgB,OAAO,IAAI,KAAA;IAExE,OAAO,EAAE,yCAAyC;IAClD,GAAI,SAAS,iBAAiB;IAC9B,UAAU;IACV,MAAK;GACN,CAAA;GACA,OAAO,QAAQ,iBAAA,GAAA,kBAAA,IAAA,CAAC,6BAAA,SAAD,EAAsB,OAAO,OAAO,KAAO,CAAA;GAC3D,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAA,QAAD;IACE,OAAM;IACN,UAAU,CAAC,WAAW;IACtB,WAAW;IACX,IAAI,EAAE,IAAI,EAAE;IACZ,MAAK;IACL,SAAQ;IAEP,UAAA,EAAE,gCAAgC;GAC7B,CAAA;EACI;CACG,CAAA,EAAA,CAAA,EACL,CAAA,IACd;AACN"}
@@ -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",
@@ -1 +1 @@
1
- {"version":3,"file":"ChangePassword.mjs","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":";;;;;;;;;;;;;;;;;;;AAoBA,IAAM,uBAAiC;CACrC,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,WAAW,YAAY;CAC7B,MAAM,gBAAgB,iBAAiB;CACvC,MAAM,WAAW,mBAAmB,cAAc,IAAI;CACtD,MAAM,wBAAwB,eAAe,OAAO;CAapD,MAAM,EACJ,UACA,cACA,UACA,WAAW,EAAE,SAAS,aAfX,QAAkC;EAC7C,MAAM;EACN,eAAe;GACb,UAAU;GACV,aAAa;GACb,aAAa;GACb,iBAAiB;EACnB;EACA,UAAU,YAAY,oBAAoB;CAC5C,CAOI;CAEJ,MAAM,EAAE,YAAY,gBAAgC,UAAU,SAAS,gBAAgB,KAAK;CAE5F,MAAM,uBAAuB,YAC3B,OAAO,SAAqD;EAC1D,IAAI;GACF,MAAM,QAAQ,IAAI;EACpB,SAAS,KAAK;GACZ,MAAM,mBAAmB,GAAG;EAC9B;CACF,GACA,CAAC,OAAO,CACV;CAEA,MAAM,WAAW,YACf,OAAO,SAAmC;EACxC,IAAI;GACF,MAAM,qBAAqB,EACzB,UAAU;IACR,KAAK,KAAK;IACV,KAAK,KAAK;GACZ,EACF,CAAC;GACD,SAAS,GAAG,QAAM,QAAQ,eAAe,YAAY,gBAAgB;EACvE,QAAQ;GACN,SAAS,QAAQ;IACf,MAAM;IACN,SAAS;GACX,CAAC;EACH;CACF,GACA;EAAC;EAAsB;EAAU;CAAQ,CAC3C;CAEA,gBAAgB;EACd,IAAI,CAAC,uBACH,SAAS,GAAG;CAEhB,GAAG,CAAC,uBAAuB,QAAQ,CAAC;CAEpC,OAAO,wBACL,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,+BAA+B;GACxB,CAAA;GACZ,oBAAC,mBAAD;IACE,OAAO,CAAC,CAAC,OAAO;IAChB,YAAY,OAAO,UAAU;IAC7B,OAAO,EAAE,kCAAkC;IAC3C,GAAI,SAAS,UAAU;IACvB,UAAU;GACX,CAAA;GACD,oBAAC,mBAAD;IACE,OAAO,CAAC,CAAC,OAAO;IAChB,YAAY,OAAO,aAAa;IAChC,OAAO,EAAE,qCAAqC;IAC9C,GAAI,SAAS,aAAa;IAC1B,UAAU;IACV,MAAK;GACN,CAAA;GACD,oBAAC,mBAAD;IACE,OAAO,CAAC,CAAC,OAAO;IAChB,YAAY,OAAO,aAAa;IAChC,OAAO,EAAE,qCAAqC;IAC9C,GAAI,SAAS,aAAa;IAC1B,UAAU;IACV,MAAK;GACN,CAAA;GACD,oBAAC,mBAAD;IACE,OAAO,CAAC,CAAC,OAAO;IAChB,YAAY,OAAO,iBAAiB;IACpC,OAAO,EAAE,yCAAyC;IAClD,GAAI,SAAS,iBAAiB;IAC9B,UAAU;IACV,MAAK;GACN,CAAA;GACA,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,gCAAgC;GAC7B,CAAA;EACI;CACG,CAAA,EAAA,CAAA,EACL,CAAA,IACd;AACN"}
1
+ {"version":3,"file":"ChangePassword.mjs","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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"}
@@ -6,19 +6,20 @@ const require_configuration = require("../../configuration.js");
6
6
  const require_utils = require("../../store/utils.js");
7
7
  const require_use_data_mutation = require("../../api/use-data-mutation.js");
8
8
  const require_utils$1 = require("../../providers/AuthProvider/utils.js");
9
+ const require_AuthProvider = require("../../providers/AuthProvider/AuthProvider.js");
9
10
  const require_NotFound = require("../../components/NotFound/NotFound.js");
10
11
  require("../../components/NotFound/index.js");
11
12
  const require_styles = require("../../components/LoginForm/styles.js");
12
- const require_Login = require("../../components/LoginForm/Login.js");
13
13
  const require_schemas = require("../../utils/schemas.js");
14
+ const require_Login = require("../../components/LoginForm/Login.js");
14
15
  const require_Dialog = require("../../layouts/Security/Dialog.js");
15
16
  const require_styles$1 = require("./styles.js");
16
17
  const require_Success = require("./Success.js");
17
18
  const require_utils$2 = require("./utils.js");
18
19
  let react = require("react");
19
20
  react = require_runtime.__toESM(react);
20
- let react_jsx_runtime = require("react/jsx-runtime");
21
21
  let react_i18next = require("react-i18next");
22
+ let react_jsx_runtime = require("react/jsx-runtime");
22
23
  let react_router = require("react-router");
23
24
  let _mui_material = require("@mui/material");
24
25
  let _hookform_resolvers_yup = require("@hookform/resolvers/yup");
@@ -30,63 +31,78 @@ var Login = () => {
30
31
  const { t } = (0, react_i18next.useTranslation)();
31
32
  const location = (0, react_router.useLocation)();
32
33
  const navigate = (0, react_router.useNavigate)();
34
+ const { setUserState } = require_AuthProvider.useAuth();
33
35
  const { next } = require_utils$2.getSecurityUrlParams(location);
34
36
  const createUserEnabled = configuration?.flags?.createUser;
35
37
  const addUserLink = require_routes.Route.ADD_USER + (next ? "?next=" + next : "");
36
38
  const { trigger } = require_use_data_mutation.useDataMutation(basePath, next, "POST");
37
- const { setError, handleSubmit, register, formState: { isValid, errors } } = (0, react_hook_form.useForm)({
39
+ const { setError, handleSubmit, register, formState: { isValid, isSubmitting, errors } } = (0, react_hook_form.useForm)({
38
40
  mode: "onChange",
39
41
  resolver: (0, _hookform_resolvers_yup.yupResolver)(require_schemas.loginSchema)
40
42
  });
41
43
  const handleLogin = (0, react.useCallback)(async (body) => {
42
- try {
43
- return await trigger(body);
44
- } catch (err) {
45
- throw require_utils$1.normalizeAuthError(err);
46
- }
44
+ return await trigger(body);
47
45
  }, [trigger]);
48
46
  const onSuccess = (0, react.useCallback)(() => {
49
47
  navigate(`${require_routes.Route.SUCCESS}?messageType=${require_Success.MessageType.Login}`);
50
48
  }, [navigate]);
49
+ const inFlight = (0, react.useRef)(false);
51
50
  const onSubmit = (0, react.useCallback)(async (data) => {
51
+ if (inFlight.current) return;
52
+ inFlight.current = true;
52
53
  try {
53
54
  const result = await handleLogin?.(data);
54
- if (result && result.username && result.token) require_storage.saveAuth(result.username, result.token);
55
+ if (!result || !result.username || !result.token) throw new Error("login response is missing the token");
56
+ require_storage.saveAuth(result.username, result.token);
57
+ setUserState?.({
58
+ username: result.username,
59
+ token: result.token
60
+ });
55
61
  onSuccess();
56
- } catch {
62
+ } catch (err) {
63
+ const message = err?.code === 401 ? t("security.error.invalid-credentials") : require_utils$1.authErrorMessage(err, t("security.error.unable-to-login"));
57
64
  setError("root", {
58
65
  type: "server",
59
- message: "Invalid username or password"
66
+ message
60
67
  });
68
+ } finally {
69
+ inFlight.current = false;
61
70
  }
62
71
  }, [
63
72
  handleLogin,
64
73
  setError,
65
- onSuccess
74
+ setUserState,
75
+ onSuccess,
76
+ t
66
77
  ]);
67
- return !next ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_NotFound.default, {}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Dialog.default, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_styles$1.SecurityContainer, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_styles$1.SecurityForm, { children: [
68
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_styles.default, {}),
69
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Login.default, {
70
- errors,
71
- handleSubmit,
72
- isValid,
73
- onSubmit,
74
- register
75
- }),
76
- createUserEnabled && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material.Typography, {
77
- align: "center",
78
- sx: {
79
- mt: 2,
80
- fontSize: 12
81
- },
82
- variant: "body2",
83
- children: [t("security.login.noUserQuestion"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material.Link, {
84
- href: addUserLink,
85
- sx: { ml: 1 },
86
- children: t("security.login.createUser")
87
- })]
88
- })
89
- ] }) }) });
78
+ return !next ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_NotFound.default, {}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Dialog.default, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_styles$1.SecurityContainer, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_styles$1.SecurityForm, {
79
+ as: "div",
80
+ children: [
81
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_styles.default, {}),
82
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Login.default, {
83
+ errors,
84
+ handleSubmit,
85
+ isSubmitting,
86
+ isValid,
87
+ onSubmit,
88
+ register
89
+ }),
90
+ createUserEnabled && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material.Typography, {
91
+ align: "center",
92
+ sx: {
93
+ mt: 2,
94
+ fontSize: 12
95
+ },
96
+ variant: "body2",
97
+ children: [t("security.login.noUserQuestion"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material.Link, {
98
+ component: react_router.Link,
99
+ sx: { ml: 1 },
100
+ to: addUserLink,
101
+ children: t("security.login.createUser")
102
+ })]
103
+ })
104
+ ]
105
+ }) }) });
90
106
  };
91
107
  //#endregion
92
108
  exports.default = Login;
@@ -1 +1 @@
1
- {"version":3,"file":"Login.js","names":[],"sources":["../../../src/sections/Security/Login.tsx"],"sourcesContent":["import { yupResolver } from '@hookform/resolvers/yup';\nimport { Link, Typography } from '@mui/material';\nimport React, { useCallback } 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 type { LoginFormValues } from '../../components/LoginForm/Login';\nimport LoginForm from '../../components/LoginForm/Login';\nimport LoginFormHeader from '../../components/LoginForm/styles';\nimport NotFound from '../../components/NotFound';\nimport { getConfiguration } from '../../configuration';\nimport SecurityLayout from '../../layouts/Security/Dialog';\nimport type { LoginBody } from '../../providers/AuthProvider/types';\nimport { normalizeAuthError } from '../../providers/AuthProvider/utils';\nimport { saveAuth } from '../../store/storage';\nimport { stripTrailingSlash } from '../../store/utils';\nimport { Route } from '../../utils';\nimport { loginSchema } from '../../utils/schemas';\nimport { MessageType } from './Success';\nimport { SecurityContainer, SecurityForm } from './styles';\nimport { getSecurityUrlParams } from './utils';\n\nconst configuration = getConfiguration();\nconst basePath = stripTrailingSlash(configuration.base);\n\nconst Login: React.FC = () => {\n const { t } = useTranslation();\n const location = useLocation();\n const navigate = useNavigate();\n const { next } = getSecurityUrlParams(location);\n const createUserEnabled = configuration?.flags?.createUser;\n const addUserLink = Route.ADD_USER + (next ? '?next=' + next : '');\n\n const { trigger } = useDataMutation<LoginBody>(basePath, next, 'POST');\n\n const form = useForm<LoginFormValues>({\n mode: 'onChange',\n resolver: yupResolver(loginSchema),\n });\n\n const {\n setError,\n handleSubmit,\n register,\n formState: { isValid, errors },\n } = form;\n\n const handleLogin = useCallback(\n async (body: { username: string; password: string }) => {\n try {\n return await trigger(body);\n } catch (err) {\n throw normalizeAuthError(err);\n }\n },\n [trigger]\n );\n\n const onSuccess = useCallback(() => {\n navigate(`${Route.SUCCESS}?messageType=${MessageType.Login}`);\n }, [navigate]);\n\n const onSubmit = useCallback(\n async (data: LoginFormValues) => {\n try {\n const result = await handleLogin?.(data);\n if (result && result.username && result.token) {\n saveAuth(result.username, result.token);\n }\n onSuccess();\n } catch {\n setError('root', {\n type: 'server',\n // TODO: add translation key\n message: 'Invalid username or password',\n });\n }\n },\n [handleLogin, setError, onSuccess]\n );\n\n return !next ? (\n <NotFound />\n ) : (\n <SecurityLayout>\n <SecurityContainer>\n <SecurityForm>\n <LoginFormHeader />\n <LoginForm\n errors={errors}\n handleSubmit={handleSubmit}\n isValid={isValid}\n onSubmit={onSubmit}\n register={register}\n />\n {createUserEnabled && (\n <Typography align=\"center\" sx={{ mt: 2, fontSize: 12 }} variant=\"body2\">\n {t('security.login.noUserQuestion')}\n <Link href={addUserLink} sx={{ ml: 1 }}>\n {t('security.login.createUser')}\n </Link>\n </Typography>\n )}\n </SecurityForm>\n </SecurityContainer>\n </SecurityLayout>\n );\n};\n\nexport default Login;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAwBA,IAAM,gBAAgB,sBAAA,iBAAiB;AACvC,IAAM,WAAW,cAAA,mBAAmB,cAAc,IAAI;AAEtD,IAAM,cAAwB;CAC5B,MAAM,EAAE,OAAA,GAAM,cAAA,eAAA,CAAe;CAC7B,MAAM,YAAA,GAAW,aAAA,YAAA,CAAY;CAC7B,MAAM,YAAA,GAAW,aAAA,YAAA,CAAY;CAC7B,MAAM,EAAE,SAAS,gBAAA,qBAAqB,QAAQ;CAC9C,MAAM,oBAAoB,eAAe,OAAO;CAChD,MAAM,cAAc,eAAA,MAAM,YAAY,OAAO,WAAW,OAAO;CAE/D,MAAM,EAAE,YAAY,0BAAA,gBAA2B,UAAU,MAAM,MAAM;CAOrE,MAAM,EACJ,UACA,cACA,UACA,WAAW,EAAE,SAAS,cAAA,GATX,gBAAA,QAAA,CAAyB;EACpC,MAAM;EACN,WAAA,GAAU,wBAAA,YAAA,CAAY,gBAAA,WAAW;CACnC,CAOI;CAEJ,MAAM,eAAA,GAAc,MAAA,YAAA,CAClB,OAAO,SAAiD;EACtD,IAAI;GACF,OAAO,MAAM,QAAQ,IAAI;EAC3B,SAAS,KAAK;GACZ,MAAM,gBAAA,mBAAmB,GAAG;EAC9B;CACF,GACA,CAAC,OAAO,CACV;CAEA,MAAM,aAAA,GAAY,MAAA,YAAA,OAAkB;EAClC,SAAS,GAAG,eAAA,MAAM,QAAQ,eAAe,gBAAA,YAAY,OAAO;CAC9D,GAAG,CAAC,QAAQ,CAAC;CAEb,MAAM,YAAA,GAAW,MAAA,YAAA,CACf,OAAO,SAA0B;EAC/B,IAAI;GACF,MAAM,SAAS,MAAM,cAAc,IAAI;GACvC,IAAI,UAAU,OAAO,YAAY,OAAO,OACtC,gBAAA,SAAS,OAAO,UAAU,OAAO,KAAK;GAExC,UAAU;EACZ,QAAQ;GACN,SAAS,QAAQ;IACf,MAAM;IAEN,SAAS;GACX,CAAC;EACH;CACF,GACA;EAAC;EAAa;EAAU;CAAS,CACnC;CAEA,OAAO,CAAC,OACN,iBAAA,GAAA,kBAAA,IAAA,CAAC,iBAAA,SAAD,CAAW,CAAA,IAEX,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAA,SAAD,EAAA,UACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,iBAAA,mBAAD,EAAA,UACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,iBAAA,cAAD,EAAA,UAAA;EACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,eAAA,SAAD,CAAkB,CAAA;EAClB,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAA,SAAD;GACU;GACM;GACL;GACC;GACA;EACX,CAAA;EACA,qBACC,iBAAA,GAAA,kBAAA,KAAA,CAAC,cAAA,YAAD;GAAY,OAAM;GAAS,IAAI;IAAE,IAAI;IAAG,UAAU;GAAG;GAAG,SAAQ;GAAhE,UAAA,CACG,EAAE,+BAA+B,GAClC,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAA,MAAD;IAAM,MAAM;IAAa,IAAI,EAAE,IAAI,EAAE;IAClC,UAAA,EAAE,2BAA2B;GAC1B,CAAA,CACI;;CAEF,EAAA,CAAA,EACG,CAAA,EACL,CAAA;AAEpB"}
1
+ {"version":3,"file":"Login.js","names":[],"sources":["../../../src/sections/Security/Login.tsx"],"sourcesContent":["import { yupResolver } from '@hookform/resolvers/yup';\nimport { Link, Typography } from '@mui/material';\nimport React, { useCallback, 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 type { LoginFormValues } from '../../components/LoginForm/Login';\nimport LoginForm from '../../components/LoginForm/Login';\nimport LoginFormHeader from '../../components/LoginForm/styles';\nimport NotFound from '../../components/NotFound';\nimport { getConfiguration } from '../../configuration';\nimport SecurityLayout from '../../layouts/Security/Dialog';\nimport { useAuth } from '../../providers/AuthProvider/AuthProvider';\nimport type { LoginBody } from '../../providers/AuthProvider/types';\nimport { authErrorMessage } from '../../providers/AuthProvider/utils';\nimport { saveAuth } from '../../store/storage';\nimport { stripTrailingSlash } from '../../store/utils';\nimport { Route } from '../../utils';\nimport { loginSchema } from '../../utils/schemas';\nimport { MessageType } from './Success';\nimport { SecurityContainer, SecurityForm } from './styles';\nimport { getSecurityUrlParams } from './utils';\n\nconst configuration = getConfiguration();\nconst basePath = stripTrailingSlash(configuration.base);\n\nconst Login: React.FC = () => {\n const { t } = useTranslation();\n const location = useLocation();\n const navigate = useNavigate();\n const { setUserState } = useAuth();\n const { next } = getSecurityUrlParams(location);\n const createUserEnabled = configuration?.flags?.createUser;\n const addUserLink = Route.ADD_USER + (next ? '?next=' + next : '');\n\n const { trigger } = useDataMutation<LoginBody>(basePath, next, 'POST');\n\n const form = useForm<LoginFormValues>({\n mode: 'onChange',\n resolver: yupResolver(loginSchema),\n });\n\n const {\n setError,\n handleSubmit,\n register,\n formState: { isValid, isSubmitting, errors },\n } = form;\n\n const handleLogin = useCallback(\n async (body: { username: string; password: string }) => {\n return await trigger(body);\n },\n [trigger]\n );\n\n const onSuccess = useCallback(() => {\n navigate(`${Route.SUCCESS}?messageType=${MessageType.Login}`);\n }, [navigate]);\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: LoginFormValues) => {\n if (inFlight.current) {\n return;\n }\n inFlight.current = true;\n try {\n const result = await handleLogin?.(data);\n if (!result || !result.username || !result.token) {\n // a 2xx with an unexpected body must not pass as a successful login\n throw new Error('login 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 onSuccess();\n } catch (err: any) {\n // only a 401 means wrong credentials; a dead server, 500 or 429 must\n // not claim the credentials were invalid\n const message =\n err?.code === 401\n ? t('security.error.invalid-credentials')\n : authErrorMessage(err, t('security.error.unable-to-login'));\n setError('root', { type: 'server', message });\n } finally {\n inFlight.current = false;\n }\n },\n [handleLogin, setError, setUserState, onSuccess, t]\n );\n\n return !next ? (\n <NotFound />\n ) : (\n <SecurityLayout>\n <SecurityContainer>\n {/* container only: LoginForm renders the real <form>, and a <form>\n cannot be a descendant of another <form> */}\n <SecurityForm as=\"div\">\n <LoginFormHeader />\n <LoginForm\n errors={errors}\n handleSubmit={handleSubmit}\n isSubmitting={isSubmitting}\n isValid={isValid}\n onSubmit={onSubmit}\n register={register}\n />\n {createUserEnabled && (\n <Typography align=\"center\" sx={{ mt: 2, fontSize: 12 }} variant=\"body2\">\n {t('security.login.noUserQuestion')}\n <Link component={RouterLink} sx={{ ml: 1 }} to={addUserLink}>\n {t('security.login.createUser')}\n </Link>\n </Typography>\n )}\n </SecurityForm>\n </SecurityContainer>\n </SecurityLayout>\n );\n};\n\nexport default Login;\n"],"mappings":"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"}