Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 60323d8

Browse files
committed
Switch fully to generated types
In some places the organization ID is part of the URL but not part of the request so I separated out the ID into a separate argument in the relevant API functions. Otherwise this was a straightforward replacement where I mostly only needed to change some of the interface names (User instead of UserResponse for example) and add a few missing but required properties. Arguably `parameter_values` could be made optional but I am just passing in an empty array for now mostly just to make it obvious that we could pass stuff there if we need to. I kind of winged the template form; I am not sure what the difference between a template and template version is or why the latter comes before the former so the form just returns all the data required to create both.
1 parent d5eb87f commit 60323d8

File tree

22 files changed

+137
-115
lines changed

22 files changed

+137
-115
lines changed

site/src/api/index.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import axios from "axios"
22
import { getApiKey, login, logout } from "."
3-
import { APIKeyResponse, LoginResponse } from "./types"
3+
import * as TypesGen from "./typesGenerated"
44

55
// Mock the axios module so that no real network requests are made, but rather
66
// we swap in a resolved or rejected value
@@ -12,7 +12,7 @@ describe("api.ts", () => {
1212
describe("login", () => {
1313
it("should return LoginResponse", async () => {
1414
// given
15-
const loginResponse: LoginResponse = {
15+
const loginResponse: TypesGen.LoginWithPasswordResponse = {
1616
session_token: "abc_123_test",
1717
}
1818
const axiosMockPost = jest.fn().mockImplementationOnce(() => {
@@ -87,7 +87,7 @@ describe("api.ts", () => {
8787
describe("getApiKey", () => {
8888
it("should return APIKeyResponse", async () => {
8989
// given
90-
const apiKeyResponse: APIKeyResponse = {
90+
const apiKeyResponse: TypesGen.GenerateAPIKeyResponse = {
9191
key: "abc_123_test",
9292
}
9393
const axiosMockPost = jest.fn().mockImplementationOnce(() => {

site/src/api/index.ts

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,32 @@
11
import axios, { AxiosRequestHeaders } from "axios"
22
import { mutate } from "swr"
3-
import * as Types from "./types"
43
import * as TypesGen from "./typesGenerated"
54

65
const CONTENT_TYPE_JSON: AxiosRequestHeaders = {
76
"Content-Type": "application/json",
87
}
98

10-
export const provisioners: Types.Provisioner[] = [
9+
export const provisioners: TypesGen.ProvisionerDaemon[] = [
1110
{
1211
id: "terraform",
1312
name: "Terraform",
13+
created_at: "",
14+
provisioners: [],
1415
},
1516
{
1617
id: "cdr-basic",
1718
name: "Basic",
19+
created_at: "",
20+
provisioners: [],
1821
},
1922
]
2023

2124
export namespace Workspace {
22-
export const create = async (request: Types.CreateWorkspaceRequest): Promise<Types.Workspace> => {
23-
const response = await fetch(`/api/v2/organizations/${request.organization_id}/workspaces`, {
25+
export const create = async (
26+
organizationId: string,
27+
request: TypesGen.CreateWorkspaceRequest,
28+
): Promise<TypesGen.Workspace> => {
29+
const response = await fetch(`/api/v2/organizations/${organizationId}/workspaces`, {
2430
method: "POST",
2531
headers: {
2632
"Content-Type": "application/json",
@@ -43,13 +49,13 @@ export namespace Workspace {
4349
}
4450
}
4551

46-
export const login = async (email: string, password: string): Promise<Types.LoginResponse> => {
52+
export const login = async (email: string, password: string): Promise<TypesGen.LoginWithPasswordResponse> => {
4753
const payload = JSON.stringify({
4854
email,
4955
password,
5056
})
5157

52-
const response = await axios.post<Types.LoginResponse>("/api/v2/users/login", payload, {
58+
const response = await axios.post<TypesGen.LoginWithPasswordResponse>("/api/v2/users/login", payload, {
5359
headers: { ...CONTENT_TYPE_JSON },
5460
})
5561

@@ -60,8 +66,8 @@ export const logout = async (): Promise<void> => {
6066
await axios.post("/api/v2/users/logout")
6167
}
6268

63-
export const getUser = async (): Promise<Types.UserResponse> => {
64-
const response = await axios.get<Types.UserResponse>("/api/v2/users/me")
69+
export const getUser = async (): Promise<TypesGen.User> => {
70+
const response = await axios.get<TypesGen.User>("/api/v2/users/me")
6571
return response.data
6672
}
6773

@@ -70,8 +76,8 @@ export const getAuthMethods = async (): Promise<TypesGen.AuthMethods> => {
7076
return response.data
7177
}
7278

73-
export const getApiKey = async (): Promise<Types.APIKeyResponse> => {
74-
const response = await axios.post<Types.APIKeyResponse>("/api/v2/users/me/keys")
79+
export const getApiKey = async (): Promise<TypesGen.GenerateAPIKeyResponse> => {
80+
const response = await axios.post<TypesGen.GenerateAPIKeyResponse>("/api/v2/users/me/keys")
7581
return response.data
7682
}
7783

@@ -80,55 +86,57 @@ export const getUsers = async (): Promise<TypesGen.User[]> => {
8086
return response.data
8187
}
8288

83-
export const getOrganization = async (organizationId: string): Promise<Types.Organization> => {
84-
const response = await axios.get<Types.Organization>(`/api/v2/organizations/${organizationId}`)
89+
export const getOrganization = async (organizationId: string): Promise<TypesGen.Organization> => {
90+
const response = await axios.get<TypesGen.Organization>(`/api/v2/organizations/${organizationId}`)
8591
return response.data
8692
}
8793

88-
export const getOrganizations = async (): Promise<Types.Organization[]> => {
89-
const response = await axios.get<Types.Organization[]>("/api/v2/users/me/organizations")
94+
export const getOrganizations = async (): Promise<TypesGen.Organization[]> => {
95+
const response = await axios.get<TypesGen.Organization[]>("/api/v2/users/me/organizations")
9096
return response.data
9197
}
9298

93-
export const getTemplate = async (templateId: string): Promise<Types.Template> => {
94-
const response = await axios.get<Types.Template>(`/api/v2/templates/${templateId}`)
99+
export const getTemplate = async (templateId: string): Promise<TypesGen.Template> => {
100+
const response = await axios.get<TypesGen.Template>(`/api/v2/templates/${templateId}`)
95101
return response.data
96102
}
97103

98-
export const getWorkspace = async (workspaceId: string): Promise<Types.Workspace> => {
99-
const response = await axios.get<Types.Workspace>(`/api/v2/workspaces/${workspaceId}`)
104+
export const getWorkspace = async (workspaceId: string): Promise<TypesGen.Workspace> => {
105+
const response = await axios.get<TypesGen.Workspace>(`/api/v2/workspaces/${workspaceId}`)
100106
return response.data
101107
}
102108

103109
export const getWorkspaceByOwnerAndName = async (
104110
organizationID: string,
105111
username = "me",
106112
workspaceName: string,
107-
): Promise<Types.Workspace> => {
108-
const response = await axios.get<Types.Workspace>(
113+
): Promise<TypesGen.Workspace> => {
114+
const response = await axios.get<TypesGen.Workspace>(
109115
`/api/v2/organizations/${organizationID}/workspaces/${username}/${workspaceName}`,
110116
)
111117
return response.data
112118
}
113119

114-
export const getWorkspaceResources = async (workspaceBuildID: string): Promise<Types.WorkspaceResource[]> => {
115-
const response = await axios.get<Types.WorkspaceResource[]>(`/api/v2/workspacebuilds/${workspaceBuildID}/resources`)
120+
export const getWorkspaceResources = async (workspaceBuildID: string): Promise<TypesGen.WorkspaceResource[]> => {
121+
const response = await axios.get<TypesGen.WorkspaceResource[]>(
122+
`/api/v2/workspacebuilds/${workspaceBuildID}/resources`,
123+
)
116124
return response.data
117125
}
118126

119-
export const createUser = async (user: Types.CreateUserRequest): Promise<TypesGen.User> => {
127+
export const createUser = async (user: TypesGen.CreateUserRequest): Promise<TypesGen.User> => {
120128
const response = await axios.post<TypesGen.User>("/api/v2/users", user)
121129
return response.data
122130
}
123131

124-
export const getBuildInfo = async (): Promise<Types.BuildInfoResponse> => {
132+
export const getBuildInfo = async (): Promise<TypesGen.BuildInfoResponse> => {
125133
const response = await axios.get("/api/v2/buildinfo")
126134
return response.data
127135
}
128136

129137
export const putWorkspaceAutostart = async (
130138
workspaceID: string,
131-
autostart: Types.WorkspaceAutostartRequest,
139+
autostart: TypesGen.UpdateWorkspaceAutostartRequest,
132140
): Promise<void> => {
133141
const payload = JSON.stringify(autostart)
134142
await axios.put(`/api/v2/workspaces/${workspaceID}/autostart`, payload, {
@@ -138,15 +146,18 @@ export const putWorkspaceAutostart = async (
138146

139147
export const putWorkspaceAutostop = async (
140148
workspaceID: string,
141-
autostop: Types.WorkspaceAutostopRequest,
149+
autostop: TypesGen.UpdateWorkspaceAutostopRequest,
142150
): Promise<void> => {
143151
const payload = JSON.stringify(autostop)
144152
await axios.put(`/api/v2/workspaces/${workspaceID}/autostop`, payload, {
145153
headers: { ...CONTENT_TYPE_JSON },
146154
})
147155
}
148156

149-
export const updateProfile = async (userId: string, data: Types.UpdateProfileRequest): Promise<Types.UserResponse> => {
157+
export const updateProfile = async (
158+
userId: string,
159+
data: TypesGen.UpdateUserProfileRequest,
160+
): Promise<TypesGen.User> => {
150161
const response = await axios.put(`/api/v2/users/${userId}/profile`, data)
151162
return response.data
152163
}

site/src/components/CreateUserForm/CreateUserForm.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import TextField from "@material-ui/core/TextField"
33
import { FormikContextType, FormikErrors, useFormik } from "formik"
44
import React from "react"
55
import * as Yup from "yup"
6-
import { CreateUserRequest } from "../../api/types"
6+
import * as TypesGen from "../../api/typesGenerated"
77
import { getFormHelpers, onChangeTrimmed } from "../../util/formUtils"
88
import { FormFooter } from "../FormFooter/FormFooter"
99
import { FullPageForm } from "../FullPageForm/FullPageForm"
@@ -21,9 +21,9 @@ export const Language = {
2121
}
2222

2323
export interface CreateUserFormProps {
24-
onSubmit: (user: CreateUserRequest) => void
24+
onSubmit: (user: TypesGen.CreateUserRequest) => void
2525
onCancel: () => void
26-
formErrors?: FormikErrors<CreateUserRequest>
26+
formErrors?: FormikErrors<TypesGen.CreateUserRequest>
2727
isLoading: boolean
2828
error?: string
2929
myOrgId: string
@@ -43,7 +43,7 @@ export const CreateUserForm: React.FC<CreateUserFormProps> = ({
4343
error,
4444
myOrgId,
4545
}) => {
46-
const form: FormikContextType<CreateUserRequest> = useFormik<CreateUserRequest>({
46+
const form: FormikContextType<TypesGen.CreateUserRequest> = useFormik<TypesGen.CreateUserRequest>({
4747
initialValues: {
4848
email: "",
4949
password: "",
@@ -53,7 +53,7 @@ export const CreateUserForm: React.FC<CreateUserFormProps> = ({
5353
validationSchema,
5454
onSubmit,
5555
})
56-
const getFieldHelpers = getFormHelpers<CreateUserRequest>(form, formErrors)
56+
const getFieldHelpers = getFormHelpers<TypesGen.CreateUserRequest>(form, formErrors)
5757

5858
return (
5959
<FullPageForm title="Create user" onCancel={onCancel}>

site/src/components/Footer/Footer.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import { makeStyles } from "@material-ui/core/styles"
33
import Typography from "@material-ui/core/Typography"
44
import { useActor } from "@xstate/react"
55
import React, { useContext } from "react"
6-
import { BuildInfoResponse } from "../../api/types"
6+
import * as TypesGen from "../../api/typesGenerated"
77
import { XServiceContext } from "../../xServices/StateContext"
88

99
export const Language = {
10-
buildInfoText: (buildInfo: BuildInfoResponse): string => {
10+
buildInfoText: (buildInfo: TypesGen.BuildInfoResponse): string => {
1111
return `Coder ${buildInfo.version}`
1212
},
1313
}

site/src/components/NavbarView/NavbarView.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ import ListItem from "@material-ui/core/ListItem"
33
import { fade, makeStyles } from "@material-ui/core/styles"
44
import React from "react"
55
import { NavLink } from "react-router-dom"
6-
import { UserResponse } from "../../api/types"
6+
import * as TypesGen from "../../api/typesGenerated"
77
import { navHeight } from "../../theme/constants"
88
import { AdminDropdown } from "../AdminDropdown/AdminDropdown"
99
import { Logo } from "../Icons/Logo"
1010
import { UserDropdown } from "../UserDropdown/UsersDropdown"
1111

1212
export interface NavbarViewProps {
13-
user?: UserResponse
13+
user?: TypesGen.User
1414
onSignOut: () => void
1515
}
1616

site/src/components/UserDropdown/UsersDropdown.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { fade, makeStyles } from "@material-ui/core/styles"
77
import AccountIcon from "@material-ui/icons/AccountCircleOutlined"
88
import React, { useState } from "react"
99
import { Link } from "react-router-dom"
10-
import { UserResponse } from "../../api/types"
10+
import * as TypesGen from "../../api/typesGenerated"
1111
import { BorderedMenu } from "../BorderedMenu/BorderedMenu"
1212
import { CloseDropdown, OpenDropdown } from "../DropdownArrows/DropdownArrows"
1313
import { DocsIcon } from "../Icons/DocsIcon"
@@ -21,7 +21,7 @@ export const Language = {
2121
signOutLabel: "Sign Out",
2222
}
2323
export interface UserDropdownProps {
24-
user: UserResponse
24+
user: TypesGen.User
2525
onSignOut: () => void
2626
}
2727

site/src/components/UserProfileCard/UserProfileCard.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { makeStyles } from "@material-ui/core/styles"
22
import Typography from "@material-ui/core/Typography"
33
import React from "react"
4-
import { UserResponse } from "../../api/types"
4+
import * as TypesGen from "../../api/typesGenerated"
55
import { UserAvatar } from "../UserAvatar/UserAvatar"
66

77
interface UserProfileCardProps {
8-
user: UserResponse
8+
user: TypesGen.User
99
}
1010

1111
export const UserProfileCard: React.FC<UserProfileCardProps> = ({ user }) => {

site/src/components/UsersTable/UsersTable.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import TableCell from "@material-ui/core/TableCell"
55
import TableHead from "@material-ui/core/TableHead"
66
import TableRow from "@material-ui/core/TableRow"
77
import React from "react"
8-
import { UserResponse } from "../../api/types"
98
import * as TypesGen from "../../api/typesGenerated"
109
import { EmptyState } from "../EmptyState/EmptyState"
1110
import { RoleSelect } from "../RoleSelect/RoleSelect"
@@ -25,10 +24,10 @@ export const Language = {
2524
}
2625

2726
export interface UsersTableProps {
28-
users: UserResponse[]
29-
onSuspendUser: (user: UserResponse) => void
30-
onResetUserPassword: (user: UserResponse) => void
31-
onUpdateUserRoles: (user: UserResponse, roles: TypesGen.Role["name"][]) => void
27+
users: TypesGen.User[]
28+
onSuspendUser: (user: TypesGen.User) => void
29+
onResetUserPassword: (user: TypesGen.User) => void
30+
onUpdateUserRoles: (user: TypesGen.User, roles: TypesGen.Role["name"][]) => void
3231
roles: TypesGen.Role[]
3332
isUpdatingUserRoles?: boolean
3433
}

site/src/components/Workspace/Workspace.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ import Typography from "@material-ui/core/Typography"
55
import CloudCircleIcon from "@material-ui/icons/CloudCircle"
66
import React from "react"
77
import { Link } from "react-router-dom"
8-
import * as Types from "../../api/types"
8+
import * as TypesGen from "../../api/typesGenerated"
99
import { WorkspaceSchedule } from "../WorkspaceSchedule/WorkspaceSchedule"
1010
import { WorkspaceSection } from "../WorkspaceSection/WorkspaceSection"
1111
import * as Constants from "./constants"
1212

1313
export interface WorkspaceProps {
14-
organization: Types.Organization
15-
workspace: Types.Workspace
16-
template: Types.Template
14+
organization: TypesGen.Organization
15+
workspace: TypesGen.Workspace
16+
template: TypesGen.Template
1717
}
1818

1919
/**

site/src/forms/CreateTemplateForm.tsx

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { makeStyles } from "@material-ui/core/styles"
33
import { FormikContextType, useFormik } from "formik"
44
import React from "react"
55
import * as Yup from "yup"
6-
import { CreateTemplateRequest, Organization, Provisioner, Template } from "../api/types"
6+
import * as TypesGen from "../api/typesGenerated"
77
import { FormCloseButton } from "../components/FormCloseButton/FormCloseButton"
88
import { FormDropdownField, FormDropdownItem } from "../components/FormDropdownField/FormDropdownField"
99
import { FormSection } from "../components/FormSection/FormSection"
@@ -12,13 +12,21 @@ import { FormTitle } from "../components/FormTitle/FormTitle"
1212
import { LoadingButton } from "../components/LoadingButton/LoadingButton"
1313
import { maxWidth } from "../theme/constants"
1414

15+
// It appears that to create a template you need to create a template version
16+
// and then a template so this contains the information to do both.
17+
export type CreateTemplateRequest = TypesGen.CreateTemplateVersionRequest & Pick<TypesGen.CreateTemplateRequest, "name">
18+
1519
export interface CreateTemplateFormProps {
16-
provisioners: Provisioner[]
17-
organizations: Organization[]
18-
onSubmit: (request: CreateTemplateRequest) => Promise<Template>
20+
provisioners: TypesGen.ProvisionerDaemon[]
21+
organizations: TypesGen.Organization[]
22+
onSubmit: (organizationId: string, request: CreateTemplateRequest) => Promise<TypesGen.Template>
1923
onCancel: () => void
2024
}
2125

26+
interface CreateTemplateFields extends Pick<CreateTemplateRequest, "name" | "provisioner"> {
27+
organizationId: string
28+
}
29+
2230
const validationSchema = Yup.object({
2331
provisioner: Yup.string().required("Provisioner is required."),
2432
organizationId: Yup.string().required("Organization is required."),
@@ -33,7 +41,7 @@ export const CreateTemplateForm: React.FC<CreateTemplateFormProps> = ({
3341
}) => {
3442
const styles = useStyles()
3543

36-
const form: FormikContextType<CreateTemplateRequest> = useFormik<CreateTemplateRequest>({
44+
const form: FormikContextType<CreateTemplateFields> = useFormik<CreateTemplateFields>({
3745
initialValues: {
3846
provisioner: provisioners[0].id,
3947
organizationId: organizations[0].name,
@@ -42,7 +50,13 @@ export const CreateTemplateForm: React.FC<CreateTemplateFormProps> = ({
4250
enableReinitialize: true,
4351
validationSchema: validationSchema,
4452
onSubmit: (req) => {
45-
return onSubmit(req)
53+
return onSubmit(req.organizationId, {
54+
name: req.name,
55+
storage_method: "file",
56+
storage_source: "hash",
57+
provisioner: req.provisioner,
58+
parameter_values: [],
59+
})
4660
},
4761
})
4862

0 commit comments

Comments
 (0)