Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitca72c6a

Browse files
greyscaledkylecarbs
authored andcommitted
fix: CreateWorkspaceForm name validation (#1453)
* refactor: allow helperText in getFormHelpersBy passing in helperText, we will not accidentally overwrite it.* fix: CreateWorkspaceForm name validationResolves:#1421
1 parent9505202 commitca72c6a

File tree

3 files changed

+75
-17
lines changed

3 files changed

+75
-17
lines changed

‎site/src/forms/CreateWorkspaceForm.test.tsx

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import{render,screen}from"@testing-library/react"
22
importReactfrom"react"
3+
import{reach,StringSchema}from"yup"
34
import{MockOrganization,MockTemplate,MockWorkspace}from"../testHelpers/renderHelpers"
4-
import{CreateWorkspaceForm}from"./CreateWorkspaceForm"
5+
import{CreateWorkspaceForm,validationSchema}from"./CreateWorkspaceForm"
6+
7+
constnameSchema=reach(validationSchema,"name")asStringSchema
58

69
describe("CreateWorkspaceForm",()=>{
710
it("renders",async()=>{
@@ -24,4 +27,38 @@ describe("CreateWorkspaceForm", () => {
2427
constelement=awaitscreen.findByText("Create Workspace")
2528
expect(element).toBeDefined()
2629
})
30+
31+
describe("validationSchema",()=>{
32+
it("allows a 1-letter name",()=>{
33+
constvalidate=()=>nameSchema.validateSync("t")
34+
expect(validate).not.toThrow()
35+
})
36+
37+
it("allows a 32-letter name",()=>{
38+
constinput=Array(32).fill("a").join("")
39+
constvalidate=()=>nameSchema.validateSync(input)
40+
expect(validate).not.toThrow()
41+
})
42+
43+
it("allows 'test-3' to be used as name",()=>{
44+
constvalidate=()=>nameSchema.validateSync("test-3")
45+
expect(validate).not.toThrow()
46+
})
47+
48+
it("allows '3-test' to be used as a name",()=>{
49+
constvalidate=()=>nameSchema.validateSync("3-test")
50+
expect(validate).not.toThrow()
51+
})
52+
53+
it("disallows a 33-letter name",()=>{
54+
constinput=Array(33).fill("a").join("")
55+
constvalidate=()=>nameSchema.validateSync(input)
56+
expect(validate).toThrow()
57+
})
58+
59+
it("disallows a space",()=>{
60+
constvalidate=()=>nameSchema.validateSync("test 3")
61+
expect(validate).toThrow()
62+
})
63+
})
2764
})

‎site/src/forms/CreateWorkspaceForm.tsx

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,47 @@
11
importButtonfrom"@material-ui/core/Button"
22
import{makeStyles}from"@material-ui/core/styles"
3-
import{FormikContextType,useFormik}from"formik"
3+
importTextFieldfrom"@material-ui/core/TextField"
4+
import{useFormik}from"formik"
45
importReactfrom"react"
56
import*asYupfrom"yup"
67
import*asTypesGenfrom"../api/typesGenerated"
78
import{FormCloseButton}from"../components/FormCloseButton/FormCloseButton"
89
import{FormSection}from"../components/FormSection/FormSection"
9-
import{FormTextField}from"../components/FormTextField/FormTextField"
1010
import{FormTitle}from"../components/FormTitle/FormTitle"
1111
import{LoadingButton}from"../components/LoadingButton/LoadingButton"
1212
import{maxWidth}from"../theme/constants"
13+
import{getFormHelpers,onChangeTrimmed}from"../util/formUtils"
1314

15+
exportconstLanguage={
16+
nameHelperText:"A unique name describing your workspace",
17+
nameLabel:"Workspace Name",
18+
nameMatches:"Name must start with a-Z or 0-9 and can contain a-Z, 0-9 or -",
19+
nameMax:"Name cannot be longer than 32 characters",
20+
namePlaceholder:"my-workspace",
21+
nameRequired:"Name is required",
22+
}
1423
exportinterfaceCreateWorkspaceForm{
1524
template:TypesGen.Template
1625
onSubmit:(organizationId:string,request:TypesGen.CreateWorkspaceRequest)=>Promise<TypesGen.Workspace>
1726
onCancel:()=>void
1827
organizationId:string
1928
}
2029

21-
constvalidationSchema=Yup.object({
22-
name:Yup.string().required("Name is required"),
30+
exportinterfaceCreateWorkspaceFormValues{
31+
name:string
32+
}
33+
34+
// REMARK: Keep in sync with coderd/httpapi/httpapi.go#L40
35+
constmaxLenName=32
36+
37+
// REMARK: Keep in sync with coderd/httpapi/httpapi.go#L18
38+
constusernameRE=/^[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*$/
39+
40+
exportconstvalidationSchema=Yup.object({
41+
name:Yup.string()
42+
.matches(usernameRE,Language.nameMatches)
43+
.max(maxLenName,Language.nameMax)
44+
.required(Language.nameRequired),
2345
})
2446

2547
exportconstCreateWorkspaceForm:React.FC<CreateWorkspaceForm>=({
@@ -30,19 +52,19 @@ export const CreateWorkspaceForm: React.FC<CreateWorkspaceForm> = ({
3052
})=>{
3153
conststyles=useStyles()
3254

33-
constform:FormikContextType<{name:string}>=useFormik<{name:string}>({
55+
constform=useFormik<CreateWorkspaceFormValues>({
3456
initialValues:{
3557
name:"",
3658
},
37-
enableReinitialize:true,
38-
validationSchema:validationSchema,
3959
onSubmit:({ name})=>{
4060
returnonSubmit(organizationId,{
4161
template_id:template.id,
4262
name:name,
4363
})
4464
},
65+
validationSchema:validationSchema,
4566
})
67+
constgetFieldHelpers=getFormHelpers<CreateWorkspaceFormValues>(form)
4668

4769
return(
4870
<divclassName={styles.root}>
@@ -57,14 +79,13 @@ export const CreateWorkspaceForm: React.FC<CreateWorkspaceForm> = ({
5779
<FormCloseButtononClose={onCancel}/>
5880

5981
<FormSectiontitle="Name">
60-
<FormTextField
61-
form={form}
62-
formFieldName="name"
82+
<TextField
83+
{...getFieldHelpers("name",Language.nameHelperText)}
84+
onChange={onChangeTrimmed(form)}
85+
autoFocus
6386
fullWidth
64-
helperText="A unique name describing your workspace."
65-
label="Workspace Name"
66-
placeholder="my-workspace"
67-
required
87+
label={Language.nameLabel}
88+
placeholder={Language.namePlaceholder}
6889
/>
6990
</FormSection>
7091

‎site/src/util/formUtils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ interface FormHelpers {
1313

1414
exportconstgetFormHelpers=
1515
<T>(form:FormikContextType<T>,formErrors?:FormikErrors<T>)=>
16-
(name:keyofT):FormHelpers=>{
16+
(name:keyofT,helperText=""):FormHelpers=>{
1717
if(typeofname!=="string"){
1818
thrownewError(`name must be type of string, instead received '${typeofname}'`)
1919
}
@@ -28,7 +28,7 @@ export const getFormHelpers =
2828
...form.getFieldProps(name),
2929
id:name,
3030
error:touched&&Boolean(error),
31-
helperText:touched&&error,
31+
helperText:touched?error :helperText,
3232
}
3333
}
3434

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp