diff --git a/site/src/AppRouter.tsx b/site/src/AppRouter.tsx index 599d410d07f02..8bfd505949f82 100644 --- a/site/src/AppRouter.tsx +++ b/site/src/AppRouter.tsx @@ -55,6 +55,12 @@ const WorkspaceSchedulePage = lazy( "./pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceSchedulePage" ), ) +const WorkspaceParametersPage = lazy( + () => + import( + "./pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPage" + ), +) const TerminalPage = lazy(() => import("./pages/TerminalPage/TerminalPage")) const TemplatePermissionsPage = lazy( () => @@ -291,6 +297,10 @@ export const AppRouter: FC = () => { /> }> } /> + } + /> } diff --git a/site/src/api/api.ts b/site/src/api/api.ts index 1613a52384618..31a634997427d 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -1021,7 +1021,7 @@ export const getWorkspaceBuildParameters = async ( return response.data } type Claims = { - license_expires?: jwt.NumericDate + license_expires?: number account_type?: string account_id?: string trial: boolean diff --git a/site/src/pages/WorkspaceSettingsPage/Sidebar.tsx b/site/src/pages/WorkspaceSettingsPage/Sidebar.tsx index c325d3a4cb8f1..b53f80bd8a6b9 100644 --- a/site/src/pages/WorkspaceSettingsPage/Sidebar.tsx +++ b/site/src/pages/WorkspaceSettingsPage/Sidebar.tsx @@ -6,6 +6,7 @@ import { FC, ElementType, PropsWithChildren, ReactNode } from "react" import { Link, NavLink } from "react-router-dom" import { combineClasses } from "utils/combineClasses" import GeneralIcon from "@material-ui/icons/SettingsOutlined" +import ParameterIcon from "@material-ui/icons/CodeOutlined" import { Avatar } from "components/Avatar/Avatar" const SidebarNavItem: FC< @@ -65,6 +66,12 @@ export const Sidebar: React.FC<{ username: string; workspace: Workspace }> = ({ }> General + } + > + Parameters + } diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersForm.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersForm.tsx new file mode 100644 index 0000000000000..f1b380298469b --- /dev/null +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersForm.tsx @@ -0,0 +1,147 @@ +import { + FormFields, + FormFooter, + FormSection, + HorizontalForm, +} from "components/Form/Form" +import { RichParameterInput } from "components/RichParameterInput/RichParameterInput" +import { useFormik } from "formik" +import { FC } from "react" +import { useTranslation } from "react-i18next" +import { + useValidationSchemaForRichParameters, + workspaceBuildParameterValue, +} from "utils/richParameters" +import * as Yup from "yup" +import { getFormHelpers } from "utils/formUtils" +import { + TemplateVersionParameter, + WorkspaceBuildParameter, +} from "api/typesGenerated" + +export type WorkspaceParametersFormValues = { + rich_parameter_values: WorkspaceBuildParameter[] +} + +export const WorkspaceParametersForm: FC<{ + isSubmitting: boolean + templateVersionRichParameters: TemplateVersionParameter[] + buildParameters: WorkspaceBuildParameter[] + error: unknown + onCancel: () => void + onSubmit: (values: WorkspaceParametersFormValues) => void +}> = ({ + onCancel, + onSubmit, + templateVersionRichParameters, + buildParameters, + error, + isSubmitting, +}) => { + const { t } = useTranslation("workspaceSettingsPage") + const mutableParameters = templateVersionRichParameters.filter( + (param) => param.mutable === true, + ) + const immutableParameters = templateVersionRichParameters.filter( + (param) => param.mutable === false, + ) + const form = useFormik({ + onSubmit, + initialValues: { + rich_parameter_values: mutableParameters.map((parameter) => { + const buildParameter = buildParameters.find( + (p) => p.name === parameter.name, + ) + if (!buildParameter) { + return { + name: parameter.name, + value: parameter.default_value, + } + } + return buildParameter + }), + }, + validationSchema: Yup.object({ + rich_parameter_values: useValidationSchemaForRichParameters( + "createWorkspacePage", + templateVersionRichParameters, + ), + }), + }) + const getFieldHelpers = getFormHelpers( + form, + error, + ) + + return ( + + {mutableParameters.length > 0 && ( + + + {mutableParameters.map((parameter, index) => ( + { + await form.setFieldValue("rich_parameter_values." + index, { + name: parameter.name, + value: value, + }) + }} + parameter={parameter} + initialValue={workspaceBuildParameterValue( + buildParameters, + parameter, + )} + /> + ))} + + + )} + {/* They are displayed here only for visibility purposes */} + {immutableParameters.length > 0 && ( + + These parameters are also provided by your Terraform configuration + but they{" "} + cannot be changed after creating the workspace. + + } + > + + {immutableParameters.map((parameter, index) => ( + { + throw new Error( + "Cannot change immutable parameter after creation", + ) + }} + parameter={parameter} + initialValue={workspaceBuildParameterValue( + buildParameters, + parameter, + )} + /> + ))} + + + )} + + + ) +} diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPage.stories.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPage.stories.tsx new file mode 100644 index 0000000000000..6639674566251 --- /dev/null +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPage.stories.tsx @@ -0,0 +1,46 @@ +import { ComponentMeta, Story } from "@storybook/react" +import { + WorkspaceParametersPageView, + WorkspaceParametersPageViewProps, +} from "./WorkspaceParametersPage" +import { action } from "@storybook/addon-actions" +import { + MockWorkspaceBuildParameter1, + MockWorkspaceBuildParameter2, + MockTemplateVersionParameter1, + MockTemplateVersionParameter2, + MockTemplateVersionParameter3, + MockWorkspaceBuildParameter3, +} from "testHelpers/entities" + +export default { + title: "pages/WorkspaceParametersPageView", + component: WorkspaceParametersPageView, + args: { + submitError: undefined, + isSubmitting: false, + onCancel: action("cancel"), + data: { + buildParameters: [ + MockWorkspaceBuildParameter1, + MockWorkspaceBuildParameter2, + MockWorkspaceBuildParameter3, + ], + templateVersionRichParameters: [ + MockTemplateVersionParameter1, + MockTemplateVersionParameter2, + { + ...MockTemplateVersionParameter3, + mutable: false, + }, + ], + }, + }, +} as ComponentMeta + +const Template: Story = (args) => ( + +) + +export const Example = Template.bind({}) +Example.args = {} diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPage.test.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPage.test.tsx new file mode 100644 index 0000000000000..aae32a16c175d --- /dev/null +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPage.test.tsx @@ -0,0 +1,73 @@ +import userEvent from "@testing-library/user-event" +import { + renderWithWorkspaceSettingsLayout, + waitForLoaderToBeRemoved, +} from "testHelpers/renderHelpers" +import WorkspaceParametersPage from "./WorkspaceParametersPage" +import { screen, waitFor, within } from "@testing-library/react" +import * as api from "api/api" +import { + MockWorkspace, + MockTemplateVersionParameter1, + MockTemplateVersionParameter2, + MockWorkspaceBuildParameter1, + MockWorkspaceBuildParameter2, + MockWorkspaceBuild, +} from "testHelpers/entities" + +test("Submit the workspace settings page successfully", async () => { + // Mock the API calls that loads data + jest + .spyOn(api, "getWorkspaceByOwnerAndName") + .mockResolvedValueOnce(MockWorkspace) + jest + .spyOn(api, "getTemplateVersionRichParameters") + .mockResolvedValueOnce([ + MockTemplateVersionParameter1, + MockTemplateVersionParameter2, + ]) + jest + .spyOn(api, "getWorkspaceBuildParameters") + .mockResolvedValueOnce([ + MockWorkspaceBuildParameter1, + MockWorkspaceBuildParameter2, + ]) + // Mock the API calls that submit data + const postWorkspaceBuildSpy = jest + .spyOn(api, "postWorkspaceBuild") + .mockResolvedValue(MockWorkspaceBuild) + // Setup event and rendering + const user = userEvent.setup() + renderWithWorkspaceSettingsLayout(, { + route: "/@test-user/test-workspace/settings", + path: "/@:username/:workspace/settings", + // Need this because after submit the user is redirected + extraRoutes: [{ path: "/@:username/:workspace", element:
}], + }) + await waitForLoaderToBeRemoved() + // Fill the form and submit + const form = screen.getByTestId("form") + const parameter1 = within(form).getByLabelText( + MockWorkspaceBuildParameter1.name, + { exact: false }, + ) + await user.clear(parameter1) + await user.type(parameter1, "new-value") + const parameter2 = within(form).getByLabelText( + MockWorkspaceBuildParameter2.name, + { exact: false }, + ) + await user.clear(parameter2) + await user.type(parameter2, "1") + await user.click(within(form).getByRole("button", { name: "Submit" })) + // Assert that the API calls were made with the correct data + await waitFor(() => { + expect(postWorkspaceBuildSpy).toHaveBeenCalledWith(MockWorkspace.id, { + transition: "start", + rich_parameter_values: [ + { name: MockTemplateVersionParameter1.name, value: "new-value" }, + { name: MockTemplateVersionParameter2.name, value: "1" }, + ], + }) + }) +}) diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPage.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPage.tsx new file mode 100644 index 0000000000000..5b9795d13a755 --- /dev/null +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPage.tsx @@ -0,0 +1,115 @@ +import { + getTemplateVersionRichParameters, + getWorkspaceBuildParameters, + postWorkspaceBuild, +} from "api/api" +import { Workspace } from "api/typesGenerated" +import { Helmet } from "react-helmet-async" +import { pageTitle } from "utils/page" +import { useWorkspaceSettingsContext } from "../WorkspaceSettingsLayout" +import { useMutation, useQuery } from "@tanstack/react-query" +import { Loader } from "components/Loader/Loader" +import { + WorkspaceParametersFormValues, + WorkspaceParametersForm, +} from "./WorkspaceParametersForm" +import { useNavigate } from "react-router-dom" +import { makeStyles } from "@material-ui/core/styles" +import { PageHeader, PageHeaderTitle } from "components/PageHeader/PageHeader" +import { displaySuccess } from "components/GlobalSnackbar/utils" +import { FC } from "react" + +const getWorkspaceParameters = async (workspace: Workspace) => { + const latestBuild = workspace.latest_build + const [templateVersionRichParameters, buildParameters] = await Promise.all([ + getTemplateVersionRichParameters(latestBuild.template_version_id), + getWorkspaceBuildParameters(latestBuild.id), + ]) + return { + templateVersionRichParameters, + buildParameters, + } +} + +const WorkspaceParametersPage = () => { + const { workspace } = useWorkspaceSettingsContext() + const query = useQuery({ + queryKey: ["workspaceSettings", workspace.id], + queryFn: () => getWorkspaceParameters(workspace), + }) + const navigate = useNavigate() + const mutation = useMutation({ + mutationFn: (formValues: WorkspaceParametersFormValues) => + postWorkspaceBuild(workspace.id, { + transition: "start", + rich_parameter_values: formValues.rich_parameter_values, + }), + onSuccess: () => { + displaySuccess( + "Parameters updated successfully", + "A new build was started to apply the new parameters", + ) + }, + }) + + return ( + <> + + {pageTitle([workspace.name, "Parameters"])} + + + { + navigate("../..") + }} + /> + + ) +} + +export type WorkspaceParametersPageViewProps = { + data: Awaited> | undefined + submitError: unknown + isSubmitting: boolean + onSubmit: (formValues: WorkspaceParametersFormValues) => void + onCancel: () => void +} + +export const WorkspaceParametersPageView: FC< + WorkspaceParametersPageViewProps +> = ({ data, submitError, isSubmitting, onSubmit, onCancel }) => { + const styles = useStyles() + + return ( + <> + + Workspace parameters + + + {data ? ( + + ) : ( + + )} + + ) +} + +const useStyles = makeStyles(() => ({ + pageHeader: { + paddingTop: 0, + }, +})) + +export default WorkspaceParametersPage diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceSettingsForm.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceSettingsForm.tsx index ef3a7ce4ad488..33f2e36019819 100644 --- a/site/src/pages/WorkspaceSettingsPage/WorkspaceSettingsForm.tsx +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceSettingsForm.tsx @@ -4,56 +4,37 @@ import { FormSection, HorizontalForm, } from "components/Form/Form" -import { RichParameterInput } from "components/RichParameterInput/RichParameterInput" import { useFormik } from "formik" import { FC } from "react" import { useTranslation } from "react-i18next" -import { - useValidationSchemaForRichParameters, - workspaceBuildParameterValue, -} from "utils/richParameters" -import { WorkspaceSettings, WorkspaceSettingsFormValue } from "./data" import * as Yup from "yup" import { nameValidator, getFormHelpers, onChangeTrimmed } from "utils/formUtils" import TextField from "@material-ui/core/TextField" +import { Workspace } from "api/typesGenerated" + +export type WorkspaceSettingsFormValues = { + name: string +} export const WorkspaceSettingsForm: FC<{ isSubmitting: boolean - settings: WorkspaceSettings + workspace: Workspace error: unknown onCancel: () => void - onSubmit: (values: WorkspaceSettingsFormValue) => void -}> = ({ onCancel, onSubmit, settings, error, isSubmitting }) => { + onSubmit: (values: WorkspaceSettingsFormValues) => void +}> = ({ onCancel, onSubmit, workspace, error, isSubmitting }) => { const { t } = useTranslation("workspaceSettingsPage") - const mutableParameters = settings.templateVersionRichParameters.filter( - (param) => param.mutable, - ) - const form = useFormik({ + + const form = useFormik({ onSubmit, initialValues: { - name: settings.workspace.name, - rich_parameter_values: mutableParameters.map((parameter) => { - const buildParameter = settings.buildParameters.find( - (p) => p.name === parameter.name, - ) - if (!buildParameter) { - return { - name: parameter.name, - value: parameter.default_value, - } - } - return buildParameter - }), + name: workspace.name, }, validationSchema: Yup.object({ name: nameValidator(t("nameLabel")), - rich_parameter_values: useValidationSchemaForRichParameters( - "createWorkspacePage", - settings.templateVersionRichParameters, - ), }), }) - const getFieldHelpers = getFormHelpers( + const getFieldHelpers = getFormHelpers( form, error, ) @@ -76,36 +57,6 @@ export const WorkspaceSettingsForm: FC<{ /> - {mutableParameters.length > 0 && ( - - - {mutableParameters.map((parameter, index) => ( - { - await form.setFieldValue("rich_parameter_values." + index, { - name: parameter.name, - value: value, - }) - }} - parameter={parameter} - initialValue={workspaceBuildParameterValue( - settings.buildParameters, - parameter, - )} - /> - ))} - - - )} ) diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceSettingsPage.test.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceSettingsPage.test.tsx index 39c48363fbf63..049fc97f131d7 100644 --- a/site/src/pages/WorkspaceSettingsPage/WorkspaceSettingsPage.test.tsx +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceSettingsPage.test.tsx @@ -6,39 +6,17 @@ import { import WorkspaceSettingsPage from "./WorkspaceSettingsPage" import { screen, waitFor, within } from "@testing-library/react" import * as api from "api/api" -import { - MockWorkspace, - MockTemplateVersionParameter1, - MockTemplateVersionParameter2, - MockWorkspaceBuildParameter1, - MockWorkspaceBuildParameter2, - MockWorkspaceBuild, -} from "testHelpers/entities" +import { MockWorkspace } from "testHelpers/entities" test("Submit the workspace settings page successfully", async () => { // Mock the API calls that loads data jest .spyOn(api, "getWorkspaceByOwnerAndName") .mockResolvedValueOnce(MockWorkspace) - jest - .spyOn(api, "getTemplateVersionRichParameters") - .mockResolvedValueOnce([ - MockTemplateVersionParameter1, - MockTemplateVersionParameter2, - ]) - jest - .spyOn(api, "getWorkspaceBuildParameters") - .mockResolvedValueOnce([ - MockWorkspaceBuildParameter1, - MockWorkspaceBuildParameter2, - ]) // Mock the API calls that submit data const patchWorkspaceSpy = jest .spyOn(api, "patchWorkspace") .mockResolvedValue() - const postWorkspaceBuildSpy = jest - .spyOn(api, "postWorkspaceBuild") - .mockResolvedValue(MockWorkspaceBuild) // Setup event and rendering const user = userEvent.setup() renderWithWorkspaceSettingsLayout(, { @@ -53,18 +31,6 @@ test("Submit the workspace settings page successfully", async () => { const name = within(form).getByLabelText("Name") await user.clear(name) await user.type(within(form).getByLabelText("Name"), "new-name") - const parameter1 = within(form).getByLabelText( - MockWorkspaceBuildParameter1.name, - { exact: false }, - ) - await user.clear(parameter1) - await user.type(parameter1, "new-value") - const parameter2 = within(form).getByLabelText( - MockWorkspaceBuildParameter2.name, - { exact: false }, - ) - await user.clear(parameter2) - await user.type(parameter2, "1") await user.click(within(form).getByRole("button", { name: "Submit" })) // Assert that the API calls were made with the correct data await waitFor(() => { @@ -72,11 +38,4 @@ test("Submit the workspace settings page successfully", async () => { name: "new-name", }) }) - expect(postWorkspaceBuildSpy).toHaveBeenCalledWith(MockWorkspace.id, { - transition: "start", - rich_parameter_values: [ - { name: MockTemplateVersionParameter1.name, value: "new-value" }, - { name: MockTemplateVersionParameter2.name, value: "1" }, - ], - }) }) diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceSettingsPage.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceSettingsPage.tsx index ac7ea30e73cad..0e3fc4f06dec4 100644 --- a/site/src/pages/WorkspaceSettingsPage/WorkspaceSettingsPage.tsx +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceSettingsPage.tsx @@ -1,28 +1,27 @@ -import { getErrorMessage } from "api/errors" -import { displayError } from "components/GlobalSnackbar/utils" import { Helmet } from "react-helmet-async" -import { useTranslation } from "react-i18next" import { useNavigate, useParams } from "react-router-dom" import { pageTitle } from "utils/page" -import { useUpdateWorkspaceSettings, useWorkspaceSettings } from "./data" import { useWorkspaceSettingsContext } from "./WorkspaceSettingsLayout" import { WorkspaceSettingsPageView } from "./WorkspaceSettingsPageView" +import { useMutation } from "@tanstack/react-query" +import { displaySuccess } from "components/GlobalSnackbar/utils" +import { patchWorkspace } from "api/api" +import { WorkspaceSettingsFormValues } from "./WorkspaceSettingsForm" const WorkspaceSettingsPage = () => { - const { t } = useTranslation("workspaceSettingsPage") const { username, workspace: workspaceName } = useParams() as { username: string workspace: string } const { workspace } = useWorkspaceSettingsContext() - const { data: settings, error, isLoading } = useWorkspaceSettings(workspace) const navigate = useNavigate() - const updateSettings = useUpdateWorkspaceSettings(workspace.id, { - onSuccess: ({ name }) => { - navigate(`/@${username}/${name}`) + const mutation = useMutation({ + mutationFn: (formValues: WorkspaceSettingsFormValues) => + patchWorkspace(workspace.id, { name: formValues.name }), + onSuccess: (_, formValues) => { + displaySuccess("Workspace updated successfully") + navigate(`/@${username}/${formValues.name}/settings`) }, - onError: (error) => - displayError(getErrorMessage(error, t("defaultErrorMessage"))), }) return ( @@ -32,13 +31,11 @@ const WorkspaceSettingsPage = () => { navigate(`/@${username}/${workspaceName}`)} - onSubmit={updateSettings.mutate} + onSubmit={mutation.mutate} /> ) diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceSettingsPageView.stories.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceSettingsPageView.stories.tsx index cc32594a7c759..eb21ad342fb86 100644 --- a/site/src/pages/WorkspaceSettingsPage/WorkspaceSettingsPageView.stories.tsx +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceSettingsPageView.stories.tsx @@ -1,35 +1,19 @@ import { ComponentMeta, Story } from "@storybook/react" -import { - MockTemplateVersionParameter1, - MockTemplateVersionParameter2, - MockWorkspace, - MockWorkspaceBuildParameter1, - MockWorkspaceBuildParameter2, -} from "testHelpers/entities" +import { MockWorkspace } from "testHelpers/entities" import { WorkspaceSettingsPageView, WorkspaceSettingsPageViewProps, } from "./WorkspaceSettingsPageView" +import { action } from "@storybook/addon-actions" export default { title: "pages/WorkspaceSettingsPageView", component: WorkspaceSettingsPageView, args: { - formError: undefined, - loadingError: undefined, - isLoading: false, + error: undefined, isSubmitting: false, - settings: { - workspace: MockWorkspace, - buildParameters: [ - MockWorkspaceBuildParameter1, - MockWorkspaceBuildParameter2, - ], - templateVersionRichParameters: [ - MockTemplateVersionParameter1, - MockTemplateVersionParameter2, - ], - }, + workspace: MockWorkspace, + onCancel: action("cancel"), }, } as ComponentMeta diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceSettingsPageView.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceSettingsPageView.tsx index 99bf6342ab885..4460428e51362 100644 --- a/site/src/pages/WorkspaceSettingsPage/WorkspaceSettingsPageView.tsx +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceSettingsPageView.tsx @@ -1,30 +1,24 @@ import { makeStyles } from "@material-ui/core/styles" -import { AlertBanner } from "components/AlertBanner/AlertBanner" -import { Loader } from "components/Loader/Loader" import { PageHeader, PageHeaderTitle } from "components/PageHeader/PageHeader" -import { FC } from "react" +import { ComponentProps, FC } from "react" import { useTranslation } from "react-i18next" -import { WorkspaceSettings, WorkspaceSettingsFormValue } from "./data" import { WorkspaceSettingsForm } from "./WorkspaceSettingsForm" +import { Workspace } from "api/typesGenerated" export type WorkspaceSettingsPageViewProps = { - formError: unknown - loadingError: unknown - isLoading: boolean + error: unknown isSubmitting: boolean - settings: WorkspaceSettings | undefined + workspace: Workspace onCancel: () => void - onSubmit: (formValues: WorkspaceSettingsFormValue) => void + onSubmit: ComponentProps["onSubmit"] } export const WorkspaceSettingsPageView: FC = ({ onCancel, onSubmit, - isLoading, isSubmitting, - settings, - formError, - loadingError, + error, + workspace, }) => { const { t } = useTranslation("workspaceSettingsPage") const styles = useStyles() @@ -35,17 +29,13 @@ export const WorkspaceSettingsPageView: FC = ({ {t("title")} - {loadingError && } - {isLoading && } - {settings && ( - - )} + ) } diff --git a/site/src/pages/WorkspaceSettingsPage/data.ts b/site/src/pages/WorkspaceSettingsPage/data.ts deleted file mode 100644 index 46e72b5b33616..0000000000000 --- a/site/src/pages/WorkspaceSettingsPage/data.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { useMutation, useQuery } from "@tanstack/react-query" -import { - getWorkspaceBuildParameters, - getTemplateVersionRichParameters, - patchWorkspace, - postWorkspaceBuild, -} from "api/api" -import { Workspace, WorkspaceBuildParameter } from "api/typesGenerated" - -const getWorkspaceSettings = async (workspace: Workspace) => { - const latestBuild = workspace.latest_build - const [templateVersionRichParameters, buildParameters] = await Promise.all([ - getTemplateVersionRichParameters(latestBuild.template_version_id), - getWorkspaceBuildParameters(latestBuild.id), - ]) - return { - workspace, - templateVersionRichParameters, - buildParameters, - } -} - -export const useWorkspaceSettings = (workspace: Workspace) => { - return useQuery({ - queryKey: ["workspaceSettings", workspace.id], - queryFn: () => getWorkspaceSettings(workspace), - }) -} - -export type WorkspaceSettings = Awaited> - -export type WorkspaceSettingsFormValue = { - name: string - rich_parameter_values: WorkspaceBuildParameter[] -} - -const updateWorkspaceSettings = async ( - workspaceId: string, - formValues: WorkspaceSettingsFormValue, -) => { - await Promise.all([ - patchWorkspace(workspaceId, { name: formValues.name }), - postWorkspaceBuild(workspaceId, { - transition: "start", - rich_parameter_values: formValues.rich_parameter_values, - }), - ]) - - return formValues // So we can get then on the onSuccess callback -} - -export const useUpdateWorkspaceSettings = ( - workspaceId?: string, - options?: { - onSuccess?: ( - result: Awaited>, - ) => void - onError?: (error: unknown) => void - }, -) => { - return useMutation({ - mutationFn: (formValues: WorkspaceSettingsFormValue) => { - if (!workspaceId) { - throw new Error("No workspace id") - } - return updateWorkspaceSettings(workspaceId, formValues) - }, - onSuccess: options?.onSuccess, - onError: options?.onError, - }) -} diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index c0df35ba41fc1..91dc24132f009 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -1532,6 +1532,11 @@ export const MockWorkspaceBuildParameter2: TypesGen.WorkspaceBuildParameter = { value: "3", } +export const MockWorkspaceBuildParameter3: TypesGen.WorkspaceBuildParameter = { + name: MockTemplateVersionParameter3.name, + value: "my-database", +} + export const MockWorkspaceBuildParameter5: TypesGen.WorkspaceBuildParameter = { name: MockTemplateVersionParameter5.name, value: "5",