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

Commit6ef3f8a

Browse files
BrunoQuaresmakylecarbs
authored andcommitted
refactor: Update create workspace flow to allow creation from the workspaces page (#1684)
1 parentaaf08d5 commit6ef3f8a

File tree

11 files changed

+366
-260
lines changed

11 files changed

+366
-260
lines changed

‎.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@
1515
"drpcserver",
1616
"Dsts",
1717
"fatih",
18+
"Formik",
1819
"goarch",
1920
"gographviz",
2021
"goleak",
2122
"gossh",
2223
"gsyslog",
2324
"hashicorp",
2425
"hclsyntax",
26+
"httpapi",
2527
"httpmw",
2628
"idtoken",
2729
"Iflag",
@@ -63,6 +65,7 @@
6365
"tfjson",
6466
"tfstate",
6567
"trimprefix",
68+
"typegen",
6669
"unconvert",
6770
"Untar",
6871
"VMID",

‎site/src/AppRouter.tsx

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,16 @@ export const AppRouter: React.FC = () => (
5656
</AuthAndFrame>
5757
}
5858
/>
59+
60+
<Route
61+
path="new"
62+
element={
63+
<RequireAuth>
64+
<CreateWorkspacePage/>
65+
</RequireAuth>
66+
}
67+
/>
68+
5969
<Routepath=":workspace">
6070
<Route
6171
index
@@ -85,17 +95,6 @@ export const AppRouter: React.FC = () => (
8595
</AuthAndFrame>
8696
}
8797
/>
88-
89-
<Routepath=":template">
90-
<Route
91-
path="new"
92-
element={
93-
<RequireAuth>
94-
<CreateWorkspacePage/>
95-
</RequireAuth>
96-
}
97-
/>
98-
</Route>
9998
</Route>
10099

101100
<Routepath="users">

‎site/src/components/FormFooter/FormFooter.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export const FormFooter: React.FC<FormFooterProps> = ({
3535
conststyles=useStyles()
3636
return(
3737
<divclassName={styles.footer}>
38-
<ButtonclassName={styles.button}onClick={onCancel}variant="outlined">
38+
<Buttontype="button"className={styles.button}onClick={onCancel}variant="outlined">
3939
{Language.cancelLabel}
4040
</Button>
4141
<LoadingButtonloading={isLoading}className={styles.button}variant="contained"color="primary"type="submit">

‎site/src/pages/CreateWorkspacePage/CreateWorkspacePage.test.tsx

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,17 @@ import { reach, StringSchema } from "yup"
55
import*asAPIfrom"../../api/api"
66
import{LanguageasFooterLanguage}from"../../components/FormFooter/FormFooter"
77
import{MockTemplate,MockWorkspace}from"../../testHelpers/entities"
8-
import{history,render}from"../../testHelpers/renderHelpers"
8+
import{renderWithAuth}from"../../testHelpers/renderHelpers"
99
importCreateWorkspacePagefrom"./CreateWorkspacePage"
1010
import{Language,validationSchema}from"./CreateWorkspacePageView"
1111

12+
constrenderCreateWorkspacePage=()=>{
13+
returnrenderWithAuth(<CreateWorkspacePage/>,{
14+
route:"/workspaces/new?template="+MockTemplate.name,
15+
path:"/workspaces/new",
16+
})
17+
}
18+
1219
constfillForm=async({ name="example"}:{name?:string})=>{
1320
constnameField=awaitscreen.findByLabelText(Language.nameLabel)
1421
awaituserEvent.type(nameField,name)
@@ -19,25 +26,21 @@ const fillForm = async ({ name = "example" }: { name?: string }) => {
1926
constnameSchema=reach(validationSchema,"name")asStringSchema
2027

2128
describe("CreateWorkspacePage",()=>{
22-
beforeEach(()=>{
23-
history.replace("/templates/"+MockTemplate.name+"/new")
24-
})
25-
2629
it("renders",async()=>{
27-
render(<CreateWorkspacePage/>)
30+
renderCreateWorkspacePage()
2831
constelement=awaitscreen.findByText("Create workspace")
2932
expect(element).toBeDefined()
3033
})
3134

3235
it("shows validation error message",async()=>{
33-
render(<CreateWorkspacePage/>)
36+
renderCreateWorkspacePage()
3437
awaitfillForm({name:"$$$"})
3538
consterrorMessage=awaitscreen.findByText(Language.nameMatches)
3639
expect(errorMessage).toBeDefined()
3740
})
3841

3942
it("succeeds",async()=>{
40-
render(<CreateWorkspacePage/>)
43+
renderCreateWorkspacePage()
4144
// You have to spy the method before it is used.
4245
jest.spyOn(API,"createWorkspace").mockResolvedValueOnce(MockWorkspace)
4346
awaitfillForm({name:"test"})

‎site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,59 @@
1-
import{useMachine}from"@xstate/react"
2-
importReactfrom"react"
3-
import{useNavigate}from"react-router"
4-
import{useParams}from"react-router-dom"
5-
import{createWorkspace}from"../../api/api"
6-
import{templateMachine}from"../../xServices/template/templateXService"
1+
import{useActor,useMachine}from"@xstate/react"
2+
importReact,{useContext}from"react"
3+
import{useNavigate,useSearchParams}from"react-router-dom"
4+
import{Template}from"../../api/typesGenerated"
5+
import{createWorkspaceMachine}from"../../xServices/createWorkspace/createWorkspaceXService"
6+
import{XServiceContext}from"../../xServices/StateContext"
77
import{CreateWorkspacePageView}from"./CreateWorkspacePageView"
88

9+
constuseOrganizationId=()=>{
10+
constxServices=useContext(XServiceContext)
11+
const[authState]=useActor(xServices.authXService)
12+
constorganizationId=authState.context.me?.organization_ids[0]
13+
14+
if(!organizationId){
15+
thrownewError("No organization ID found")
16+
}
17+
18+
returnorganizationId
19+
}
20+
921
constCreateWorkspacePage:React.FC=()=>{
10-
const{ template}=useParams()
11-
const[templateState]=useMachine(templateMachine,{
12-
context:{
13-
name:template,
22+
constorganizationId=useOrganizationId()
23+
const[searchParams]=useSearchParams()
24+
constpreSelectedTemplateName=searchParams.get("template")
25+
constnavigate=useNavigate()
26+
const[createWorkspaceState,send]=useMachine(createWorkspaceMachine,{
27+
context:{ organizationId, preSelectedTemplateName},
28+
actions:{
29+
onCreateWorkspace:(_,event)=>{
30+
navigate("/workspaces/"+event.data.id)
31+
},
1432
},
1533
})
16-
constnavigate=useNavigate()
17-
constloading=templateState.hasTag("loading")
18-
if(!templateState.context.template||!templateState.context.templateSchema){
19-
returnnull
20-
}
2134

2235
return(
2336
<CreateWorkspacePageView
24-
template={templateState.context.template}
25-
templateSchema={templateState.context.templateSchema}
26-
loading={loading}
27-
onCancel={()=>navigate("/templates")}
28-
onSubmit={async(req)=>{
29-
if(!templateState.context.template){
30-
thrownewError("template isn't valid")
31-
}
32-
constworkspace=awaitcreateWorkspace(templateState.context.template.organization_id,req)
33-
navigate("/workspaces/"+workspace.id)
37+
loadingTemplates={createWorkspaceState.matches("gettingTemplates")}
38+
loadingTemplateSchema={createWorkspaceState.matches("gettingTemplateSchema")}
39+
creatingWorkspace={createWorkspaceState.matches("creatingWorkspace")}
40+
templates={createWorkspaceState.context.templates}
41+
selectedTemplate={createWorkspaceState.context.selectedTemplate}
42+
templateSchema={createWorkspaceState.context.templateSchema}
43+
onCancel={()=>{
44+
navigate(preSelectedTemplateName ?"/templates" :"/workspaces")
45+
}}
46+
onSubmit={(request)=>{
47+
send({
48+
type:"CREATE_WORKSPACE",
49+
request,
50+
})
51+
}}
52+
onSelectTemplate={(template:Template)=>{
53+
send({
54+
type:"SELECT_TEMPLATE",
55+
template,
56+
})
3457
}}
3558
/>
3659
)

‎site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,32 @@
11
import{ComponentMeta,Story}from"@storybook/react"
22
importReactfrom"react"
3-
import{createParameterSchema}from"../../components/ParameterInput/ParameterInput.stories"
3+
import{ParameterSchema}from"../../api/typesGenerated"
44
import{MockTemplate}from"../../testHelpers/entities"
55
import{CreateWorkspacePageView,CreateWorkspacePageViewProps}from"./CreateWorkspacePageView"
66

7+
constcreateParameterSchema=(partial:Partial<ParameterSchema>):ParameterSchema=>{
8+
return{
9+
id:"000000",
10+
job_id:"000000",
11+
allow_override_destination:false,
12+
allow_override_source:true,
13+
created_at:"",
14+
default_destination_scheme:"none",
15+
default_refresh:"",
16+
default_source_scheme:"data",
17+
default_source_value:"default-value",
18+
name:"parameter name",
19+
description:"Some description!",
20+
redisplay_value:false,
21+
validation_condition:"",
22+
validation_contains:[],
23+
validation_error:"",
24+
validation_type_system:"",
25+
validation_value_type:"",
26+
...partial,
27+
}
28+
}
29+
730
exportdefault{
831
title:"pages/CreateWorkspacePageView",
932
component:CreateWorkspacePageView,
@@ -13,13 +36,15 @@ const Template: Story<CreateWorkspacePageViewProps> = (args) => <CreateWorkspace
1336

1437
exportconstNoParameters=Template.bind({})
1538
NoParameters.args={
16-
template:MockTemplate,
39+
templates:[MockTemplate],
40+
selectedTemplate:MockTemplate,
1741
templateSchema:[],
1842
}
1943

2044
exportconstParameters=Template.bind({})
2145
Parameters.args={
22-
template:MockTemplate,
46+
templates:[MockTemplate],
47+
selectedTemplate:MockTemplate,
2348
templateSchema:[
2449
createParameterSchema({
2550
name:"region",

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp