Skip to content

feat: implement conditional build parameters flow based on template setting #18390

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,13 @@ export const UpdateBuildParametersDialogExperimental: FC<
<DialogDescription>
This template has{" "}
<strong className="text-content-primary">
{missedParameters.length} new parameter
{missedParameters.length} ephemeral parameter
{missedParameters.length === 1 ? "" : "s"}
</strong>{" "}
that must be configured to complete the update.
that need to be configured before continuing. Ephemeral parameters may depend on values of non-ephemeral parameters.
</DialogDescription>
<DialogDescription>
Would you like to go to the workspace parameters page to review and
update these parameters before continuing?
Please go to the workspace settings page to provide values for these ephemeral parameters before continuing.
</DialogDescription>
</DialogHeader>
<DialogFooter>
Expand Down
6 changes: 3 additions & 3 deletions site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
StarOffIcon,
} from "lucide-react";
import type { FC } from "react";
import { BuildParametersPopover } from "./BuildParametersPopover";
import { ConditionalBuildParametersPopover } from "./ConditionalBuildParametersPopover";

export interface ActionButtonProps {
loading?: boolean;
Expand Down Expand Up @@ -74,7 +74,7 @@ export const StartButton: FC<ActionButtonPropsWithWorkspace> = ({
return (
<div className="flex gap-1 items-center">
{mainButton}
<BuildParametersPopover
<ConditionalBuildParametersPopover
label="Start with build parameters"
workspace={workspace}
disabled={loading}
Expand Down Expand Up @@ -128,7 +128,7 @@ export const RestartButton: FC<ActionButtonPropsWithWorkspace> = ({
<RotateCcwIcon />
{loading ? <>Restarting&hellip;</> : <>Restart&hellip;</>}
</TopbarButton>
<BuildParametersPopover
<ConditionalBuildParametersPopover
label="Restart with build parameters"
workspace={workspace}
disabled={loading}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import type { Workspace, WorkspaceBuildParameter } from "api/typesGenerated";
import { TopbarButton } from "components/FullPageLayout/Topbar";
import visuallyHidden from "@mui/utils/visuallyHidden";
import { ChevronDownIcon } from "lucide-react";
import type { FC } from "react";
import { useState } from "react";
import { BuildParametersPopover } from "./BuildParametersPopover";
import { UpdateBuildParametersDialogExperimental } from "modules/workspaces/WorkspaceMoreActions/UpdateBuildParametersDialogExperimental";
import { useQuery } from "react-query";
import { API } from "api/api";

interface ConditionalBuildParametersPopoverProps {
workspace: Workspace;
disabled?: boolean;
onSubmit: (buildParameters?: WorkspaceBuildParameter[]) => void;
label: string;
}

export const ConditionalBuildParametersPopover: FC<ConditionalBuildParametersPopoverProps> = ({
workspace,
disabled,
label,
onSubmit,
}) => {
const [isDialogOpen, setIsDialogOpen] = useState(false);

const { data: parameters } = useQuery({
queryKey: ["workspace", workspace.id, "parameters"],
queryFn: () => API.getWorkspaceParameters(workspace),
});

const ephemeralParameters = parameters
? parameters.templateVersionRichParameters.filter((p) => p.ephemeral)
: [];

// If using classic parameter flow, render the original BuildParametersPopover
if (workspace.template_use_classic_parameter_flow) {
return (
<BuildParametersPopover
workspace={workspace}
disabled={disabled}
label={label}
onSubmit={onSubmit}
/>
);
}

// For experimental flow, show dialog directing to workspace settings
const handleClick = () => {
if (ephemeralParameters.length > 0) {
setIsDialogOpen(true);
} else {
// If no ephemeral parameters, proceed with the action
onSubmit();
}
};

return (
<>
<TopbarButton
data-testid="build-parameters-button"
disabled={disabled}
className="min-w-fit"
onClick={handleClick}
>
<ChevronDownIcon />
<span css={{ ...visuallyHidden }}>{label}</span>
</TopbarButton>

<UpdateBuildParametersDialogExperimental
open={isDialogOpen}
onClose={() => setIsDialogOpen(false)}
missedParameters={ephemeralParameters}
workspaceOwnerName={workspace.owner_name}
workspaceName={workspace.name}
templateVersionId={workspace.latest_build.template_version_id}
/>
</>
);
};
4 changes: 2 additions & 2 deletions site/src/pages/WorkspacePage/WorkspaceActions/DebugButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { Workspace } from "api/typesGenerated";
import { TopbarButton } from "components/FullPageLayout/Topbar";
import { BugIcon } from "lucide-react";
import type { FC } from "react";
import { BuildParametersPopover } from "./BuildParametersPopover";
import { ConditionalBuildParametersPopover } from "./ConditionalBuildParametersPopover";
import type { ActionButtonProps } from "./Buttons";

type DebugButtonProps = Omit<ActionButtonProps, "loading"> & {
Expand All @@ -29,7 +29,7 @@ export const DebugButton: FC<DebugButtonProps> = ({
return (
<div className="flex gap-1 items-center">
{mainAction}
<BuildParametersPopover
<ConditionalBuildParametersPopover
label="Debug with build parameters"
workspace={workspace}
onSubmit={handleAction}
Expand Down
4 changes: 2 additions & 2 deletions site/src/pages/WorkspacePage/WorkspaceActions/RetryButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import type { Workspace } from "api/typesGenerated";
import { TopbarButton } from "components/FullPageLayout/Topbar";
import { RotateCcwIcon } from "lucide-react";
import type { FC } from "react";
import { BuildParametersPopover } from "./BuildParametersPopover";
import type { ActionButtonProps } from "./Buttons";
import { ConditionalBuildParametersPopover } from "./ConditionalBuildParametersPopover";

type RetryButtonProps = Omit<ActionButtonProps, "loading"> & {
enableBuildParameters: boolean;
Expand All @@ -29,7 +29,7 @@ export const RetryButton: FC<RetryButtonProps> = ({
return (
<div className="flex gap-1 items-center">
{mainAction}
<BuildParametersPopover
<ConditionalBuildParametersPopover
label="Retry with build parameters"
workspace={workspace}
onSubmit={handleAction}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,13 +204,14 @@ export const WorkspaceParametersPageViewExperimental: FC<
)}

<form onSubmit={form.handleSubmit} className="flex flex-col gap-8">
{standardParameters.length > 0 && (
{(standardParameters.length > 0 || ephemeralParameters.length > 0) && (
<section className="flex flex-col gap-9">
<hgroup>
<h2 className="text-xl font-medium mb-0">Parameters</h2>
<p className="text-sm text-content-secondary m-0">
These are the settings used by your template. Immutable
parameters cannot be modified once the workspace is created.
Ephemeral parameters only apply for a single workspace start.
<Link
href={docs(
"/admin/templates/extending-templates/parameters#enable-dynamic-parameters-early-access",
Expand All @@ -220,7 +221,8 @@ export const WorkspaceParametersPageViewExperimental: FC<
</Link>
</p>
</hgroup>
{standardParameters.map((parameter, index) => {
{/* Render all parameters together, with ephemeral parameters marked */}
{parameters.map((parameter, index) => {
const currentParameterValueIndex =
form.values.rich_parameter_values?.findIndex(
(p) => p.name === parameter.name,
Expand All @@ -241,57 +243,30 @@ export const WorkspaceParametersPageViewExperimental: FC<
const isDisabled =
disabled ||
parameter.styling?.disabled ||
!parameter.mutable ||
(!parameter.ephemeral && !parameter.mutable) ||
isSubmitting;

return (
<DynamicParameter
key={parameter.name}
parameter={parameter}
onChange={(value) =>
handleChange(parameter, parameterField, value)
}
autofill={false}
disabled={isDisabled}
value={formValue}
/>
);
})}
</section>
)}

{ephemeralParameters.length > 0 && (
<section className="flex flex-col gap-6">
<hgroup>
<h2 className="text-xl font-medium mb-1">Ephemeral Parameters</h2>
<p className="text-sm text-content-secondary m-0">
These parameters only apply for a single workspace start
</p>
</hgroup>

<div className="flex flex-col gap-9">
{ephemeralParameters.map((parameter, index) => {
const actualIndex = standardParameters.length + index;
const parameterField = `rich_parameter_values.${actualIndex}`;
const isDisabled =
disabled || parameter.styling?.disabled || isSubmitting;

return (
<div key={parameter.name} className="relative">
{parameter.ephemeral && (
<div className="mb-2">
<span className="inline-flex items-center px-2 py-1 text-xs font-medium bg-blue-100 text-blue-800 rounded-md">
Ephemeral
</span>
</div>
)}
<DynamicParameter
key={parameter.name}
parameter={parameter}
onChange={(value) =>
handleChange(parameter, parameterField, value)
}
autofill={false}
disabled={isDisabled}
value={
form.values?.rich_parameter_values?.[index]?.value || ""
}
value={formValue}
/>
);
})}
</div>
</div>
);
})}
</section>
)}

Expand Down
Loading