Skip to content

Commit e57d1b6

Browse files
committed
Set up dynamic form components
1 parent 6fc0a54 commit e57d1b6

File tree

8 files changed

+138
-44
lines changed

8 files changed

+138
-44
lines changed

site/api.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,22 @@ import { SvgIcon } from "@material-ui/core"
22
import { Logo } from "./components/Icons"
33
import { wait } from "./util"
44

5+
export type ProjectParameterType = "string" | "number"
6+
7+
export interface ProjectParameter {
8+
id: string
9+
name: string
10+
description: string
11+
defaultValue?: string
12+
type: ProjectParameterType
13+
}
14+
515
export interface Project {
616
id: string
717
icon?: string
818
name: string
919
description: string
20+
parameters: ProjectParameter[]
1021
}
1122

1223
export namespace Project {
@@ -15,12 +26,35 @@ export namespace Project {
1526
icon: "https://www.datocms-assets.com/2885/1620155117-brandhcterraformverticalcolorwhite.svg",
1627
name: "Terraform Project 1",
1728
description: "Simple terraform project that deploys a kubernetes provider",
29+
parameters: [
30+
{
31+
id: "namespace",
32+
name: "Namespace",
33+
description: "The kubernetes namespace that will own the workspace pod.",
34+
defaultValue: "default",
35+
type: "string",
36+
},
37+
{
38+
id: "cpu_cores",
39+
name: "CPU Cores",
40+
description: "Number of CPU cores to allocate for pod.",
41+
type: "number",
42+
},
43+
],
1844
}
1945

2046
const testProject2: Project = {
2147
id: "test-echo-1",
2248
name: "Echo Project",
2349
description: "Project built on echo provisioner",
50+
parameters: [
51+
{
52+
id: "echo_string",
53+
name: "Echo string",
54+
description: "String that will be echoed out during build.",
55+
type: "string",
56+
},
57+
],
2458
}
2559

2660
const allProjects = [testProject1, testProject2]
@@ -51,7 +85,15 @@ export namespace Project {
5185
export namespace Workspace {
5286
export type WorkspaceId = string
5387

54-
export const createWorkspace = (name: string, projectTemplate: string): Promise<WorkspaceId> => {
88+
export const createWorkspace = (
89+
name: string,
90+
projectTemplate: string,
91+
parameters: Record<string, string>,
92+
): Promise<WorkspaceId> => {
93+
alert(
94+
`Creating workspace named ${name} for project ${projectTemplate} with parameters: ${JSON.stringify(parameters)}`,
95+
)
96+
5597
return Promise.resolve("test-workspace")
5698
}
5799
}

site/components/Form/FormRow.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { makeStyles } from "@material-ui/core/styles"
2+
import React from "react"
3+
4+
const useStyles = makeStyles((theme) => ({
5+
row: {
6+
marginTop: theme.spacing(2),
7+
marginBottom: theme.spacing(2),
8+
},
9+
}))
10+
11+
export const FormRow: React.FC = ({ children }) => {
12+
const styles = useStyles()
13+
return <div className={styles.row}>{children}</div>
14+
}

site/components/Form/FormSection.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ export const useStyles = makeStyles((theme) => ({
2323
flex: "0 0 200px",
2424
display: "flex",
2525
flexDirection: "column",
26-
justifyContent: "center",
26+
justifyContent: "flex-start",
2727
alignItems: "flex-start",
28-
marginTop: theme.spacing(2),
28+
marginTop: theme.spacing(5),
2929
marginBottom: theme.spacing(2),
3030
},
3131
descriptionText: {
File renamed without changes.

site/components/Form/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1-
export * from "./Title"
1+
export * from "./FormTitle"
2+
export * from "./FormRow"
23
export * from "./FormSection"

site/components/PageTemplates/LoadingPage.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ export const LoadingPage: React.FC<LoadingPageProps<T>> = <T,>(props: LoadingPag
2525

2626
const { request, children } = props
2727
const { state } = request
28+
2829
switch (state) {
2930
case "error":
30-
return <div>{request.error.toString()}</div>
31+
return <div className={styles.fullScreenLoader}>{request.error.toString()}</div>
3132
case "loading":
3233
return (
3334
<div className={styles.fullScreenLoader}>
34-
{" "}
3535
<CircularProgress />
3636
</div>
3737
)

site/pages/workspaces/create/[projectId].tsx

Lines changed: 74 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -7,71 +7,89 @@ import * as API from "../../../api"
77

88
import { FormPage, FormButton } from "../../../components/PageTemplates"
99
import { useRequestor } from "../../../hooks/useRequest"
10-
import { FormSection } from "../../../components/Form"
10+
import { FormSection, FormRow } from "../../../components/Form"
1111
import { formTextFieldFactory } from "../../../components/Form/FormTextField"
1212
import { LoadingPage } from "../../../components/PageTemplates/LoadingPage"
1313

1414
namespace CreateProjectForm {
1515
export interface Schema {
1616
name: string
17-
parameters: any[]
17+
parameters: Record<string, string>
1818
}
1919

2020
export const initial: Schema = {
2121
name: "",
22-
parameters: [],
22+
parameters: {},
2323
}
2424
}
2525

2626
const FormTextField = formTextFieldFactory<CreateProjectForm.Schema>()
2727

28+
namespace Helpers {
29+
export const projectParametersToValues = (parameters: API.ProjectParameter[]) => {
30+
const parameterValues: Record<string, string> = {}
31+
return parameters.reduce((acc, curr) => {
32+
return {
33+
...acc,
34+
[curr.id]: curr.defaultValue || "",
35+
}
36+
}, parameterValues)
37+
}
38+
}
39+
2840
const CreateProjectPage: React.FC = () => {
2941
const router = useRouter()
3042
const { projectId: routeProjectId } = router.query
31-
console.log(routeProjectId)
3243
const projectId = firstOrOnly(routeProjectId)
44+
3345
const projectToLoad = useRequestor(() => API.Project.getProject("test-org", projectId), [projectId])
3446

47+
const parametersWithMetadata = projectToLoad.state === "success" ? projectToLoad.payload.parameters : []
48+
const parameters = Helpers.projectParametersToValues(parametersWithMetadata)
49+
3550
const form = useFormik({
3651
enableReinitialize: true,
37-
initialValues: CreateProjectForm.initial,
38-
onSubmit: async ({ name }) => {
39-
return API.Workspace.createWorkspace(name, projectId)
52+
initialValues: {
53+
name: "",
54+
parameters,
55+
},
56+
onSubmit: async ({ name, parameters }) => {
57+
return API.Workspace.createWorkspace(name, projectId, parameters)
4058
},
4159
})
4260

4361
const cancel = () => {
44-
router.back()
62+
router.push(`/workspaces/create`)
4563
}
4664

4765
const submit = async () => {
4866
const workspaceId = await form.submitForm()
4967
router.push(`/workspaces/${workspaceId}`)
5068
}
5169

52-
const buttons: FormButton[] = [
53-
{
54-
title: "Cancel",
55-
props: {
56-
variant: "outlined",
57-
onClick: cancel,
58-
},
59-
},
60-
{
61-
title: "Submit",
62-
props: {
63-
variant: "contained",
64-
color: "primary",
65-
disabled: false,
66-
type: "submit",
67-
onClick: submit,
68-
},
69-
},
70-
]
71-
7270
return (
7371
<LoadingPage request={projectToLoad}>
7472
{(project) => {
73+
const buttons: FormButton[] = [
74+
{
75+
title: "Back",
76+
props: {
77+
variant: "outlined",
78+
onClick: cancel,
79+
},
80+
},
81+
{
82+
title: "Create Workspace",
83+
props: {
84+
variant: "contained",
85+
color: "primary",
86+
disabled: false,
87+
type: "submit",
88+
onClick: submit,
89+
},
90+
},
91+
]
92+
7593
const detail = (
7694
<>
7795
<strong>{project.name}</strong> in <strong> {"test-org"}</strong> organization
@@ -80,15 +98,34 @@ const CreateProjectPage: React.FC = () => {
8098
return (
8199
<FormPage title={"Create Project"} detail={detail} buttons={buttons}>
82100
<FormSection title="General">
83-
<FormTextField
84-
form={form}
85-
formFieldName="name"
86-
fullWidth
87-
helperText="A unique name describing your workspace."
88-
label="Workspace Name"
89-
placeholder={project.id}
90-
required
91-
/>
101+
<FormRow>
102+
<FormTextField
103+
form={form}
104+
formFieldName="name"
105+
fullWidth
106+
helperText="A unique name describing your workspace."
107+
label="Workspace Name"
108+
placeholder={project.id}
109+
required
110+
/>
111+
</FormRow>
112+
</FormSection>
113+
<FormSection title="Parameters">
114+
{parametersWithMetadata.map((param) => {
115+
return (
116+
<FormRow>
117+
<FormTextField
118+
form={form}
119+
formFieldName={"parameters." + param.id}
120+
fullWidth
121+
label={param.name}
122+
helperText={param.description}
123+
placeholder={param.defaultValue}
124+
required
125+
/>
126+
</FormRow>
127+
)
128+
})}
92129
</FormSection>
93130
</FormPage>
94131
)

site/pages/workspaces/create/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const CreateSelectProjectPage: React.FC = () => {
1414
const requestState = useRequestor(() => Api.Project.getAllProjectsInOrg("test-org"))
1515

1616
const cancel = () => {
17-
router.back()
17+
router.push(`/workspaces`)
1818
}
1919

2020
const select = (projectId: string) => () => {

0 commit comments

Comments
 (0)