@verdaccio/ui-components 5.0.0-next-9.22 → 5.0.0-next-9.23
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.
- package/build/Theme/ResetStyles.js.map +1 -1
- package/build/Theme/ResetStyles.mjs.map +1 -1
- package/build/Theme/StyleBaseline.js.map +1 -1
- package/build/Theme/StyleBaseline.mjs.map +1 -1
- package/build/Theme/ThemeProvider.js.map +1 -1
- package/build/Theme/ThemeProvider.mjs.map +1 -1
- package/build/Theme/colors.js.map +1 -1
- package/build/Theme/modes.js.map +1 -1
- package/build/Theme/theme.js.map +1 -1
- package/build/api/use-data-mutation.js.map +1 -1
- package/build/api/use-data-mutation.mjs.map +1 -1
- package/build/api/use-data.js.map +1 -1
- package/build/api/use-data.mjs.map +1 -1
- package/build/components/ActionBar/ActionBar.js.map +1 -1
- package/build/components/ActionBar/ActionBar.mjs.map +1 -1
- package/build/components/ActionBar/ActionBarAction.js.map +1 -1
- package/build/components/ActionBar/index.mjs +1 -2
- package/build/components/AppRoute/AppRoute.js.map +1 -1
- package/build/components/AppRoute/AppRoute.mjs.map +1 -1
- package/build/components/Author/Author.js.map +1 -1
- package/build/components/Author/index.mjs +1 -2
- package/build/components/Author/styles.js.map +1 -1
- package/build/components/CopyClipboard/CopyToClipBoard.js.map +1 -1
- package/build/components/Dependencies/Dependencies.js.map +1 -1
- package/build/components/Dependencies/DependencyBlock.js.map +1 -1
- package/build/components/Dependencies/DependencyBlock.mjs.map +1 -1
- package/build/components/Dependencies/index.mjs +1 -2
- package/build/components/Deprecated/Deprecated.js.map +1 -1
- package/build/components/Deprecated/index.mjs +1 -2
- package/build/components/Developers/Developers.js.map +1 -1
- package/build/components/Developers/Developers.mjs.map +1 -1
- package/build/components/Developers/Title.js.map +1 -1
- package/build/components/Distribution/Dist.js.map +1 -1
- package/build/components/Distribution/Dist.mjs.map +1 -1
- package/build/components/Distribution/index.mjs +1 -2
- package/build/components/Distribution/styles.js.map +1 -1
- package/build/components/Engines/Engines.js.map +1 -1
- package/build/components/Engines/index.mjs +1 -2
- package/build/components/Engines/styles.js.map +1 -1
- package/build/components/ErrorBoundary/ErrorBoundary.js.map +1 -1
- package/build/components/ErrorBoundary/index.mjs +1 -2
- package/build/components/Forbidden/Forbidden.js.map +1 -1
- package/build/components/Forbidden/index.mjs +1 -2
- package/build/components/FundButton/FundButton.js.map +1 -1
- package/build/components/FundButton/FundButton.mjs.map +1 -1
- package/build/components/FundButton/index.mjs +1 -2
- package/build/components/GenericError/GenericError.js.map +1 -1
- package/build/components/GenericError/index.mjs +1 -2
- package/build/components/HeaderInfoDialog/HeaderInfoDialog.js.map +1 -1
- package/build/components/HeaderInfoDialog/index.mjs +1 -2
- package/build/components/Heading/Heading.js.map +1 -1
- package/build/components/Heading/Heading.mjs.map +1 -1
- package/build/components/Heading/index.mjs +1 -2
- package/build/components/Help/Help.js.map +1 -1
- package/build/components/Help/Help.mjs.map +1 -1
- package/build/components/Help/index.mjs +1 -2
- package/build/components/Help/styles.js.map +1 -1
- package/build/components/Icons/DevsIcons/CommonJS2.js.map +1 -1
- package/build/components/Icons/DevsIcons/CommonJS2.mjs.map +1 -1
- package/build/components/Icons/DevsIcons/ES6Module2.js.map +1 -1
- package/build/components/Icons/DevsIcons/ES6Module2.mjs.map +1 -1
- package/build/components/Icons/DevsIcons/Git2.js.map +1 -1
- package/build/components/Icons/DevsIcons/Git2.mjs.map +1 -1
- package/build/components/Icons/DevsIcons/NodeJS2.js.map +1 -1
- package/build/components/Icons/DevsIcons/NodeJS2.mjs.map +1 -1
- package/build/components/Icons/DevsIcons/TypeScript2.js.map +1 -1
- package/build/components/Icons/DevsIcons/TypeScript2.mjs.map +1 -1
- package/build/components/Icons/Earth.js.map +1 -1
- package/build/components/Icons/FileBinary.js.map +1 -1
- package/build/components/Icons/Law.js.map +1 -1
- package/build/components/Icons/License.js.map +1 -1
- package/build/components/Icons/Managers/Npm2.js.map +1 -1
- package/build/components/Icons/Managers/Npm2.mjs.map +1 -1
- package/build/components/Icons/Managers/Pnpm2.js.map +1 -1
- package/build/components/Icons/Managers/Pnpm2.mjs.map +1 -1
- package/build/components/Icons/Managers/Yarn2.js.map +1 -1
- package/build/components/Icons/Managers/Yarn2.mjs.map +1 -1
- package/build/components/Icons/SvgIcon.js.map +1 -1
- package/build/components/Icons/Time.js.map +1 -1
- package/build/components/Icons/Version.js.map +1 -1
- package/build/components/Install/Install.js.map +1 -1
- package/build/components/Install/Install.mjs.map +1 -1
- package/build/components/Install/InstallListItem.js.map +1 -1
- package/build/components/Install/index.mjs +1 -2
- package/build/components/Keywords/KeywordListItems.js.map +1 -1
- package/build/components/Keywords/Keywords.js.map +1 -1
- package/build/components/Keywords/index.mjs +1 -2
- package/build/components/Label/Label.js.map +1 -1
- package/build/components/Label/index.mjs +1 -2
- package/build/components/Link/Link.js.map +1 -1
- package/build/components/Link/Link.mjs.map +1 -1
- package/build/components/Link/index.mjs +1 -2
- package/build/components/LinkExternal/LinkExternal.js.map +1 -1
- package/build/components/LinkExternal/index.mjs +1 -2
- package/build/components/Loading/Loading.js.map +1 -1
- package/build/components/Loading/Spinner/Spinner.js.map +1 -1
- package/build/components/Loading/Spinner/index.mjs +1 -2
- package/build/components/Loading/index.mjs +1 -2
- package/build/components/Loading/styles.js.map +1 -1
- package/build/components/LoginDialog/LoginDialog.d.ts +1 -0
- package/build/components/LoginDialog/LoginDialog.js +11 -2
- package/build/components/LoginDialog/LoginDialog.js.map +1 -1
- package/build/components/LoginDialog/LoginDialog.mjs +10 -2
- package/build/components/LoginDialog/LoginDialog.mjs.map +1 -1
- package/build/components/LoginDialog/LoginDialogCloseButton.js.map +1 -1
- package/build/components/LoginDialog/LoginDialogForm.js.map +1 -1
- package/build/components/LoginDialog/LoginDialogFormError.js.map +1 -1
- package/build/components/LoginDialog/index.mjs +1 -2
- package/build/components/LoginForm/Login.js +0 -23
- package/build/components/LoginForm/Login.js.map +1 -1
- package/build/components/LoginForm/Login.mjs +0 -21
- package/build/components/LoginForm/Login.mjs.map +1 -1
- package/build/components/LoginForm/PasswordField.js.map +1 -1
- package/build/components/LoginForm/UsernameField.js.map +1 -1
- package/build/components/LoginForm/styles.js.map +1 -1
- package/build/components/LoginForm/useLoginForm.js.map +1 -1
- package/build/components/Logo/Logo.js.map +1 -1
- package/build/components/Logo/Logo.mjs.map +1 -1
- package/build/components/Logo/index.mjs +1 -2
- package/build/components/MenuItem/MenuItem.js.map +1 -1
- package/build/components/MenuItem/MenuItem.mjs.map +1 -1
- package/build/components/MenuItem/index.mjs +1 -2
- package/build/components/NoItems/NoItems.js.map +1 -1
- package/build/components/NoItems/index.mjs +1 -2
- package/build/components/NotFound/NotFound.js.map +1 -1
- package/build/components/NotFound/index.mjs +1 -2
- package/build/components/Package/Package.js.map +1 -1
- package/build/components/Package/Package.mjs.map +1 -1
- package/build/components/Package/index.mjs +1 -2
- package/build/components/Package/styles.js.map +1 -1
- package/build/components/Package/styles.mjs.map +1 -1
- package/build/components/PackageList/PackageList.js.map +1 -1
- package/build/components/PackageList/PackageList.mjs.map +1 -1
- package/build/components/PackageList/index.mjs +1 -2
- package/build/components/Person/Person.js.map +1 -1
- package/build/components/Person/Person.mjs.map +1 -1
- package/build/components/Person/PersonTooltip.js.map +1 -1
- package/build/components/Person/PersonTooltip.mjs.map +1 -1
- package/build/components/Person/index.mjs +1 -2
- package/build/components/Person/utils.mjs.map +1 -1
- package/build/components/RawViewer/RawViewer.js.map +1 -1
- package/build/components/RawViewer/index.mjs +1 -2
- package/build/components/Readme/Readme.js.map +1 -1
- package/build/components/Readme/index.mjs +1 -2
- package/build/components/Readme/utils.js.map +1 -1
- package/build/components/RegistryInfoDialog/RegistryInfoDialog.js.map +1 -1
- package/build/components/RegistryInfoDialog/index.mjs +1 -2
- package/build/components/RegistryInfoDialog/styles.js.map +1 -1
- package/build/components/Repository/Repository.js.map +1 -1
- package/build/components/Repository/Repository.mjs.map +1 -1
- package/build/components/Repository/index.mjs +1 -2
- package/build/components/Search/AutoComplete/AutoComplete.js.map +1 -1
- package/build/components/Search/AutoComplete/index.mjs +1 -2
- package/build/components/Search/AutoComplete/styles.js.map +1 -1
- package/build/components/Search/Search.js.map +1 -1
- package/build/components/Search/Search.mjs.map +1 -1
- package/build/components/Search/SearchItem.js.map +1 -1
- package/build/components/Search/index.mjs +1 -2
- package/build/components/Search/styles.js.map +1 -1
- package/build/components/SettingsMenu/SettingsMenu.js.map +1 -1
- package/build/components/SettingsMenu/SettingsMenu.mjs.map +1 -1
- package/build/components/SettingsMenu/index.mjs +1 -2
- package/build/components/SideBarTitle/SideBarTitle.js.map +1 -1
- package/build/components/SideBarTitle/SideBarTitle.mjs.map +1 -1
- package/build/components/SideBarTitle/index.mjs +1 -2
- package/build/components/UpLinks/UpLinks.js.map +1 -1
- package/build/components/UpLinks/UpLinks.mjs.map +1 -1
- package/build/components/UpLinks/UplinkLink.js.map +1 -1
- package/build/components/UpLinks/UplinkLink.mjs.map +1 -1
- package/build/components/UpLinks/index.mjs +1 -2
- package/build/components/UpLinks/styles.js.map +1 -1
- package/build/components/UpLinks/styles.mjs.map +1 -1
- package/build/components/Versions/HistoryList.js.map +1 -1
- package/build/components/Versions/HistoryList.mjs.map +1 -1
- package/build/components/Versions/TagList.js.map +1 -1
- package/build/components/Versions/Versions.js.map +1 -1
- package/build/components/Versions/Versions.mjs.map +1 -1
- package/build/components/Versions/index.mjs +1 -2
- package/build/components/Versions/styles.js.map +1 -1
- package/build/components/Versions/styles.mjs.map +1 -1
- package/build/hooks/useLocalStorage.js.map +1 -1
- package/build/layouts/Security/Dialog.js.map +1 -1
- package/build/layouts/Version/Version.js.map +1 -1
- package/build/layouts/Version/Version.mjs.map +1 -1
- package/build/layouts/Version/index.mjs +1 -2
- package/build/pages/Front/Home.js.map +1 -1
- package/build/pages/Front/index.mjs +1 -2
- package/build/pages/Security/AddUser.js.map +1 -1
- package/build/pages/Security/ChangePassword.js.map +1 -1
- package/build/pages/Security/Login.js.map +1 -1
- package/build/pages/Security/Success.js.map +1 -1
- package/build/pages/Stage/StageDetail.js.map +1 -1
- package/build/pages/Stage/StageList.js.map +1 -1
- package/build/pages/Version/Version.js.map +1 -1
- package/build/pages/Version/index.mjs +1 -2
- package/build/providers/AppConfigurationProvider/AppConfigurationProvider.js.map +1 -1
- package/build/providers/AppConfigurationProvider/index.mjs +1 -2
- package/build/providers/AuthProvider/AuthProvider.js.map +1 -1
- package/build/providers/AuthProvider/index.mjs +1 -2
- package/build/providers/AuthProvider/utils.js.map +1 -1
- package/build/providers/DownloadProvider/DownloadProvider.js.map +1 -1
- package/build/providers/DownloadProvider/index.mjs +1 -2
- package/build/providers/ManifestsProvider/ManifestsProvider.js.map +1 -1
- package/build/providers/ManifestsProvider/index.mjs +1 -2
- package/build/providers/PersistenceSettingProvider/PersistenceSettingProvider.js.map +1 -1
- package/build/providers/PersistenceSettingProvider/index.mjs +1 -2
- package/build/providers/SearchProvider/SearchProvider.js.map +1 -1
- package/build/providers/SearchProvider/index.mjs +1 -2
- package/build/providers/TranslatorProvider/TranslatorProvider.js.map +1 -1
- package/build/providers/TranslatorProvider/index.mjs +1 -2
- package/build/providers/VersionProvider/VersionProvider.js.map +1 -1
- package/build/providers/VersionProvider/index.mjs +1 -2
- package/build/sections/Detail/ContainerContent.js.map +1 -1
- package/build/sections/Detail/ContainerContent.mjs.map +1 -1
- package/build/sections/Detail/Detail.js.map +1 -1
- package/build/sections/Detail/Detail.mjs.map +1 -1
- package/build/sections/Detail/ReadmeSection.js.map +1 -1
- package/build/sections/Detail/Tabs.js.map +1 -1
- package/build/sections/Detail/Tabs.mjs.map +1 -1
- package/build/sections/Detail/index.mjs +1 -2
- package/build/sections/Footer/Footer.js.map +1 -1
- package/build/sections/Footer/Footer.mjs.map +1 -1
- package/build/sections/Footer/index.mjs +1 -2
- package/build/sections/Footer/styles.js.map +1 -1
- package/build/sections/Header/Header.js.map +1 -1
- package/build/sections/Header/Header.mjs.map +1 -1
- package/build/sections/Header/HeaderGreetings.js.map +1 -1
- package/build/sections/Header/HeaderGreetings.mjs.map +1 -1
- package/build/sections/Header/HeaderLeft.js.map +1 -1
- package/build/sections/Header/HeaderLeft.mjs.map +1 -1
- package/build/sections/Header/HeaderMenu.js +10 -0
- package/build/sections/Header/HeaderMenu.js.map +1 -1
- package/build/sections/Header/HeaderMenu.mjs +10 -0
- package/build/sections/Header/HeaderMenu.mjs.map +1 -1
- package/build/sections/Header/HeaderRight.js.map +1 -1
- package/build/sections/Header/HeaderRight.mjs.map +1 -1
- package/build/sections/Header/HeaderSettingsDialog.js.map +1 -1
- package/build/sections/Header/HeaderToolTip.js.map +1 -1
- package/build/sections/Header/HeaderToolTipIcon.js.map +1 -1
- package/build/sections/Header/HeaderToolTipIcon.mjs.map +1 -1
- package/build/sections/Header/LanguageSwitch.js.map +1 -1
- package/build/sections/Header/LanguageSwitch.mjs.map +1 -1
- package/build/sections/Header/RegistryInfoContent/RegistryInfoContent.js.map +1 -1
- package/build/sections/Header/RegistryInfoContent/RegistryInfoContent.mjs.map +1 -1
- package/build/sections/Header/RegistryInfoContent/index.mjs +1 -2
- package/build/sections/Header/RegistryInfoContent/styles.js.map +1 -1
- package/build/sections/Header/index.mjs +1 -2
- package/build/sections/Header/styles.js.map +1 -1
- package/build/sections/Home/Home.js.map +1 -1
- package/build/sections/Home/index.mjs +1 -2
- package/build/sections/Security/AddUser.js.map +1 -1
- package/build/sections/Security/AddUser.mjs.map +1 -1
- package/build/sections/Security/ChangePassword.js +41 -16
- package/build/sections/Security/ChangePassword.js.map +1 -1
- package/build/sections/Security/ChangePassword.mjs +41 -16
- package/build/sections/Security/ChangePassword.mjs.map +1 -1
- package/build/sections/Security/Login.js.map +1 -1
- package/build/sections/Security/Login.mjs.map +1 -1
- package/build/sections/Security/Success.js.map +1 -1
- package/build/sections/Security/styles.js.map +1 -1
- package/build/sections/Security/utils.js.map +1 -1
- package/build/sections/SideBar/Sidebar.js.map +1 -1
- package/build/sections/SideBar/Sidebar.mjs.map +1 -1
- package/build/sections/SideBar/index.mjs +1 -2
- package/build/sections/Stage/StageActions.js.map +1 -1
- package/build/sections/Stage/StageActions.mjs.map +1 -1
- package/build/sections/Stage/StageDetail.js.map +1 -1
- package/build/sections/Stage/StageDetail.mjs.map +1 -1
- package/build/sections/Stage/StageList.js.map +1 -1
- package/build/sections/Stage/StageList.mjs.map +1 -1
- package/build/sections/Stage/useRequireSession.js.map +1 -1
- package/build/sections/Stage/useRequireSession.mjs.map +1 -1
- package/build/sections/Stage/useStage.js.map +1 -1
- package/build/sections/Stage/useStage.mjs.map +1 -1
- package/build/store/api.js.map +1 -1
- package/build/store/api.mjs.map +1 -1
- package/build/store/index.mjs +1 -2
- package/build/store/storage.js.map +1 -1
- package/build/utils/loadable.js.map +1 -1
- package/build/utils/schemas.d.ts +0 -2
- package/build/utils/schemas.js +0 -1
- package/build/utils/schemas.js.map +1 -1
- package/build/utils/schemas.mjs +0 -1
- package/build/utils/schemas.mjs.map +1 -1
- package/build/utils/token.js.map +1 -1
- package/build/utils/url.js.map +1 -1
- package/build/utils/url.mjs.map +1 -1
- package/build/utils/utils.js.map +1 -1
- package/package.json +19 -19
|
@@ -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, 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":";;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,IAAM,gBAA0B;CAC9B,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,WAAW,YAAY;CAC7B,MAAM,WAAW,YAAY;CAC7B,MAAM,EAAE,iBAAiB,QAAQ;CACjC,MAAM,gBAAgB,iBAAiB;CACvC,MAAM,WAAW,mBAAmB,cAAc,IAAI;CACtD,MAAM,EAAE,MAAM,SAAS,qBAAqB,QAAQ;CACpD,MAAM,
|
|
1
|
+
{"version":3,"file":"AddUser.mjs","names":["Route","Link","RouterLink"],"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":";;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,IAAM,gBAA0B;CAC9B,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,WAAW,YAAY;CAC7B,MAAM,WAAW,YAAY;CAC7B,MAAM,EAAE,iBAAiB,QAAQ;CACjC,MAAM,gBAAgB,iBAAiB;CACvC,MAAM,WAAW,mBAAmB,cAAc,IAAI;CACtD,MAAM,EAAE,MAAM,SAAS,qBAAqB,QAAQ;CACpD,MAAM,YAAYA,QAAM,SAAS,OAAO,SAAS,mBAAmB,IAAI,MAAM;CAC9E,MAAM,oBAAoB,eAAe,OAAO;CAWhD,MAAM,EACJ,UACA,cACA,UACA,WAAW,EAAE,SAAS,cAAc,aAdzB,QAA2B;EACtC,MAAM;EACN,eAAe;GACb,UAAU,OAAO,SAAS,WAAW,OAAO;GAC5C,UAAU;GACV,OAAO;EACT;EACA,UAAU,YAAY,aAAa;CACrC,CAOI;CAEJ,MAAM,EAAE,YAAY,gBAClB,UACA,SAAS,QACT,KACF;CAEA,MAAM,gBAAgB,YACpB,OAAO,SAAsB;EAC3B,OAAO,MAAM,QAAQ,IAAI;CAC3B,GACA,CAAC,OAAO,CACV;CAIA,MAAM,WAAW,OAAO,KAAK;CAE7B,MAAM,WAAW,YACf,OAAO,SAA4B;EACjC,IAAI,SAAS,SACX;EAEF,SAAS,UAAU;EACnB,IAAI;GACF,MAAM,SAAS,MAAM,cAAc;IACjC,MAAM,KAAK;IACX,UAAU,KAAK;IACf,OAAO,KAAK;IACZ,WAAW,kBAAkB;GAC/B,CAAC;GACD,IAAI,CAAC,UAAU,CAAC,OAAO,YAAY,CAAC,OAAO,OAEzC,MAAM,IAAI,MAAM,sCAAsC;GAExD,SAAS,OAAO,UAAU,OAAO,KAAK;GAEtC,eAAe;IAAE,UAAU,OAAO;IAAU,OAAO,OAAO;GAAM,CAAC;GACjE,SAAS,GAAGA,QAAM,QAAQ,eAAe,YAAY,SAAS;EAChE,SAAS,KAAK;GACZ,SAAS,QAAQ;IACf,MAAM;IACN,SAAS,iBAAiB,KAAK,EAAE,mCAAmC,CAAC;GACvE,CAAC;EACH,UAAU;GACR,SAAS,UAAU;EACrB;CACF,GACA;EAAC;EAAe;EAAU;EAAc;EAAU;CAAC,CACrD;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,CAAC,CAAC,OAAO;IAGhB,YAAY,OAAO,OAAO,UAAU,EAAE,OAAO,MAAM,OAAO,IAAI,KAAA;IAC9D,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,WAAW;IACtB,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,oBAACC,QAAD;KAAM,WAAWC;KAAY,IAAI,EAAE,IAAI,EAAE;KAAG,IAAI;KAC7C,UAAA,EAAE,wBAAwB;IACvB,CAAA,CACI;;EACA;CACG,CAAA,EAAA,CAAA,EACL,CAAA,IACd;AACN"}
|
|
@@ -1,12 +1,17 @@
|
|
|
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");
|
|
5
|
+
const require_api = require("../../store/api.js");
|
|
4
6
|
const require_configuration = require("../../configuration.js");
|
|
5
7
|
const require_utils = require("../../store/utils.js");
|
|
6
8
|
const require_use_data_mutation = require("../../api/use-data-mutation.js");
|
|
7
9
|
const require_utils$1 = require("../../providers/AuthProvider/utils.js");
|
|
10
|
+
const require_AuthProvider = require("../../providers/AuthProvider/AuthProvider.js");
|
|
11
|
+
require("../../providers/AuthProvider/index.js");
|
|
8
12
|
const require_LoginDialogFormError = require("../../components/LoginDialog/LoginDialogFormError.js");
|
|
9
13
|
const require_schemas = require("../../utils/schemas.js");
|
|
14
|
+
const require_LoginDialog = require("../../components/LoginDialog/LoginDialog.js");
|
|
10
15
|
const require_Dialog = require("../../layouts/Security/Dialog.js");
|
|
11
16
|
const require_styles = require("./styles.js");
|
|
12
17
|
const require_Success = require("./Success.js");
|
|
@@ -22,13 +27,27 @@ let react_hook_form = require("react-hook-form");
|
|
|
22
27
|
var ChangePassword = () => {
|
|
23
28
|
const { t } = (0, react_i18next.useTranslation)();
|
|
24
29
|
const navigate = (0, react_router.useNavigate)();
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
|
|
30
|
+
const changePasswordEnabled = require_configuration.getConfiguration()?.flags?.changePassword;
|
|
31
|
+
const { userState } = require_AuthProvider.useAuth();
|
|
32
|
+
(0, react.useEffect)(() => {
|
|
33
|
+
if (!changePasswordEnabled) navigate("/");
|
|
34
|
+
}, [changePasswordEnabled, navigate]);
|
|
35
|
+
if (!changePasswordEnabled) return null;
|
|
36
|
+
if (!userState?.token) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_LoginDialog.default, {
|
|
37
|
+
message: t("security.changePassword.loginRequired"),
|
|
38
|
+
onClose: () => navigate(require_routes.Route.ROOT),
|
|
39
|
+
open: true
|
|
40
|
+
});
|
|
41
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChangePasswordForm, {});
|
|
42
|
+
};
|
|
43
|
+
var ChangePasswordForm = () => {
|
|
44
|
+
const { t } = (0, react_i18next.useTranslation)();
|
|
45
|
+
const navigate = (0, react_router.useNavigate)();
|
|
46
|
+
const { setUserState } = require_AuthProvider.useAuth();
|
|
47
|
+
const basePath = require_utils.stripTrailingSlash(require_configuration.getConfiguration().base);
|
|
28
48
|
const { setError, handleSubmit, register, formState: { isValid, isSubmitting, errors } } = (0, react_hook_form.useForm)({
|
|
29
49
|
mode: "onChange",
|
|
30
50
|
defaultValues: {
|
|
31
|
-
username: "",
|
|
32
51
|
oldPassword: "",
|
|
33
52
|
newPassword: "",
|
|
34
53
|
confirmPassword: ""
|
|
@@ -50,6 +69,21 @@ var ChangePassword = () => {
|
|
|
50
69
|
} });
|
|
51
70
|
navigate(`${require_routes.Route.SUCCESS}?messageType=${require_Success.MessageType.ChangePassword}`);
|
|
52
71
|
} catch (err) {
|
|
72
|
+
if (err instanceof require_api.CustomError && err.code === 401) {
|
|
73
|
+
require_storage.clearAuth();
|
|
74
|
+
setUserState?.({
|
|
75
|
+
username: null,
|
|
76
|
+
token: null
|
|
77
|
+
});
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (err instanceof require_api.CustomError && err.code === 400 && err.message === "invalid old password") {
|
|
81
|
+
setError("oldPassword", {
|
|
82
|
+
type: "server",
|
|
83
|
+
message: "security.changePassword.invalidOldPassword"
|
|
84
|
+
}, { shouldFocus: true });
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
53
87
|
setError("root", {
|
|
54
88
|
type: "server",
|
|
55
89
|
message: require_utils$1.authErrorMessage(err, t("security.error.unable-to-change-password"))
|
|
@@ -60,13 +94,11 @@ var ChangePassword = () => {
|
|
|
60
94
|
}, [
|
|
61
95
|
handleChangePassword,
|
|
62
96
|
setError,
|
|
97
|
+
setUserState,
|
|
63
98
|
navigate,
|
|
64
99
|
t
|
|
65
100
|
]);
|
|
66
|
-
(0,
|
|
67
|
-
if (!changePasswordEnabled) navigate("/");
|
|
68
|
-
}, [changePasswordEnabled, navigate]);
|
|
69
|
-
return changePasswordEnabled ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Dialog.default, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_styles.SecurityContainer, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_styles.SecurityForm, {
|
|
101
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Dialog.default, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_styles.SecurityContainer, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_styles.SecurityForm, {
|
|
70
102
|
onSubmit: handleSubmit(onSubmit),
|
|
71
103
|
children: [
|
|
72
104
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material.Typography, {
|
|
@@ -76,13 +108,6 @@ var ChangePassword = () => {
|
|
|
76
108
|
variant: "h4",
|
|
77
109
|
children: t("security.changePassword.title")
|
|
78
110
|
}),
|
|
79
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_styles.SecurityTextField, {
|
|
80
|
-
error: !!errors.username,
|
|
81
|
-
helperText: errors.username?.message ? t(errors.username.message, { length: 2 }) : void 0,
|
|
82
|
-
label: t("security.changePassword.username"),
|
|
83
|
-
...register("username"),
|
|
84
|
-
required: true
|
|
85
|
-
}),
|
|
86
111
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_styles.SecurityTextField, {
|
|
87
112
|
error: !!errors.oldPassword,
|
|
88
113
|
helperText: errors.oldPassword?.message ? t(errors.oldPassword.message, { length: 2 }) : void 0,
|
|
@@ -118,7 +143,7 @@ var ChangePassword = () => {
|
|
|
118
143
|
children: t("security.changePassword.submit")
|
|
119
144
|
})
|
|
120
145
|
]
|
|
121
|
-
}) }) })
|
|
146
|
+
}) }) });
|
|
122
147
|
};
|
|
123
148
|
//#endregion
|
|
124
149
|
exports.default = ChangePassword;
|
|
@@ -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, 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 {
|
|
1
|
+
{"version":3,"file":"ChangePassword.js","names":["useTranslation","useNavigate","getConfiguration","useAuth","LoginDialog","Route","stripTrailingSlash","useForm","yupResolver","changePasswordSchema","useDataMutation","APIRoute","useCallback","useRef","MessageType","CustomError","authErrorMessage","SecurityLayout","SecurityContainer","SecurityForm","Typography","SecurityTextField","LoginDialogFormError","Button"],"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 LoginDialog from '../../components/LoginDialog/LoginDialog';\nimport LoginDialogFormError from '../../components/LoginDialog/LoginDialogFormError';\nimport { getConfiguration } from '../../configuration';\nimport SecurityLayout from '../../layouts/Security/Dialog';\nimport { useAuth } from '../../providers/AuthProvider';\nimport { authErrorMessage } from '../../providers/AuthProvider/utils';\nimport { CustomError } from '../../store/api';\nimport { clearAuth } from '../../store/storage';\nimport { stripTrailingSlash } from '../../store/utils';\nimport { Route } from '../../utils';\nimport { APIRoute } from '../../utils/routes';\nimport type { ChangePasswordFormValues } from '../../utils/schemas';\nimport { PASSWORD_MIN_LENGTH, 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 changePasswordEnabled = configuration?.flags?.changePassword;\n\n const { userState } = useAuth();\n\n useEffect(() => {\n if (!changePasswordEnabled) {\n navigate('/');\n }\n }, [changePasswordEnabled, navigate]);\n\n if (!changePasswordEnabled) {\n return null;\n }\n\n if (!userState?.token) {\n return (\n <LoginDialog\n message={t('security.changePassword.loginRequired')}\n onClose={() => navigate(Route.ROOT)}\n open={true}\n />\n );\n }\n\n return <ChangePasswordForm />;\n};\n\nconst ChangePasswordForm: React.FC = () => {\n const { t } = useTranslation();\n const navigate = useNavigate();\n const { setUserState } = useAuth();\n const basePath = stripTrailingSlash(getConfiguration().base);\n const form = useForm<ChangePasswordFormValues>({\n mode: 'onChange',\n defaultValues: {\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 if (err instanceof CustomError && err.code === 401) {\n clearAuth();\n setUserState?.({ username: null, token: null });\n return;\n }\n if (\n err instanceof CustomError &&\n err.code === 400 &&\n err.message === 'invalid old password'\n ) {\n setError(\n 'oldPassword',\n {\n type: 'server',\n message: 'security.changePassword.invalidOldPassword',\n },\n { shouldFocus: true }\n );\n return;\n }\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, setUserState, navigate, t]\n );\n\n return (\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.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 );\n};\n\nexport default ChangePassword;\n"],"mappings":"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"}
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { APIRoute, Route as Route$1 } from "../../utils/routes.mjs";
|
|
2
2
|
import "../../utils/index.mjs";
|
|
3
|
+
import { clearAuth } from "../../store/storage.mjs";
|
|
4
|
+
import { CustomError } from "../../store/api.mjs";
|
|
3
5
|
import { getConfiguration } from "../../configuration.mjs";
|
|
4
6
|
import { stripTrailingSlash } from "../../store/utils.mjs";
|
|
5
7
|
import { useDataMutation } from "../../api/use-data-mutation.mjs";
|
|
6
8
|
import { authErrorMessage } from "../../providers/AuthProvider/utils.mjs";
|
|
9
|
+
import { useAuth } from "../../providers/AuthProvider/AuthProvider.mjs";
|
|
10
|
+
import "../../providers/AuthProvider/index.mjs";
|
|
7
11
|
import LoginDialogFormError from "../../components/LoginDialog/LoginDialogFormError.mjs";
|
|
8
12
|
import { changePasswordSchema } from "../../utils/schemas.mjs";
|
|
13
|
+
import LoginDialog from "../../components/LoginDialog/LoginDialog.mjs";
|
|
9
14
|
import SecurityLayout from "../../layouts/Security/Dialog.mjs";
|
|
10
15
|
import { SecurityContainer, SecurityForm, SecurityTextField } from "./styles.mjs";
|
|
11
16
|
import { MessageType } from "./Success.mjs";
|
|
@@ -20,13 +25,27 @@ import { useForm } from "react-hook-form";
|
|
|
20
25
|
var ChangePassword = () => {
|
|
21
26
|
const { t } = useTranslation();
|
|
22
27
|
const navigate = useNavigate();
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
|
|
28
|
+
const changePasswordEnabled = getConfiguration()?.flags?.changePassword;
|
|
29
|
+
const { userState } = useAuth();
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (!changePasswordEnabled) navigate("/");
|
|
32
|
+
}, [changePasswordEnabled, navigate]);
|
|
33
|
+
if (!changePasswordEnabled) return null;
|
|
34
|
+
if (!userState?.token) return /* @__PURE__ */ jsx(LoginDialog, {
|
|
35
|
+
message: t("security.changePassword.loginRequired"),
|
|
36
|
+
onClose: () => navigate(Route$1.ROOT),
|
|
37
|
+
open: true
|
|
38
|
+
});
|
|
39
|
+
return /* @__PURE__ */ jsx(ChangePasswordForm, {});
|
|
40
|
+
};
|
|
41
|
+
var ChangePasswordForm = () => {
|
|
42
|
+
const { t } = useTranslation();
|
|
43
|
+
const navigate = useNavigate();
|
|
44
|
+
const { setUserState } = useAuth();
|
|
45
|
+
const basePath = stripTrailingSlash(getConfiguration().base);
|
|
26
46
|
const { setError, handleSubmit, register, formState: { isValid, isSubmitting, errors } } = useForm({
|
|
27
47
|
mode: "onChange",
|
|
28
48
|
defaultValues: {
|
|
29
|
-
username: "",
|
|
30
49
|
oldPassword: "",
|
|
31
50
|
newPassword: "",
|
|
32
51
|
confirmPassword: ""
|
|
@@ -48,6 +67,21 @@ var ChangePassword = () => {
|
|
|
48
67
|
} });
|
|
49
68
|
navigate(`${Route$1.SUCCESS}?messageType=${MessageType.ChangePassword}`);
|
|
50
69
|
} catch (err) {
|
|
70
|
+
if (err instanceof CustomError && err.code === 401) {
|
|
71
|
+
clearAuth();
|
|
72
|
+
setUserState?.({
|
|
73
|
+
username: null,
|
|
74
|
+
token: null
|
|
75
|
+
});
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (err instanceof CustomError && err.code === 400 && err.message === "invalid old password") {
|
|
79
|
+
setError("oldPassword", {
|
|
80
|
+
type: "server",
|
|
81
|
+
message: "security.changePassword.invalidOldPassword"
|
|
82
|
+
}, { shouldFocus: true });
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
51
85
|
setError("root", {
|
|
52
86
|
type: "server",
|
|
53
87
|
message: authErrorMessage(err, t("security.error.unable-to-change-password"))
|
|
@@ -58,13 +92,11 @@ var ChangePassword = () => {
|
|
|
58
92
|
}, [
|
|
59
93
|
handleChangePassword,
|
|
60
94
|
setError,
|
|
95
|
+
setUserState,
|
|
61
96
|
navigate,
|
|
62
97
|
t
|
|
63
98
|
]);
|
|
64
|
-
|
|
65
|
-
if (!changePasswordEnabled) navigate("/");
|
|
66
|
-
}, [changePasswordEnabled, navigate]);
|
|
67
|
-
return changePasswordEnabled ? /* @__PURE__ */ jsx(SecurityLayout, { children: /* @__PURE__ */ jsx(SecurityContainer, { children: /* @__PURE__ */ jsxs(SecurityForm, {
|
|
99
|
+
return /* @__PURE__ */ jsx(SecurityLayout, { children: /* @__PURE__ */ jsx(SecurityContainer, { children: /* @__PURE__ */ jsxs(SecurityForm, {
|
|
68
100
|
onSubmit: handleSubmit(onSubmit),
|
|
69
101
|
children: [
|
|
70
102
|
/* @__PURE__ */ jsx(Typography, {
|
|
@@ -74,13 +106,6 @@ var ChangePassword = () => {
|
|
|
74
106
|
variant: "h4",
|
|
75
107
|
children: t("security.changePassword.title")
|
|
76
108
|
}),
|
|
77
|
-
/* @__PURE__ */ jsx(SecurityTextField, {
|
|
78
|
-
error: !!errors.username,
|
|
79
|
-
helperText: errors.username?.message ? t(errors.username.message, { length: 2 }) : void 0,
|
|
80
|
-
label: t("security.changePassword.username"),
|
|
81
|
-
...register("username"),
|
|
82
|
-
required: true
|
|
83
|
-
}),
|
|
84
109
|
/* @__PURE__ */ jsx(SecurityTextField, {
|
|
85
110
|
error: !!errors.oldPassword,
|
|
86
111
|
helperText: errors.oldPassword?.message ? t(errors.oldPassword.message, { length: 2 }) : void 0,
|
|
@@ -116,7 +141,7 @@ var ChangePassword = () => {
|
|
|
116
141
|
children: t("security.changePassword.submit")
|
|
117
142
|
})
|
|
118
143
|
]
|
|
119
|
-
}) }) })
|
|
144
|
+
}) }) });
|
|
120
145
|
};
|
|
121
146
|
//#endregion
|
|
122
147
|
export { ChangePassword as default };
|
|
@@ -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, 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 {
|
|
1
|
+
{"version":3,"file":"ChangePassword.mjs","names":["Route"],"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 LoginDialog from '../../components/LoginDialog/LoginDialog';\nimport LoginDialogFormError from '../../components/LoginDialog/LoginDialogFormError';\nimport { getConfiguration } from '../../configuration';\nimport SecurityLayout from '../../layouts/Security/Dialog';\nimport { useAuth } from '../../providers/AuthProvider';\nimport { authErrorMessage } from '../../providers/AuthProvider/utils';\nimport { CustomError } from '../../store/api';\nimport { clearAuth } from '../../store/storage';\nimport { stripTrailingSlash } from '../../store/utils';\nimport { Route } from '../../utils';\nimport { APIRoute } from '../../utils/routes';\nimport type { ChangePasswordFormValues } from '../../utils/schemas';\nimport { PASSWORD_MIN_LENGTH, 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 changePasswordEnabled = configuration?.flags?.changePassword;\n\n const { userState } = useAuth();\n\n useEffect(() => {\n if (!changePasswordEnabled) {\n navigate('/');\n }\n }, [changePasswordEnabled, navigate]);\n\n if (!changePasswordEnabled) {\n return null;\n }\n\n if (!userState?.token) {\n return (\n <LoginDialog\n message={t('security.changePassword.loginRequired')}\n onClose={() => navigate(Route.ROOT)}\n open={true}\n />\n );\n }\n\n return <ChangePasswordForm />;\n};\n\nconst ChangePasswordForm: React.FC = () => {\n const { t } = useTranslation();\n const navigate = useNavigate();\n const { setUserState } = useAuth();\n const basePath = stripTrailingSlash(getConfiguration().base);\n const form = useForm<ChangePasswordFormValues>({\n mode: 'onChange',\n defaultValues: {\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 if (err instanceof CustomError && err.code === 401) {\n clearAuth();\n setUserState?.({ username: null, token: null });\n return;\n }\n if (\n err instanceof CustomError &&\n err.code === 400 &&\n err.message === 'invalid old password'\n ) {\n setError(\n 'oldPassword',\n {\n type: 'server',\n message: 'security.changePassword.invalidOldPassword',\n },\n { shouldFocus: true }\n );\n return;\n }\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, setUserState, navigate, t]\n );\n\n return (\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.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 );\n};\n\nexport default ChangePassword;\n"],"mappings":"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"}
|
|
@@ -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, 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":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,IAAM,
|
|
1
|
+
{"version":3,"file":"Login.js","names":["getConfiguration","stripTrailingSlash","useTranslation","useLocation","useNavigate","useAuth","getSecurityUrlParams","Route","useDataMutation","useForm","yupResolver","loginSchema","useCallback","MessageType","useRef","authErrorMessage","NotFound","SecurityLayout","SecurityContainer","SecurityForm","LoginFormHeader","LoginForm","Typography","Link","RouterLink"],"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":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,IAAM,gBAAgBA,sBAAAA,iBAAiB;AACvC,IAAM,WAAWC,cAAAA,mBAAmB,cAAc,IAAI;AAEtD,IAAM,cAAwB;CAC5B,MAAM,EAAE,OAAA,GAAMC,cAAAA,eAAAA,CAAe;CAC7B,MAAM,YAAA,GAAWC,aAAAA,YAAAA,CAAY;CAC7B,MAAM,YAAA,GAAWC,aAAAA,YAAAA,CAAY;CAC7B,MAAM,EAAE,iBAAiBC,qBAAAA,QAAQ;CACjC,MAAM,EAAE,SAASC,gBAAAA,qBAAqB,QAAQ;CAC9C,MAAM,oBAAoB,eAAe,OAAO;CAChD,MAAM,cAAcC,eAAAA,MAAM,YAAY,OAAO,WAAW,OAAO;CAE/D,MAAM,EAAE,YAAYC,0BAAAA,gBAA2B,UAAU,MAAM,MAAM;CAOrE,MAAM,EACJ,UACA,cACA,UACA,WAAW,EAAE,SAAS,cAAc,cAAA,GATzBC,gBAAAA,QAAAA,CAAyB;EACpC,MAAM;EACN,WAAA,GAAUC,wBAAAA,YAAAA,CAAYC,gBAAAA,WAAW;CACnC,CAOI;CAEJ,MAAM,eAAA,GAAcC,MAAAA,YAAAA,CAClB,OAAO,SAAiD;EACtD,OAAO,MAAM,QAAQ,IAAI;CAC3B,GACA,CAAC,OAAO,CACV;CAEA,MAAM,aAAA,GAAYA,MAAAA,YAAAA,OAAkB;EAClC,SAAS,GAAGL,eAAAA,MAAM,QAAQ,eAAeM,gBAAAA,YAAY,OAAO;CAC9D,GAAG,CAAC,QAAQ,CAAC;CAIb,MAAM,YAAA,GAAWC,MAAAA,OAAAA,CAAO,KAAK;CAE7B,MAAM,YAAA,GAAWF,MAAAA,YAAAA,CACf,OAAO,SAA0B;EAC/B,IAAI,SAAS,SACX;EAEF,SAAS,UAAU;EACnB,IAAI;GACF,MAAM,SAAS,MAAM,cAAc,IAAI;GACvC,IAAI,CAAC,UAAU,CAAC,OAAO,YAAY,CAAC,OAAO,OAEzC,MAAM,IAAI,MAAM,qCAAqC;GAEvD,gBAAA,SAAS,OAAO,UAAU,OAAO,KAAK;GAEtC,eAAe;IAAE,UAAU,OAAO;IAAU,OAAO,OAAO;GAAM,CAAC;GACjE,UAAU;EACZ,SAAS,KAAU;GAGjB,MAAM,UACJ,KAAK,SAAS,MACV,EAAE,oCAAoC,IACtCG,gBAAAA,iBAAiB,KAAK,EAAE,gCAAgC,CAAC;GAC/D,SAAS,QAAQ;IAAE,MAAM;IAAU;GAAQ,CAAC;EAC9C,UAAU;GACR,SAAS,UAAU;EACrB;CACF,GACA;EAAC;EAAa;EAAU;EAAc;EAAW;CAAC,CACpD;CAEA,OAAO,CAAC,OACN,iBAAA,GAAA,kBAAA,IAAA,CAACC,iBAAAA,SAAD,CAAW,CAAA,IAEX,iBAAA,GAAA,kBAAA,IAAA,CAACC,eAAAA,SAAD,EAAA,UACE,iBAAA,GAAA,kBAAA,IAAA,CAACC,iBAAAA,mBAAD,EAAA,UAGE,iBAAA,GAAA,kBAAA,KAAA,CAACC,iBAAAA,cAAD;EAAc,IAAG;EAAjB,UAAA;GACE,iBAAA,GAAA,kBAAA,IAAA,CAACC,eAAAA,SAAD,CAAkB,CAAA;GAClB,iBAAA,GAAA,kBAAA,IAAA,CAACC,cAAAA,SAAD;IACU;IACM;IACA;IACL;IACC;IACA;GACX,CAAA;GACA,qBACC,iBAAA,GAAA,kBAAA,KAAA,CAACC,cAAAA,YAAD;IAAY,OAAM;IAAS,IAAI;KAAE,IAAI;KAAG,UAAU;IAAG;IAAG,SAAQ;IAAhE,UAAA,CACG,EAAE,+BAA+B,GAClC,iBAAA,GAAA,kBAAA,IAAA,CAACC,cAAAA,MAAD;KAAM,WAAWC,aAAAA;KAAY,IAAI,EAAE,IAAI,EAAE;KAAG,IAAI;KAC7C,UAAA,EAAE,2BAA2B;IAC1B,CAAA,CACI;;EAEF;CACG,CAAA,EAAA,CAAA,EACL,CAAA;AAEpB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Login.mjs","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":";;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,IAAM,gBAAgB,iBAAiB;AACvC,IAAM,WAAW,mBAAmB,cAAc,IAAI;AAEtD,IAAM,cAAwB;CAC5B,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,WAAW,YAAY;CAC7B,MAAM,WAAW,YAAY;CAC7B,MAAM,EAAE,iBAAiB,QAAQ;CACjC,MAAM,EAAE,SAAS,qBAAqB,QAAQ;CAC9C,MAAM,oBAAoB,eAAe,OAAO;CAChD,MAAM,
|
|
1
|
+
{"version":3,"file":"Login.mjs","names":["Route","Link","RouterLink"],"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":";;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,IAAM,gBAAgB,iBAAiB;AACvC,IAAM,WAAW,mBAAmB,cAAc,IAAI;AAEtD,IAAM,cAAwB;CAC5B,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,WAAW,YAAY;CAC7B,MAAM,WAAW,YAAY;CAC7B,MAAM,EAAE,iBAAiB,QAAQ;CACjC,MAAM,EAAE,SAAS,qBAAqB,QAAQ;CAC9C,MAAM,oBAAoB,eAAe,OAAO;CAChD,MAAM,cAAcA,QAAM,YAAY,OAAO,WAAW,OAAO;CAE/D,MAAM,EAAE,YAAY,gBAA2B,UAAU,MAAM,MAAM;CAOrE,MAAM,EACJ,UACA,cACA,UACA,WAAW,EAAE,SAAS,cAAc,aATzB,QAAyB;EACpC,MAAM;EACN,UAAU,YAAY,WAAW;CACnC,CAOI;CAEJ,MAAM,cAAc,YAClB,OAAO,SAAiD;EACtD,OAAO,MAAM,QAAQ,IAAI;CAC3B,GACA,CAAC,OAAO,CACV;CAEA,MAAM,YAAY,kBAAkB;EAClC,SAAS,GAAGA,QAAM,QAAQ,eAAe,YAAY,OAAO;CAC9D,GAAG,CAAC,QAAQ,CAAC;CAIb,MAAM,WAAW,OAAO,KAAK;CAE7B,MAAM,WAAW,YACf,OAAO,SAA0B;EAC/B,IAAI,SAAS,SACX;EAEF,SAAS,UAAU;EACnB,IAAI;GACF,MAAM,SAAS,MAAM,cAAc,IAAI;GACvC,IAAI,CAAC,UAAU,CAAC,OAAO,YAAY,CAAC,OAAO,OAEzC,MAAM,IAAI,MAAM,qCAAqC;GAEvD,SAAS,OAAO,UAAU,OAAO,KAAK;GAEtC,eAAe;IAAE,UAAU,OAAO;IAAU,OAAO,OAAO;GAAM,CAAC;GACjE,UAAU;EACZ,SAAS,KAAU;GAGjB,MAAM,UACJ,KAAK,SAAS,MACV,EAAE,oCAAoC,IACtC,iBAAiB,KAAK,EAAE,gCAAgC,CAAC;GAC/D,SAAS,QAAQ;IAAE,MAAM;IAAU;GAAQ,CAAC;EAC9C,UAAU;GACR,SAAS,UAAU;EACrB;CACF,GACA;EAAC;EAAa;EAAU;EAAc;EAAW;CAAC,CACpD;CAEA,OAAO,CAAC,OACN,oBAAC,UAAD,CAAW,CAAA,IAEX,oBAAC,gBAAD,EAAA,UACE,oBAAC,mBAAD,EAAA,UAGE,qBAAC,cAAD;EAAc,IAAG;EAAjB,UAAA;GACE,oBAAC,iBAAD,CAAkB,CAAA;GAClB,oBAAC,WAAD;IACU;IACM;IACA;IACL;IACC;IACA;GACX,CAAA;GACA,qBACC,qBAAC,YAAD;IAAY,OAAM;IAAS,IAAI;KAAE,IAAI;KAAG,UAAU;IAAG;IAAG,SAAQ;IAAhE,UAAA,CACG,EAAE,+BAA+B,GAClC,oBAACC,QAAD;KAAM,WAAWC;KAAY,IAAI,EAAE,IAAI,EAAE;KAAG,IAAI;KAC7C,UAAA,EAAE,2BAA2B;IAC1B,CAAA,CACI;;EAEF;CACG,CAAA,EAAA,CAAA,EACL,CAAA;AAEpB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Success.js","names":[],"sources":["../../../src/sections/Security/Success.tsx"],"sourcesContent":["import CheckCircleIcon from '@mui/icons-material/CheckCircle';\nimport { Button, Typography } from '@mui/material';\nimport React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useLocation, useNavigate } from 'react-router';\n\nimport SecurityLayout from '../../layouts/Security/Dialog';\nimport { SecurityContainer, SecurityForm } from './styles';\n\nexport enum MessageType {\n Login = 'Login',\n ChangePassword = 'ChangePassword',\n AddUser = 'AddUser',\n Success = 'Success',\n}\n\nconst Success: React.FC = () => {\n const { t } = useTranslation();\n const location = useLocation();\n const navigate = useNavigate();\n const queryParams = new URLSearchParams(location.search);\n const messageType = queryParams.get('messageType') as MessageType;\n const message = !messageType\n ? t('security.success.messageSuccess')\n : t(`security.success.message${messageType}`);\n\n const handleClose = () => {\n // navigate() keeps the router basename; window.location.href = '/' left the\n // registry entirely when it is served under a sub-path\n navigate('/');\n };\n\n return (\n <SecurityLayout>\n <SecurityContainer>\n {/* container only: this page has no form to submit */}\n <SecurityForm as=\"div\">\n <CheckCircleIcon color=\"success\" />\n <Typography component=\"h1\" gutterBottom={true} variant=\"h4\">\n {t('security.success.title')}\n </Typography>\n <Typography color=\"text.secondary\" paragraph={true} variant=\"body1\">\n {message}\n </Typography>\n <Button color=\"primary\" onClick={handleClose} sx={{ mt: 2 }} variant=\"contained\">\n {t('security.success.submit')}\n </Button>\n </SecurityForm>\n </SecurityContainer>\n </SecurityLayout>\n );\n};\n\nexport default Success;\n"],"mappings":";;;;;;;;;;;;AASA,IAAY,cAAL,yBAAA,aAAA;CACL,YAAA,WAAA;CACA,YAAA,oBAAA;CACA,YAAA,aAAA;CACA,YAAA,aAAA;;AACF,EAAA,CAAA,CAAA;AAEA,IAAM,gBAA0B;CAC9B,MAAM,EAAE,OAAA,
|
|
1
|
+
{"version":3,"file":"Success.js","names":["useTranslation","useLocation","useNavigate","SecurityLayout","SecurityContainer","SecurityForm","CheckCircleIcon","Typography","Button"],"sources":["../../../src/sections/Security/Success.tsx"],"sourcesContent":["import CheckCircleIcon from '@mui/icons-material/CheckCircle';\nimport { Button, Typography } from '@mui/material';\nimport React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useLocation, useNavigate } from 'react-router';\n\nimport SecurityLayout from '../../layouts/Security/Dialog';\nimport { SecurityContainer, SecurityForm } from './styles';\n\nexport enum MessageType {\n Login = 'Login',\n ChangePassword = 'ChangePassword',\n AddUser = 'AddUser',\n Success = 'Success',\n}\n\nconst Success: React.FC = () => {\n const { t } = useTranslation();\n const location = useLocation();\n const navigate = useNavigate();\n const queryParams = new URLSearchParams(location.search);\n const messageType = queryParams.get('messageType') as MessageType;\n const message = !messageType\n ? t('security.success.messageSuccess')\n : t(`security.success.message${messageType}`);\n\n const handleClose = () => {\n // navigate() keeps the router basename; window.location.href = '/' left the\n // registry entirely when it is served under a sub-path\n navigate('/');\n };\n\n return (\n <SecurityLayout>\n <SecurityContainer>\n {/* container only: this page has no form to submit */}\n <SecurityForm as=\"div\">\n <CheckCircleIcon color=\"success\" />\n <Typography component=\"h1\" gutterBottom={true} variant=\"h4\">\n {t('security.success.title')}\n </Typography>\n <Typography color=\"text.secondary\" paragraph={true} variant=\"body1\">\n {message}\n </Typography>\n <Button color=\"primary\" onClick={handleClose} sx={{ mt: 2 }} variant=\"contained\">\n {t('security.success.submit')}\n </Button>\n </SecurityForm>\n </SecurityContainer>\n </SecurityLayout>\n );\n};\n\nexport default Success;\n"],"mappings":";;;;;;;;;;;;AASA,IAAY,cAAL,yBAAA,aAAA;CACL,YAAA,WAAA;CACA,YAAA,oBAAA;CACA,YAAA,aAAA;CACA,YAAA,aAAA;;AACF,EAAA,CAAA,CAAA;AAEA,IAAM,gBAA0B;CAC9B,MAAM,EAAE,OAAA,GAAMA,cAAAA,eAAAA,CAAe;CAC7B,MAAM,YAAA,GAAWC,aAAAA,YAAAA,CAAY;CAC7B,MAAM,YAAA,GAAWC,aAAAA,YAAAA,CAAY;CAE7B,MAAM,cAAc,IADI,gBAAgB,SAAS,MAC7B,CAAA,CAAY,IAAI,aAAa;CACjD,MAAM,UAAU,CAAC,cACb,EAAE,iCAAiC,IACnC,EAAE,2BAA2B,aAAa;CAE9C,MAAM,oBAAoB;EAGxB,SAAS,GAAG;CACd;CAEA,OACE,iBAAA,GAAA,kBAAA,IAAA,CAACC,eAAAA,SAAD,EAAA,UACE,iBAAA,GAAA,kBAAA,IAAA,CAACC,eAAAA,mBAAD,EAAA,UAEE,iBAAA,GAAA,kBAAA,KAAA,CAACC,eAAAA,cAAD;EAAc,IAAG;EAAjB,UAAA;GACE,iBAAA,GAAA,kBAAA,IAAA,CAACC,gCAAAA,SAAD,EAAiB,OAAM,UAAW,CAAA;GAClC,iBAAA,GAAA,kBAAA,IAAA,CAACC,cAAAA,YAAD;IAAY,WAAU;IAAK,cAAc;IAAM,SAAQ;IACpD,UAAA,EAAE,wBAAwB;GACjB,CAAA;GACZ,iBAAA,GAAA,kBAAA,IAAA,CAACA,cAAAA,YAAD;IAAY,OAAM;IAAiB,WAAW;IAAM,SAAQ;IACzD,UAAA;GACS,CAAA;GACZ,iBAAA,GAAA,kBAAA,IAAA,CAACC,cAAAA,QAAD;IAAQ,OAAM;IAAU,SAAS;IAAa,IAAI,EAAE,IAAI,EAAE;IAAG,SAAQ;IAClE,UAAA,EAAE,yBAAyB;GACtB,CAAA;EACI;CACG,CAAA,EAAA,CAAA,EACL,CAAA;AAEpB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styles.js","names":[],"sources":["../../../src/sections/Security/styles.ts"],"sourcesContent":["import { Box, TextField } from '@mui/material';\nimport { styled } from '@mui/material/styles';\n\nexport const SecurityContainer = styled(Box)(({ theme }) => ({\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: '100%',\n padding: theme.spacing(2),\n backgroundColor: theme.palette.background.default,\n}));\n\nexport const SecurityForm = styled('form')(({ theme }) => ({\n width: '100%',\n maxWidth: 420,\n padding: theme.spacing(4),\n backgroundColor: theme.palette.background.paper,\n borderRadius: theme.shape.borderRadius,\n boxShadow: theme.shadows[3],\n}));\n\nexport const SecurityTextField = styled(TextField)(({ theme }) => ({\n width: '100%',\n marginTop: theme.spacing(1),\n marginBottom: theme.spacing(1),\n}));\n"],"mappings":";;;AAGA,IAAa,qBAAA,
|
|
1
|
+
{"version":3,"file":"styles.js","names":["styled","Box","TextField"],"sources":["../../../src/sections/Security/styles.ts"],"sourcesContent":["import { Box, TextField } from '@mui/material';\nimport { styled } from '@mui/material/styles';\n\nexport const SecurityContainer = styled(Box)(({ theme }) => ({\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: '100%',\n padding: theme.spacing(2),\n backgroundColor: theme.palette.background.default,\n}));\n\nexport const SecurityForm = styled('form')(({ theme }) => ({\n width: '100%',\n maxWidth: 420,\n padding: theme.spacing(4),\n backgroundColor: theme.palette.background.paper,\n borderRadius: theme.shape.borderRadius,\n boxShadow: theme.shadows[3],\n}));\n\nexport const SecurityTextField = styled(TextField)(({ theme }) => ({\n width: '100%',\n marginTop: theme.spacing(1),\n marginBottom: theme.spacing(1),\n}));\n"],"mappings":";;;AAGA,IAAa,qBAAA,GAAoBA,qBAAAA,OAAAA,CAAOC,cAAAA,GAAG,CAAC,EAAE,EAAE,aAAa;CAC3D,SAAS;CACT,eAAe;CACf,YAAY;CACZ,gBAAgB;CAChB,WAAW;CACX,SAAS,MAAM,QAAQ,CAAC;CACxB,iBAAiB,MAAM,QAAQ,WAAW;AAC5C,EAAE;AAEF,IAAa,gBAAA,GAAeD,qBAAAA,OAAAA,CAAO,MAAM,CAAC,EAAE,EAAE,aAAa;CACzD,OAAO;CACP,UAAU;CACV,SAAS,MAAM,QAAQ,CAAC;CACxB,iBAAiB,MAAM,QAAQ,WAAW;CAC1C,cAAc,MAAM,MAAM;CAC1B,WAAW,MAAM,QAAQ;AAC3B,EAAE;AAEF,IAAa,qBAAA,GAAoBA,qBAAAA,OAAAA,CAAOE,cAAAA,SAAS,CAAC,EAAE,EAAE,aAAa;CACjE,OAAO;CACP,WAAW,MAAM,QAAQ,CAAC;CAC1B,cAAc,MAAM,QAAQ,CAAC;AAC/B,EAAE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","names":[],"sources":["../../../src/sections/Security/utils.ts"],"sourcesContent":["import { isEmpty } from 'lodash-es';\n\nimport { Route } from '../../utils';\n\nexport interface SecurityUrlParams {\n readonly next: string;\n readonly user: string;\n}\n\nexport interface LocationLike {\n readonly search: string;\n}\n\nexport function getSecurityUrlParams(location: LocationLike): SecurityUrlParams {\n const queryParams = new URLSearchParams(location.search);\n\n // Get next parameter to match v1 URLs\n let next = queryParams.get('next') || '';\n if (next.length > 0 && (!next.startsWith(Route.LOGIN_API) || !next.match(/\\/[-0-9a-f]{36}$/))) {\n next = '';\n }\n\n // Ignore user parameter if it does not match expected format (prevent XSS attacks)\n let user = queryParams.get('user') || '';\n if (user.length > 0 && !user.match(/^[a-zA-Z0-9-_]{1,255}$/)) {\n user = '';\n }\n\n return { next, user };\n}\n\nexport interface TranslationFunction {\n (key: string, options?: Record<string, unknown>): string;\n}\n\nexport interface DispatchAction {\n (payload: { type: string; description: string }): void;\n}\n\nexport const validateCredentials = (\n username: string,\n password: string,\n t: TranslationFunction,\n dispatchAction: DispatchAction\n): boolean => {\n if (!username || !password || isEmpty(username) || isEmpty(password)) {\n dispatchAction({\n type: 'error',\n description: t('security.error.username-or-password-cant-be-empty'),\n });\n return false;\n }\n\n if (username.length < 2) {\n dispatchAction({\n type: 'error',\n description: t('security.error.username-min-length', { length: 2 }),\n });\n return false;\n }\n\n // Validate username contains only url-safe characters\n if (!username.match(/^[-a-zA-Z0-9_.!~*'()@]+$/)) {\n dispatchAction({\n type: 'error',\n description: t('security.error.username-must-be-url-safe'),\n });\n return false;\n }\n\n // Note: password rules should be checked in auth plugin\n return true;\n};\n"],"mappings":";;;;AAaA,SAAgB,qBAAqB,UAA2C;CAC9E,MAAM,cAAc,IAAI,gBAAgB,SAAS,MAAM;CAGvD,IAAI,OAAO,YAAY,IAAI,MAAM,KAAK;CACtC,IAAI,KAAK,SAAS,MAAM,CAAC,KAAK,
|
|
1
|
+
{"version":3,"file":"utils.js","names":["Route"],"sources":["../../../src/sections/Security/utils.ts"],"sourcesContent":["import { isEmpty } from 'lodash-es';\n\nimport { Route } from '../../utils';\n\nexport interface SecurityUrlParams {\n readonly next: string;\n readonly user: string;\n}\n\nexport interface LocationLike {\n readonly search: string;\n}\n\nexport function getSecurityUrlParams(location: LocationLike): SecurityUrlParams {\n const queryParams = new URLSearchParams(location.search);\n\n // Get next parameter to match v1 URLs\n let next = queryParams.get('next') || '';\n if (next.length > 0 && (!next.startsWith(Route.LOGIN_API) || !next.match(/\\/[-0-9a-f]{36}$/))) {\n next = '';\n }\n\n // Ignore user parameter if it does not match expected format (prevent XSS attacks)\n let user = queryParams.get('user') || '';\n if (user.length > 0 && !user.match(/^[a-zA-Z0-9-_]{1,255}$/)) {\n user = '';\n }\n\n return { next, user };\n}\n\nexport interface TranslationFunction {\n (key: string, options?: Record<string, unknown>): string;\n}\n\nexport interface DispatchAction {\n (payload: { type: string; description: string }): void;\n}\n\nexport const validateCredentials = (\n username: string,\n password: string,\n t: TranslationFunction,\n dispatchAction: DispatchAction\n): boolean => {\n if (!username || !password || isEmpty(username) || isEmpty(password)) {\n dispatchAction({\n type: 'error',\n description: t('security.error.username-or-password-cant-be-empty'),\n });\n return false;\n }\n\n if (username.length < 2) {\n dispatchAction({\n type: 'error',\n description: t('security.error.username-min-length', { length: 2 }),\n });\n return false;\n }\n\n // Validate username contains only url-safe characters\n if (!username.match(/^[-a-zA-Z0-9_.!~*'()@]+$/)) {\n dispatchAction({\n type: 'error',\n description: t('security.error.username-must-be-url-safe'),\n });\n return false;\n }\n\n // Note: password rules should be checked in auth plugin\n return true;\n};\n"],"mappings":";;;;AAaA,SAAgB,qBAAqB,UAA2C;CAC9E,MAAM,cAAc,IAAI,gBAAgB,SAAS,MAAM;CAGvD,IAAI,OAAO,YAAY,IAAI,MAAM,KAAK;CACtC,IAAI,KAAK,SAAS,MAAM,CAAC,KAAK,WAAWA,eAAAA,MAAM,SAAS,KAAK,CAAC,KAAK,MAAM,kBAAkB,IACzF,OAAO;CAIT,IAAI,OAAO,YAAY,IAAI,MAAM,KAAK;CACtC,IAAI,KAAK,SAAS,KAAK,CAAC,KAAK,MAAM,wBAAwB,GACzD,OAAO;CAGT,OAAO;EAAE;EAAM;CAAK;AACtB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Sidebar.js","names":[],"sources":["../../../src/sections/SideBar/Sidebar.tsx"],"sourcesContent":["import Paper from '@mui/material/Paper';\nimport React from 'react';\n\nimport ActionBar from '../../components/ActionBar';\nimport Author from '../../components/Author';\nimport Developers, { DeveloperType } from '../../components/Developers';\nimport Dist from '../../components/Distribution';\nimport Engines from '../../components/Engines';\nimport FundButton from '../../components/FundButton';\nimport Install from '../../components/Install';\nimport Keywords from '../../components/Keywords';\nimport Repository from '../../components/Repository';\nimport SideBarTitle from '../../components/SideBarTitle';\nimport { DownloadProvider, useConfig, useVersion } from '../../providers';\nimport type { ModuleType, PackageMetaInterface } from '../../types/packageMeta';\n\nconst getModuleTypes = (manifest: PackageMetaInterface) => {\n if (!manifest.latest) return [];\n\n const moduleTypes: ModuleType[] = [manifest.latest.type || 'commonjs'];\n\n if (manifest.latest.main) {\n moduleTypes.push('commonjs');\n }\n\n return Array.from(new Set(moduleTypes));\n};\n\nconst DetailSidebar: React.FC = () => {\n const { packageMeta, packageName, packageVersion } = useVersion();\n\n const { configOptions } = useConfig();\n const version = packageVersion || packageMeta?.latest.version || '';\n const time = packageMeta?.time ? packageMeta.time[version] : '';\n if (!packageMeta || !packageName) {\n return null;\n }\n\n return (\n <Paper data-testid=\"sidebar\" sx={{ position: 'sticky', top: 0, p: 2, ml: { xs: 0, md: 2 } }}>\n <SideBarTitle\n description={packageMeta.latest?.description}\n hasTypes={typeof packageMeta.latest?.types === 'string'}\n isLatest={typeof packageVersion === 'undefined'}\n moduleTypes={getModuleTypes(packageMeta)}\n packageName={packageName}\n time={time}\n version={version}\n />\n <DownloadProvider>\n <ActionBar\n packageMeta={packageMeta}\n showDownloadTarball={configOptions.showDownloadTarball}\n showRaw={configOptions.showRaw}\n />\n </DownloadProvider>\n <FundButton packageMeta={packageMeta} />\n <Install configOptions={configOptions} packageMeta={packageMeta} packageName={packageName} />\n <Repository packageMeta={packageMeta} />\n <Engines packageMeta={packageMeta} />\n <Dist packageMeta={packageMeta} />\n <Keywords packageMeta={packageMeta} />\n <Author packageMeta={packageMeta} />\n <Developers packageMeta={packageMeta} type={DeveloperType.MAINTAINERS} />\n <Developers packageMeta={packageMeta} type={DeveloperType.CONTRIBUTORS} />\n </Paper>\n );\n};\n\nexport default DetailSidebar;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgBA,IAAM,kBAAkB,aAAmC;CACzD,IAAI,CAAC,SAAS,QAAQ,OAAO,CAAC;CAE9B,MAAM,cAA4B,CAAC,SAAS,OAAO,QAAQ,UAAU;CAErE,IAAI,SAAS,OAAO,MAClB,YAAY,KAAK,UAAU;CAG7B,OAAO,MAAM,KAAK,IAAI,IAAI,WAAW,CAAC;AACxC;AAEA,IAAM,sBAAgC;CACpC,MAAM,EAAE,aAAa,aAAa,
|
|
1
|
+
{"version":3,"file":"Sidebar.js","names":["useVersion","useConfig","Paper","SideBarTitle","DownloadProvider","ActionBar","FundButton","Install","Repository","Engines","Dist","Keywords","Author","Developers","DeveloperType"],"sources":["../../../src/sections/SideBar/Sidebar.tsx"],"sourcesContent":["import Paper from '@mui/material/Paper';\nimport React from 'react';\n\nimport ActionBar from '../../components/ActionBar';\nimport Author from '../../components/Author';\nimport Developers, { DeveloperType } from '../../components/Developers';\nimport Dist from '../../components/Distribution';\nimport Engines from '../../components/Engines';\nimport FundButton from '../../components/FundButton';\nimport Install from '../../components/Install';\nimport Keywords from '../../components/Keywords';\nimport Repository from '../../components/Repository';\nimport SideBarTitle from '../../components/SideBarTitle';\nimport { DownloadProvider, useConfig, useVersion } from '../../providers';\nimport type { ModuleType, PackageMetaInterface } from '../../types/packageMeta';\n\nconst getModuleTypes = (manifest: PackageMetaInterface) => {\n if (!manifest.latest) return [];\n\n const moduleTypes: ModuleType[] = [manifest.latest.type || 'commonjs'];\n\n if (manifest.latest.main) {\n moduleTypes.push('commonjs');\n }\n\n return Array.from(new Set(moduleTypes));\n};\n\nconst DetailSidebar: React.FC = () => {\n const { packageMeta, packageName, packageVersion } = useVersion();\n\n const { configOptions } = useConfig();\n const version = packageVersion || packageMeta?.latest.version || '';\n const time = packageMeta?.time ? packageMeta.time[version] : '';\n if (!packageMeta || !packageName) {\n return null;\n }\n\n return (\n <Paper data-testid=\"sidebar\" sx={{ position: 'sticky', top: 0, p: 2, ml: { xs: 0, md: 2 } }}>\n <SideBarTitle\n description={packageMeta.latest?.description}\n hasTypes={typeof packageMeta.latest?.types === 'string'}\n isLatest={typeof packageVersion === 'undefined'}\n moduleTypes={getModuleTypes(packageMeta)}\n packageName={packageName}\n time={time}\n version={version}\n />\n <DownloadProvider>\n <ActionBar\n packageMeta={packageMeta}\n showDownloadTarball={configOptions.showDownloadTarball}\n showRaw={configOptions.showRaw}\n />\n </DownloadProvider>\n <FundButton packageMeta={packageMeta} />\n <Install configOptions={configOptions} packageMeta={packageMeta} packageName={packageName} />\n <Repository packageMeta={packageMeta} />\n <Engines packageMeta={packageMeta} />\n <Dist packageMeta={packageMeta} />\n <Keywords packageMeta={packageMeta} />\n <Author packageMeta={packageMeta} />\n <Developers packageMeta={packageMeta} type={DeveloperType.MAINTAINERS} />\n <Developers packageMeta={packageMeta} type={DeveloperType.CONTRIBUTORS} />\n </Paper>\n );\n};\n\nexport default DetailSidebar;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgBA,IAAM,kBAAkB,aAAmC;CACzD,IAAI,CAAC,SAAS,QAAQ,OAAO,CAAC;CAE9B,MAAM,cAA4B,CAAC,SAAS,OAAO,QAAQ,UAAU;CAErE,IAAI,SAAS,OAAO,MAClB,YAAY,KAAK,UAAU;CAG7B,OAAO,MAAM,KAAK,IAAI,IAAI,WAAW,CAAC;AACxC;AAEA,IAAM,sBAAgC;CACpC,MAAM,EAAE,aAAa,aAAa,mBAAmBA,wBAAAA,WAAW;CAEhE,MAAM,EAAE,kBAAkBC,iCAAAA,UAAU;CACpC,MAAM,UAAU,kBAAkB,aAAa,OAAO,WAAW;CACjE,MAAM,OAAO,aAAa,OAAO,YAAY,KAAK,WAAW;CAC7D,IAAI,CAAC,eAAe,CAAC,aACnB,OAAO;CAGT,OACE,iBAAA,GAAA,kBAAA,KAAA,CAACC,oBAAAA,SAAD;EAAO,eAAY;EAAU,IAAI;GAAE,UAAU;GAAU,KAAK;GAAG,GAAG;GAAG,IAAI;IAAE,IAAI;IAAG,IAAI;GAAE;EAAE;EAA1F,UAAA;GACE,iBAAA,GAAA,kBAAA,IAAA,CAACC,qBAAAA,SAAD;IACE,aAAa,YAAY,QAAQ;IACjC,UAAU,OAAO,YAAY,QAAQ,UAAU;IAC/C,UAAU,OAAO,mBAAmB;IACpC,aAAa,eAAe,WAAW;IAC1B;IACP;IACG;GACV,CAAA;GACD,iBAAA,GAAA,kBAAA,IAAA,CAACC,yBAAAA,kBAAD,EAAA,UACE,iBAAA,GAAA,kBAAA,IAAA,CAACC,kBAAAA,SAAD;IACe;IACb,qBAAqB,cAAc;IACnC,SAAS,cAAc;GACxB,CAAA,EACe,CAAA;GAClB,iBAAA,GAAA,kBAAA,IAAA,CAACC,mBAAAA,SAAD,EAAyB,YAAc,CAAA;GACvC,iBAAA,GAAA,kBAAA,IAAA,CAACC,gBAAAA,SAAD;IAAwB;IAA4B;IAA0B;GAAc,CAAA;GAC5F,iBAAA,GAAA,kBAAA,IAAA,CAACC,mBAAAA,SAAD,EAAyB,YAAc,CAAA;GACvC,iBAAA,GAAA,kBAAA,IAAA,CAACC,gBAAAA,SAAD,EAAsB,YAAc,CAAA;GACpC,iBAAA,GAAA,kBAAA,IAAA,CAACC,aAAAA,SAAD,EAAmB,YAAc,CAAA;GACjC,iBAAA,GAAA,kBAAA,IAAA,CAACC,iBAAAA,SAAD,EAAuB,YAAc,CAAA;GACrC,iBAAA,GAAA,kBAAA,IAAA,CAACC,eAAAA,SAAD,EAAqB,YAAc,CAAA;GACnC,iBAAA,GAAA,kBAAA,IAAA,CAACC,mBAAAA,SAAD;IAAyB;IAAa,MAAMC,sBAAAA,cAAc;GAAc,CAAA;GACxE,iBAAA,GAAA,kBAAA,IAAA,CAACD,mBAAAA,SAAD;IAAyB;IAAa,MAAMC,sBAAAA,cAAc;GAAe,CAAA;EACpE;;AAEX"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Sidebar.mjs","names":[],"sources":["../../../src/sections/SideBar/Sidebar.tsx"],"sourcesContent":["import Paper from '@mui/material/Paper';\nimport React from 'react';\n\nimport ActionBar from '../../components/ActionBar';\nimport Author from '../../components/Author';\nimport Developers, { DeveloperType } from '../../components/Developers';\nimport Dist from '../../components/Distribution';\nimport Engines from '../../components/Engines';\nimport FundButton from '../../components/FundButton';\nimport Install from '../../components/Install';\nimport Keywords from '../../components/Keywords';\nimport Repository from '../../components/Repository';\nimport SideBarTitle from '../../components/SideBarTitle';\nimport { DownloadProvider, useConfig, useVersion } from '../../providers';\nimport type { ModuleType, PackageMetaInterface } from '../../types/packageMeta';\n\nconst getModuleTypes = (manifest: PackageMetaInterface) => {\n if (!manifest.latest) return [];\n\n const moduleTypes: ModuleType[] = [manifest.latest.type || 'commonjs'];\n\n if (manifest.latest.main) {\n moduleTypes.push('commonjs');\n }\n\n return Array.from(new Set(moduleTypes));\n};\n\nconst DetailSidebar: React.FC = () => {\n const { packageMeta, packageName, packageVersion } = useVersion();\n\n const { configOptions } = useConfig();\n const version = packageVersion || packageMeta?.latest.version || '';\n const time = packageMeta?.time ? packageMeta.time[version] : '';\n if (!packageMeta || !packageName) {\n return null;\n }\n\n return (\n <Paper data-testid=\"sidebar\" sx={{ position: 'sticky', top: 0, p: 2, ml: { xs: 0, md: 2 } }}>\n <SideBarTitle\n description={packageMeta.latest?.description}\n hasTypes={typeof packageMeta.latest?.types === 'string'}\n isLatest={typeof packageVersion === 'undefined'}\n moduleTypes={getModuleTypes(packageMeta)}\n packageName={packageName}\n time={time}\n version={version}\n />\n <DownloadProvider>\n <ActionBar\n packageMeta={packageMeta}\n showDownloadTarball={configOptions.showDownloadTarball}\n showRaw={configOptions.showRaw}\n />\n </DownloadProvider>\n <FundButton packageMeta={packageMeta} />\n <Install configOptions={configOptions} packageMeta={packageMeta} packageName={packageName} />\n <Repository packageMeta={packageMeta} />\n <Engines packageMeta={packageMeta} />\n <Dist packageMeta={packageMeta} />\n <Keywords packageMeta={packageMeta} />\n <Author packageMeta={packageMeta} />\n <Developers packageMeta={packageMeta} type={DeveloperType.MAINTAINERS} />\n <Developers packageMeta={packageMeta} type={DeveloperType.CONTRIBUTORS} />\n </Paper>\n );\n};\n\nexport default DetailSidebar;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgBA,IAAM,kBAAkB,aAAmC;CACzD,IAAI,CAAC,SAAS,QAAQ,OAAO,CAAC;CAE9B,MAAM,cAA4B,CAAC,SAAS,OAAO,QAAQ,UAAU;CAErE,IAAI,SAAS,OAAO,MAClB,YAAY,KAAK,UAAU;CAG7B,OAAO,MAAM,KAAK,IAAI,IAAI,WAAW,CAAC;AACxC;AAEA,IAAM,sBAAgC;CACpC,MAAM,EAAE,aAAa,aAAa,mBAAmB,WAAW;CAEhE,MAAM,EAAE,kBAAkB,UAAU;CACpC,MAAM,UAAU,kBAAkB,aAAa,OAAO,WAAW;CACjE,MAAM,OAAO,aAAa,OAAO,YAAY,KAAK,WAAW;CAC7D,IAAI,CAAC,eAAe,CAAC,aACnB,OAAO;CAGT,OACE,qBAAC,OAAD;EAAO,eAAY;EAAU,IAAI;GAAE,UAAU;GAAU,KAAK;GAAG,GAAG;GAAG,IAAI;IAAE,IAAI;IAAG,IAAI;GAAE;EAAE;EAA1F,UAAA;GACE,
|
|
1
|
+
{"version":3,"file":"Sidebar.mjs","names":["SideBarTitle","Engines"],"sources":["../../../src/sections/SideBar/Sidebar.tsx"],"sourcesContent":["import Paper from '@mui/material/Paper';\nimport React from 'react';\n\nimport ActionBar from '../../components/ActionBar';\nimport Author from '../../components/Author';\nimport Developers, { DeveloperType } from '../../components/Developers';\nimport Dist from '../../components/Distribution';\nimport Engines from '../../components/Engines';\nimport FundButton from '../../components/FundButton';\nimport Install from '../../components/Install';\nimport Keywords from '../../components/Keywords';\nimport Repository from '../../components/Repository';\nimport SideBarTitle from '../../components/SideBarTitle';\nimport { DownloadProvider, useConfig, useVersion } from '../../providers';\nimport type { ModuleType, PackageMetaInterface } from '../../types/packageMeta';\n\nconst getModuleTypes = (manifest: PackageMetaInterface) => {\n if (!manifest.latest) return [];\n\n const moduleTypes: ModuleType[] = [manifest.latest.type || 'commonjs'];\n\n if (manifest.latest.main) {\n moduleTypes.push('commonjs');\n }\n\n return Array.from(new Set(moduleTypes));\n};\n\nconst DetailSidebar: React.FC = () => {\n const { packageMeta, packageName, packageVersion } = useVersion();\n\n const { configOptions } = useConfig();\n const version = packageVersion || packageMeta?.latest.version || '';\n const time = packageMeta?.time ? packageMeta.time[version] : '';\n if (!packageMeta || !packageName) {\n return null;\n }\n\n return (\n <Paper data-testid=\"sidebar\" sx={{ position: 'sticky', top: 0, p: 2, ml: { xs: 0, md: 2 } }}>\n <SideBarTitle\n description={packageMeta.latest?.description}\n hasTypes={typeof packageMeta.latest?.types === 'string'}\n isLatest={typeof packageVersion === 'undefined'}\n moduleTypes={getModuleTypes(packageMeta)}\n packageName={packageName}\n time={time}\n version={version}\n />\n <DownloadProvider>\n <ActionBar\n packageMeta={packageMeta}\n showDownloadTarball={configOptions.showDownloadTarball}\n showRaw={configOptions.showRaw}\n />\n </DownloadProvider>\n <FundButton packageMeta={packageMeta} />\n <Install configOptions={configOptions} packageMeta={packageMeta} packageName={packageName} />\n <Repository packageMeta={packageMeta} />\n <Engines packageMeta={packageMeta} />\n <Dist packageMeta={packageMeta} />\n <Keywords packageMeta={packageMeta} />\n <Author packageMeta={packageMeta} />\n <Developers packageMeta={packageMeta} type={DeveloperType.MAINTAINERS} />\n <Developers packageMeta={packageMeta} type={DeveloperType.CONTRIBUTORS} />\n </Paper>\n );\n};\n\nexport default DetailSidebar;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgBA,IAAM,kBAAkB,aAAmC;CACzD,IAAI,CAAC,SAAS,QAAQ,OAAO,CAAC;CAE9B,MAAM,cAA4B,CAAC,SAAS,OAAO,QAAQ,UAAU;CAErE,IAAI,SAAS,OAAO,MAClB,YAAY,KAAK,UAAU;CAG7B,OAAO,MAAM,KAAK,IAAI,IAAI,WAAW,CAAC;AACxC;AAEA,IAAM,sBAAgC;CACpC,MAAM,EAAE,aAAa,aAAa,mBAAmB,WAAW;CAEhE,MAAM,EAAE,kBAAkB,UAAU;CACpC,MAAM,UAAU,kBAAkB,aAAa,OAAO,WAAW;CACjE,MAAM,OAAO,aAAa,OAAO,YAAY,KAAK,WAAW;CAC7D,IAAI,CAAC,eAAe,CAAC,aACnB,OAAO;CAGT,OACE,qBAAC,OAAD;EAAO,eAAY;EAAU,IAAI;GAAE,UAAU;GAAU,KAAK;GAAG,GAAG;GAAG,IAAI;IAAE,IAAI;IAAG,IAAI;GAAE;EAAE;EAA1F,UAAA;GACE,oBAACA,oBAAD;IACE,aAAa,YAAY,QAAQ;IACjC,UAAU,OAAO,YAAY,QAAQ,UAAU;IAC/C,UAAU,OAAO,mBAAmB;IACpC,aAAa,eAAe,WAAW;IAC1B;IACP;IACG;GACV,CAAA;GACD,oBAAC,kBAAD,EAAA,UACE,oBAAC,WAAD;IACe;IACb,qBAAqB,cAAc;IACnC,SAAS,cAAc;GACxB,CAAA,EACe,CAAA;GAClB,oBAAC,YAAD,EAAyB,YAAc,CAAA;GACvC,oBAAC,SAAD;IAAwB;IAA4B;IAA0B;GAAc,CAAA;GAC5F,oBAAC,YAAD,EAAyB,YAAc,CAAA;GACvC,oBAACC,QAAD,EAAsB,YAAc,CAAA;GACpC,oBAAC,MAAD,EAAmB,YAAc,CAAA;GACjC,oBAAC,UAAD,EAAuB,YAAc,CAAA;GACrC,oBAAC,QAAD,EAAqB,YAAc,CAAA;GACnC,oBAAC,YAAD;IAAyB;IAAa,MAAM,cAAc;GAAc,CAAA;GACxE,oBAAC,YAAD;IAAyB;IAAa,MAAM,cAAc;GAAe,CAAA;EACpE;;AAEX"}
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export { DetailSidebar as default };
|
|
1
|
+
export { default } from "./Sidebar.mjs";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StageActions.js","names":[],"sources":["../../../src/sections/Stage/StageActions.tsx"],"sourcesContent":["import {\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogContentText,\n DialogTitle,\n Typography,\n} from '@mui/material';\nimport React, { useCallback, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\n\nimport type { StagePackageVersion } from './types';\nimport { approveStagedVersion, rejectStagedVersion } from './useStage';\n\ntype PendingAction = 'approve' | 'reject' | null;\n\ninterface Props {\n item: StagePackageVersion;\n /** Called after a successful approve/reject so the caller can refresh. */\n onDone: () => void;\n}\n\n/**\n * Approve / reject buttons with a confirmation step.\n *\n * Both actions are irreversible from the UI: approving publishes the version\n * for real, rejecting deletes the staged record and its tarball.\n */\nconst StageActions: React.FC<Props> = ({ item, onDone }) => {\n const { t } = useTranslation();\n const [pending, setPending] = useState<PendingAction>(null);\n const [isBusy, setIsBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const close = useCallback(() => {\n if (!isBusy) {\n setPending(null);\n setError(null);\n }\n }, [isBusy]);\n\n const confirm = useCallback(async () => {\n if (!pending) {\n return;\n }\n setIsBusy(true);\n setError(null);\n try {\n if (pending === 'approve') {\n await approveStagedVersion(item.id);\n } else {\n await rejectStagedVersion(item.id);\n }\n setPending(null);\n onDone();\n } catch (err: any) {\n // 409 here means the version got published by another route meanwhile,\n // and the staged item is deliberately kept so it can still be inspected\n setError(err?.message ?? t('stage.error.action'));\n } finally {\n setIsBusy(false);\n }\n }, [item.id, onDone, pending, t]);\n\n return (\n <>\n <Button\n color=\"primary\"\n data-testid={`stage-approve-${item.id}`}\n disabled={isBusy}\n onClick={() => setPending('approve')}\n size=\"small\"\n variant=\"outlined\"\n >\n {t('stage.action.approve')}\n </Button>\n <Button\n color=\"error\"\n data-testid={`stage-reject-${item.id}`}\n disabled={isBusy}\n onClick={() => setPending('reject')}\n size=\"small\"\n >\n {t('stage.action.reject')}\n </Button>\n\n <Dialog onClose={close} open={pending !== null}>\n <DialogTitle>\n {pending === 'approve' ? t('stage.confirm.approveTitle') : t('stage.confirm.rejectTitle')}\n </DialogTitle>\n <DialogContent>\n <DialogContentText>\n {pending === 'approve'\n ? t('stage.confirm.approveBody', {\n package: item.packageName,\n version: item.version,\n tag: item.tag,\n })\n : t('stage.confirm.rejectBody', {\n package: item.packageName,\n version: item.version,\n })}\n </DialogContentText>\n {error && (\n <Typography color=\"error\" marginTop={2} role=\"alert\">\n {error}\n </Typography>\n )}\n </DialogContent>\n <DialogActions>\n <Button disabled={isBusy} onClick={close}>\n {t('button.cancel')}\n </Button>\n <Button\n color={pending === 'approve' ? 'primary' : 'error'}\n data-testid=\"stage-confirm\"\n disabled={isBusy}\n onClick={confirm}\n variant=\"contained\"\n >\n {pending === 'approve' ? t('stage.action.approve') : t('stage.action.reject')}\n </Button>\n </DialogActions>\n </Dialog>\n </>\n );\n};\n\nexport default StageActions;\n"],"mappings":";;;;;;;;;;;;;;AA6BA,IAAM,gBAAiC,EAAE,MAAM,aAAa;CAC1D,MAAM,EAAE,OAAA,
|
|
1
|
+
{"version":3,"file":"StageActions.js","names":["useTranslation","useState","useCallback","approveStagedVersion","rejectStagedVersion","_Fragment","Button","Dialog","DialogTitle","DialogContent","DialogContentText","Typography","DialogActions"],"sources":["../../../src/sections/Stage/StageActions.tsx"],"sourcesContent":["import {\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogContentText,\n DialogTitle,\n Typography,\n} from '@mui/material';\nimport React, { useCallback, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\n\nimport type { StagePackageVersion } from './types';\nimport { approveStagedVersion, rejectStagedVersion } from './useStage';\n\ntype PendingAction = 'approve' | 'reject' | null;\n\ninterface Props {\n item: StagePackageVersion;\n /** Called after a successful approve/reject so the caller can refresh. */\n onDone: () => void;\n}\n\n/**\n * Approve / reject buttons with a confirmation step.\n *\n * Both actions are irreversible from the UI: approving publishes the version\n * for real, rejecting deletes the staged record and its tarball.\n */\nconst StageActions: React.FC<Props> = ({ item, onDone }) => {\n const { t } = useTranslation();\n const [pending, setPending] = useState<PendingAction>(null);\n const [isBusy, setIsBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const close = useCallback(() => {\n if (!isBusy) {\n setPending(null);\n setError(null);\n }\n }, [isBusy]);\n\n const confirm = useCallback(async () => {\n if (!pending) {\n return;\n }\n setIsBusy(true);\n setError(null);\n try {\n if (pending === 'approve') {\n await approveStagedVersion(item.id);\n } else {\n await rejectStagedVersion(item.id);\n }\n setPending(null);\n onDone();\n } catch (err: any) {\n // 409 here means the version got published by another route meanwhile,\n // and the staged item is deliberately kept so it can still be inspected\n setError(err?.message ?? t('stage.error.action'));\n } finally {\n setIsBusy(false);\n }\n }, [item.id, onDone, pending, t]);\n\n return (\n <>\n <Button\n color=\"primary\"\n data-testid={`stage-approve-${item.id}`}\n disabled={isBusy}\n onClick={() => setPending('approve')}\n size=\"small\"\n variant=\"outlined\"\n >\n {t('stage.action.approve')}\n </Button>\n <Button\n color=\"error\"\n data-testid={`stage-reject-${item.id}`}\n disabled={isBusy}\n onClick={() => setPending('reject')}\n size=\"small\"\n >\n {t('stage.action.reject')}\n </Button>\n\n <Dialog onClose={close} open={pending !== null}>\n <DialogTitle>\n {pending === 'approve' ? t('stage.confirm.approveTitle') : t('stage.confirm.rejectTitle')}\n </DialogTitle>\n <DialogContent>\n <DialogContentText>\n {pending === 'approve'\n ? t('stage.confirm.approveBody', {\n package: item.packageName,\n version: item.version,\n tag: item.tag,\n })\n : t('stage.confirm.rejectBody', {\n package: item.packageName,\n version: item.version,\n })}\n </DialogContentText>\n {error && (\n <Typography color=\"error\" marginTop={2} role=\"alert\">\n {error}\n </Typography>\n )}\n </DialogContent>\n <DialogActions>\n <Button disabled={isBusy} onClick={close}>\n {t('button.cancel')}\n </Button>\n <Button\n color={pending === 'approve' ? 'primary' : 'error'}\n data-testid=\"stage-confirm\"\n disabled={isBusy}\n onClick={confirm}\n variant=\"contained\"\n >\n {pending === 'approve' ? t('stage.action.approve') : t('stage.action.reject')}\n </Button>\n </DialogActions>\n </Dialog>\n </>\n );\n};\n\nexport default StageActions;\n"],"mappings":"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"}
|