Skip to content

Commit 77f0fb2

Browse files
committed
PR Feedback and split up SignInForm.tsx
1 parent 77b230c commit 77f0fb2

File tree

10 files changed

+241
-178
lines changed

10 files changed

+241
-178
lines changed

cli/deployment/config.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -255,9 +255,10 @@ func newConfig() *codersdk.DeploymentConfig {
255255
Default: "preferred_username",
256256
},
257257
SignInText: &codersdk.DeploymentConfigField[string]{
258-
Name: "OpenID Connect sign in text",
259-
Usage: "The text to show on the OpenID Connect sign in button",
260-
Flag: "oidc-sign-in-text",
258+
Name: "OpenID Connect sign in text",
259+
Usage: "The text to show on the OpenID Connect sign in button",
260+
Flag: "oidc-sign-in-text",
261+
Default: "OpenID Connect",
261262
},
262263
IconURL: &codersdk.DeploymentConfigField[string]{
263264
Name: "OpenID connect icon URL",

coderd/userauth.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ func (api *API) userAuthMethods(rw http.ResponseWriter, r *http.Request) {
6464
httpapi.Write(r.Context(), rw, http.StatusOK, codersdk.AuthMethods{
6565
Password: codersdk.AuthMethod{Enabled: true},
6666
Github: codersdk.AuthMethod{Enabled: api.GithubOAuth2Config != nil},
67-
OIDC: codersdk.OIDCMethod{
67+
OIDC: codersdk.OIDCAuthMethod{
6868
AuthMethod: codersdk.AuthMethod{Enabled: api.OIDCConfig != nil},
6969
SignInText: signInText,
7070
IconURL: iconURL,

codersdk/users.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -107,16 +107,16 @@ type CreateOrganizationRequest struct {
107107

108108
// AuthMethods contains authentication method information like whether they are enabled or not or custom text, etc.
109109
type AuthMethods struct {
110-
Password AuthMethod `json:"password"`
111-
Github AuthMethod `json:"github"`
112-
OIDC OIDCMethod `json:"oidc"`
110+
Password AuthMethod `json:"password"`
111+
Github AuthMethod `json:"github"`
112+
OIDC OIDCAuthMethod `json:"oidc"`
113113
}
114114

115115
type AuthMethod struct {
116116
Enabled bool `json:"enabled"`
117117
}
118118

119-
type OIDCMethod struct {
119+
type OIDCAuthMethod struct {
120120
AuthMethod
121121
SignInText string `json:"signInText"`
122122
IconURL string `json:"iconUrl"`

site/src/api/typesGenerated.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ export interface AuthMethod {
9898
export interface AuthMethods {
9999
readonly password: AuthMethod
100100
readonly github: AuthMethod
101-
readonly oidc: OIDCMethod
101+
readonly oidc: OIDCAuthMethod
102102
}
103103

104104
// From codersdk/authorization.go
@@ -461,6 +461,12 @@ export interface OAuth2GithubConfig {
461461
readonly enterprise_base_url: DeploymentConfigField<string>
462462
}
463463

464+
// From codersdk/users.go
465+
export interface OIDCAuthMethod extends AuthMethod {
466+
readonly signInText: string
467+
readonly iconUrl: string
468+
}
469+
464470
// From codersdk/deploymentconfig.go
465471
export interface OIDCConfig {
466472
readonly allow_signups: DeploymentConfigField<boolean>
@@ -475,12 +481,6 @@ export interface OIDCConfig {
475481
readonly icon_url: DeploymentConfigField<string>
476482
}
477483

478-
// From codersdk/users.go
479-
export interface OIDCMethod extends AuthMethod {
480-
readonly signInText: string
481-
readonly iconUrl: string
482-
}
483-
484484
// From codersdk/organizations.go
485485
export interface Organization {
486486
readonly id: string
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import Link from "@material-ui/core/Link"
2+
import Button from "@material-ui/core/Button"
3+
import GitHubIcon from "@material-ui/icons/GitHub"
4+
import KeyIcon from "@material-ui/icons/VpnKey"
5+
import Box from "@material-ui/core/Box"
6+
import { Language } from "./SignInForm"
7+
import { AuthMethods } from "../../api/typesGenerated"
8+
import { FC } from "react"
9+
import { makeStyles } from "@material-ui/core/styles"
10+
11+
type OAuthSignInFormProps = {
12+
isLoading: boolean
13+
redirectTo: string
14+
authMethods?: AuthMethods
15+
}
16+
17+
const useStyles = makeStyles(() => ({
18+
buttonIcon: {
19+
width: 14,
20+
height: 14,
21+
},
22+
}))
23+
24+
export const OAuthSignInForm: FC<OAuthSignInFormProps> = ({
25+
isLoading,
26+
redirectTo,
27+
authMethods,
28+
}) => {
29+
const styles = useStyles()
30+
31+
return (
32+
<Box display="grid" gridGap="16px">
33+
{authMethods?.github.enabled && (
34+
<Link
35+
underline="none"
36+
href={`/api/v2/users/oauth2/github/callback?redirect=${encodeURIComponent(
37+
redirectTo,
38+
)}`}
39+
>
40+
<Button
41+
startIcon={<GitHubIcon className={styles.buttonIcon} />}
42+
disabled={isLoading}
43+
fullWidth
44+
type="submit"
45+
variant="contained"
46+
>
47+
{Language.githubSignIn}
48+
</Button>
49+
</Link>
50+
)}
51+
52+
{authMethods?.oidc.enabled && (
53+
<Link
54+
underline="none"
55+
href={`/api/v2/users/oidc/callback?redirect=${encodeURIComponent(
56+
redirectTo,
57+
)}`}
58+
>
59+
<Button
60+
startIcon={
61+
authMethods.oidc.iconUrl ? (
62+
<img
63+
alt="Open ID Connect icon"
64+
src={authMethods.oidc.iconUrl}
65+
width="24"
66+
height="24"
67+
/>
68+
) : (
69+
<KeyIcon className={styles.buttonIcon} />
70+
)
71+
}
72+
disabled={isLoading}
73+
fullWidth
74+
type="submit"
75+
variant="contained"
76+
>
77+
{authMethods.oidc.signInText || Language.oidcSignIn}
78+
</Button>
79+
</Link>
80+
)}
81+
</Box>
82+
)
83+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { Stack } from "../Stack/Stack"
2+
import { AlertBanner } from "../AlertBanner/AlertBanner"
3+
import TextField from "@material-ui/core/TextField"
4+
import { getFormHelpers, onChangeTrimmed } from "../../util/formUtils"
5+
import { LoadingButton } from "../LoadingButton/LoadingButton"
6+
import { Language, LoginErrors } from "./SignInForm"
7+
import { FormikContextType, FormikTouched, useFormik } from "formik"
8+
import * as Yup from "yup"
9+
import { FC } from "react"
10+
import { BuiltInAuthFormValues } from "./SignInForm.types"
11+
12+
type PasswordSignInFormProps = {
13+
loginErrors: Partial<Record<LoginErrors, Error | unknown>>
14+
onSubmit: (credentials: { email: string; password: string }) => void
15+
initialTouched?: FormikTouched<BuiltInAuthFormValues>
16+
isLoading: boolean
17+
}
18+
19+
export const PasswordSignInForm: FC<PasswordSignInFormProps> = ({
20+
loginErrors,
21+
onSubmit,
22+
initialTouched,
23+
isLoading,
24+
}) => {
25+
const validationSchema = Yup.object({
26+
email: Yup.string()
27+
.trim()
28+
.email(Language.emailInvalid)
29+
.required(Language.emailRequired),
30+
password: Yup.string(),
31+
})
32+
33+
const form: FormikContextType<BuiltInAuthFormValues> =
34+
useFormik<BuiltInAuthFormValues>({
35+
initialValues: {
36+
email: "",
37+
password: "",
38+
},
39+
validationSchema,
40+
// The email field has an autoFocus, but users may log in with a button click.
41+
// This is set to `false` in order to keep the autoFocus, validateOnChange
42+
// and Formik experience friendly. Validation will kick in onChange (any
43+
// field), or after a submission attempt.
44+
validateOnBlur: false,
45+
onSubmit,
46+
initialTouched,
47+
})
48+
const getFieldHelpers = getFormHelpers<BuiltInAuthFormValues>(
49+
form,
50+
loginErrors.authError,
51+
)
52+
53+
return (
54+
<form onSubmit={form.handleSubmit}>
55+
<Stack>
56+
{Object.keys(loginErrors).map(
57+
(errorKey: string) =>
58+
Boolean(loginErrors[errorKey as LoginErrors]) && (
59+
<AlertBanner
60+
key={errorKey}
61+
severity="error"
62+
error={loginErrors[errorKey as LoginErrors]}
63+
text={Language.errorMessages[errorKey as LoginErrors]}
64+
/>
65+
),
66+
)}
67+
<TextField
68+
{...getFieldHelpers("email")}
69+
onChange={onChangeTrimmed(form)}
70+
autoFocus
71+
autoComplete="email"
72+
fullWidth
73+
label={Language.emailLabel}
74+
type="email"
75+
variant="outlined"
76+
/>
77+
<TextField
78+
{...getFieldHelpers("password")}
79+
autoComplete="current-password"
80+
fullWidth
81+
id="password"
82+
label={Language.passwordLabel}
83+
type="password"
84+
variant="outlined"
85+
/>
86+
<div>
87+
<LoadingButton
88+
loading={isLoading}
89+
fullWidth
90+
type="submit"
91+
variant="contained"
92+
>
93+
{isLoading ? "" : Language.passwordSignIn}
94+
</LoadingButton>
95+
</div>
96+
</Stack>
97+
</form>
98+
)
99+
}

0 commit comments

Comments
 (0)