Skip to content

Commit 72cb42b

Browse files
authored
feat(site): add descriptions for each auth method to the selection menu (#9252)
1 parent b6aedb9 commit 72cb42b

File tree

1 file changed

+86
-66
lines changed

1 file changed

+86
-66
lines changed

site/src/components/CreateUserForm/CreateUserForm.tsx

Lines changed: 86 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ import { Stack } from "../Stack/Stack"
1414
import { ErrorAlert } from "components/Alert/ErrorAlert"
1515
import { hasApiFieldErrors, isApiError } from "api/errors"
1616
import MenuItem from "@mui/material/MenuItem"
17+
import { makeStyles } from "@mui/styles"
18+
import { Theme } from "@mui/material/styles"
19+
import Link from "@mui/material/Link"
1720

1821
export const Language = {
1922
emailLabel: "Email",
@@ -26,6 +29,37 @@ export const Language = {
2629
cancel: "Cancel",
2730
}
2831

32+
export const authMethodLanguage = {
33+
password: {
34+
displayName: "Password",
35+
description: "Use an email address and password to login",
36+
},
37+
oidc: {
38+
displayName: "OpenID Connect",
39+
description: "Use an OpenID Connect provider for authentication",
40+
},
41+
github: {
42+
displayName: "Github",
43+
description: "Use Github OAuth for authentication",
44+
},
45+
none: {
46+
displayName: "None",
47+
description: (
48+
<>
49+
Disable authentication for this user (See the{" "}
50+
<Link
51+
target="_blank"
52+
rel="noopener"
53+
href="https://coder.com/docs/v2/latest/admin/auth#disable-built-in-authentication"
54+
>
55+
documentation
56+
</Link>{" "}
57+
for more details)
58+
</>
59+
),
60+
},
61+
}
62+
2963
export interface CreateUserFormProps {
3064
onSubmit: (user: TypesGen.CreateUserRequest) => void
3165
onCancel: () => void
@@ -46,22 +80,9 @@ const validationSchema = Yup.object({
4680
otherwise: (schema) => schema,
4781
}),
4882
username: nameValidator(Language.usernameLabel),
83+
login_type: Yup.string().oneOf(Object.keys(authMethodLanguage)),
4984
})
5085

51-
const authMethodSelect = (
52-
title: string,
53-
value: string,
54-
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- future will use this
55-
description: string,
56-
) => {
57-
return (
58-
<MenuItem key="value" id={"item-" + value} value={value}>
59-
{title}
60-
{/* TODO: Add description */}
61-
</MenuItem>
62-
)
63-
}
64-
6586
export const CreateUserForm: FC<
6687
React.PropsWithChildren<CreateUserFormProps>
6788
> = ({ onSubmit, onCancel, error, isLoading, myOrgId, authMethods }) => {
@@ -73,7 +94,7 @@ export const CreateUserForm: FC<
7394
username: "",
7495
organization_id: myOrgId,
7596
disable_login: false,
76-
login_type: "password",
97+
login_type: "",
7798
},
7899
validationSchema,
79100
onSubmit,
@@ -83,41 +104,14 @@ export const CreateUserForm: FC<
83104
error,
84105
)
85106

86-
const methods = []
87-
if (authMethods?.password.enabled) {
88-
methods.push(
89-
authMethodSelect(
90-
"Password",
91-
"password",
92-
"User can provide their email and password to login.",
93-
),
94-
)
95-
}
96-
if (authMethods?.oidc.enabled) {
97-
methods.push(
98-
authMethodSelect(
99-
"OpenID Connect",
100-
"oidc",
101-
"Uses an OpenID connect provider to authenticate the user.",
102-
),
103-
)
104-
}
105-
if (authMethods?.github.enabled) {
106-
methods.push(
107-
authMethodSelect(
108-
"Github",
109-
"github",
110-
"Uses github oauth to authenticate the user.",
111-
),
112-
)
113-
}
114-
methods.push(
115-
authMethodSelect(
116-
"None",
117-
"none",
118-
"User authentication is disabled. This user an only be used if an api token is created for them.",
119-
),
120-
)
107+
const styles = useStyles()
108+
109+
const methods = [
110+
authMethods?.password.enabled && "password",
111+
authMethods?.oidc.enabled && "oidc",
112+
authMethods?.github.enabled && "github",
113+
"none",
114+
].filter(Boolean) as Array<keyof typeof authMethodLanguage>
121115

122116
return (
123117
<FullPageForm title="Create user">
@@ -141,21 +135,6 @@ export const CreateUserForm: FC<
141135
fullWidth
142136
label={Language.emailLabel}
143137
/>
144-
<TextField
145-
{...getFieldHelpers(
146-
"password",
147-
form.values.login_type === "password"
148-
? ""
149-
: "No password required for this login type",
150-
)}
151-
autoComplete="current-password"
152-
fullWidth
153-
id="password"
154-
data-testid="password-input"
155-
disabled={form.values.login_type !== "password"}
156-
label={Language.passwordLabel}
157-
type="password"
158-
/>
159138
<TextField
160139
{...getFieldHelpers(
161140
"login_type",
@@ -172,12 +151,53 @@ export const CreateUserForm: FC<
172151
}
173152
await form.setFieldValue("login_type", e.target.value)
174153
}}
154+
SelectProps={{
155+
renderValue: (selected: unknown) =>
156+
authMethodLanguage[selected as keyof typeof authMethodLanguage]
157+
?.displayName ?? "",
158+
}}
175159
>
176-
{methods}
160+
{methods.map((value) => {
161+
const language = authMethodLanguage[value]
162+
return (
163+
<MenuItem key={value} id={"item-" + value} value={value}>
164+
<Stack spacing={0} maxWidth={400}>
165+
{language.displayName}
166+
<span className={styles.labelDescription}>
167+
{language.description}
168+
</span>
169+
</Stack>
170+
</MenuItem>
171+
)
172+
})}
177173
</TextField>
174+
<TextField
175+
{...getFieldHelpers(
176+
"password",
177+
form.values.login_type === "password"
178+
? ""
179+
: "No password required for this login type",
180+
)}
181+
autoComplete="current-password"
182+
fullWidth
183+
id="password"
184+
data-testid="password-input"
185+
disabled={form.values.login_type !== "password"}
186+
label={Language.passwordLabel}
187+
type="password"
188+
/>
178189
</Stack>
179190
<FormFooter onCancel={onCancel} isLoading={isLoading} />
180191
</form>
181192
</FullPageForm>
182193
)
183194
}
195+
196+
const useStyles = makeStyles<Theme>((theme) => ({
197+
labelDescription: {
198+
fontSize: 14,
199+
color: theme.palette.text.secondary,
200+
wordWrap: "normal",
201+
whiteSpace: "break-spaces",
202+
},
203+
}))

0 commit comments

Comments
 (0)