Skip to content

Commit 0ba035a

Browse files
refactor(site): improve parameters field (#11802)
1 parent 4c71ccc commit 0ba035a

File tree

6 files changed

+141
-175
lines changed

6 files changed

+141
-175
lines changed

site/src/components/RichParameterInput/RichParameterInput.stories.tsx

+41-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const createTemplateVersionParameter = (
1919
name: "first_parameter",
2020
description: "This is first parameter.",
2121
type: "string",
22-
mutable: false,
22+
mutable: true,
2323
default_value: "default string",
2424
icon: "/icon/folder.svg",
2525
options: [],
@@ -47,6 +47,46 @@ export const Basic: Story = {
4747
},
4848
};
4949

50+
export const Optional: Story = {
51+
args: {
52+
value: "initial-value",
53+
id: "project_name",
54+
parameter: createTemplateVersionParameter({
55+
required: false,
56+
name: "project_name",
57+
description:
58+
"Customize the name of a Google Cloud project that will be created!",
59+
}),
60+
},
61+
};
62+
63+
export const Immutable: Story = {
64+
args: {
65+
value: "initial-value",
66+
id: "project_name",
67+
parameter: createTemplateVersionParameter({
68+
mutable: false,
69+
name: "project_name",
70+
description:
71+
"Customize the name of a Google Cloud project that will be created!",
72+
}),
73+
},
74+
};
75+
76+
export const WithError: Story = {
77+
args: {
78+
id: "number_parameter",
79+
parameter: createTemplateVersionParameter({
80+
name: "number_parameter",
81+
type: "number",
82+
description: "Numeric parameter",
83+
default_value: "",
84+
}),
85+
error: true,
86+
helperText: "Number must be greater than 5",
87+
},
88+
};
89+
5090
export const NumberType: Story = {
5191
args: {
5292
value: "4",

site/src/components/RichParameterInput/RichParameterInput.tsx

+33-3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import { MemoizedMarkdown } from "components/Markdown/Markdown";
1010
import { Stack } from "components/Stack/Stack";
1111
import { MultiTextField } from "./MultiTextField";
1212
import { ExternalImage } from "components/ExternalImage/ExternalImage";
13+
import { Pill } from "components/Pill/Pill";
14+
import ErrorOutline from "@mui/icons-material/ErrorOutline";
1315

1416
const isBoolean = (parameter: TemplateVersionParameter) => {
1517
return parameter.type === "bool";
@@ -31,7 +33,11 @@ const styles = {
3133
labelPrimary: (theme) => ({
3234
fontSize: 16,
3335
color: theme.palette.text.primary,
34-
fontWeight: 600,
36+
fontWeight: 500,
37+
display: "flex",
38+
alignItems: "center",
39+
flexWrap: "wrap",
40+
gap: 8,
3541

3642
"& p": {
3743
margin: 0,
@@ -42,6 +48,11 @@ const styles = {
4248
fontSize: 14,
4349
},
4450
}),
51+
optionalLabel: (theme) => ({
52+
fontSize: 14,
53+
color: theme.palette.text.disabled,
54+
fontWeight: 500,
55+
}),
4556
textField: {
4657
".small & .MuiInputBase-root": {
4758
height: 36,
@@ -102,6 +113,25 @@ const ParameterLabel: FC<ParameterLabelProps> = ({ parameter }) => {
102113
? parameter.display_name
103114
: parameter.name;
104115

116+
const labelPrimary = (
117+
<span css={styles.labelPrimary}>
118+
{displayName}
119+
120+
{!parameter.required && (
121+
<Tooltip title="If no value is specified, the system will default to the value set by the administrator.">
122+
<span css={styles.optionalLabel}>(optional)</span>
123+
</Tooltip>
124+
)}
125+
{!parameter.mutable && (
126+
<Tooltip title="This value cannot be modified after the workspace has been created.">
127+
<Pill type="warning" icon={<ErrorOutline />}>
128+
Immutable
129+
</Pill>
130+
</Tooltip>
131+
)}
132+
</span>
133+
);
134+
105135
return (
106136
<label htmlFor={parameter.name}>
107137
<Stack direction="row" alignItems="center">
@@ -117,13 +147,13 @@ const ParameterLabel: FC<ParameterLabelProps> = ({ parameter }) => {
117147

118148
{hasDescription ? (
119149
<Stack spacing={0}>
120-
<span css={styles.labelPrimary}>{displayName}</span>
150+
{labelPrimary}
121151
<MemoizedMarkdown css={styles.labelCaption}>
122152
{parameter.description}
123153
</MemoizedMarkdown>
124154
</Stack>
125155
) : (
126-
<span css={styles.labelPrimary}>{displayName}</span>
156+
labelPrimary
127157
)}
128158
</Stack>
129159
</label>

site/src/components/TemplateParameters/TemplateParameters.tsx

+5-40
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ export type TemplateParametersSectionProps = {
1414
) => Omit<RichParameterInputProps, "parameter" | "index">;
1515
} & Pick<ComponentProps<typeof FormSection>, "classes">;
1616

17-
export const MutableTemplateParametersSection: FC<
18-
TemplateParametersSectionProps
19-
> = ({ templateParameters, getInputProps, ...formSectionProps }) => {
17+
export const TemplateParametersSection: FC<TemplateParametersSectionProps> = ({
18+
templateParameters,
19+
getInputProps,
20+
...formSectionProps
21+
}) => {
2022
const hasMutableParameters =
2123
templateParameters.filter((p) => p.mutable).length > 0;
2224

@@ -45,40 +47,3 @@ export const MutableTemplateParametersSection: FC<
4547
</>
4648
);
4749
};
48-
49-
export const ImmutableTemplateParametersSection: FC<
50-
TemplateParametersSectionProps
51-
> = ({ templateParameters, getInputProps, ...formSectionProps }) => {
52-
const hasImmutableParameters =
53-
templateParameters.filter((p) => !p.mutable).length > 0;
54-
55-
return (
56-
<>
57-
{hasImmutableParameters && (
58-
<FormSection
59-
{...formSectionProps}
60-
title="Immutable parameters"
61-
description={
62-
<>
63-
These settings <strong>cannot be changed</strong> after creating
64-
the workspace.
65-
</>
66-
}
67-
>
68-
<FormFields>
69-
{templateParameters.map(
70-
(parameter, index) =>
71-
!parameter.mutable && (
72-
<RichParameterInput
73-
{...getInputProps(parameter, index)}
74-
key={parameter.name}
75-
parameter={parameter}
76-
/>
77-
),
78-
)}
79-
</FormFields>
80-
</FormSection>
81-
)}
82-
</>
83-
);
84-
};

site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx

+36-65
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { css } from "@emotion/css";
2-
import { useTheme, type Interpolation, type Theme } from "@emotion/react";
1+
import { type Interpolation, type Theme } from "@emotion/react";
32
import TextField from "@mui/material/TextField";
43
import type * as TypesGen from "api/typesGenerated";
54
import { UserAutocomplete } from "components/UserAutocomplete/UserAutocomplete";
@@ -21,10 +20,6 @@ import {
2120
getInitialRichParameterValues,
2221
useValidationSchemaForRichParameters,
2322
} from "utils/richParameters";
24-
import {
25-
ImmutableTemplateParametersSection,
26-
MutableTemplateParametersSection,
27-
} from "components/TemplateParameters/TemplateParameters";
2823
import { ErrorAlert } from "components/Alert/ErrorAlert";
2924
import { Stack } from "components/Stack/Stack";
3025
import {
@@ -44,6 +39,7 @@ import {
4439
PageHeaderSubtitle,
4540
} from "components/PageHeader/PageHeader";
4641
import { Pill } from "components/Pill/Pill";
42+
import { RichParameterInput } from "components/RichParameterInput/RichParameterInput";
4743

4844
export const Language = {
4945
duplicationWarning:
@@ -90,7 +86,6 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = ({
9086
onSubmit,
9187
onCancel,
9288
}) => {
93-
const theme = useTheme();
9489
const [owner, setOwner] = useState(defaultOwner);
9590
const [searchParams] = useSearchParams();
9691
const disabledParamsList = searchParams?.get("disable_params")?.split(",");
@@ -222,65 +217,41 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = ({
222217
</FormFields>
223218
</FormSection>
224219

225-
{parameters && (
226-
<>
227-
<MutableTemplateParametersSection
228-
templateParameters={parameters}
229-
getInputProps={(parameter, index) => {
230-
return {
231-
...getFieldHelpers(
232-
"rich_parameter_values[" + index + "].value",
233-
),
234-
onChange: async (value) => {
235-
await form.setFieldValue(
236-
"rich_parameter_values." + index,
237-
{
238-
name: parameter.name,
239-
value: value,
240-
},
241-
);
242-
},
243-
disabled:
244-
disabledParamsList?.includes(
245-
parameter.name.toLowerCase().replace(/ /g, "_"),
246-
) || creatingWorkspace,
247-
};
248-
}}
249-
/>
250-
<ImmutableTemplateParametersSection
251-
templateParameters={parameters}
252-
classes={{
253-
root: css`
254-
border: 1px solid ${theme.palette.warning.light};
255-
border-radius: 8px;
256-
background-color: ${theme.palette.background.paper};
257-
padding: 80px;
258-
margin-left: -80px;
259-
margin-right: -80px;
260-
`,
261-
}}
262-
getInputProps={(parameter, index) => {
263-
return {
264-
...getFieldHelpers(
265-
"rich_parameter_values[" + index + "].value",
266-
),
267-
onChange: async (value) => {
268-
await form.setFieldValue(
269-
"rich_parameter_values." + index,
270-
{
220+
{parameters.length > 0 && (
221+
<FormSection
222+
title="Parameters"
223+
description="These are the settings used by your template. Please note that immutable parameters cannot be modified once the workspace is created."
224+
>
225+
{/*
226+
Opted not to use FormFields in order to increase spacing.
227+
This decision was made because rich parameter inputs are more visually dense than standard text fields.
228+
*/}
229+
<div css={{ display: "flex", flexDirection: "column", gap: 36 }}>
230+
{parameters.map((parameter, index) => {
231+
const parameterField = `rich_parameter_values.${index}`;
232+
const parameterInputName = `${parameterField}.value`;
233+
const isDisabled =
234+
disabledParamsList?.includes(
235+
parameter.name.toLowerCase().replace(/ /g, "_"),
236+
) || creatingWorkspace;
237+
238+
return (
239+
<RichParameterInput
240+
{...getFieldHelpers(parameterInputName)}
241+
onChange={async (value) => {
242+
await form.setFieldValue(parameterField, {
271243
name: parameter.name,
272-
value: value,
273-
},
274-
);
275-
},
276-
disabled:
277-
disabledParamsList?.includes(
278-
parameter.name.toLowerCase().replace(/ /g, "_"),
279-
) || creatingWorkspace,
280-
};
281-
}}
282-
/>
283-
</>
244+
value,
245+
});
246+
}}
247+
key={parameter.name}
248+
parameter={parameter}
249+
disabled={isDisabled}
250+
/>
251+
);
252+
})}
253+
</div>
254+
</FormSection>
284255
)}
285256

286257
<FormFooter

0 commit comments

Comments
 (0)