mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix: handle more auth API errors (#3241)
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { Story } from "@storybook/react"
|
||||
import { SignInForm, SignInFormProps } from "./SignInForm"
|
||||
import { makeMockApiError } from "testHelpers/entities"
|
||||
import { LoginErrors, SignInForm, SignInFormProps } from "./SignInForm"
|
||||
|
||||
export default {
|
||||
title: "components/SignInForm",
|
||||
@@ -15,7 +16,7 @@ const Template: Story<SignInFormProps> = (args: SignInFormProps) => <SignInForm
|
||||
export const SignedOut = Template.bind({})
|
||||
SignedOut.args = {
|
||||
isLoading: false,
|
||||
authError: undefined,
|
||||
loginErrors: {},
|
||||
onSubmit: () => {
|
||||
return Promise.resolve()
|
||||
},
|
||||
@@ -34,29 +35,39 @@ Loading.args = {
|
||||
export const WithLoginError = Template.bind({})
|
||||
WithLoginError.args = {
|
||||
...SignedOut.args,
|
||||
authError: {
|
||||
response: {
|
||||
data: {
|
||||
message: "Email or password was invalid",
|
||||
validations: [
|
||||
{
|
||||
field: "password",
|
||||
detail: "Password is invalid.",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
isAxiosError: true,
|
||||
loginErrors: {
|
||||
[LoginErrors.AUTH_ERROR]: makeMockApiError({
|
||||
message: "Email or password was invalid",
|
||||
validations: [
|
||||
{
|
||||
field: "password",
|
||||
detail: "Password is invalid.",
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
initialTouched: {
|
||||
password: true,
|
||||
},
|
||||
}
|
||||
|
||||
export const WithCheckPermissionsError = Template.bind({})
|
||||
WithCheckPermissionsError.args = {
|
||||
...SignedOut.args,
|
||||
loginErrors: {
|
||||
[LoginErrors.CHECK_PERMISSIONS_ERROR]: makeMockApiError({
|
||||
message: "Unable to fetch user permissions",
|
||||
detail: "Resource not found or you do not have access to this resource.",
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
export const WithAuthMethodsError = Template.bind({})
|
||||
WithAuthMethodsError.args = {
|
||||
...SignedOut.args,
|
||||
methodsError: new Error("Failed to fetch auth methods"),
|
||||
loginErrors: {
|
||||
[LoginErrors.GET_METHODS_ERROR]: new Error("Failed to fetch auth methods"),
|
||||
},
|
||||
}
|
||||
|
||||
export const WithGithub = Template.bind({})
|
||||
|
||||
@@ -23,13 +23,22 @@ interface BuiltInAuthFormValues {
|
||||
password: string
|
||||
}
|
||||
|
||||
export enum LoginErrors {
|
||||
AUTH_ERROR = "authError",
|
||||
CHECK_PERMISSIONS_ERROR = "checkPermissionsError",
|
||||
GET_METHODS_ERROR = "getMethodsError",
|
||||
}
|
||||
|
||||
export const Language = {
|
||||
emailLabel: "Email",
|
||||
passwordLabel: "Password",
|
||||
emailInvalid: "Please enter a valid email address.",
|
||||
emailRequired: "Please enter an email address.",
|
||||
authErrorMessage: "Incorrect email or password.",
|
||||
methodsErrorMessage: "Unable to fetch auth methods.",
|
||||
errorMessages: {
|
||||
[LoginErrors.AUTH_ERROR]: "Incorrect email or password.",
|
||||
[LoginErrors.CHECK_PERMISSIONS_ERROR]: "Unable to fetch user permissions.",
|
||||
[LoginErrors.GET_METHODS_ERROR]: "Unable to fetch auth methods.",
|
||||
},
|
||||
passwordSignIn: "Sign In",
|
||||
githubSignIn: "GitHub",
|
||||
}
|
||||
@@ -68,8 +77,7 @@ const useStyles = makeStyles((theme) => ({
|
||||
export interface SignInFormProps {
|
||||
isLoading: boolean
|
||||
redirectTo: string
|
||||
authError?: Error | unknown
|
||||
methodsError?: Error | unknown
|
||||
loginErrors: Partial<Record<LoginErrors, Error | unknown>>
|
||||
authMethods?: AuthMethods
|
||||
onSubmit: ({ email, password }: { email: string; password: string }) => Promise<void>
|
||||
// initialTouched is only used for testing the error state of the form.
|
||||
@@ -80,8 +88,7 @@ export const SignInForm: FC<SignInFormProps> = ({
|
||||
authMethods,
|
||||
redirectTo,
|
||||
isLoading,
|
||||
authError,
|
||||
methodsError,
|
||||
loginErrors,
|
||||
onSubmit,
|
||||
initialTouched,
|
||||
}) => {
|
||||
@@ -101,18 +108,24 @@ export const SignInForm: FC<SignInFormProps> = ({
|
||||
onSubmit,
|
||||
initialTouched,
|
||||
})
|
||||
const getFieldHelpers = getFormHelpersWithError<BuiltInAuthFormValues>(form, authError)
|
||||
const getFieldHelpers = getFormHelpersWithError<BuiltInAuthFormValues>(
|
||||
form,
|
||||
loginErrors.authError,
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
<Welcome />
|
||||
<form onSubmit={form.handleSubmit}>
|
||||
<Stack>
|
||||
{authError && (
|
||||
<ErrorSummary error={authError} defaultMessage={Language.authErrorMessage} />
|
||||
)}
|
||||
{methodsError && (
|
||||
<ErrorSummary error={methodsError} defaultMessage={Language.methodsErrorMessage} />
|
||||
{Object.keys(loginErrors).map((errorKey: string) =>
|
||||
loginErrors[errorKey as LoginErrors] ? (
|
||||
<ErrorSummary
|
||||
key={errorKey}
|
||||
error={loginErrors[errorKey as LoginErrors]}
|
||||
defaultMessage={Language.errorMessages[errorKey as LoginErrors]}
|
||||
/>
|
||||
) : null,
|
||||
)}
|
||||
<TextField
|
||||
{...getFieldHelpers("email")}
|
||||
|
||||
Reference in New Issue
Block a user