diff --git a/site/src/components/Badge/Badge.tsx b/site/src/components/Badge/Badge.tsx index 3b2a5d5897eb3..0d11c96d30433 100644 --- a/site/src/components/Badge/Badge.tsx +++ b/site/src/components/Badge/Badge.tsx @@ -22,6 +22,8 @@ const badgeVariants = cva( "border border-solid border-border-warning bg-surface-orange text-content-warning shadow", destructive: "border border-solid border-border-destructive bg-surface-red text-highlight-red shadow", + green: + "border border-solid border-surface-green bg-surface-green text-highlight-green shadow", }, size: { xs: "text-2xs font-regular h-5 [&_svg]:hidden rounded px-1.5", diff --git a/site/src/components/EphemeralParametersDialog/EphemeralParametersDialog.tsx b/site/src/components/EphemeralParametersDialog/EphemeralParametersDialog.tsx new file mode 100644 index 0000000000000..d1713d920f4a9 --- /dev/null +++ b/site/src/components/EphemeralParametersDialog/EphemeralParametersDialog.tsx @@ -0,0 +1,86 @@ +import type { TemplateVersionParameter } from "api/typesGenerated"; +import { Button } from "components/Button/Button"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "components/Dialog/Dialog"; +import type { FC } from "react"; +import { useNavigate } from "react-router-dom"; + +interface EphemeralParametersDialogProps { + open: boolean; + onClose: () => void; + onContinue: () => void; + ephemeralParameters: TemplateVersionParameter[]; + workspaceOwner: string; + workspaceName: string; + templateVersionId: string; +} + +export const EphemeralParametersDialog: FC = ({ + open, + onClose, + onContinue, + ephemeralParameters, + workspaceOwner, + workspaceName, + templateVersionId, +}) => { + const navigate = useNavigate(); + + const handleGoToParameters = () => { + onClose(); + navigate( + `/@${workspaceOwner}/${workspaceName}/settings/parameters?templateVersionId=${templateVersionId}`, + ); + }; + + return ( + !isOpen && onClose()}> + + + Ephemeral Parameters Detected + + This workspace template has{" "} + + {ephemeralParameters.length} + {" "} + ephemeral parameters that will be reset to their default values + + +
    + {ephemeralParameters.map((param) => ( +
  • +

    + {param.display_name || param.name} +

    + {param.description && ( +

    + {param.description} +

    + )} +
  • + ))} +
+
+ + Would you like to go to the workspace parameters page to review and + update these parameters before continuing? + +
+ + + + +
+
+ ); +}; diff --git a/site/src/modules/workspaces/DynamicParameter/DynamicParameter.stories.tsx b/site/src/modules/workspaces/DynamicParameter/DynamicParameter.stories.tsx index 4d1e91d9bf3e3..db3fa2f404c53 100644 --- a/site/src/modules/workspaces/DynamicParameter/DynamicParameter.stories.tsx +++ b/site/src/modules/workspaces/DynamicParameter/DynamicParameter.stories.tsx @@ -211,6 +211,15 @@ export const Immutable: Story = { }, }; +export const Ephemeral: Story = { + args: { + parameter: { + ...MockPreviewParameter, + ephemeral: true, + }, + }, +}; + export const AllBadges: Story = { args: { parameter: { diff --git a/site/src/modules/workspaces/DynamicParameter/DynamicParameter.tsx b/site/src/modules/workspaces/DynamicParameter/DynamicParameter.tsx index c3448ac7d7182..9f97d558c8f08 100644 --- a/site/src/modules/workspaces/DynamicParameter/DynamicParameter.tsx +++ b/site/src/modules/workspaces/DynamicParameter/DynamicParameter.tsx @@ -36,6 +36,7 @@ import { useDebouncedValue } from "hooks/debounce"; import { useEffectEvent } from "hooks/hookPolyfills"; import { CircleAlert, + Hourglass, Info, LinkIcon, Settings, @@ -162,6 +163,23 @@ const ParameterLabel: FC = ({ )} + {parameter.ephemeral && ( + + + + + + + Ephemeral + + + + + This parameter only applies for a single workspace start + + + + )} {isPreset && ( diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/BuildParametersPopover.tsx b/site/src/pages/WorkspacePage/WorkspaceActions/BuildParametersPopover.tsx index d594351d8dcae..76b100fc96745 100644 --- a/site/src/pages/WorkspacePage/WorkspaceActions/BuildParametersPopover.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceActions/BuildParametersPopover.tsx @@ -1,5 +1,4 @@ import { useTheme } from "@emotion/react"; -import Button from "@mui/material/Button"; import visuallyHidden from "@mui/utils/visuallyHidden"; import { API } from "api/api"; import type { @@ -7,6 +6,7 @@ import type { Workspace, WorkspaceBuildParameter, } from "api/typesGenerated"; +import { Button } from "components/Button/Button"; import { FormFields } from "components/Form/Form"; import { TopbarButton } from "components/FullPageLayout/Topbar"; import { @@ -27,6 +27,7 @@ import { useFormik } from "formik"; import { ChevronDownIcon } from "lucide-react"; import type { FC } from "react"; import { useQuery } from "react-query"; +import { useNavigate } from "react-router-dom"; import { docs } from "utils/docs"; import { getFormHelpers } from "utils/formUtils"; import { @@ -72,6 +73,7 @@ export const BuildParametersPopover: FC = ({ css={{ ".MuiPaper-root": { width: 304 } }} > = ({ }; interface BuildParametersPopoverContentProps { + workspace: Workspace; ephemeralParameters?: TemplateVersionParameter[]; buildParameters?: WorkspaceBuildParameter[]; onSubmit: (buildParameters: WorkspaceBuildParameter[]) => void; } const BuildParametersPopoverContent: FC = ({ + workspace, ephemeralParameters, buildParameters, onSubmit, }) => { const theme = useTheme(); const popover = usePopover(); + const navigate = useNavigate(); + + if ( + !workspace.template_use_classic_parameter_flow && + ephemeralParameters && + ephemeralParameters.length > 0 + ) { + const handleGoToParameters = () => { + popover.setOpen(false); + navigate( + `/@${workspace.owner_name}/${workspace.name}/settings/parameters`, + ); + }; + + return ( +
+

+ Ephemeral Parameters +

+

+ This template has ephemeral parameters that must be configured on the + workspace parameters page +

+ +
+
    + {ephemeralParameters.map((param) => ( +
  • +

    + {param.display_name || param.name} +

    + {param.description && ( +

    + {param.description} +

    + )} +
  • + ))} +
+
+ + +
+ ); + } return ( <> @@ -206,8 +257,6 @@ const Form: FC = ({