@@ -14,6 +14,10 @@ import { Stack } from "../Stack/Stack"
14
14
import { ErrorAlert } from "components/Alert/ErrorAlert"
15
15
import { hasApiFieldErrors , isApiError } from "api/errors"
16
16
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"
20
+ import { Link as RouterLink } from "react-router-dom"
17
21
18
22
export const Language = {
19
23
emailLabel : "Email" ,
@@ -26,6 +30,38 @@ export const Language = {
26
30
cancel : "Cancel" ,
27
31
}
28
32
33
+ export const authMethodLanguage = {
34
+ password : {
35
+ displayName : "Password" ,
36
+ description : "Use an email address and password to login" ,
37
+ } ,
38
+ oidc : {
39
+ displayName : "OpenID Connect" ,
40
+ description : "Use an OpenID Connect provider for authentication" ,
41
+ } ,
42
+ github : {
43
+ displayName : "Github" ,
44
+ description : "Use Github OAuth for authentication" ,
45
+ } ,
46
+ none : {
47
+ displayName : "None" ,
48
+ description : (
49
+ < >
50
+ Disable authentication for this user (See the{ " " }
51
+ < Link
52
+ component = { RouterLink }
53
+ target = "_blank"
54
+ rel = "noopener"
55
+ to = "https://coder.com/docs/v2/latest/admin/auth#disable-built-in-authentication"
56
+ >
57
+ documentation
58
+ </ Link > { " " }
59
+ for more details)
60
+ </ >
61
+ ) ,
62
+ } ,
63
+ }
64
+
29
65
export interface CreateUserFormProps {
30
66
onSubmit : ( user : TypesGen . CreateUserRequest ) => void
31
67
onCancel : ( ) => void
@@ -46,22 +82,9 @@ const validationSchema = Yup.object({
46
82
otherwise : ( schema ) => schema ,
47
83
} ) ,
48
84
username : nameValidator ( Language . usernameLabel ) ,
85
+ login_type : Yup . string ( ) . oneOf ( Object . keys ( authMethodLanguage ) ) ,
49
86
} )
50
87
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
-
65
88
export const CreateUserForm : FC <
66
89
React . PropsWithChildren < CreateUserFormProps >
67
90
> = ( { onSubmit, onCancel, error, isLoading, myOrgId, authMethods } ) => {
@@ -73,7 +96,7 @@ export const CreateUserForm: FC<
73
96
username : "" ,
74
97
organization_id : myOrgId ,
75
98
disable_login : false ,
76
- login_type : "password " ,
99
+ login_type : "" ,
77
100
} ,
78
101
validationSchema,
79
102
onSubmit,
@@ -83,41 +106,34 @@ export const CreateUserForm: FC<
83
106
error ,
84
107
)
85
108
109
+ const styles = useStyles ( )
110
+ // This, unfortunately, cannot be an actual component because mui requires
111
+ // that all `MenuItem`s but be direct children of the `Select` the belong to
112
+ const authMethodSelect = ( value : keyof typeof authMethodLanguage ) => {
113
+ const language = authMethodLanguage [ value ]
114
+ return (
115
+ < MenuItem key = { value } id = { "item-" + value } value = { value } >
116
+ < Stack spacing = { 0 } maxWidth = { 400 } >
117
+ { language . displayName }
118
+ < span className = { styles . labelDescription } >
119
+ { language . description }
120
+ </ span >
121
+ </ Stack >
122
+ </ MenuItem >
123
+ )
124
+ }
125
+
86
126
const methods = [ ]
87
127
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
- )
128
+ methods . push ( authMethodSelect ( "password" ) )
95
129
}
96
130
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
- )
131
+ methods . push ( authMethodSelect ( "oidc" ) )
104
132
}
105
133
if ( authMethods ?. github . enabled ) {
106
- methods . push (
107
- authMethodSelect (
108
- "Github" ,
109
- "github" ,
110
- "Uses github oauth to authenticate the user." ,
111
- ) ,
112
- )
134
+ methods . push ( authMethodSelect ( "github" ) )
113
135
}
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
- )
136
+ methods . push ( authMethodSelect ( "none" ) )
121
137
122
138
return (
123
139
< FullPageForm title = "Create user" >
@@ -141,21 +157,6 @@ export const CreateUserForm: FC<
141
157
fullWidth
142
158
label = { Language . emailLabel }
143
159
/>
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
- />
159
160
< TextField
160
161
{ ...getFieldHelpers (
161
162
"login_type" ,
@@ -172,12 +173,41 @@ export const CreateUserForm: FC<
172
173
}
173
174
await form . setFieldValue ( "login_type" , e . target . value )
174
175
} }
176
+ SelectProps = { {
177
+ renderValue : ( selected : unknown ) =>
178
+ authMethodLanguage [ selected as keyof typeof authMethodLanguage ]
179
+ ?. displayName ?? "" ,
180
+ } }
175
181
>
176
182
{ methods }
177
183
</ TextField >
184
+ < TextField
185
+ { ...getFieldHelpers (
186
+ "password" ,
187
+ form . values . login_type === "password"
188
+ ? ""
189
+ : "No password required for this login type" ,
190
+ ) }
191
+ autoComplete = "current-password"
192
+ fullWidth
193
+ id = "password"
194
+ data-testid = "password-input"
195
+ disabled = { form . values . login_type !== "password" }
196
+ label = { Language . passwordLabel }
197
+ type = "password"
198
+ />
178
199
</ Stack >
179
200
< FormFooter onCancel = { onCancel } isLoading = { isLoading } />
180
201
</ form >
181
202
</ FullPageForm >
182
203
)
183
204
}
205
+
206
+ const useStyles = makeStyles < Theme > ( ( theme ) => ( {
207
+ labelDescription : {
208
+ fontSize : 14 ,
209
+ color : theme . palette . text . secondary ,
210
+ wordWrap : "normal" ,
211
+ whiteSpace : "break-spaces" ,
212
+ } ,
213
+ } ) )
0 commit comments