mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
refactor(site): refactor rich parameter input and form initial data (#9440)
This commit is contained in:
@@ -5,12 +5,14 @@ import { FC } from "react"
|
||||
|
||||
export type MultiTextFieldProps = {
|
||||
label: string
|
||||
id?: string
|
||||
values: string[]
|
||||
onChange: (values: string[]) => void
|
||||
}
|
||||
|
||||
export const MultiTextField: FC<MultiTextFieldProps> = ({
|
||||
label,
|
||||
id,
|
||||
values,
|
||||
onChange,
|
||||
}) => {
|
||||
@@ -30,6 +32,7 @@ export const MultiTextField: FC<MultiTextFieldProps> = ({
|
||||
/>
|
||||
))}
|
||||
<input
|
||||
id={id}
|
||||
aria-label={label}
|
||||
className={styles.input}
|
||||
onKeyDown={(event) => {
|
||||
|
||||
@@ -35,7 +35,7 @@ const createTemplateVersionParameter = (
|
||||
|
||||
export const Basic: Story = {
|
||||
args: {
|
||||
initialValue: "initial-value",
|
||||
value: "initial-value",
|
||||
id: "project_name",
|
||||
parameter: createTemplateVersionParameter({
|
||||
name: "project_name",
|
||||
@@ -47,7 +47,7 @@ export const Basic: Story = {
|
||||
|
||||
export const NumberType: Story = {
|
||||
args: {
|
||||
initialValue: "4",
|
||||
value: "4",
|
||||
id: "number_parameter",
|
||||
parameter: createTemplateVersionParameter({
|
||||
name: "number_parameter",
|
||||
@@ -59,7 +59,7 @@ export const NumberType: Story = {
|
||||
|
||||
export const BooleanType: Story = {
|
||||
args: {
|
||||
initialValue: "false",
|
||||
value: "false",
|
||||
id: "bool_parameter",
|
||||
parameter: createTemplateVersionParameter({
|
||||
name: "bool_parameter",
|
||||
@@ -71,7 +71,7 @@ export const BooleanType: Story = {
|
||||
|
||||
export const OptionsType: Story = {
|
||||
args: {
|
||||
initialValue: "first_option",
|
||||
value: "first_option",
|
||||
id: "options_parameter",
|
||||
parameter: createTemplateVersionParameter({
|
||||
name: "options_parameter",
|
||||
@@ -103,7 +103,7 @@ export const OptionsType: Story = {
|
||||
|
||||
export const ListStringType: Story = {
|
||||
args: {
|
||||
initialValue: JSON.stringify(["first", "second", "third"]),
|
||||
value: JSON.stringify(["first", "second", "third"]),
|
||||
id: "list_string_parameter",
|
||||
parameter: createTemplateVersionParameter({
|
||||
name: "list_string_parameter",
|
||||
@@ -115,7 +115,7 @@ export const ListStringType: Story = {
|
||||
|
||||
export const IconLabel: Story = {
|
||||
args: {
|
||||
initialValue: "initial-value",
|
||||
value: "initial-value",
|
||||
id: "project_name",
|
||||
parameter: createTemplateVersionParameter({
|
||||
name: "project_name",
|
||||
@@ -128,7 +128,7 @@ export const IconLabel: Story = {
|
||||
|
||||
export const NoDescription: Story = {
|
||||
args: {
|
||||
initialValue: "",
|
||||
value: "",
|
||||
id: "region",
|
||||
parameter: createTemplateVersionParameter({
|
||||
name: "Region",
|
||||
@@ -164,7 +164,7 @@ export const NoDescription: Story = {
|
||||
|
||||
export const DescriptionWithLinks: Story = {
|
||||
args: {
|
||||
initialValue: "",
|
||||
value: "",
|
||||
id: "coder-repository-directory",
|
||||
parameter: createTemplateVersionParameter({
|
||||
name: "Coder Repository Directory",
|
||||
@@ -183,7 +183,7 @@ export const DescriptionWithLinks: Story = {
|
||||
|
||||
export const BasicWithDisplayName: Story = {
|
||||
args: {
|
||||
initialValue: "initial-value",
|
||||
value: "initial-value",
|
||||
id: "project_name",
|
||||
parameter: createTemplateVersionParameter({
|
||||
name: "project_name",
|
||||
|
||||
@@ -4,7 +4,7 @@ import RadioGroup from "@mui/material/RadioGroup"
|
||||
import { makeStyles } from "@mui/styles"
|
||||
import TextField, { TextFieldProps } from "@mui/material/TextField"
|
||||
import { Stack } from "components/Stack/Stack"
|
||||
import { FC, useState } from "react"
|
||||
import { FC } from "react"
|
||||
import { TemplateVersionParameter } from "../../api/typesGenerated"
|
||||
import { colors } from "theme/colors"
|
||||
import { MemoizedMarkdown } from "components/Markdown/Markdown"
|
||||
@@ -17,11 +17,10 @@ const isBoolean = (parameter: TemplateVersionParameter) => {
|
||||
}
|
||||
|
||||
export interface ParameterLabelProps {
|
||||
id: string
|
||||
parameter: TemplateVersionParameter
|
||||
}
|
||||
|
||||
const ParameterLabel: FC<ParameterLabelProps> = ({ id, parameter }) => {
|
||||
const ParameterLabel: FC<ParameterLabelProps> = ({ parameter }) => {
|
||||
const styles = useStyles()
|
||||
const hasDescription = parameter.description && parameter.description !== ""
|
||||
const displayName = parameter.display_name
|
||||
@@ -29,7 +28,7 @@ const ParameterLabel: FC<ParameterLabelProps> = ({ id, parameter }) => {
|
||||
: parameter.name
|
||||
|
||||
return (
|
||||
<label htmlFor={id}>
|
||||
<label htmlFor={parameter.name}>
|
||||
<Stack direction="row" alignItems="center">
|
||||
{parameter.icon && (
|
||||
<span className={styles.labelIconWrapper}>
|
||||
@@ -60,22 +59,15 @@ type Size = "medium" | "small"
|
||||
|
||||
export type RichParameterInputProps = Omit<
|
||||
TextFieldProps,
|
||||
"onChange" | "size"
|
||||
"size" | "onChange"
|
||||
> & {
|
||||
index: number
|
||||
parameter: TemplateVersionParameter
|
||||
onChange: (value: string) => void
|
||||
initialValue?: string
|
||||
id: string
|
||||
size?: Size
|
||||
}
|
||||
|
||||
export const RichParameterInput: FC<RichParameterInputProps> = ({
|
||||
index,
|
||||
disabled,
|
||||
onChange,
|
||||
parameter,
|
||||
initialValue,
|
||||
size = "medium",
|
||||
...fieldProps
|
||||
}) => {
|
||||
@@ -86,16 +78,9 @@ export const RichParameterInput: FC<RichParameterInputProps> = ({
|
||||
className={size}
|
||||
data-testid={`parameter-field-${parameter.name}`}
|
||||
>
|
||||
<ParameterLabel id={fieldProps.id} parameter={parameter} />
|
||||
<ParameterLabel parameter={parameter} />
|
||||
<Box sx={{ display: "flex", flexDirection: "column" }}>
|
||||
<RichParameterField
|
||||
{...fieldProps}
|
||||
index={index}
|
||||
disabled={disabled}
|
||||
onChange={onChange}
|
||||
parameter={parameter}
|
||||
initialValue={initialValue}
|
||||
/>
|
||||
<RichParameterField {...fieldProps} size={size} parameter={parameter} />
|
||||
</Box>
|
||||
</Stack>
|
||||
)
|
||||
@@ -105,22 +90,20 @@ const RichParameterField: React.FC<RichParameterInputProps> = ({
|
||||
disabled,
|
||||
onChange,
|
||||
parameter,
|
||||
initialValue,
|
||||
value,
|
||||
size,
|
||||
...props
|
||||
}) => {
|
||||
const [parameterValue, setParameterValue] = useState(initialValue)
|
||||
const styles = useStyles()
|
||||
|
||||
if (isBoolean(parameter)) {
|
||||
return (
|
||||
<RadioGroup
|
||||
id={parameter.name}
|
||||
data-testid="parameter-field-bool"
|
||||
className={styles.radioGroup}
|
||||
defaultValue={parameterValue}
|
||||
onChange={(event) => {
|
||||
onChange(event.target.value)
|
||||
}}
|
||||
value={value}
|
||||
onChange={(_, value) => onChange(value)}
|
||||
>
|
||||
<FormControlLabel
|
||||
disabled={disabled}
|
||||
@@ -141,12 +124,11 @@ const RichParameterField: React.FC<RichParameterInputProps> = ({
|
||||
if (parameter.options.length > 0) {
|
||||
return (
|
||||
<RadioGroup
|
||||
id={parameter.name}
|
||||
data-testid="parameter-field-options"
|
||||
className={styles.radioGroup}
|
||||
defaultValue={parameterValue}
|
||||
onChange={(event) => {
|
||||
onChange(event.target.value)
|
||||
}}
|
||||
value={value}
|
||||
onChange={(_, value) => onChange(value)}
|
||||
>
|
||||
{parameter.options.map((option) => (
|
||||
<FormControlLabel
|
||||
@@ -178,9 +160,13 @@ const RichParameterField: React.FC<RichParameterInputProps> = ({
|
||||
if (parameter.type === "list(string)") {
|
||||
let values: string[] = []
|
||||
|
||||
if (parameterValue) {
|
||||
if (typeof value !== "string") {
|
||||
throw new Error("Expected value to be a string")
|
||||
}
|
||||
|
||||
if (value) {
|
||||
try {
|
||||
values = JSON.parse(parameterValue) as string[]
|
||||
values = JSON.parse(value) as string[]
|
||||
} catch (e) {
|
||||
console.error("Error parsing list(string) parameter", e)
|
||||
}
|
||||
@@ -188,13 +174,13 @@ const RichParameterField: React.FC<RichParameterInputProps> = ({
|
||||
|
||||
return (
|
||||
<MultiTextField
|
||||
id={parameter.name}
|
||||
data-testid="parameter-field-list-of-string"
|
||||
label={props.label as string}
|
||||
values={values}
|
||||
onChange={(values) => {
|
||||
try {
|
||||
const value = JSON.stringify(values)
|
||||
setParameterValue(value)
|
||||
onChange(value)
|
||||
} catch (e) {
|
||||
console.error("Error on change of list(string) parameter", e)
|
||||
@@ -210,15 +196,15 @@ const RichParameterField: React.FC<RichParameterInputProps> = ({
|
||||
return (
|
||||
<TextField
|
||||
{...props}
|
||||
id={parameter.name}
|
||||
data-testid="parameter-field-text"
|
||||
className={styles.textField}
|
||||
type={parameter.type}
|
||||
disabled={disabled}
|
||||
required={parameter.required}
|
||||
placeholder={parameter.default_value}
|
||||
value={parameterValue}
|
||||
value={value}
|
||||
onChange={(event) => {
|
||||
setParameterValue(event.target.value)
|
||||
onChange(event.target.value)
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -34,7 +34,6 @@ export const MutableTemplateParametersSection: FC<
|
||||
parameter.mutable && (
|
||||
<RichParameterInput
|
||||
{...getInputProps(parameter, index)}
|
||||
index={index}
|
||||
key={parameter.name}
|
||||
parameter={parameter}
|
||||
/>
|
||||
@@ -73,7 +72,6 @@ export const ImmutableTemplateParametersSection: FC<
|
||||
!parameter.mutable && (
|
||||
<RichParameterInput
|
||||
{...getInputProps(parameter, index)}
|
||||
index={index}
|
||||
key={parameter.name}
|
||||
parameter={parameter}
|
||||
/>
|
||||
|
||||
@@ -22,7 +22,7 @@ import { useFormik } from "formik"
|
||||
import { useRef, useState } from "react"
|
||||
import { docs } from "utils/docs"
|
||||
import { getFormHelpers } from "utils/formUtils"
|
||||
import { getInitialParameterValues } from "utils/richParameters"
|
||||
import { getInitialRichParameterValues } from "utils/richParameters"
|
||||
|
||||
export const BuildParametersPopover = ({
|
||||
workspace,
|
||||
@@ -148,7 +148,7 @@ const Form = ({
|
||||
}) => {
|
||||
const form = useFormik({
|
||||
initialValues: {
|
||||
rich_parameter_values: getInitialParameterValues(
|
||||
rich_parameter_values: getInitialRichParameterValues(
|
||||
ephemeralParameters,
|
||||
buildParameters,
|
||||
),
|
||||
@@ -168,8 +168,6 @@ const Form = ({
|
||||
{...getFieldHelpers("rich_parameter_values[" + index + "].value")}
|
||||
key={parameter.name}
|
||||
parameter={parameter}
|
||||
initialValue={form.values.rich_parameter_values[index]?.value}
|
||||
index={index}
|
||||
size="small"
|
||||
onChange={async (value) => {
|
||||
await form.setFieldValue(`rich_parameter_values[${index}]`, {
|
||||
|
||||
@@ -16,9 +16,8 @@ import {
|
||||
} from "components/Form/Form"
|
||||
import { makeStyles } from "@mui/styles"
|
||||
import {
|
||||
selectInitialRichParametersValues,
|
||||
getInitialRichParameterValues,
|
||||
useValidationSchemaForRichParameters,
|
||||
workspaceBuildParameterValue,
|
||||
} from "utils/richParameters"
|
||||
import {
|
||||
ImmutableTemplateParametersSection,
|
||||
@@ -55,10 +54,6 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = ({
|
||||
onSubmit,
|
||||
onCancel,
|
||||
}) => {
|
||||
const initialRichParameterValues = selectInitialRichParametersValues(
|
||||
parameters,
|
||||
defaultBuildParameters,
|
||||
)
|
||||
const { t } = useTranslation("createWorkspacePage")
|
||||
const styles = useStyles()
|
||||
const [owner, setOwner] = useState(defaultOwner)
|
||||
@@ -68,7 +63,10 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = ({
|
||||
initialValues: {
|
||||
name: defaultName,
|
||||
template_id: template.id,
|
||||
rich_parameter_values: initialRichParameterValues,
|
||||
rich_parameter_values: getInitialRichParameterValues(
|
||||
parameters,
|
||||
defaultBuildParameters,
|
||||
),
|
||||
},
|
||||
validationSchema: Yup.object({
|
||||
name: nameValidator(t("nameLabel", { ns: "createWorkspacePage" })),
|
||||
@@ -173,10 +171,6 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = ({
|
||||
value: value,
|
||||
})
|
||||
},
|
||||
initialValue: workspaceBuildParameterValue(
|
||||
initialRichParameterValues,
|
||||
parameter,
|
||||
),
|
||||
disabled: form.isSubmitting,
|
||||
}
|
||||
}}
|
||||
@@ -195,10 +189,6 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = ({
|
||||
value: value,
|
||||
})
|
||||
},
|
||||
initialValue: workspaceBuildParameterValue(
|
||||
initialRichParameterValues,
|
||||
parameter,
|
||||
),
|
||||
disabled: form.isSubmitting,
|
||||
}
|
||||
}}
|
||||
|
||||
@@ -17,13 +17,10 @@ import {
|
||||
TemplateParametersSectionProps,
|
||||
} from "components/TemplateParameters/TemplateParameters"
|
||||
import { useClipboard } from "hooks/useClipboard"
|
||||
import { FC, useState } from "react"
|
||||
import { FC, useEffect, useState } from "react"
|
||||
import { Helmet } from "react-helmet-async"
|
||||
import { pageTitle } from "utils/page"
|
||||
import {
|
||||
selectInitialRichParametersValues,
|
||||
workspaceBuildParameterValue,
|
||||
} from "utils/richParameters"
|
||||
import { getInitialRichParameterValues } from "utils/richParameters"
|
||||
import { paramsUsedToCreateWorkspace } from "utils/workspace"
|
||||
|
||||
type ButtonValues = Record<string, string>
|
||||
@@ -54,31 +51,23 @@ export const TemplateEmbedPageView: FC<{
|
||||
template: Template
|
||||
templateParameters?: TemplateVersionParameter[]
|
||||
}> = ({ template, templateParameters }) => {
|
||||
const [buttonValues, setButtonValues] = useState<ButtonValues>({
|
||||
mode: "manual",
|
||||
})
|
||||
const initialRichParametersValues = templateParameters
|
||||
? selectInitialRichParametersValues(templateParameters)
|
||||
: undefined
|
||||
const [buttonValues, setButtonValues] = useState<ButtonValues | undefined>(
|
||||
undefined,
|
||||
)
|
||||
const deploymentUrl = `${window.location.protocol}//${window.location.host}`
|
||||
const createWorkspaceUrl = `${deploymentUrl}/templates/${template.name}/workspace`
|
||||
const createWorkspaceParams = new URLSearchParams(buttonValues)
|
||||
const buttonUrl = `${createWorkspaceUrl}?${createWorkspaceParams.toString()}`
|
||||
const buttonMkdCode = `[](${buttonUrl})`
|
||||
const clipboard = useClipboard(buttonMkdCode)
|
||||
|
||||
const getInputProps: TemplateParametersSectionProps["getInputProps"] = (
|
||||
parameter,
|
||||
) => {
|
||||
if (!initialRichParametersValues) {
|
||||
throw new Error("initialRichParametersValues is undefined")
|
||||
if (!buttonValues) {
|
||||
throw new Error("buttonValues is undefined")
|
||||
}
|
||||
return {
|
||||
id: parameter.name,
|
||||
initialValue: workspaceBuildParameterValue(
|
||||
initialRichParametersValues,
|
||||
parameter,
|
||||
),
|
||||
value: buttonValues[`param.${parameter.name}`] ?? "",
|
||||
onChange: (value) => {
|
||||
setButtonValues((buttonValues) => ({
|
||||
...buttonValues,
|
||||
@@ -88,12 +77,28 @@ export const TemplateEmbedPageView: FC<{
|
||||
}
|
||||
}
|
||||
|
||||
// template parameters is async so we need to initialize the values after it
|
||||
// is loaded
|
||||
useEffect(() => {
|
||||
if (templateParameters && !buttonValues) {
|
||||
const buttonValues: ButtonValues = {
|
||||
mode: "manual",
|
||||
}
|
||||
for (const parameter of getInitialRichParameterValues(
|
||||
templateParameters,
|
||||
)) {
|
||||
buttonValues[`param.${parameter.name}`] = parameter.value
|
||||
}
|
||||
setButtonValues(buttonValues)
|
||||
}
|
||||
}, [buttonValues, templateParameters])
|
||||
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<title>{pageTitle(`${template.name} · Embed`)}</title>
|
||||
</Helmet>
|
||||
{!templateParameters ? (
|
||||
{!buttonValues || !templateParameters ? (
|
||||
<Loader />
|
||||
) : (
|
||||
<Box display="flex" alignItems="flex-start" gap={6}>
|
||||
|
||||
@@ -14,9 +14,8 @@ import {
|
||||
import { RichParameterInput } from "components/RichParameterInput/RichParameterInput"
|
||||
import { useFormik } from "formik"
|
||||
import {
|
||||
selectInitialRichParametersValues,
|
||||
getInitialRichParameterValues,
|
||||
useValidationSchemaForRichParameters,
|
||||
workspaceBuildParameterValue,
|
||||
} from "utils/richParameters"
|
||||
import * as Yup from "yup"
|
||||
import DialogActions from "@mui/material/DialogActions"
|
||||
@@ -26,18 +25,16 @@ import { useTranslation } from "react-i18next"
|
||||
export type UpdateBuildParametersDialogProps = DialogProps & {
|
||||
onClose: () => void
|
||||
onUpdate: (buildParameters: WorkspaceBuildParameter[]) => void
|
||||
missedParameters?: TemplateVersionParameter[]
|
||||
missedParameters: TemplateVersionParameter[]
|
||||
}
|
||||
|
||||
export const UpdateBuildParametersDialog: FC<
|
||||
UpdateBuildParametersDialogProps
|
||||
> = ({ missedParameters, onUpdate, ...dialogProps }) => {
|
||||
const styles = useStyles()
|
||||
const initialRichParameterValues =
|
||||
selectInitialRichParametersValues(missedParameters)
|
||||
const form = useFormik({
|
||||
initialValues: {
|
||||
rich_parameter_values: initialRichParameterValues,
|
||||
rich_parameter_values: getInitialRichParameterValues(missedParameters),
|
||||
},
|
||||
validationSchema: Yup.object({
|
||||
rich_parameter_values: useValidationSchemaForRichParameters(
|
||||
@@ -84,13 +81,8 @@ export const UpdateBuildParametersDialog: FC<
|
||||
{...getFieldHelpers(
|
||||
"rich_parameter_values[" + index + "].value",
|
||||
)}
|
||||
initialValue={workspaceBuildParameterValue(
|
||||
initialRichParameterValues,
|
||||
parameter,
|
||||
)}
|
||||
key={parameter.name}
|
||||
parameter={parameter}
|
||||
index={index}
|
||||
onChange={async (value) => {
|
||||
await form.setFieldValue(
|
||||
"rich_parameter_values." + index,
|
||||
|
||||
@@ -212,7 +212,7 @@ export const WorkspaceReadyPage = ({
|
||||
}}
|
||||
/>
|
||||
<UpdateBuildParametersDialog
|
||||
missedParameters={missedParameters}
|
||||
missedParameters={missedParameters ?? []}
|
||||
open={workspaceState.matches(
|
||||
"ready.build.askingForMissedBuildParameters",
|
||||
)}
|
||||
|
||||
+30
-45
@@ -9,9 +9,8 @@ import { useFormik } from "formik"
|
||||
import { FC } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import {
|
||||
getInitialParameterValues,
|
||||
getInitialRichParameterValues,
|
||||
useValidationSchemaForRichParameters,
|
||||
workspaceBuildParameterValue,
|
||||
} from "utils/richParameters"
|
||||
import * as Yup from "yup"
|
||||
import { getFormHelpers } from "utils/formUtils"
|
||||
@@ -40,17 +39,12 @@ export const WorkspaceParametersForm: FC<{
|
||||
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: getInitialParameterValues(
|
||||
mutableParameters,
|
||||
rich_parameter_values: getInitialRichParameterValues(
|
||||
templateVersionRichParameters,
|
||||
buildParameters,
|
||||
),
|
||||
},
|
||||
@@ -65,12 +59,15 @@ export const WorkspaceParametersForm: FC<{
|
||||
form,
|
||||
error,
|
||||
)
|
||||
const hasEphemeralParameters = mutableParameters.some(
|
||||
const hasEphemeralParameters = templateVersionRichParameters.some(
|
||||
(parameter) => parameter.ephemeral,
|
||||
)
|
||||
const hasNonEphemeralParameters = mutableParameters.some(
|
||||
const hasNonEphemeralParameters = templateVersionRichParameters.some(
|
||||
(parameter) => !parameter.ephemeral,
|
||||
)
|
||||
const hasImmutableParameters = templateVersionRichParameters.some(
|
||||
(parameter) => !parameter.mutable,
|
||||
)
|
||||
|
||||
return (
|
||||
<HorizontalForm onSubmit={form.handleSubmit} data-testid="form">
|
||||
@@ -80,16 +77,15 @@ export const WorkspaceParametersForm: FC<{
|
||||
description={t("parametersDescription").toString()}
|
||||
>
|
||||
<FormFields>
|
||||
{mutableParameters.map((parameter, index) =>
|
||||
{templateVersionRichParameters.map((parameter, index) =>
|
||||
// Since we are adding the values to the form based on the index
|
||||
// we can't filter them to not loose the right index position
|
||||
parameter.ephemeral ? null : (
|
||||
parameter.mutable && !parameter.ephemeral ? (
|
||||
<RichParameterInput
|
||||
{...getFieldHelpers(
|
||||
"rich_parameter_values[" + index + "].value",
|
||||
)}
|
||||
disabled={isSubmitting}
|
||||
index={index}
|
||||
key={parameter.name}
|
||||
onChange={async (value) => {
|
||||
await form.setFieldValue("rich_parameter_values." + index, {
|
||||
@@ -98,12 +94,8 @@ export const WorkspaceParametersForm: FC<{
|
||||
})
|
||||
}}
|
||||
parameter={parameter}
|
||||
initialValue={workspaceBuildParameterValue(
|
||||
buildParameters,
|
||||
parameter,
|
||||
)}
|
||||
/>
|
||||
),
|
||||
) : null,
|
||||
)}
|
||||
</FormFields>
|
||||
</FormSection>
|
||||
@@ -114,16 +106,15 @@ export const WorkspaceParametersForm: FC<{
|
||||
description="These parameters only apply for a single workspace start."
|
||||
>
|
||||
<FormFields>
|
||||
{mutableParameters.map((parameter, index) =>
|
||||
{templateVersionRichParameters.map((parameter, index) =>
|
||||
// Since we are adding the values to the form based on the index
|
||||
// we can't filter them to not loose the right index position
|
||||
parameter.ephemeral ? (
|
||||
parameter.mutable && parameter.ephemeral ? (
|
||||
<RichParameterInput
|
||||
{...getFieldHelpers(
|
||||
"rich_parameter_values[" + index + "].value",
|
||||
)}
|
||||
disabled={isSubmitting}
|
||||
index={index}
|
||||
key={parameter.name}
|
||||
onChange={async (value) => {
|
||||
await form.setFieldValue("rich_parameter_values." + index, {
|
||||
@@ -132,7 +123,6 @@ export const WorkspaceParametersForm: FC<{
|
||||
})
|
||||
}}
|
||||
parameter={parameter}
|
||||
initialValue={form.values.rich_parameter_values[index]?.value}
|
||||
/>
|
||||
) : null,
|
||||
)}
|
||||
@@ -140,7 +130,7 @@ export const WorkspaceParametersForm: FC<{
|
||||
</FormSection>
|
||||
)}
|
||||
{/* They are displayed here only for visibility purposes */}
|
||||
{immutableParameters.length > 0 && (
|
||||
{hasImmutableParameters && (
|
||||
<FormSection
|
||||
title="Immutable parameters"
|
||||
description={
|
||||
@@ -152,26 +142,21 @@ export const WorkspaceParametersForm: FC<{
|
||||
}
|
||||
>
|
||||
<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,
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
{templateVersionRichParameters.map((parameter, index) =>
|
||||
!parameter.mutable ? (
|
||||
<RichParameterInput
|
||||
disabled
|
||||
{...getFieldHelpers(
|
||||
"rich_parameter_values[" + index + "].value",
|
||||
)}
|
||||
key={parameter.name}
|
||||
parameter={parameter}
|
||||
onChange={() => {
|
||||
throw new Error("Immutable parameters cannot be changed")
|
||||
}}
|
||||
/>
|
||||
) : null,
|
||||
)}
|
||||
</FormFields>
|
||||
</FormSection>
|
||||
)}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { TemplateVersionParameter } from "api/typesGenerated"
|
||||
import { selectInitialRichParametersValues } from "./richParameters"
|
||||
import { getInitialRichParameterValues } from "./richParameters"
|
||||
|
||||
test("selectInitialRichParametersValues return default value when default build parameter is not valid", () => {
|
||||
test("getInitialRichParameterValues return default value when default build parameter is not valid", () => {
|
||||
const templateParameters: TemplateVersionParameter[] = [
|
||||
{
|
||||
name: "cpu",
|
||||
@@ -44,7 +44,7 @@ test("selectInitialRichParametersValues return default value when default build
|
||||
]
|
||||
|
||||
const cpuParameter = templateParameters[0]
|
||||
const [cpuParameterInitialValue] = selectInitialRichParametersValues(
|
||||
const [cpuParameterInitialValue] = getInitialRichParameterValues(
|
||||
templateParameters,
|
||||
[{ name: cpuParameter.name, value: "100" }],
|
||||
)
|
||||
|
||||
@@ -5,65 +5,38 @@ import {
|
||||
import { useTranslation } from "react-i18next"
|
||||
import * as Yup from "yup"
|
||||
|
||||
export const selectInitialRichParametersValues = (
|
||||
templateParameters?: TemplateVersionParameter[],
|
||||
defaultBuildParameters?: WorkspaceBuildParameter[],
|
||||
export const getInitialRichParameterValues = (
|
||||
templateParameters: TemplateVersionParameter[],
|
||||
buildParameters?: WorkspaceBuildParameter[],
|
||||
): WorkspaceBuildParameter[] => {
|
||||
const defaults: WorkspaceBuildParameter[] = []
|
||||
if (!templateParameters) {
|
||||
return defaults
|
||||
return templateParameters.map((parameter) => {
|
||||
const existentBuildParameter = buildParameters?.find(
|
||||
(p) => p.name === parameter.name,
|
||||
)
|
||||
const shouldReturnTheDefaultValue =
|
||||
!existentBuildParameter ||
|
||||
!isValidValue(parameter, existentBuildParameter) ||
|
||||
parameter.ephemeral
|
||||
if (shouldReturnTheDefaultValue) {
|
||||
return {
|
||||
name: parameter.name,
|
||||
value: parameter.default_value,
|
||||
}
|
||||
}
|
||||
return existentBuildParameter
|
||||
})
|
||||
}
|
||||
|
||||
const isValidValue = (
|
||||
templateParam: TemplateVersionParameter,
|
||||
buildParam: WorkspaceBuildParameter,
|
||||
) => {
|
||||
if (templateParam.options.length > 0) {
|
||||
const validValues = templateParam.options.map((option) => option.value)
|
||||
return validValues.includes(buildParam.value)
|
||||
}
|
||||
|
||||
templateParameters.forEach((parameter) => {
|
||||
let parameterValue = parameter.default_value
|
||||
|
||||
if (parameter.options.length > 0) {
|
||||
parameterValue = parameterValue ?? parameter.options[0].value
|
||||
const validValues = parameter.options.map((option) => option.value)
|
||||
|
||||
if (defaultBuildParameters) {
|
||||
const defaultBuildParameter = defaultBuildParameters.find(
|
||||
(p) => p.name === parameter.name,
|
||||
)
|
||||
|
||||
// We don't want invalid values from default parameters to be set
|
||||
if (
|
||||
defaultBuildParameter &&
|
||||
validValues.includes(defaultBuildParameter.value)
|
||||
) {
|
||||
parameterValue = defaultBuildParameter?.value
|
||||
}
|
||||
}
|
||||
|
||||
const buildParameter: WorkspaceBuildParameter = {
|
||||
name: parameter.name,
|
||||
value: parameterValue,
|
||||
}
|
||||
defaults.push(buildParameter)
|
||||
return
|
||||
}
|
||||
|
||||
if (parameter.ephemeral) {
|
||||
parameterValue = parameter.default_value
|
||||
}
|
||||
|
||||
if (defaultBuildParameters) {
|
||||
const buildParameter = defaultBuildParameters.find(
|
||||
(p) => p.name === parameter.name,
|
||||
)
|
||||
|
||||
if (buildParameter) {
|
||||
parameterValue = buildParameter?.value
|
||||
}
|
||||
}
|
||||
|
||||
const buildParameter: WorkspaceBuildParameter = {
|
||||
name: parameter.name,
|
||||
value: parameterValue || "",
|
||||
}
|
||||
defaults.push(buildParameter)
|
||||
})
|
||||
return defaults
|
||||
return true
|
||||
}
|
||||
|
||||
export const useValidationSchemaForRichParameters = (
|
||||
@@ -193,31 +166,3 @@ export const useValidationSchemaForRichParameters = (
|
||||
)
|
||||
.required()
|
||||
}
|
||||
|
||||
export const workspaceBuildParameterValue = (
|
||||
workspaceBuildParameters: WorkspaceBuildParameter[],
|
||||
parameter: TemplateVersionParameter,
|
||||
): string => {
|
||||
const buildParameter = workspaceBuildParameters.find((buildParameter) => {
|
||||
return buildParameter.name === parameter.name
|
||||
})
|
||||
return (buildParameter && buildParameter.value) || ""
|
||||
}
|
||||
|
||||
export const getInitialParameterValues = (
|
||||
templateParameters: TemplateVersionParameter[],
|
||||
buildParameters: WorkspaceBuildParameter[],
|
||||
) => {
|
||||
return templateParameters.map((parameter) => {
|
||||
const buildParameter = buildParameters.find(
|
||||
(p) => p.name === parameter.name,
|
||||
)
|
||||
if (!buildParameter || parameter.ephemeral) {
|
||||
return {
|
||||
name: parameter.name,
|
||||
value: parameter.default_value,
|
||||
}
|
||||
}
|
||||
return buildParameter
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user