Skip to content

Commit 6b75f3e

Browse files
committed
Add error validation for submitting the create workspace form
1 parent e418892 commit 6b75f3e

File tree

2 files changed

+57
-35
lines changed

2 files changed

+57
-35
lines changed

site/src/components/GitAuth/GitAuth.tsx

Lines changed: 35 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import Button from "@material-ui/core/Button"
2-
import { makeStyles } from "@material-ui/core/styles"
2+
import FormHelperText from "@material-ui/core/FormHelperText"
3+
import { makeStyles, Theme } from "@material-ui/core/styles"
34
import { SvgIconProps } from "@material-ui/core/SvgIcon"
45
import Tooltip from "@material-ui/core/Tooltip"
56
import GitHub from "@material-ui/icons/GitHub"
@@ -14,14 +15,18 @@ export interface GitAuthProps {
1415
type: TypesGen.GitProvider
1516
authenticated: boolean
1617
authenticateURL: string
18+
error?: string
1719
}
1820

1921
export const GitAuth: FC<GitAuthProps> = ({
2022
type,
2123
authenticated,
2224
authenticateURL,
25+
error,
2326
}) => {
24-
const styles = useStyles()
27+
const styles = useStyles({
28+
error: typeof error !== "undefined",
29+
})
2530

2631
let prettyName: string
2732
let Icon: (props: SvgIconProps) => JSX.Element
@@ -57,41 +62,42 @@ export const GitAuth: FC<GitAuthProps> = ({
5762
authenticated ? "You're already authenticated! No action needed." : ``
5863
}
5964
>
60-
<a
61-
href={redirectURL}
62-
className={styles.link}
63-
onClick={(event) => {
64-
event.preventDefault()
65-
// If the user is already authenticated, we don't want to redirect them
66-
if (authenticated || authenticateURL === "") {
67-
return
68-
}
69-
window.open(redirectURL, "_blank", "width=900,height=600")
70-
}}
71-
>
72-
<Button className={styles.button} disabled={authenticated} fullWidth>
73-
<div className={styles.root}>
74-
<Icon className={styles.icon} />
75-
<div className={styles.text}>
65+
<div>
66+
<a
67+
href={redirectURL}
68+
className={styles.link}
69+
onClick={(event) => {
70+
event.preventDefault()
71+
// If the user is already authenticated, we don't want to redirect them
72+
if (authenticated || authenticateURL === "") {
73+
return
74+
}
75+
window.open(redirectURL, "_blank", "width=900,height=600")
76+
}}
77+
>
78+
<Button className={styles.button} disabled={authenticated} fullWidth>
79+
<div className={styles.root}>
80+
<Icon className={styles.icon} />
7681
<Typography variant="body2">
7782
{authenticated
7883
? `You're authenticated with ${prettyName}!`
7984
: `Click to login with ${prettyName}!`}
8085
</Typography>
81-
{!authenticated && (
82-
<Typography variant="caption" color="textSecondary">
83-
{"You'll be redirected back here once authenticated."}
84-
</Typography>
85-
)}
8686
</div>
87-
</div>
88-
</Button>
89-
</a>
87+
</Button>
88+
</a>
89+
{error && <FormHelperText error>{error}</FormHelperText>}
90+
</div>
9091
</Tooltip>
9192
)
9293
}
9394

94-
const useStyles = makeStyles(() => ({
95+
const useStyles = makeStyles<
96+
Theme,
97+
{
98+
error: boolean
99+
}
100+
>((theme) => ({
95101
link: {
96102
textDecoration: "none",
97103
},
@@ -104,11 +110,8 @@ const useStyles = makeStyles(() => ({
104110
},
105111
button: {
106112
height: "unset",
107-
},
108-
text: {
109-
display: "flex",
110-
flexDirection: "column",
111-
gap: 4,
113+
border: ({ error }) =>
114+
error ? `1px solid ${theme.palette.error.main}` : "unset",
112115
},
113116
icon: {
114117
width: 32,

site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { RichParameterInput } from "components/RichParameterInput/RichParameterI
66
import { Stack } from "components/Stack/Stack"
77
import { UserAutocomplete } from "components/UserAutocomplete/UserAutocomplete"
88
import { FormikContextType, FormikTouched, useFormik } from "formik"
9-
import { FC, useState } from "react"
9+
import { FC, useEffect, useState } from "react"
1010
import { useTranslation } from "react-i18next"
1111
import { getFormHelpers, nameValidator, onChangeTrimmed } from "util/formUtils"
1212
import * as Yup from "yup"
@@ -58,6 +58,10 @@ export const CreateWorkspacePageView: FC<
5858
props.templateParameters,
5959
props.defaultParameterValues,
6060
)
61+
const [gitAuthErrors, setGitAuthErrors] = useState<Record<string, string>>({})
62+
useEffect(() => {
63+
setGitAuthErrors({})
64+
}, [props.templateGitAuth])
6165

6266
const { t } = useTranslation("createWorkspacePage")
6367

@@ -78,6 +82,20 @@ export const CreateWorkspacePageView: FC<
7882
enableReinitialize: true,
7983
initialTouched: props.initialTouched,
8084
onSubmit: (request) => {
85+
for (let i = 0; i < (props.templateGitAuth?.length || 0); i++) {
86+
const auth = props.templateGitAuth?.[i]
87+
if (!auth) {
88+
continue
89+
}
90+
if (!auth.authenticated) {
91+
setGitAuthErrors({
92+
[auth.id]: "You must authenticate to create a workspace!",
93+
})
94+
form.setSubmitting(false)
95+
return
96+
}
97+
}
98+
8199
if (!props.templateSchema) {
82100
throw new Error("No template schema loaded")
83101
}
@@ -231,8 +249,8 @@ export const CreateWorkspacePageView: FC<
231249
Git Authentication
232250
</h2>
233251
<p className={styles.formSectionInfoDescription}>
234-
This template requires authentication to automatically
235-
perform Git operations on create.
252+
This template requires authentication to automatically perform
253+
Git operations on create.
236254
</p>
237255
</div>
238256

@@ -247,6 +265,7 @@ export const CreateWorkspacePageView: FC<
247265
authenticateURL={auth.authenticate_url}
248266
authenticated={auth.authenticated}
249267
type={auth.type}
268+
error={gitAuthErrors[auth.id]}
250269
/>
251270
))}
252271
</Stack>

0 commit comments

Comments
 (0)