1
+ import Link from "@mui/material/Link" ;
1
2
import TextField from "@mui/material/TextField" ;
2
3
import { useFormik } from "formik" ;
3
4
import camelCase from "lodash/camelCase" ;
4
5
import capitalize from "lodash/capitalize" ;
5
6
import { useState , type FC } from "react" ;
7
+ import { useQuery } from "react-query" ;
6
8
import { useSearchParams } from "react-router-dom" ;
7
9
import * as Yup from "yup" ;
10
+ import { provisionerDaemons } from "api/queries/organizations" ;
8
11
import type {
9
12
Organization ,
10
13
ProvisionerJobLog ,
@@ -14,6 +17,7 @@ import type {
14
17
TemplateVersionVariable ,
15
18
VariableValue ,
16
19
} from "api/typesGenerated" ;
20
+ import { Alert } from "components/Alert/Alert" ;
17
21
import {
18
22
HorizontalForm ,
19
23
FormSection ,
@@ -23,6 +27,7 @@ import {
23
27
import { IconField } from "components/IconField/IconField" ;
24
28
import { OrganizationAutocomplete } from "components/OrganizationAutocomplete/OrganizationAutocomplete" ;
25
29
import { SelectedTemplate } from "pages/CreateWorkspacePage/SelectedTemplate" ;
30
+ import { docs } from "utils/docs" ;
26
31
import {
27
32
nameValidator ,
28
33
getFormHelpers ,
@@ -210,6 +215,24 @@ export const CreateTemplateForm: FC<CreateTemplateFormProps> = (props) => {
210
215
} ) ;
211
216
const getFieldHelpers = getFormHelpers < CreateTemplateFormData > ( form , error ) ;
212
217
218
+ const provisionerDaemonsQuery = useQuery (
219
+ selectedOrg
220
+ ? {
221
+ ...provisionerDaemons ( selectedOrg . id ) ,
222
+ enabled : showOrganizationPicker ,
223
+ select : ( provisioners ) => provisioners . length < 1 ,
224
+ }
225
+ : { enabled : false } ,
226
+ ) ;
227
+
228
+ // TODO: Ideally, we would have a backend endpoint that could notify the
229
+ // frontend that a provisioner has been connected, so that we could hide
230
+ // this warning. In the meantime, **do not use this variable to disable
231
+ // form submission**!! A user could easily see this warning, connect a
232
+ // provisioner, and then not refresh the page. Even if they submit without
233
+ // a provisioner, it'll just sit in the job queue until they connect one.
234
+ const showProvisionerWarning = provisionerDaemonsQuery . data ;
235
+
213
236
return (
214
237
< HorizontalForm onSubmit = { form . handleSubmit } >
215
238
{ /* General info */ }
@@ -232,17 +255,20 @@ export const CreateTemplateForm: FC<CreateTemplateFormProps> = (props) => {
232
255
) }
233
256
234
257
{ showOrganizationPicker && (
235
- < OrganizationAutocomplete
236
- { ...getFieldHelpers ( "organization" ) }
237
- required
238
- label = "Belongs to"
239
- value = { selectedOrg }
240
- onChange = { ( newValue ) => {
241
- setSelectedOrg ( newValue ) ;
242
- void form . setFieldValue ( "organization" , newValue ?. name || "" ) ;
243
- } }
244
- size = "medium"
245
- />
258
+ < >
259
+ { showProvisionerWarning && < ProvisionerWarning /> }
260
+ < OrganizationAutocomplete
261
+ { ...getFieldHelpers ( "organization" ) }
262
+ required
263
+ label = "Belongs to"
264
+ value = { selectedOrg }
265
+ onChange = { ( newValue ) => {
266
+ setSelectedOrg ( newValue ) ;
267
+ void form . setFieldValue ( "organization" , newValue ?. name || "" ) ;
268
+ } }
269
+ size = "medium"
270
+ />
271
+ </ >
246
272
) }
247
273
248
274
{ "copiedTemplate" in props && (
@@ -369,3 +395,15 @@ const fillNameAndDisplayWithFilename = async (
369
395
form . setFieldValue ( "display_name" , capitalize ( name ) ) ,
370
396
] ) ;
371
397
} ;
398
+
399
+ const ProvisionerWarning : FC = ( ) => {
400
+ return (
401
+ < Alert severity = "warning" css = { { marginBottom : 16 } } >
402
+ This organization does not have any provisioners. Before you create a
403
+ template, you'll need to configure a provisioner.{ " " }
404
+ < Link href = { docs ( "/admin/provisioners#organization-scoped-provisioners" ) } >
405
+ See our documentation.
406
+ </ Link >
407
+ </ Alert >
408
+ ) ;
409
+ } ;
0 commit comments