From f5d1b623f41af5d514cc4967c38d6bd0076f32ff Mon Sep 17 00:00:00 2001 From: Asher Date: Wed, 11 May 2022 12:43:36 -0500 Subject: [PATCH 1/9] Add missing return when template version is not found --- coderd/organizations.go | 1 + 1 file changed, 1 insertion(+) diff --git a/coderd/organizations.go b/coderd/organizations.go index 686b526fa2e02..1796c8f9857a9 100644 --- a/coderd/organizations.go +++ b/coderd/organizations.go @@ -180,6 +180,7 @@ func (api *api) postTemplatesByOrganization(rw http.ResponseWriter, r *http.Requ httpapi.Write(rw, http.StatusNotFound, httpapi.Response{ Message: "template version does not exist", }) + return } if err != nil { httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ From 80a5d1a3081ffef2ce6cbb0cbf24ca99f567d637 Mon Sep 17 00:00:00 2001 From: Asher Date: Wed, 11 May 2022 12:44:14 -0500 Subject: [PATCH 2/9] Make template ID optional in create template version request --- codersdk/organizations.go | 2 +- site/src/api/typesGenerated.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/codersdk/organizations.go b/codersdk/organizations.go index ce0690c466203..885fc68f3b86e 100644 --- a/codersdk/organizations.go +++ b/codersdk/organizations.go @@ -24,7 +24,7 @@ type Organization struct { // CreateTemplateVersionRequest enables callers to create a new Template Version. type CreateTemplateVersionRequest struct { // TemplateID optionally associates a version with a template. - TemplateID uuid.UUID `json:"template_id"` + TemplateID uuid.UUID `json:"template_id,omitempty"` StorageMethod database.ProvisionerStorageMethod `json:"storage_method" validate:"oneof=file,required"` StorageSource string `json:"storage_source" validate:"required"` diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index e30c94e8663e6..fa050802f1349 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -68,7 +68,7 @@ export interface CreateTemplateRequest { // From codersdk/organizations.go:25:6 export interface CreateTemplateVersionRequest { - readonly template_id: string + readonly template_id?: string // This is likely an enum in an external package ("github.com/coder/coder/coderd/database.ProvisionerStorageMethod") readonly storage_method: string readonly storage_source: string From 10bb649c42beaba054f3273ae4093b31f5c15a70 Mon Sep 17 00:00:00 2001 From: Asher Date: Wed, 11 May 2022 12:44:59 -0500 Subject: [PATCH 3/9] Use generated types in test helper entities --- site/src/testHelpers/entities.ts | 107 +++++++++++++++++++------------ 1 file changed, 67 insertions(+), 40 deletions(-) diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index cb978bc43cad2..6d6139c9e1341 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -1,44 +1,37 @@ -import { - BuildInfoResponse, - Organization, - Provisioner, - Template, - UserAgent, - UserResponse, - Workspace, - WorkspaceAgent, - WorkspaceAutostartRequest, - WorkspaceResource, -} from "../api/types" -import { AuthMethods, Role } from "../api/typesGenerated" - -export const MockSessionToken = { session_token: "my-session-token" } - -export const MockAPIKey = { key: "my-api-key" } - -export const MockBuildInfo: BuildInfoResponse = { +import * as Types from "../api/types" +import * as TypesGen from "../api/typesGenerated" + +export const MockSessionToken: TypesGen.LoginWithPasswordResponse = { + session_token: "my-session-token", +} + +export const MockAPIKey: TypesGen.GenerateAPIKeyResponse = { + key: "my-api-key", +} + +export const MockBuildInfo: TypesGen.BuildInfoResponse = { external_url: "file:///mock-url", version: "v99.999.9999+c9cdf14", } -export const MockAdminRole: Role = { +export const MockAdminRole: TypesGen.Role = { name: "admin", display_name: "Admin", } -export const MockMemberRole: Role = { +export const MockMemberRole: TypesGen.Role = { name: "member", display_name: "Member", } -export const MockAuditorRole: Role = { +export const MockAuditorRole: TypesGen.Role = { name: "auditor", display_name: "Auditor", } export const MockSiteRoles = [MockAdminRole, MockAuditorRole, MockMemberRole] -export const MockUser: UserResponse = { +export const MockUser: TypesGen.User = { id: "test-user", username: "TestUser", email: "test@coder.com", @@ -48,7 +41,7 @@ export const MockUser: UserResponse = { roles: [MockAdminRole, MockMemberRole], } -export const MockUser2: UserResponse = { +export const MockUser2: TypesGen.User = { id: "test-user-2", username: "TestUser2", email: "test2@coder.com", @@ -58,19 +51,27 @@ export const MockUser2: UserResponse = { roles: [MockMemberRole], } -export const MockOrganization: Organization = { +export const MockOrganization: TypesGen.Organization = { id: "test-org", name: "Test Organization", created_at: "", updated_at: "", } -export const MockProvisioner: Provisioner = { +export const MockProvisioner: TypesGen.ProvisionerDaemon = { + created_at: "", id: "test-provisioner", name: "Test Provisioner", + provisioners: [], +} + +export const MockProvisionerJob: TypesGen.ProvisionerJob = { + created_at: "", + id: "test-provisioner-job", + status: "succeeded", } -export const MockTemplate: Template = { +export const MockTemplate: TypesGen.Template = { id: "test-template", created_at: "", updated_at: "", @@ -78,60 +79,86 @@ export const MockTemplate: Template = { name: "Test Template", provisioner: MockProvisioner.id, active_version_id: "", + workspace_owner_count: 1, } -export const MockWorkspaceAutostartDisabled: WorkspaceAutostartRequest = { +export const MockWorkspaceAutostartDisabled: TypesGen.UpdateWorkspaceAutostartRequest = { schedule: "", } -export const MockWorkspaceAutostartEnabled: WorkspaceAutostartRequest = { +export const MockWorkspaceAutostartEnabled: TypesGen.UpdateWorkspaceAutostartRequest = { // Runs at 9:30am Monday through Friday using Canada/Eastern // (America/Toronto) time schedule: "CRON_TZ=Canada/Eastern 30 9 * * 1-5", } -export const MockWorkspaceAutostopDisabled: WorkspaceAutostartRequest = { +export const MockWorkspaceAutostopDisabled: TypesGen.UpdateWorkspaceAutostartRequest = { schedule: "", } -export const MockWorkspaceAutostopEnabled: WorkspaceAutostartRequest = { +export const MockWorkspaceAutostopEnabled: TypesGen.UpdateWorkspaceAutostartRequest = { // Runs at 9:30pm Monday through Friday using America/Toronto schedule: "CRON_TZ=America/Toronto 30 21 * * 1-5", } -export const MockWorkspace: Workspace = { +export const MockWorkspaceBuild: TypesGen.WorkspaceBuild = { + after_id: "", + before_id: "", + created_at: "", + id: "test-workspace-build", + initiator_id: "", + job: MockProvisionerJob, + name: "a-workspace-build", + template_version_id: "", + transition: "start", + updated_at: "", + workspace_id: "test-workspace", +} + +export const MockWorkspace: TypesGen.Workspace = { id: "test-workspace", name: "Test-Workspace", created_at: "", updated_at: "", template_id: MockTemplate.id, + template_name: MockTemplate.name, + outdated: false, owner_id: MockUser.id, autostart_schedule: MockWorkspaceAutostartEnabled.schedule, autostop_schedule: MockWorkspaceAutostopEnabled.schedule, - latest_build: { - id: "test-workspace-build", - }, + latest_build: MockWorkspaceBuild, } -export const MockWorkspaceAgent: WorkspaceAgent = { +export const MockWorkspaceAgent: TypesGen.WorkspaceAgent = { + architecture: "amd64", + created_at: "", + environment_variables: {}, id: "test-workspace-agent", name: "a-workspace-agent", operating_system: "linux", + resource_id: "", + status: "connected", + updated_at: "", } -export const MockWorkspaceResource: WorkspaceResource = { - id: "test-workspace-resource", +export const MockWorkspaceResource: TypesGen.WorkspaceResource = { agents: [MockWorkspaceAgent], + created_at: "", + id: "test-workspace-resource", + job_id: "", + name: "a-workspace-resource", + type: "google_compute_disk", + workspace_transition: "start", } -export const MockUserAgent: UserAgent = { +export const MockUserAgent: Types.UserAgent = { browser: "Chrome 99.0.4844", device: "Other", ip_address: "11.22.33.44", os: "Windows 10", } -export const MockAuthMethods: AuthMethods = { +export const MockAuthMethods: TypesGen.AuthMethods = { password: true, github: false, } From d5eb87f4b6bb5698509069cc1b828af51f1828f5 Mon Sep 17 00:00:00 2001 From: Asher Date: Wed, 11 May 2022 14:04:54 -0500 Subject: [PATCH 4/9] Make column renderer use the same type as its key That way the renderer only takes `string` for example when rendering the name field instead of `string | number` when the interface has some fields that are strings and some fields are numbers. This will be necessary when switching to generated types since some of the fields are numbers (like the owner count on a template). --- site/src/components/Table/Table.tsx | 30 +++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/site/src/components/Table/Table.tsx b/site/src/components/Table/Table.tsx index e8445464c9378..82c68a9f9cc93 100644 --- a/site/src/components/Table/Table.tsx +++ b/site/src/components/Table/Table.tsx @@ -8,20 +8,22 @@ import React from "react" import { TableHeaders } from "../TableHeaders/TableHeaders" import { TableTitle } from "../TableTitle/TableTitle" -export interface Column { - /** - * The field of type T that this column is associated with - */ - key: keyof T - /** - * Friendly name of the field, shown in headers - */ - name: string - /** - * Custom render for the field inside the table - */ - renderer?: (field: T[keyof T], data: T) => React.ReactElement -} +export type Column = { + [K in keyof T]: { + /** + * The field of type T that this column is associated with + */ + key: K + /** + * Friendly name of the field, shown in headers + */ + name: string + /** + * Custom render for the field inside the table + */ + renderer?: (field: T[K], data: T) => React.ReactElement + } +}[keyof T] export interface TableProps { /** From 60323d8c6dcbd08865f5e6cf0bf04fffcc4e07ca Mon Sep 17 00:00:00 2001 From: Asher Date: Wed, 11 May 2022 12:45:36 -0500 Subject: [PATCH 5/9] 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. --- site/src/api/index.test.ts | 6 +- site/src/api/index.ts | 65 +++++++++++-------- .../CreateUserForm/CreateUserForm.tsx | 10 +-- site/src/components/Footer/Footer.tsx | 4 +- site/src/components/NavbarView/NavbarView.tsx | 4 +- .../components/UserDropdown/UsersDropdown.tsx | 4 +- .../UserProfileCard/UserProfileCard.tsx | 4 +- site/src/components/UsersTable/UsersTable.tsx | 9 ++- site/src/components/Workspace/Workspace.tsx | 8 +-- site/src/forms/CreateTemplateForm.tsx | 26 ++++++-- site/src/forms/CreateWorkspaceForm.test.tsx | 2 +- site/src/forms/CreateWorkspaceForm.tsx | 14 ++-- .../TemplatePage/CreateWorkspacePage.tsx | 12 ++-- .../TemplatePage/TemplatePage.tsx | 12 ++-- .../pages/TemplatesPages/TemplatesPage.tsx | 12 ++-- .../CreateUserPage/CreateUserPage.tsx | 4 +- site/src/pages/UsersPage/UsersPageView.tsx | 9 ++- site/src/xServices/auth/authXService.ts | 11 ++-- .../xServices/buildInfo/buildInfoXService.ts | 6 +- .../xServices/terminal/terminalXService.ts | 13 ++-- site/src/xServices/users/usersXService.ts | 3 +- .../xServices/workspace/workspaceXService.ts | 14 ++-- 22 files changed, 137 insertions(+), 115 deletions(-) diff --git a/site/src/api/index.test.ts b/site/src/api/index.test.ts index c29be8728d544..81a36c681cd6e 100644 --- a/site/src/api/index.test.ts +++ b/site/src/api/index.test.ts @@ -1,6 +1,6 @@ import axios from "axios" import { getApiKey, login, logout } from "." -import { APIKeyResponse, LoginResponse } from "./types" +import * as TypesGen from "./typesGenerated" // Mock the axios module so that no real network requests are made, but rather // we swap in a resolved or rejected value @@ -12,7 +12,7 @@ describe("api.ts", () => { describe("login", () => { it("should return LoginResponse", async () => { // given - const loginResponse: LoginResponse = { + const loginResponse: TypesGen.LoginWithPasswordResponse = { session_token: "abc_123_test", } const axiosMockPost = jest.fn().mockImplementationOnce(() => { @@ -87,7 +87,7 @@ describe("api.ts", () => { describe("getApiKey", () => { it("should return APIKeyResponse", async () => { // given - const apiKeyResponse: APIKeyResponse = { + const apiKeyResponse: TypesGen.GenerateAPIKeyResponse = { key: "abc_123_test", } const axiosMockPost = jest.fn().mockImplementationOnce(() => { diff --git a/site/src/api/index.ts b/site/src/api/index.ts index d300c7aa8a660..0be44bde17fde 100644 --- a/site/src/api/index.ts +++ b/site/src/api/index.ts @@ -1,26 +1,32 @@ import axios, { AxiosRequestHeaders } from "axios" import { mutate } from "swr" -import * as Types from "./types" import * as TypesGen from "./typesGenerated" const CONTENT_TYPE_JSON: AxiosRequestHeaders = { "Content-Type": "application/json", } -export const provisioners: Types.Provisioner[] = [ +export const provisioners: TypesGen.ProvisionerDaemon[] = [ { id: "terraform", name: "Terraform", + created_at: "", + provisioners: [], }, { id: "cdr-basic", name: "Basic", + created_at: "", + provisioners: [], }, ] export namespace Workspace { - export const create = async (request: Types.CreateWorkspaceRequest): Promise => { - const response = await fetch(`/api/v2/organizations/${request.organization_id}/workspaces`, { + export const create = async ( + organizationId: string, + request: TypesGen.CreateWorkspaceRequest, + ): Promise => { + const response = await fetch(`/api/v2/organizations/${organizationId}/workspaces`, { method: "POST", headers: { "Content-Type": "application/json", @@ -43,13 +49,13 @@ export namespace Workspace { } } -export const login = async (email: string, password: string): Promise => { +export const login = async (email: string, password: string): Promise => { const payload = JSON.stringify({ email, password, }) - const response = await axios.post("/api/v2/users/login", payload, { + const response = await axios.post("/api/v2/users/login", payload, { headers: { ...CONTENT_TYPE_JSON }, }) @@ -60,8 +66,8 @@ export const logout = async (): Promise => { await axios.post("/api/v2/users/logout") } -export const getUser = async (): Promise => { - const response = await axios.get("/api/v2/users/me") +export const getUser = async (): Promise => { + const response = await axios.get("/api/v2/users/me") return response.data } @@ -70,8 +76,8 @@ export const getAuthMethods = async (): Promise => { return response.data } -export const getApiKey = async (): Promise => { - const response = await axios.post("/api/v2/users/me/keys") +export const getApiKey = async (): Promise => { + const response = await axios.post("/api/v2/users/me/keys") return response.data } @@ -80,23 +86,23 @@ export const getUsers = async (): Promise => { return response.data } -export const getOrganization = async (organizationId: string): Promise => { - const response = await axios.get(`/api/v2/organizations/${organizationId}`) +export const getOrganization = async (organizationId: string): Promise => { + const response = await axios.get(`/api/v2/organizations/${organizationId}`) return response.data } -export const getOrganizations = async (): Promise => { - const response = await axios.get("/api/v2/users/me/organizations") +export const getOrganizations = async (): Promise => { + const response = await axios.get("/api/v2/users/me/organizations") return response.data } -export const getTemplate = async (templateId: string): Promise => { - const response = await axios.get(`/api/v2/templates/${templateId}`) +export const getTemplate = async (templateId: string): Promise => { + const response = await axios.get(`/api/v2/templates/${templateId}`) return response.data } -export const getWorkspace = async (workspaceId: string): Promise => { - const response = await axios.get(`/api/v2/workspaces/${workspaceId}`) +export const getWorkspace = async (workspaceId: string): Promise => { + const response = await axios.get(`/api/v2/workspaces/${workspaceId}`) return response.data } @@ -104,31 +110,33 @@ export const getWorkspaceByOwnerAndName = async ( organizationID: string, username = "me", workspaceName: string, -): Promise => { - const response = await axios.get( +): Promise => { + const response = await axios.get( `/api/v2/organizations/${organizationID}/workspaces/${username}/${workspaceName}`, ) return response.data } -export const getWorkspaceResources = async (workspaceBuildID: string): Promise => { - const response = await axios.get(`/api/v2/workspacebuilds/${workspaceBuildID}/resources`) +export const getWorkspaceResources = async (workspaceBuildID: string): Promise => { + const response = await axios.get( + `/api/v2/workspacebuilds/${workspaceBuildID}/resources`, + ) return response.data } -export const createUser = async (user: Types.CreateUserRequest): Promise => { +export const createUser = async (user: TypesGen.CreateUserRequest): Promise => { const response = await axios.post("/api/v2/users", user) return response.data } -export const getBuildInfo = async (): Promise => { +export const getBuildInfo = async (): Promise => { const response = await axios.get("/api/v2/buildinfo") return response.data } export const putWorkspaceAutostart = async ( workspaceID: string, - autostart: Types.WorkspaceAutostartRequest, + autostart: TypesGen.UpdateWorkspaceAutostartRequest, ): Promise => { const payload = JSON.stringify(autostart) await axios.put(`/api/v2/workspaces/${workspaceID}/autostart`, payload, { @@ -138,7 +146,7 @@ export const putWorkspaceAutostart = async ( export const putWorkspaceAutostop = async ( workspaceID: string, - autostop: Types.WorkspaceAutostopRequest, + autostop: TypesGen.UpdateWorkspaceAutostopRequest, ): Promise => { const payload = JSON.stringify(autostop) await axios.put(`/api/v2/workspaces/${workspaceID}/autostop`, payload, { @@ -146,7 +154,10 @@ export const putWorkspaceAutostop = async ( }) } -export const updateProfile = async (userId: string, data: Types.UpdateProfileRequest): Promise => { +export const updateProfile = async ( + userId: string, + data: TypesGen.UpdateUserProfileRequest, +): Promise => { const response = await axios.put(`/api/v2/users/${userId}/profile`, data) return response.data } diff --git a/site/src/components/CreateUserForm/CreateUserForm.tsx b/site/src/components/CreateUserForm/CreateUserForm.tsx index f95e7fd0c8757..cc7e8fcdeab76 100644 --- a/site/src/components/CreateUserForm/CreateUserForm.tsx +++ b/site/src/components/CreateUserForm/CreateUserForm.tsx @@ -3,7 +3,7 @@ import TextField from "@material-ui/core/TextField" import { FormikContextType, FormikErrors, useFormik } from "formik" import React from "react" import * as Yup from "yup" -import { CreateUserRequest } from "../../api/types" +import * as TypesGen from "../../api/typesGenerated" import { getFormHelpers, onChangeTrimmed } from "../../util/formUtils" import { FormFooter } from "../FormFooter/FormFooter" import { FullPageForm } from "../FullPageForm/FullPageForm" @@ -21,9 +21,9 @@ export const Language = { } export interface CreateUserFormProps { - onSubmit: (user: CreateUserRequest) => void + onSubmit: (user: TypesGen.CreateUserRequest) => void onCancel: () => void - formErrors?: FormikErrors + formErrors?: FormikErrors isLoading: boolean error?: string myOrgId: string @@ -43,7 +43,7 @@ export const CreateUserForm: React.FC = ({ error, myOrgId, }) => { - const form: FormikContextType = useFormik({ + const form: FormikContextType = useFormik({ initialValues: { email: "", password: "", @@ -53,7 +53,7 @@ export const CreateUserForm: React.FC = ({ validationSchema, onSubmit, }) - const getFieldHelpers = getFormHelpers(form, formErrors) + const getFieldHelpers = getFormHelpers(form, formErrors) return ( diff --git a/site/src/components/Footer/Footer.tsx b/site/src/components/Footer/Footer.tsx index 6dded833c5c5c..c27b5c344aa25 100644 --- a/site/src/components/Footer/Footer.tsx +++ b/site/src/components/Footer/Footer.tsx @@ -3,11 +3,11 @@ import { makeStyles } from "@material-ui/core/styles" import Typography from "@material-ui/core/Typography" import { useActor } from "@xstate/react" import React, { useContext } from "react" -import { BuildInfoResponse } from "../../api/types" +import * as TypesGen from "../../api/typesGenerated" import { XServiceContext } from "../../xServices/StateContext" export const Language = { - buildInfoText: (buildInfo: BuildInfoResponse): string => { + buildInfoText: (buildInfo: TypesGen.BuildInfoResponse): string => { return `Coder ${buildInfo.version}` }, } diff --git a/site/src/components/NavbarView/NavbarView.tsx b/site/src/components/NavbarView/NavbarView.tsx index ad2108abf6f47..5f098718cd1e8 100644 --- a/site/src/components/NavbarView/NavbarView.tsx +++ b/site/src/components/NavbarView/NavbarView.tsx @@ -3,14 +3,14 @@ import ListItem from "@material-ui/core/ListItem" import { fade, makeStyles } from "@material-ui/core/styles" import React from "react" import { NavLink } from "react-router-dom" -import { UserResponse } from "../../api/types" +import * as TypesGen from "../../api/typesGenerated" import { navHeight } from "../../theme/constants" import { AdminDropdown } from "../AdminDropdown/AdminDropdown" import { Logo } from "../Icons/Logo" import { UserDropdown } from "../UserDropdown/UsersDropdown" export interface NavbarViewProps { - user?: UserResponse + user?: TypesGen.User onSignOut: () => void } diff --git a/site/src/components/UserDropdown/UsersDropdown.tsx b/site/src/components/UserDropdown/UsersDropdown.tsx index c7aa3ba49f47a..7c05c41efad29 100644 --- a/site/src/components/UserDropdown/UsersDropdown.tsx +++ b/site/src/components/UserDropdown/UsersDropdown.tsx @@ -7,7 +7,7 @@ import { fade, makeStyles } from "@material-ui/core/styles" import AccountIcon from "@material-ui/icons/AccountCircleOutlined" import React, { useState } from "react" import { Link } from "react-router-dom" -import { UserResponse } from "../../api/types" +import * as TypesGen from "../../api/typesGenerated" import { BorderedMenu } from "../BorderedMenu/BorderedMenu" import { CloseDropdown, OpenDropdown } from "../DropdownArrows/DropdownArrows" import { DocsIcon } from "../Icons/DocsIcon" @@ -21,7 +21,7 @@ export const Language = { signOutLabel: "Sign Out", } export interface UserDropdownProps { - user: UserResponse + user: TypesGen.User onSignOut: () => void } diff --git a/site/src/components/UserProfileCard/UserProfileCard.tsx b/site/src/components/UserProfileCard/UserProfileCard.tsx index 7e542335c5093..dc63b08ea2ef0 100644 --- a/site/src/components/UserProfileCard/UserProfileCard.tsx +++ b/site/src/components/UserProfileCard/UserProfileCard.tsx @@ -1,11 +1,11 @@ import { makeStyles } from "@material-ui/core/styles" import Typography from "@material-ui/core/Typography" import React from "react" -import { UserResponse } from "../../api/types" +import * as TypesGen from "../../api/typesGenerated" import { UserAvatar } from "../UserAvatar/UserAvatar" interface UserProfileCardProps { - user: UserResponse + user: TypesGen.User } export const UserProfileCard: React.FC = ({ user }) => { diff --git a/site/src/components/UsersTable/UsersTable.tsx b/site/src/components/UsersTable/UsersTable.tsx index 913ec85ea7c08..ec548cc47d6e8 100644 --- a/site/src/components/UsersTable/UsersTable.tsx +++ b/site/src/components/UsersTable/UsersTable.tsx @@ -5,7 +5,6 @@ import TableCell from "@material-ui/core/TableCell" import TableHead from "@material-ui/core/TableHead" import TableRow from "@material-ui/core/TableRow" import React from "react" -import { UserResponse } from "../../api/types" import * as TypesGen from "../../api/typesGenerated" import { EmptyState } from "../EmptyState/EmptyState" import { RoleSelect } from "../RoleSelect/RoleSelect" @@ -25,10 +24,10 @@ export const Language = { } export interface UsersTableProps { - users: UserResponse[] - onSuspendUser: (user: UserResponse) => void - onResetUserPassword: (user: UserResponse) => void - onUpdateUserRoles: (user: UserResponse, roles: TypesGen.Role["name"][]) => void + users: TypesGen.User[] + onSuspendUser: (user: TypesGen.User) => void + onResetUserPassword: (user: TypesGen.User) => void + onUpdateUserRoles: (user: TypesGen.User, roles: TypesGen.Role["name"][]) => void roles: TypesGen.Role[] isUpdatingUserRoles?: boolean } diff --git a/site/src/components/Workspace/Workspace.tsx b/site/src/components/Workspace/Workspace.tsx index b349569b51b29..3e8efdd8d271f 100644 --- a/site/src/components/Workspace/Workspace.tsx +++ b/site/src/components/Workspace/Workspace.tsx @@ -5,15 +5,15 @@ import Typography from "@material-ui/core/Typography" import CloudCircleIcon from "@material-ui/icons/CloudCircle" import React from "react" import { Link } from "react-router-dom" -import * as Types from "../../api/types" +import * as TypesGen from "../../api/typesGenerated" import { WorkspaceSchedule } from "../WorkspaceSchedule/WorkspaceSchedule" import { WorkspaceSection } from "../WorkspaceSection/WorkspaceSection" import * as Constants from "./constants" export interface WorkspaceProps { - organization: Types.Organization - workspace: Types.Workspace - template: Types.Template + organization: TypesGen.Organization + workspace: TypesGen.Workspace + template: TypesGen.Template } /** diff --git a/site/src/forms/CreateTemplateForm.tsx b/site/src/forms/CreateTemplateForm.tsx index 34b5568ccdb38..cfa6eb0eaca49 100644 --- a/site/src/forms/CreateTemplateForm.tsx +++ b/site/src/forms/CreateTemplateForm.tsx @@ -3,7 +3,7 @@ import { makeStyles } from "@material-ui/core/styles" import { FormikContextType, useFormik } from "formik" import React from "react" import * as Yup from "yup" -import { CreateTemplateRequest, Organization, Provisioner, Template } from "../api/types" +import * as TypesGen from "../api/typesGenerated" import { FormCloseButton } from "../components/FormCloseButton/FormCloseButton" import { FormDropdownField, FormDropdownItem } from "../components/FormDropdownField/FormDropdownField" import { FormSection } from "../components/FormSection/FormSection" @@ -12,13 +12,21 @@ import { FormTitle } from "../components/FormTitle/FormTitle" import { LoadingButton } from "../components/LoadingButton/LoadingButton" import { maxWidth } from "../theme/constants" +// It appears that to create a template you need to create a template version +// and then a template so this contains the information to do both. +export type CreateTemplateRequest = TypesGen.CreateTemplateVersionRequest & Pick + export interface CreateTemplateFormProps { - provisioners: Provisioner[] - organizations: Organization[] - onSubmit: (request: CreateTemplateRequest) => Promise