Skip to content

feat: add the ability to hide preset parameters #17168

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Apr 1, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -374,3 +374,44 @@ export const SmallBasicWithDisplayName: Story = {
size: "small",
},
};

export const WithPreset: Story = {
args: {
value: "preset-value",
id: "project_name",
parameter: createTemplateVersionParameter({
name: "project_name",
description:
"Customize the name of a Google Cloud project that will be created!",
}),
isPreset: true,
},
};

export const WithPresetAndImmutable: Story = {
args: {
value: "preset-value",
id: "project_name",
parameter: createTemplateVersionParameter({
name: "project_name",
description:
"Customize the name of a Google Cloud project that will be created!",
mutable: false,
}),
isPreset: true,
},
};

export const WithPresetAndOptional: Story = {
args: {
value: "preset-value",
id: "project_name",
parameter: createTemplateVersionParameter({
name: "project_name",
description:
"Customize the name of a Google Cloud project that will be created!",
required: false,
}),
isPreset: true,
},
};
15 changes: 13 additions & 2 deletions site/src/components/RichParameterInput/RichParameterInput.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Interpolation, Theme } from "@emotion/react";
import ErrorOutline from "@mui/icons-material/ErrorOutline";
import SettingsIcon from "@mui/icons-material/Settings";
import Button from "@mui/material/Button";
import FormControlLabel from "@mui/material/FormControlLabel";
import FormHelperText from "@mui/material/FormHelperText";
Expand Down Expand Up @@ -122,9 +123,10 @@ const styles = {

export interface ParameterLabelProps {
parameter: TemplateVersionParameter;
isPreset?: boolean;
}

const ParameterLabel: FC<ParameterLabelProps> = ({ parameter }) => {
const ParameterLabel: FC<ParameterLabelProps> = ({ parameter, isPreset }) => {
const hasDescription = parameter.description && parameter.description !== "";
const displayName = parameter.display_name
? parameter.display_name
Expand All @@ -146,6 +148,13 @@ const ParameterLabel: FC<ParameterLabelProps> = ({ parameter }) => {
</Pill>
</Tooltip>
)}
{isPreset && (
<Tooltip title="This value was set by a preset">
<Pill type="info" icon={<SettingsIcon />}>
Preset
</Pill>
</Tooltip>
)}
</span>
);

Expand Down Expand Up @@ -187,6 +196,7 @@ export type RichParameterInputProps = Omit<
parameterAutofill?: AutofillBuildParameter;
onChange: (value: string) => void;
size?: Size;
isPreset?: boolean;
};

const autofillDescription: Partial<Record<AutofillSource, ReactNode>> = {
Expand All @@ -198,6 +208,7 @@ export const RichParameterInput: FC<RichParameterInputProps> = ({
parameter,
parameterAutofill,
onChange,
isPreset,
...fieldProps
}) => {
const autofillSource = parameterAutofill?.source;
Expand All @@ -211,7 +222,7 @@ export const RichParameterInput: FC<RichParameterInputProps> = ({
className={size}
data-testid={`parameter-field-${parameter.name}`}
>
<ParameterLabel parameter={parameter} />
<ParameterLabel parameter={parameter} isPreset={isPreset} />
<div css={{ display: "flex", flexDirection: "column" }}>
<RichParameterField
{...fieldProps}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,28 @@ export const PresetSelected: Story = {
},
};

export const PresetSelectedWithHiddenParameters: Story = {
args: PresetsButNoneSelected.args,
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
// Select a preset
await userEvent.click(canvas.getByLabelText("Preset"));
await userEvent.click(canvas.getByText("Preset 1"));
},
};

export const PresetSelectedWithVisibleParameters: Story = {
args: PresetsButNoneSelected.args,
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
// Select a preset
await userEvent.click(canvas.getByLabelText("Preset"));
await userEvent.click(canvas.getByText("Preset 1"));
// Toggle off the show preset parameters switch
await userEvent.click(canvas.getByLabelText("Show preset parameters"));
},
};

export const PresetReselected: Story = {
args: PresetsButNoneSelected.args,
play: async ({ canvasElement }) => {
Expand Down
117 changes: 76 additions & 41 deletions site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Interpolation, Theme } from "@emotion/react";
import FormControlLabel from "@mui/material/FormControlLabel";
import FormHelperText from "@mui/material/FormHelperText";
import TextField from "@mui/material/TextField";
import type * as TypesGen from "api/typesGenerated";
Expand All @@ -24,6 +25,7 @@ import { Pill } from "components/Pill/Pill";
import { RichParameterInput } from "components/RichParameterInput/RichParameterInput";
import { Spinner } from "components/Spinner/Spinner";
import { Stack } from "components/Stack/Stack";
import { Switch } from "components/Switch/Switch";
import { UserAutocomplete } from "components/UserAutocomplete/UserAutocomplete";
import { type FormikContextType, useFormik } from "formik";
import { generateWorkspaceName } from "modules/workspaces/generateWorkspaceName";
Expand Down Expand Up @@ -101,6 +103,7 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = ({
const [suggestedName, setSuggestedName] = useState(() =>
generateWorkspaceName(),
);
const [showPresetParameters, setShowPresetParameters] = useState(false);

const rerollSuggestedName = useCallback(() => {
setSuggestedName(() => generateWorkspaceName());
Expand Down Expand Up @@ -273,33 +276,6 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = ({
</Stack>
)}

{presets.length > 0 && (
<Stack direction="column" spacing={2}>
<Stack direction="row" spacing={2} alignItems="center">
<span css={styles.description}>
Select a preset to get started
</span>
<FeatureStageBadge contentType={"beta"} size="md" />
</Stack>
<Stack direction="row" spacing={2}>
<SelectFilter
label="Preset"
options={presetOptions}
onSelect={(option) => {
const index = presetOptions.findIndex(
(preset) => preset.value === option?.value,
);
if (index === -1) {
return;
}
setSelectedPresetIndex(index);
}}
placeholder="Select a preset"
selectedOption={presetOptions[selectedPresetIndex]}
/>
</Stack>
</Stack>
)}
<div>
<TextField
{...getFieldHelpers("name")}
Expand Down Expand Up @@ -373,30 +349,89 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = ({
hence they require additional vertical spacing for better readability and
user experience. */}
<FormFields css={{ gap: 36 }}>
{presets.length > 0 && (
<Stack direction="column" spacing={2}>
<Stack direction="row" spacing={2} alignItems="center">
<span css={styles.description}>
Select a preset to get started
</span>
<FeatureStageBadge contentType={"beta"} size="md" />
</Stack>
<Stack direction="column" spacing={2}>
<Stack direction="row" spacing={2}>
<SelectFilter
label="Preset"
options={presetOptions}
onSelect={(option) => {
const index = presetOptions.findIndex(
(preset) => preset.value === option?.value,
);
if (index === -1) {
return;
}
setSelectedPresetIndex(index);
}}
placeholder="Select a preset"
selectedOption={presetOptions[selectedPresetIndex]}
/>
</Stack>
<div
css={{
display: "flex",
alignItems: "center",
gap: "8px",
}}
>
<Switch
id="show-preset-parameters"
checked={showPresetParameters}
onCheckedChange={setShowPresetParameters}
/>
<label
htmlFor="show-preset-parameters"
css={styles.description}
>
Show preset parameters
</label>
</div>
</Stack>
</Stack>
)}

{parameters.map((parameter, index) => {
const parameterField = `rich_parameter_values.${index}`;
const parameterInputName = `${parameterField}.value`;
const isPresetParameter = presetParameterNames.includes(
parameter.name,
);
const isDisabled =
disabledParams?.includes(
parameter.name.toLowerCase().replace(/ /g, "_"),
) ||
creatingWorkspace ||
presetParameterNames.includes(parameter.name);
isPresetParameter;

// Hide preset parameters if showPresetParameters is false
if (!showPresetParameters && isPresetParameter) {
return null;
}

return (
<RichParameterInput
{...getFieldHelpers(parameterInputName)}
onChange={async (value) => {
await form.setFieldValue(parameterField, {
name: parameter.name,
value,
});
}}
key={parameter.name}
parameter={parameter}
parameterAutofill={autofillByName[parameter.name]}
disabled={isDisabled}
/>
<div key={parameter.name}>
<RichParameterInput
{...getFieldHelpers(parameterInputName)}
onChange={async (value) => {
await form.setFieldValue(parameterField, {
name: parameter.name,
value,
});
}}
parameter={parameter}
parameterAutofill={autofillByName[parameter.name]}
disabled={isDisabled}
isPreset={isPresetParameter}
/>
</div>
);
})}
</FormFields>
Expand Down
Loading