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

Commit3cf235c

Browse files
feat(site): Ask for parameter values when updating a workspace (#6586)
1 parentf91b3ac commit3cf235c

File tree

15 files changed

+689
-278
lines changed

15 files changed

+689
-278
lines changed

‎site/src/api/api.test.ts

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
importaxiosfrom"axios"
2-
import{getApiKey,getURLWithSearchParams,login,logout}from"./api"
2+
import{
3+
MockTemplate,
4+
MockTemplateVersionParameter1,
5+
MockWorkspace,
6+
MockWorkspaceBuild,
7+
}from"testHelpers/entities"
8+
import*asapifrom"./api"
39
import*asTypesGenfrom"./typesGenerated"
410

511
describe("api.ts",()=>{
@@ -12,7 +18,7 @@ describe("api.ts", () => {
1218
jest.spyOn(axios,"post").mockResolvedValueOnce({data:loginResponse})
1319

1420
// when
15-
constresult=awaitlogin("test","123")
21+
constresult=awaitapi.login("test","123")
1622

1723
// then
1824
expect(axios.post).toHaveBeenCalled()
@@ -33,7 +39,7 @@ describe("api.ts", () => {
3339
axios.post=axiosMockPost
3440

3541
try{
36-
awaitlogin("test","123")
42+
awaitapi.login("test","123")
3743
}catch(error){
3844
expect(error).toStrictEqual(expectedError)
3945
}
@@ -49,7 +55,7 @@ describe("api.ts", () => {
4955
axios.post=axiosMockPost
5056

5157
// when
52-
awaitlogout()
58+
awaitapi.logout()
5359

5460
// then
5561
expect(axiosMockPost).toHaveBeenCalled()
@@ -68,7 +74,7 @@ describe("api.ts", () => {
6874
axios.post=axiosMockPost
6975

7076
try{
71-
awaitlogout()
77+
awaitapi.logout()
7278
}catch(error){
7379
expect(error).toStrictEqual(expectedError)
7480
}
@@ -87,7 +93,7 @@ describe("api.ts", () => {
8793
axios.post=axiosMockPost
8894

8995
// when
90-
constresult=awaitgetApiKey()
96+
constresult=awaitapi.getApiKey()
9197

9298
// then
9399
expect(axiosMockPost).toHaveBeenCalled()
@@ -107,7 +113,7 @@ describe("api.ts", () => {
107113
axios.post=axiosMockPost
108114

109115
try{
110-
awaitgetApiKey()
116+
awaitapi.getApiKey()
111117
}catch(error){
112118
expect(error).toStrictEqual(expectedError)
113119
}
@@ -133,7 +139,7 @@ describe("api.ts", () => {
133139
])(
134140
`Workspaces - getURLWithSearchParams(%p, %p) returns %p`,
135141
(basePath,filter,expected)=>{
136-
expect(getURLWithSearchParams(basePath,filter)).toBe(expected)
142+
expect(api.getURLWithSearchParams(basePath,filter)).toBe(expected)
137143
},
138144
)
139145
})
@@ -150,8 +156,38 @@ describe("api.ts", () => {
150156
])(
151157
`Users - getURLWithSearchParams(%p, %p) returns %p`,
152158
(basePath,filter,expected)=>{
153-
expect(getURLWithSearchParams(basePath,filter)).toBe(expected)
159+
expect(api.getURLWithSearchParams(basePath,filter)).toBe(expected)
154160
},
155161
)
156162
})
163+
164+
describe("update",()=>{
165+
it("creates a build with start and the latest template",async()=>{
166+
jest
167+
.spyOn(api,"postWorkspaceBuild")
168+
.mockResolvedValueOnce(MockWorkspaceBuild)
169+
jest.spyOn(api,"getTemplate").mockResolvedValueOnce(MockTemplate)
170+
awaitapi.updateWorkspace(MockWorkspace)
171+
expect(api.postWorkspaceBuild).toHaveBeenCalledWith(MockWorkspace.id,{
172+
transition:"start",
173+
template_version_id:MockTemplate.active_version_id,
174+
rich_parameter_values:[],
175+
})
176+
})
177+
178+
it("fails when having missing parameters",async()=>{
179+
jest
180+
.spyOn(api,"postWorkspaceBuild")
181+
.mockResolvedValueOnce(MockWorkspaceBuild)
182+
jest.spyOn(api,"getTemplate").mockResolvedValueOnce(MockTemplate)
183+
jest.spyOn(api,"getWorkspaceBuildParameters").mockResolvedValueOnce([])
184+
jest
185+
.spyOn(api,"getTemplateVersionRichParameters")
186+
.mockResolvedValueOnce([MockTemplateVersionParameter1])
187+
188+
awaitexpect(api.updateWorkspace(MockWorkspace)).rejects.toThrow(
189+
api.MissingBuildParameters,
190+
)
191+
})
192+
})
157193
})

‎site/src/api/api.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -897,3 +897,82 @@ export const getWorkspaceBuildParameters = async (
897897
)
898898
returnresponse.data
899899
}
900+
901+
exportclassMissingBuildParametersextendsError{
902+
parameters:TypesGen.TemplateVersionParameter[]=[]
903+
904+
constructor(parameters:TypesGen.TemplateVersionParameter[]){
905+
super("Missing build parameters.")
906+
this.parameters=parameters
907+
}
908+
}
909+
910+
/** Steps to update the workspace
911+
* - Get the latest template to access the latest active version
912+
* - Get the current build parameters
913+
* - Get the template parameters
914+
* - Update the build parameters and check if there are missed parameters for the newest version
915+
* - If there are missing parameters raise an error
916+
* - Create a build with the latest version and updated build parameters
917+
*/
918+
exportconstupdateWorkspace=async(
919+
workspace:TypesGen.Workspace,
920+
newBuildParameters:TypesGen.WorkspaceBuildParameter[]=[],
921+
):Promise<TypesGen.WorkspaceBuild>=>{
922+
const[template,oldBuildParameters]=awaitPromise.all([
923+
getTemplate(workspace.template_id),
924+
getWorkspaceBuildParameters(workspace.latest_build.id),
925+
])
926+
constactiveVersionId=template.active_version_id
927+
consttemplateParameters=awaitgetTemplateVersionRichParameters(
928+
activeVersionId,
929+
)
930+
const[updatedBuildParameters,missingParameters]=updateBuildParameters(
931+
oldBuildParameters,
932+
newBuildParameters,
933+
templateParameters,
934+
)
935+
if(missingParameters.length>0){
936+
thrownewMissingBuildParameters(missingParameters)
937+
}
938+
939+
returnpostWorkspaceBuild(workspace.id,{
940+
transition:"start",
941+
template_version_id:activeVersionId,
942+
rich_parameter_values:updatedBuildParameters,
943+
})
944+
}
945+
946+
constupdateBuildParameters=(
947+
oldBuildParameters:TypesGen.WorkspaceBuildParameter[],
948+
newBuildParameters:TypesGen.WorkspaceBuildParameter[],
949+
templateParameters:TypesGen.TemplateVersionParameter[],
950+
)=>{
951+
constmissingParameters:TypesGen.TemplateVersionParameter[]=[]
952+
constupdatedBuildParameters:TypesGen.WorkspaceBuildParameter[]=[]
953+
954+
for(constparameteroftemplateParameters){
955+
// Check if there is a new value
956+
letbuildParameter=newBuildParameters.find(
957+
(p)=>p.name===parameter.name,
958+
)
959+
960+
// If not, get the old one
961+
if(!buildParameter){
962+
buildParameter=oldBuildParameters.find((p)=>p.name===parameter.name)
963+
}
964+
965+
// If there is a value from the new or old one, add it to the list
966+
if(buildParameter){
967+
updatedBuildParameters.push(buildParameter)
968+
continue
969+
}
970+
971+
// If there is no value and it is required, add it to the list of missing parameters
972+
if(parameter.required){
973+
missingParameters.push(parameter)
974+
}
975+
}
976+
977+
return[updatedBuildParameters,missingParameters]asconst
978+
}

‎site/src/components/HorizontalForm/HorizontalForm.tsxrenamed to‎site/src/components/Form/Form.tsx

Lines changed: 77 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,36 +4,84 @@ import {
44
FormFooterasBaseFormFooter,
55
}from"components/FormFooter/FormFooter"
66
import{Stack}from"components/Stack/Stack"
7-
import{FC,HTMLProps,PropsWithChildren}from"react"
7+
import{
8+
createContext,
9+
FC,
10+
HTMLProps,
11+
PropsWithChildren,
12+
useContext,
13+
}from"react"
814
import{combineClasses}from"util/combineClasses"
915

10-
exportconstHorizontalForm:FC<
11-
PropsWithChildren&HTMLProps<HTMLFormElement>
12-
>=({ children, ...formProps})=>{
16+
typeFormContextValue={direction?:"horizontal"|"vertical"}
17+
18+
constFormContext=createContext<FormContextValue>({
19+
direction:"horizontal",
20+
})
21+
22+
typeFormProps=HTMLProps<HTMLFormElement>&{
23+
direction?:FormContextValue["direction"]
24+
}
25+
26+
exportconstForm:FC<FormProps>=({ direction, className, ...formProps})=>{
1327
conststyles=useStyles()
1428

1529
return(
16-
<form{...formProps}>
17-
<Stackdirection="column"spacing={10}className={styles.formSections}>
18-
{children}
19-
</Stack>
20-
</form>
30+
<FormContext.Providervalue={{ direction}}>
31+
<form
32+
{...formProps}
33+
className={combineClasses([styles.form,className])}
34+
/>
35+
</FormContext.Provider>
36+
)
37+
}
38+
39+
exportconstHorizontalForm:FC<HTMLProps<HTMLFormElement>>=({
40+
children,
41+
...formProps
42+
})=>{
43+
return(
44+
<Formdirection="horizontal"{...formProps}>
45+
{children}
46+
</Form>
47+
)
48+
}
49+
50+
exportconstVerticalForm:FC<HTMLProps<HTMLFormElement>>=({
51+
children,
52+
...formProps
53+
})=>{
54+
return(
55+
<Formdirection="vertical"{...formProps}>
56+
{children}
57+
</Form>
2158
)
2259
}
2360

2461
exportconstFormSection:FC<
2562
PropsWithChildren&{
26-
title:string
63+
title:string|JSX.Element
2764
description:string|JSX.Element
28-
className?:string
65+
classes?:{
66+
root?:string
67+
infoTitle?:string
68+
}
2969
}
30-
>=({ children, title, description, className})=>{
31-
conststyles=useStyles()
70+
>=({ children, title, description, classes={}})=>{
71+
constformContext=useContext(FormContext)
72+
conststyles=useStyles(formContext)
3273

3374
return(
34-
<divclassName={combineClasses([styles.formSection,className])}>
75+
<divclassName={combineClasses([styles.formSection,classes.root])}>
3576
<divclassName={styles.formSectionInfo}>
36-
<h2className={styles.formSectionInfoTitle}>{title}</h2>
77+
<h2
78+
className={combineClasses([
79+
styles.formSectionInfoTitle,
80+
classes.infoTitle,
81+
])}
82+
>
83+
{title}
84+
</h2>
3785
<divclassName={styles.formSectionInfoDescription}>{description}</div>
3886
</div>
3987

@@ -62,7 +110,12 @@ export const FormFooter: FC<BaseFormFooterProps> = (props) => {
62110
}
63111

64112
constuseStyles=makeStyles((theme)=>({
65-
formSections:{
113+
form:{
114+
display:"flex",
115+
flexDirection:"column",
116+
gap:({ direction}:FormContextValue={})=>
117+
direction==="horizontal" ?theme.spacing(10) :theme.spacing(5),
118+
66119
[theme.breakpoints.down("sm")]:{
67120
gap:theme.spacing(8),
68121
},
@@ -71,7 +124,10 @@ const useStyles = makeStyles((theme) => ({
71124
formSection:{
72125
display:"flex",
73126
alignItems:"flex-start",
74-
gap:theme.spacing(15),
127+
gap:({ direction}:FormContextValue={})=>
128+
direction==="horizontal" ?theme.spacing(15) :theme.spacing(3),
129+
flexDirection:({ direction}:FormContextValue={})=>
130+
direction==="horizontal" ?"row" :"column",
75131

76132
[theme.breakpoints.down("sm")]:{
77133
flexDirection:"column",
@@ -80,9 +136,11 @@ const useStyles = makeStyles((theme) => ({
80136
},
81137

82138
formSectionInfo:{
83-
width:312,
139+
maxWidth:({ direction}:FormContextValue={})=>
140+
direction==="horizontal" ?312 :undefined,
84141
flexShrink:0,
85-
position:"sticky",
142+
position:({ direction}:FormContextValue={})=>
143+
direction==="horizontal" ?"sticky" :undefined,
86144
top:theme.spacing(3),
87145

88146
[theme.breakpoints.down("sm")]:{

‎site/src/i18n/en/workspacePage.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,5 +65,8 @@
6565
"agentVersionLabel":"Agent version",
6666
"serverVersionLabel":"Server version",
6767
"updateWorkspaceLabel":"Update workspace"
68+
},
69+
"askParametersDialog": {
70+
"message":"It looks like the new version has new parameters that need to be filled in to update the workspace."
6871
}
6972
}

‎site/src/pages/CreateTemplatePage/CreateTemplateForm.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,12 @@ import { LazyIconField } from "components/IconField/LazyIconField"
3131
import{Maybe}from"components/Conditionals/Maybe"
3232
importi18nextfrom"i18next"
3333
importLinkfrom"@material-ui/core/Link"
34-
import{FormFooter}from"components/FormFooter/FormFooter"
3534
import{
3635
HorizontalForm,
3736
FormSection,
3837
FormFields,
39-
}from"components/HorizontalForm/HorizontalForm"
38+
FormFooter,
39+
}from"components/Form/Form"
4040
importcamelCasefrom"lodash/camelCase"
4141
importcapitalizefrom"lodash/capitalize"
4242
import{VariableInput}from"./VariableInput"

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp