Skip to content

Commit 99f7a2d

Browse files
feat: add ephemeral parameter dialog for workspace start/restart
- Add EphemeralParametersDialog component to inform users about ephemeral parameters - Modify WorkspaceReadyPage to check for ephemeral parameters before start/restart - Update BuildParametersPopover to show ephemeral parameter info for non-classic flow - Update WorkspaceParametersPageExperimental button text based on template version - Only trigger for templates with use_classic_parameter_flow = false Co-authored-by: jaaydenh <1858163+jaaydenh@users.noreply.github.com>
1 parent 7e9a9e0 commit 99f7a2d

File tree

5 files changed

+186
-8
lines changed

5 files changed

+186
-8
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import type { TemplateVersionParameter } from "api/typesGenerated";
2+
import { Button } from "components/Button/Button";
3+
import { ConfirmDialog } from "components/Dialogs/ConfirmDialog/ConfirmDialog";
4+
import { Link } from "components/Link/Link";
5+
import type { FC } from "react";
6+
7+
interface EphemeralParametersDialogProps {
8+
open: boolean;
9+
onClose: () => void;
10+
onContinue: () => void;
11+
ephemeralParameters: TemplateVersionParameter[];
12+
workspaceOwner: string;
13+
workspaceName: string;
14+
}
15+
16+
export const EphemeralParametersDialog: FC<EphemeralParametersDialogProps> = ({
17+
open,
18+
onClose,
19+
onContinue,
20+
ephemeralParameters,
21+
workspaceOwner,
22+
workspaceName,
23+
}) => {
24+
const parametersPageUrl = `/@${workspaceOwner}/${workspaceName}/settings/parameters`;
25+
26+
const description = (
27+
<>
28+
<p>This workspace template has ephemeral parameters that will be reset to their default values:</p>
29+
<div style={{ margin: "16px 0" }}>
30+
{ephemeralParameters.map((param) => (
31+
<div key={param.name} style={{ marginBottom: "8px" }}>
32+
<strong>{param.display_name || param.name}</strong>
33+
{param.description && (
34+
<div style={{ fontSize: "14px", color: "#666" }}>
35+
{param.description}
36+
</div>
37+
)}
38+
</div>
39+
))}
40+
</div>
41+
<p>You can continue without setting values for these parameters, or go to the workspace parameters page to configure them.</p>
42+
<div style={{ marginTop: "16px" }}>
43+
<Button as={Link} to={parametersPageUrl} onClick={onClose}>
44+
Go to Parameters Page
45+
</Button>
46+
</div>
47+
</>
48+
);
49+
50+
return (
51+
<ConfirmDialog
52+
open={open}
53+
onClose={onClose}
54+
onConfirm={onContinue}
55+
title="Ephemeral Parameters Detected"
56+
confirmText="Continue Without Setting"
57+
description={description}
58+
type="info"
59+
/>
60+
);
61+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { EphemeralParametersDialog } from "./EphemeralParametersDialog";

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

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useTheme } from "@emotion/react";
2-
import Button from "@mui/material/Button";
2+
import { Button } from "components/Button/Button";
33
import visuallyHidden from "@mui/utils/visuallyHidden";
44
import { API } from "api/api";
55
import type {
@@ -28,6 +28,7 @@ import { ChevronDownIcon } from "lucide-react";
2828
import type { FC } from "react";
2929
import { useQuery } from "react-query";
3030
import { docs } from "utils/docs";
31+
import { Link } from "components/Link/Link";
3132
import { getFormHelpers } from "utils/formUtils";
3233
import {
3334
type AutofillBuildParameter,
@@ -72,6 +73,7 @@ export const BuildParametersPopover: FC<BuildParametersPopoverProps> = ({
7273
css={{ ".MuiPaper-root": { width: 304 } }}
7374
>
7475
<BuildParametersPopoverContent
76+
workspace={workspace}
7577
ephemeralParameters={ephemeralParameters}
7678
buildParameters={parameters?.buildParameters}
7779
onSubmit={onSubmit}
@@ -82,19 +84,62 @@ export const BuildParametersPopover: FC<BuildParametersPopoverProps> = ({
8284
};
8385

8486
interface BuildParametersPopoverContentProps {
87+
workspace: Workspace;
8588
ephemeralParameters?: TemplateVersionParameter[];
8689
buildParameters?: WorkspaceBuildParameter[];
8790
onSubmit: (buildParameters: WorkspaceBuildParameter[]) => void;
8891
}
8992

9093
const BuildParametersPopoverContent: FC<BuildParametersPopoverContentProps> = ({
94+
workspace,
9195
ephemeralParameters,
9296
buildParameters,
9397
onSubmit,
9498
}) => {
9599
const theme = useTheme();
96100
const popover = usePopover();
97101

102+
// For templates that don't use classic parameter flow, show different UI
103+
if (!workspace.template_use_classic_parameter_flow && ephemeralParameters && ephemeralParameters.length > 0) {
104+
const parametersPageUrl = `/@${workspace.owner_name}/${workspace.name}/settings/parameters`;
105+
106+
return (
107+
<div
108+
css={{
109+
color: theme.palette.text.secondary,
110+
padding: 20,
111+
}}
112+
>
113+
<HelpTooltipTitle>Ephemeral Parameters</HelpTooltipTitle>
114+
<HelpTooltipText css={{ marginBottom: 16 }}>
115+
This template has ephemeral parameters that must be configured on the workspace parameters page:
116+
</HelpTooltipText>
117+
118+
<div css={{ marginBottom: 16 }}>
119+
{ephemeralParameters.map((param) => (
120+
<div key={param.name} css={{ marginBottom: 8 }}>
121+
<strong>{param.display_name || param.name}</strong>
122+
{param.description && (
123+
<div css={{ fontSize: 14, color: theme.palette.text.secondary }}>
124+
{param.description}
125+
</div>
126+
)}
127+
</div>
128+
))}
129+
</div>
130+
131+
<Button
132+
as={Link}
133+
to={parametersPageUrl}
134+
css={{ width: "100%" }}
135+
onClick={() => popover.setOpen(false)}
136+
>
137+
Go to Parameters Page
138+
</Button>
139+
</div>
140+
);
141+
}
142+
98143
return (
99144
<>
100145
{buildParameters && ephemeralParameters ? (
@@ -206,8 +251,6 @@ const Form: FC<FormProps> = ({
206251
<Button
207252
data-testid="build-parameters-submit"
208253
type="submit"
209-
variant="contained"
210-
color="primary"
211254
css={{ width: "100%" }}
212255
>
213256
Build workspace

site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
type ConfirmDialogProps,
1717
} from "components/Dialogs/ConfirmDialog/ConfirmDialog";
1818
import { displayError } from "components/GlobalSnackbar/utils";
19+
import { EphemeralParametersDialog } from "components/EphemeralParametersDialog";
1920
import { useWorkspaceBuildLogs } from "hooks/useWorkspaceBuildLogs";
2021
import {
2122
WorkspaceUpdateDialogs,
@@ -53,6 +54,13 @@ export const WorkspaceReadyPage: FC<WorkspaceReadyPageProps> = ({
5354
open: boolean;
5455
buildParameters?: TypesGen.WorkspaceBuildParameter[];
5556
}>({ open: false });
57+
58+
const [ephemeralParametersDialog, setEphemeralParametersDialog] = useState<{
59+
open: boolean;
60+
action: 'start' | 'restart';
61+
buildParameters?: TypesGen.WorkspaceBuildParameter[];
62+
ephemeralParameters: TypesGen.TemplateVersionParameter[];
63+
}>({ open: false, action: 'start', ephemeralParameters: [] });
5664
const { mutate: mutateRestartWorkspace, isPending: isRestarting } =
5765
useMutation({
5866
mutationFn: API.restartWorkspace,
@@ -137,6 +145,33 @@ export const WorkspaceReadyPage: FC<WorkspaceReadyPageProps> = ({
137145
},
138146
});
139147

148+
const checkEphemeralParameters = async (
149+
action: 'start' | 'restart',
150+
buildParameters?: TypesGen.WorkspaceBuildParameter[],
151+
) => {
152+
// Only check for ephemeral parameters if template doesn't use classic parameter flow
153+
if (workspace.template_use_classic_parameter_flow) {
154+
return { hasEphemeral: false, ephemeralParameters: [] };
155+
}
156+
157+
try {
158+
const dynamicParameters = await API.getDynamicParameters(
159+
workspace.latest_build.template_version_id,
160+
workspace.owner_id,
161+
buildParameters || [],
162+
);
163+
164+
const ephemeralParameters = dynamicParameters.filter(param => param.ephemeral);
165+
return {
166+
hasEphemeral: ephemeralParameters.length > 0,
167+
ephemeralParameters,
168+
};
169+
} catch (error) {
170+
console.error('Error checking ephemeral parameters:', error);
171+
return { hasEphemeral: false, ephemeralParameters: [] };
172+
}
173+
};
174+
140175
const runLastBuild = (
141176
buildParameters: TypesGen.WorkspaceBuildParameter[] | undefined,
142177
debug: boolean,
@@ -196,14 +231,34 @@ export const WorkspaceReadyPage: FC<WorkspaceReadyPageProps> = ({
196231
template={template}
197232
buildLogs={buildLogs}
198233
timings={timingsQuery.data}
199-
handleStart={(buildParameters) => {
200-
startWorkspaceMutation.mutate({ buildParameters });
234+
handleStart={async (buildParameters) => {
235+
const { hasEphemeral, ephemeralParameters } = await checkEphemeralParameters('start', buildParameters);
236+
if (hasEphemeral) {
237+
setEphemeralParametersDialog({
238+
open: true,
239+
action: 'start',
240+
buildParameters,
241+
ephemeralParameters,
242+
});
243+
} else {
244+
startWorkspaceMutation.mutate({ buildParameters });
245+
}
201246
}}
202247
handleStop={() => {
203248
stopWorkspaceMutation.mutate({});
204249
}}
205-
handleRestart={(buildParameters) => {
206-
setConfirmingRestart({ open: true, buildParameters });
250+
handleRestart={async (buildParameters) => {
251+
const { hasEphemeral, ephemeralParameters } = await checkEphemeralParameters('restart', buildParameters);
252+
if (hasEphemeral) {
253+
setEphemeralParametersDialog({
254+
open: true,
255+
action: 'restart',
256+
buildParameters,
257+
ephemeralParameters,
258+
});
259+
} else {
260+
setConfirmingRestart({ open: true, buildParameters });
261+
}
207262
}}
208263
handleUpdate={workspaceUpdate.update}
209264
handleCancel={cancelBuildMutation.mutate}
@@ -242,6 +297,22 @@ export const WorkspaceReadyPage: FC<WorkspaceReadyPageProps> = ({
242297
}
243298
/>
244299

300+
<EphemeralParametersDialog
301+
open={ephemeralParametersDialog.open}
302+
onClose={() => setEphemeralParametersDialog({ ...ephemeralParametersDialog, open: false })}
303+
onContinue={() => {
304+
if (ephemeralParametersDialog.action === 'start') {
305+
startWorkspaceMutation.mutate({ buildParameters: ephemeralParametersDialog.buildParameters });
306+
} else {
307+
setConfirmingRestart({ open: true, buildParameters: ephemeralParametersDialog.buildParameters });
308+
}
309+
setEphemeralParametersDialog({ ...ephemeralParametersDialog, open: false });
310+
}}
311+
ephemeralParameters={ephemeralParametersDialog.ephemeralParameters}
312+
workspaceOwner={workspace.owner_name}
313+
workspaceName={workspace.name}
314+
/>
315+
245316
<WorkspaceUpdateDialogs {...workspaceUpdate.dialogs} />
246317
</>
247318
);

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,9 @@ export const WorkspaceParametersPageViewExperimental: FC<
315315
}
316316
>
317317
<Spinner loading={isSubmitting} />
318-
Update and restart
318+
{templateVersionId !== workspace.latest_build.template_version_id
319+
? "Update and restart"
320+
: "Restart"}
319321
</Button>
320322
</div>
321323
</form>

0 commit comments

Comments
 (0)