Skip to content

Commit 4389001

Browse files
feat: implement conditional build parameters flow
- Add ConditionalBuildParametersPopover component that checks template_use_classic_parameter_flow - When classic flow is false, show UpdateBuildParametersDialogExperimental for ephemeral parameters - Direct users to workspace settings page for ephemeral parameter configuration - Update WorkspaceParametersPageViewExperimental to combine standard and ephemeral parameters - Add visual indicators for ephemeral parameters in unified parameter display - Update all workspace action buttons to use conditional logic Co-authored-by: jaaydenh <1858163+jaaydenh@users.noreply.github.com>
1 parent fa86cc4 commit 4389001

File tree

6 files changed

+107
-53
lines changed

6 files changed

+107
-53
lines changed

site/src/modules/workspaces/WorkspaceMoreActions/UpdateBuildParametersDialogExperimental.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,13 @@ export const UpdateBuildParametersDialogExperimental: FC<
4747
<DialogDescription>
4848
This template has{" "}
4949
<strong className="text-content-primary">
50-
{missedParameters.length} new parameter
50+
{missedParameters.length} ephemeral parameter
5151
{missedParameters.length === 1 ? "" : "s"}
5252
</strong>{" "}
53-
that must be configured to complete the update.
53+
that need to be configured before continuing. Ephemeral parameters may depend on values of non-ephemeral parameters.
5454
</DialogDescription>
5555
<DialogDescription>
56-
Would you like to go to the workspace parameters page to review and
57-
update these parameters before continuing?
56+
Please go to the workspace settings page to provide values for these ephemeral parameters before continuing.
5857
</DialogDescription>
5958
</DialogHeader>
6059
<DialogFooter>

site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
StarOffIcon,
1313
} from "lucide-react";
1414
import type { FC } from "react";
15-
import { BuildParametersPopover } from "./BuildParametersPopover";
15+
import { ConditionalBuildParametersPopover } from "./ConditionalBuildParametersPopover";
1616

1717
export interface ActionButtonProps {
1818
loading?: boolean;
@@ -74,7 +74,7 @@ export const StartButton: FC<ActionButtonPropsWithWorkspace> = ({
7474
return (
7575
<div className="flex gap-1 items-center">
7676
{mainButton}
77-
<BuildParametersPopover
77+
<ConditionalBuildParametersPopover
7878
label="Start with build parameters"
7979
workspace={workspace}
8080
disabled={loading}
@@ -128,7 +128,7 @@ export const RestartButton: FC<ActionButtonPropsWithWorkspace> = ({
128128
<RotateCcwIcon />
129129
{loading ? <>Restarting&hellip;</> : <>Restart&hellip;</>}
130130
</TopbarButton>
131-
<BuildParametersPopover
131+
<ConditionalBuildParametersPopover
132132
label="Restart with build parameters"
133133
workspace={workspace}
134134
disabled={loading}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import type { Workspace, WorkspaceBuildParameter } from "api/typesGenerated";
2+
import { TopbarButton } from "components/FullPageLayout/Topbar";
3+
import visuallyHidden from "@mui/utils/visuallyHidden";
4+
import { ChevronDownIcon } from "lucide-react";
5+
import type { FC } from "react";
6+
import { useState } from "react";
7+
import { BuildParametersPopover } from "./BuildParametersPopover";
8+
import { UpdateBuildParametersDialogExperimental } from "modules/workspaces/WorkspaceMoreActions/UpdateBuildParametersDialogExperimental";
9+
import { useQuery } from "react-query";
10+
import { API } from "api/api";
11+
12+
interface ConditionalBuildParametersPopoverProps {
13+
workspace: Workspace;
14+
disabled?: boolean;
15+
onSubmit: (buildParameters?: WorkspaceBuildParameter[]) => void;
16+
label: string;
17+
}
18+
19+
export const ConditionalBuildParametersPopover: FC<ConditionalBuildParametersPopoverProps> = ({
20+
workspace,
21+
disabled,
22+
label,
23+
onSubmit,
24+
}) => {
25+
const [isDialogOpen, setIsDialogOpen] = useState(false);
26+
27+
const { data: parameters } = useQuery({
28+
queryKey: ["workspace", workspace.id, "parameters"],
29+
queryFn: () => API.getWorkspaceParameters(workspace),
30+
});
31+
32+
const ephemeralParameters = parameters
33+
? parameters.templateVersionRichParameters.filter((p) => p.ephemeral)
34+
: [];
35+
36+
// If using classic parameter flow, render the original BuildParametersPopover
37+
if (workspace.template_use_classic_parameter_flow) {
38+
return (
39+
<BuildParametersPopover
40+
workspace={workspace}
41+
disabled={disabled}
42+
label={label}
43+
onSubmit={onSubmit}
44+
/>
45+
);
46+
}
47+
48+
// For experimental flow, show dialog directing to workspace settings
49+
const handleClick = () => {
50+
if (ephemeralParameters.length > 0) {
51+
setIsDialogOpen(true);
52+
} else {
53+
// If no ephemeral parameters, proceed with the action
54+
onSubmit();
55+
}
56+
};
57+
58+
return (
59+
<>
60+
<TopbarButton
61+
data-testid="build-parameters-button"
62+
disabled={disabled}
63+
className="min-w-fit"
64+
onClick={handleClick}
65+
>
66+
<ChevronDownIcon />
67+
<span css={{ ...visuallyHidden }}>{label}</span>
68+
</TopbarButton>
69+
70+
<UpdateBuildParametersDialogExperimental
71+
open={isDialogOpen}
72+
onClose={() => setIsDialogOpen(false)}
73+
missedParameters={ephemeralParameters}
74+
workspaceOwnerName={workspace.owner_name}
75+
workspaceName={workspace.name}
76+
templateVersionId={workspace.latest_build.template_version_id}
77+
/>
78+
</>
79+
);
80+
};

site/src/pages/WorkspacePage/WorkspaceActions/DebugButton.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { Workspace } from "api/typesGenerated";
22
import { TopbarButton } from "components/FullPageLayout/Topbar";
33
import { BugIcon } from "lucide-react";
44
import type { FC } from "react";
5-
import { BuildParametersPopover } from "./BuildParametersPopover";
5+
import { ConditionalBuildParametersPopover } from "./ConditionalBuildParametersPopover";
66
import type { ActionButtonProps } from "./Buttons";
77

88
type DebugButtonProps = Omit<ActionButtonProps, "loading"> & {
@@ -29,7 +29,7 @@ export const DebugButton: FC<DebugButtonProps> = ({
2929
return (
3030
<div className="flex gap-1 items-center">
3131
{mainAction}
32-
<BuildParametersPopover
32+
<ConditionalBuildParametersPopover
3333
label="Debug with build parameters"
3434
workspace={workspace}
3535
onSubmit={handleAction}

site/src/pages/WorkspacePage/WorkspaceActions/RetryButton.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { Workspace } from "api/typesGenerated";
22
import { TopbarButton } from "components/FullPageLayout/Topbar";
33
import { RotateCcwIcon } from "lucide-react";
44
import type { FC } from "react";
5-
import { BuildParametersPopover } from "./BuildParametersPopover";
5+
import { ConditionalBuildParametersPopover } from "./ConditionalBuildParametersPopover";
66
import type { ActionButtonProps } from "./Buttons";
77

88
type RetryButtonProps = Omit<ActionButtonProps, "loading"> & {
@@ -29,7 +29,7 @@ export const RetryButton: FC<RetryButtonProps> = ({
2929
return (
3030
<div className="flex gap-1 items-center">
3131
{mainAction}
32-
<BuildParametersPopover
32+
<ConditionalBuildParametersPopover
3333
label="Retry with build parameters"
3434
workspace={workspace}
3535
onSubmit={handleAction}

site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPageViewExperimental.tsx

Lines changed: 17 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -204,13 +204,14 @@ export const WorkspaceParametersPageViewExperimental: FC<
204204
)}
205205

206206
<form onSubmit={form.handleSubmit} className="flex flex-col gap-8">
207-
{standardParameters.length > 0 && (
207+
{(standardParameters.length > 0 || ephemeralParameters.length > 0) && (
208208
<section className="flex flex-col gap-9">
209209
<hgroup>
210210
<h2 className="text-xl font-medium mb-0">Parameters</h2>
211211
<p className="text-sm text-content-secondary m-0">
212212
These are the settings used by your template. Immutable
213213
parameters cannot be modified once the workspace is created.
214+
Ephemeral parameters only apply for a single workspace start.
214215
<Link
215216
href={docs(
216217
"/admin/templates/extending-templates/parameters#enable-dynamic-parameters-early-access",
@@ -220,7 +221,8 @@ export const WorkspaceParametersPageViewExperimental: FC<
220221
</Link>
221222
</p>
222223
</hgroup>
223-
{standardParameters.map((parameter, index) => {
224+
{/* Render all parameters together, with ephemeral parameters marked */}
225+
{parameters.map((parameter, index) => {
224226
const currentParameterValueIndex =
225227
form.values.rich_parameter_values?.findIndex(
226228
(p) => p.name === parameter.name,
@@ -241,57 +243,30 @@ export const WorkspaceParametersPageViewExperimental: FC<
241243
const isDisabled =
242244
disabled ||
243245
parameter.styling?.disabled ||
244-
!parameter.mutable ||
246+
(!parameter.ephemeral && !parameter.mutable) ||
245247
isSubmitting;
246248

247249
return (
248-
<DynamicParameter
249-
key={parameter.name}
250-
parameter={parameter}
251-
onChange={(value) =>
252-
handleChange(parameter, parameterField, value)
253-
}
254-
autofill={false}
255-
disabled={isDisabled}
256-
value={formValue}
257-
/>
258-
);
259-
})}
260-
</section>
261-
)}
262-
263-
{ephemeralParameters.length > 0 && (
264-
<section className="flex flex-col gap-6">
265-
<hgroup>
266-
<h2 className="text-xl font-medium mb-1">Ephemeral Parameters</h2>
267-
<p className="text-sm text-content-secondary m-0">
268-
These parameters only apply for a single workspace start
269-
</p>
270-
</hgroup>
271-
272-
<div className="flex flex-col gap-9">
273-
{ephemeralParameters.map((parameter, index) => {
274-
const actualIndex = standardParameters.length + index;
275-
const parameterField = `rich_parameter_values.${actualIndex}`;
276-
const isDisabled =
277-
disabled || parameter.styling?.disabled || isSubmitting;
278-
279-
return (
250+
<div key={parameter.name} className="relative">
251+
{parameter.ephemeral && (
252+
<div className="mb-2">
253+
<span className="inline-flex items-center px-2 py-1 text-xs font-medium bg-blue-100 text-blue-800 rounded-md">
254+
Ephemeral
255+
</span>
256+
</div>
257+
)}
280258
<DynamicParameter
281-
key={parameter.name}
282259
parameter={parameter}
283260
onChange={(value) =>
284261
handleChange(parameter, parameterField, value)
285262
}
286263
autofill={false}
287264
disabled={isDisabled}
288-
value={
289-
form.values?.rich_parameter_values?.[index]?.value || ""
290-
}
265+
value={formValue}
291266
/>
292-
);
293-
})}
294-
</div>
267+
</div>
268+
);
269+
})}
295270
</section>
296271
)}
297272

0 commit comments

Comments
 (0)