refactor(site): Show immutable parameters in the settings (#7383)

This commit is contained in:
Bruno Quaresma 2023-05-03 14:40:47 -03:00 committed by GitHub
parent 434c4be9f1
commit 2ea438cf4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 449 additions and 236 deletions

View File

@ -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 = () => {
/>
<Route path="settings" element={<WorkspaceSettingsLayout />}>
<Route index element={<WorkspaceSettingsPage />} />
<Route
path="parameters"
element={<WorkspaceParametersPage />}
/>
<Route
path="schedule"
element={<WorkspaceSchedulePage />}

View File

@ -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 }> = ({
<SidebarNavItem href="" icon={<SidebarNavItemIcon icon={GeneralIcon} />}>
General
</SidebarNavItem>
<SidebarNavItem
href="parameters"
icon={<SidebarNavItemIcon icon={ParameterIcon} />}
>
Parameters
</SidebarNavItem>
<SidebarNavItem
href="schedule"
icon={<SidebarNavItemIcon icon={ScheduleIcon} />}

View File

@ -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<WorkspaceParametersFormValues>({
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<WorkspaceParametersFormValues>(
form,
error,
)
return (
<HorizontalForm onSubmit={form.handleSubmit} data-testid="form">
{mutableParameters.length > 0 && (
<FormSection
title={t("parameters")}
description={t("parametersDescription")}
>
<FormFields>
{mutableParameters.map((parameter, index) => (
<RichParameterInput
{...getFieldHelpers(
"rich_parameter_values[" + index + "].value",
)}
disabled={isSubmitting}
index={index}
key={parameter.name}
onChange={async (value) => {
await form.setFieldValue("rich_parameter_values." + index, {
name: parameter.name,
value: value,
})
}}
parameter={parameter}
initialValue={workspaceBuildParameterValue(
buildParameters,
parameter,
)}
/>
))}
</FormFields>
</FormSection>
)}
{/* They are displayed here only for visibility purposes */}
{immutableParameters.length > 0 && (
<FormSection
title="Immutable parameters"
description={
<>
These parameters are also provided by your Terraform configuration
but they{" "}
<strong>cannot be changed after creating the workspace.</strong>
</>
}
>
<FormFields>
{immutableParameters.map((parameter, index) => (
<RichParameterInput
disabled
{...getFieldHelpers(
"rich_parameter_values[" + index + "].value",
)}
index={index}
key={parameter.name}
onChange={async () => {
throw new Error(
"Cannot change immutable parameter after creation",
)
}}
parameter={parameter}
initialValue={workspaceBuildParameterValue(
buildParameters,
parameter,
)}
/>
))}
</FormFields>
</FormSection>
)}
<FormFooter onCancel={onCancel} isLoading={isSubmitting} />
</HorizontalForm>
)
}

View File

@ -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<typeof WorkspaceParametersPageView>
const Template: Story<WorkspaceParametersPageViewProps> = (args) => (
<WorkspaceParametersPageView {...args} />
)
export const Example = Template.bind({})
Example.args = {}

View File

@ -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(<WorkspaceParametersPage />, {
route: "/@test-user/test-workspace/settings",
path: "/@:username/:workspace/settings",
// Need this because after submit the user is redirected
extraRoutes: [{ path: "/@:username/:workspace", element: <div /> }],
})
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" },
],
})
})
})

View File

@ -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 (
<>
<Helmet>
<title>{pageTitle([workspace.name, "Parameters"])}</title>
</Helmet>
<WorkspaceParametersPageView
data={query.data}
submitError={mutation.error}
isSubmitting={mutation.isLoading}
onSubmit={mutation.mutate}
onCancel={() => {
navigate("../..")
}}
/>
</>
)
}
export type WorkspaceParametersPageViewProps = {
data: Awaited<ReturnType<typeof getWorkspaceParameters>> | 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 (
<>
<PageHeader className={styles.pageHeader}>
<PageHeaderTitle>Workspace parameters</PageHeaderTitle>
</PageHeader>
{data ? (
<WorkspaceParametersForm
buildParameters={data.buildParameters}
templateVersionRichParameters={data.templateVersionRichParameters}
error={submitError}
isSubmitting={isSubmitting}
onSubmit={onSubmit}
onCancel={onCancel}
/>
) : (
<Loader />
)}
</>
)
}
const useStyles = makeStyles(() => ({
pageHeader: {
paddingTop: 0,
},
}))
export default WorkspaceParametersPage

View File

@ -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<WorkspaceSettingsFormValue>({
const form = useFormik<WorkspaceSettingsFormValues>({
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<WorkspaceSettingsFormValue>(
const getFieldHelpers = getFormHelpers<WorkspaceSettingsFormValues>(
form,
error,
)
@ -76,36 +57,6 @@ export const WorkspaceSettingsForm: FC<{
/>
</FormFields>
</FormSection>
{mutableParameters.length > 0 && (
<FormSection
title={t("parameters")}
description={t("parametersDescription")}
>
<FormFields>
{mutableParameters.map((parameter, index) => (
<RichParameterInput
{...getFieldHelpers(
"rich_parameter_values[" + index + "].value",
)}
disabled={isSubmitting}
index={index}
key={parameter.name}
onChange={async (value) => {
await form.setFieldValue("rich_parameter_values." + index, {
name: parameter.name,
value: value,
})
}}
parameter={parameter}
initialValue={workspaceBuildParameterValue(
settings.buildParameters,
parameter,
)}
/>
))}
</FormFields>
</FormSection>
)}
<FormFooter onCancel={onCancel} isLoading={isSubmitting} />
</HorizontalForm>
)

View File

@ -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(<WorkspaceSettingsPage />, {
@ -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" },
],
})
})

View File

@ -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 = () => {
</Helmet>
<WorkspaceSettingsPageView
formError={updateSettings.error}
loadingError={error}
isLoading={isLoading}
isSubmitting={updateSettings.isLoading}
settings={settings}
error={mutation.error}
isSubmitting={mutation.isLoading}
workspace={workspace}
onCancel={() => navigate(`/@${username}/${workspaceName}`)}
onSubmit={updateSettings.mutate}
onSubmit={mutation.mutate}
/>
</>
)

View File

@ -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<typeof WorkspaceSettingsPageView>

View File

@ -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<typeof WorkspaceSettingsForm>["onSubmit"]
}
export const WorkspaceSettingsPageView: FC<WorkspaceSettingsPageViewProps> = ({
onCancel,
onSubmit,
isLoading,
isSubmitting,
settings,
formError,
loadingError,
error,
workspace,
}) => {
const { t } = useTranslation("workspaceSettingsPage")
const styles = useStyles()
@ -35,17 +29,13 @@ export const WorkspaceSettingsPageView: FC<WorkspaceSettingsPageViewProps> = ({
<PageHeaderTitle>{t("title")}</PageHeaderTitle>
</PageHeader>
{loadingError && <AlertBanner error={loadingError} severity="error" />}
{isLoading && <Loader />}
{settings && (
<WorkspaceSettingsForm
error={formError}
isSubmitting={isSubmitting}
settings={settings}
onCancel={onCancel}
onSubmit={onSubmit}
/>
)}
<WorkspaceSettingsForm
error={error}
isSubmitting={isSubmitting}
workspace={workspace}
onCancel={onCancel}
onSubmit={onSubmit}
/>
</>
)
}

View File

@ -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<ReturnType<typeof getWorkspaceSettings>>
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<ReturnType<typeof updateWorkspaceSettings>>,
) => 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,
})
}

View File

@ -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",