diff --git a/site/src/components/RichParameterInput/RichParameterInput.stories.tsx b/site/src/components/RichParameterInput/RichParameterInput.stories.tsx index 4dcfda0ccaf4d..cef7f66388b0c 100644 --- a/site/src/components/RichParameterInput/RichParameterInput.stories.tsx +++ b/site/src/components/RichParameterInput/RichParameterInput.stories.tsx @@ -19,7 +19,7 @@ const createTemplateVersionParameter = ( name: "first_parameter", description: "This is first parameter.", type: "string", - mutable: false, + mutable: true, default_value: "default string", icon: "/icon/folder.svg", options: [], @@ -47,6 +47,46 @@ export const Basic: Story = { }, }; +export const Optional: Story = { + args: { + value: "initial-value", + id: "project_name", + parameter: createTemplateVersionParameter({ + required: false, + name: "project_name", + description: + "Customize the name of a Google Cloud project that will be created!", + }), + }, +}; + +export const Immutable: Story = { + args: { + value: "initial-value", + id: "project_name", + parameter: createTemplateVersionParameter({ + mutable: false, + name: "project_name", + description: + "Customize the name of a Google Cloud project that will be created!", + }), + }, +}; + +export const WithError: Story = { + args: { + id: "number_parameter", + parameter: createTemplateVersionParameter({ + name: "number_parameter", + type: "number", + description: "Numeric parameter", + default_value: "", + }), + error: true, + helperText: "Number must be greater than 5", + }, +}; + export const NumberType: Story = { args: { value: "4", diff --git a/site/src/components/RichParameterInput/RichParameterInput.tsx b/site/src/components/RichParameterInput/RichParameterInput.tsx index 331c67864ad65..fe9d961d0d7c2 100644 --- a/site/src/components/RichParameterInput/RichParameterInput.tsx +++ b/site/src/components/RichParameterInput/RichParameterInput.tsx @@ -10,6 +10,8 @@ import { MemoizedMarkdown } from "components/Markdown/Markdown"; import { Stack } from "components/Stack/Stack"; import { MultiTextField } from "./MultiTextField"; import { ExternalImage } from "components/ExternalImage/ExternalImage"; +import { Pill } from "components/Pill/Pill"; +import ErrorOutline from "@mui/icons-material/ErrorOutline"; const isBoolean = (parameter: TemplateVersionParameter) => { return parameter.type === "bool"; @@ -31,7 +33,11 @@ const styles = { labelPrimary: (theme) => ({ fontSize: 16, color: theme.palette.text.primary, - fontWeight: 600, + fontWeight: 500, + display: "flex", + alignItems: "center", + flexWrap: "wrap", + gap: 8, "& p": { margin: 0, @@ -42,6 +48,11 @@ const styles = { fontSize: 14, }, }), + optionalLabel: (theme) => ({ + fontSize: 14, + color: theme.palette.text.disabled, + fontWeight: 500, + }), textField: { ".small & .MuiInputBase-root": { height: 36, @@ -102,6 +113,25 @@ const ParameterLabel: FC = ({ parameter }) => { ? parameter.display_name : parameter.name; + const labelPrimary = ( + + {displayName} + + {!parameter.required && ( + + (optional) + + )} + {!parameter.mutable && ( + + }> + Immutable + + + )} + + ); + return ( diff --git a/site/src/components/TemplateParameters/TemplateParameters.tsx b/site/src/components/TemplateParameters/TemplateParameters.tsx index 9befc7c74051f..d01f5b29bf671 100644 --- a/site/src/components/TemplateParameters/TemplateParameters.tsx +++ b/site/src/components/TemplateParameters/TemplateParameters.tsx @@ -14,9 +14,11 @@ export type TemplateParametersSectionProps = { ) => Omit; } & Pick, "classes">; -export const MutableTemplateParametersSection: FC< - TemplateParametersSectionProps -> = ({ templateParameters, getInputProps, ...formSectionProps }) => { +export const TemplateParametersSection: FC = ({ + templateParameters, + getInputProps, + ...formSectionProps +}) => { const hasMutableParameters = templateParameters.filter((p) => p.mutable).length > 0; @@ -45,40 +47,3 @@ export const MutableTemplateParametersSection: FC< ); }; - -export const ImmutableTemplateParametersSection: FC< - TemplateParametersSectionProps -> = ({ templateParameters, getInputProps, ...formSectionProps }) => { - const hasImmutableParameters = - templateParameters.filter((p) => !p.mutable).length > 0; - - return ( - <> - {hasImmutableParameters && ( - - These settings cannot be changed after creating - the workspace. - - } - > - - {templateParameters.map( - (parameter, index) => - !parameter.mutable && ( - - ), - )} - - - )} - - ); -}; diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx index b6b6968e945d6..a7aabb56a57ae 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx @@ -1,5 +1,4 @@ -import { css } from "@emotion/css"; -import { useTheme, type Interpolation, type Theme } from "@emotion/react"; +import { type Interpolation, type Theme } from "@emotion/react"; import TextField from "@mui/material/TextField"; import type * as TypesGen from "api/typesGenerated"; import { UserAutocomplete } from "components/UserAutocomplete/UserAutocomplete"; @@ -21,10 +20,6 @@ import { getInitialRichParameterValues, useValidationSchemaForRichParameters, } from "utils/richParameters"; -import { - ImmutableTemplateParametersSection, - MutableTemplateParametersSection, -} from "components/TemplateParameters/TemplateParameters"; import { ErrorAlert } from "components/Alert/ErrorAlert"; import { Stack } from "components/Stack/Stack"; import { @@ -44,6 +39,7 @@ import { PageHeaderSubtitle, } from "components/PageHeader/PageHeader"; import { Pill } from "components/Pill/Pill"; +import { RichParameterInput } from "components/RichParameterInput/RichParameterInput"; export const Language = { duplicationWarning: @@ -90,7 +86,6 @@ export const CreateWorkspacePageView: FC = ({ onSubmit, onCancel, }) => { - const theme = useTheme(); const [owner, setOwner] = useState(defaultOwner); const [searchParams] = useSearchParams(); const disabledParamsList = searchParams?.get("disable_params")?.split(","); @@ -222,65 +217,41 @@ export const CreateWorkspacePageView: FC = ({ - {parameters && ( - <> - { - return { - ...getFieldHelpers( - "rich_parameter_values[" + index + "].value", - ), - onChange: async (value) => { - await form.setFieldValue( - "rich_parameter_values." + index, - { - name: parameter.name, - value: value, - }, - ); - }, - disabled: - disabledParamsList?.includes( - parameter.name.toLowerCase().replace(/ /g, "_"), - ) || creatingWorkspace, - }; - }} - /> - { - return { - ...getFieldHelpers( - "rich_parameter_values[" + index + "].value", - ), - onChange: async (value) => { - await form.setFieldValue( - "rich_parameter_values." + index, - { + {parameters.length > 0 && ( + + {/* + Opted not to use FormFields in order to increase spacing. + This decision was made because rich parameter inputs are more visually dense than standard text fields. + */} +
+ {parameters.map((parameter, index) => { + const parameterField = `rich_parameter_values.${index}`; + const parameterInputName = `${parameterField}.value`; + const isDisabled = + disabledParamsList?.includes( + parameter.name.toLowerCase().replace(/ /g, "_"), + ) || creatingWorkspace; + + return ( + { + await form.setFieldValue(parameterField, { name: parameter.name, - value: value, - }, - ); - }, - disabled: - disabledParamsList?.includes( - parameter.name.toLowerCase().replace(/ /g, "_"), - ) || creatingWorkspace, - }; - }} - /> - + value, + }); + }} + key={parameter.name} + parameter={parameter} + disabled={isDisabled} + /> + ); + })} +
+
)} ; @@ -64,22 +60,6 @@ export const TemplateEmbedPageView: FC = ({ const buttonUrl = `${createWorkspaceUrl}?${createWorkspaceParams.toString()}`; const buttonMkdCode = `[![Open in Coder](${deploymentUrl}/open-in-coder.svg)](${buttonUrl})`; const clipboard = useClipboard(buttonMkdCode); - const getInputProps: TemplateParametersSectionProps["getInputProps"] = ( - parameter, - ) => { - if (!buttonValues) { - throw new Error("buttonValues is undefined"); - } - return { - value: buttonValues[`param.${parameter.name}`] ?? "", - onChange: (value) => { - setButtonValues((buttonValues) => ({ - ...buttonValues, - [`param.${parameter.name}`]: value, - })); - }, - }; - }; // template parameters is async so we need to initialize the values after it // is loaded @@ -135,16 +115,28 @@ export const TemplateEmbedPageView: FC = ({ {templateParameters.length > 0 && ( - <> - - - +
+ {templateParameters.map((parameter) => { + const parameterValue = + buttonValues[`param.${parameter.name}`] ?? ""; + + return ( + { + setButtonValues((buttonValues) => ({ + ...buttonValues, + [`param.${parameter.name}`]: value, + })); + }} + key={parameter.name} + parameter={parameter} + /> + ); + })} +
)} diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersForm.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersForm.tsx index 12ea287acfb84..f5a03304b9eac 100644 --- a/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersForm.tsx +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersForm.tsx @@ -69,9 +69,6 @@ export const WorkspaceParametersForm: FC = ({ const hasNonEphemeralParameters = templateVersionRichParameters.some( (parameter) => !parameter.ephemeral, ); - const hasImmutableParameters = templateVersionRichParameters.some( - (parameter) => !parameter.mutable, - ); const disabled = workspace.outdated && @@ -97,12 +94,12 @@ export const WorkspaceParametersForm: FC = ({ {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.mutable && !parameter.ephemeral ? ( + !parameter.ephemeral ? ( { await form.setFieldValue( @@ -152,36 +149,7 @@ export const WorkspaceParametersForm: FC = ({ )} - {/* They are displayed here only for visibility purposes */} - {hasImmutableParameters && ( - - These settings cannot be changed after creating - the workspace. - - } - > - - {templateVersionRichParameters.map((parameter, index) => - !parameter.mutable ? ( - { - throw new Error("Immutable parameters cannot be changed"); - }} - /> - ) : null, - )} - - - )} + pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy