Skip to content

Commit 9e67844

Browse files
committed
fix: set initial autofill parameters from latest workspace build parameters
1 parent 2962196 commit 9e67844

File tree

3 files changed

+63
-22
lines changed

3 files changed

+63
-22
lines changed

site/src/modules/workspaces/DynamicParameter/DynamicParameter.tsx

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ export const DynamicParameter: FC<DynamicParameterProps> = ({
8484
value={value}
8585
onChange={onChange}
8686
disabled={disabled}
87+
isPreset={isPreset}
8788
/>
8889
) : (
8990
<ParameterField
@@ -231,6 +232,7 @@ interface DebouncedParameterFieldProps {
231232
onChange: (value: string) => void;
232233
disabled?: boolean;
233234
id: string;
235+
isPreset?: boolean;
234236
}
235237

236238
const DebouncedParameterField: FC<DebouncedParameterFieldProps> = ({
@@ -239,6 +241,7 @@ const DebouncedParameterField: FC<DebouncedParameterFieldProps> = ({
239241
onChange,
240242
disabled,
241243
id,
244+
isPreset,
242245
}) => {
243246
const [localValue, setLocalValue] = useState(
244247
value !== undefined ? value : validValue(parameter.value),
@@ -251,19 +254,26 @@ const DebouncedParameterField: FC<DebouncedParameterFieldProps> = ({
251254

252255
// This is necessary in the case of fields being set by preset parameters
253256
useEffect(() => {
254-
if (value !== undefined && value !== prevValueRef.current) {
257+
if (isPreset && value !== undefined && value !== prevValueRef.current) {
255258
setLocalValue(value);
256259
prevValueRef.current = value;
257260
}
258-
}, [value]);
261+
}, [value, isPreset]);
259262

260263
useEffect(() => {
261-
if (prevDebouncedValueRef.current !== undefined) {
264+
// Only call onChangeEvent if debouncedLocalValue is different from the previously committed value
265+
// and it's not the initial undefined state.
266+
if (
267+
prevDebouncedValueRef.current !== undefined &&
268+
prevDebouncedValueRef.current !== debouncedLocalValue
269+
) {
262270
onChangeEvent(debouncedLocalValue);
263271
}
264272

273+
// Update the ref to the current debounced value for the next comparison
265274
prevDebouncedValueRef.current = debouncedLocalValue;
266275
}, [debouncedLocalValue, onChangeEvent]);
276+
267277
const textareaRef = useRef<HTMLTextAreaElement>(null);
268278

269279
const resizeTextarea = useEffectEvent(() => {
@@ -513,7 +523,9 @@ const ParameterField: FC<ParameterFieldProps> = ({
513523
max={parameter.validations[0]?.validation_max ?? 100}
514524
disabled={disabled}
515525
/>
516-
<span className="w-4 font-medium">{parameter.value.value}</span>
526+
<span className="w-4 font-medium">
527+
{Number.isFinite(Number(value)) ? value : "0"}
528+
</span>
517529
</div>
518530
);
519531
case "error":

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

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { useMutation, useQuery } from "react-query";
2626
import { useNavigate } from "react-router-dom";
2727
import { docs } from "utils/docs";
2828
import { pageTitle } from "utils/page";
29+
import type { AutofillBuildParameter } from "utils/richParameters";
2930
import {
3031
type WorkspacePermissions,
3132
workspaceChecks,
@@ -39,8 +40,12 @@ const WorkspaceParametersPageExperimental: FC = () => {
3940
const navigate = useNavigate();
4041
const experimentalFormContext = useContext(ExperimentalFormContext);
4142

42-
const { data: originalParameters, isLoading: originalParametersLoading } = useQuery({
43-
queryKey: ["workspace", "build", workspace.id, "parameters"],
43+
// autofill the form with the workspace build parameters from the latest build
44+
const {
45+
data: latestBuildParameters,
46+
isLoading: latestBuildParametersLoading,
47+
} = useQuery({
48+
queryKey: ["workspaceBuilds", workspace.latest_build.id, "parameters"],
4449
queryFn: () => API.getWorkspaceBuildParameters(workspace.latest_build.id),
4550
});
4651

@@ -49,6 +54,13 @@ const WorkspaceParametersPageExperimental: FC = () => {
4954
const wsResponseId = useRef<number>(-1);
5055
const ws = useRef<WebSocket | null>(null);
5156
const [wsError, setWsError] = useState<Error | null>(null);
57+
const initialParamsSentRef = useRef(false);
58+
59+
const autofillParameters: AutofillBuildParameter[] =
60+
latestBuildParameters?.map((p) => ({
61+
...p,
62+
source: "active_build",
63+
})) ?? [];
5264

5365
const sendMessage = useEffectEvent((formValues: Record<string, string>) => {
5466
const request: DynamicParametersRequest = {
@@ -62,11 +74,34 @@ const WorkspaceParametersPageExperimental: FC = () => {
6274
}
6375
});
6476

77+
// On page load, sends initial workspace build parameters to the websocket.
78+
// This ensures the backend has the form's complete initial state,
79+
// vital for rendering dynamic UI elements dependent on initial parameter values.
80+
const sendInitialParameters = useEffectEvent(() => {
81+
if (initialParamsSentRef.current) return;
82+
if (autofillParameters.length === 0) return;
83+
84+
const initialParamsToSend: Record<string, string> = {};
85+
for (const param of autofillParameters) {
86+
if (param.name && param.value) {
87+
initialParamsToSend[param.name] = param.value;
88+
}
89+
}
90+
if (Object.keys(initialParamsToSend).length === 0) return;
91+
92+
sendMessage(initialParamsToSend);
93+
initialParamsSentRef.current = true;
94+
});
95+
6596
const onMessage = useEffectEvent((response: DynamicParametersResponse) => {
6697
if (latestResponse && latestResponse?.id >= response.id) {
6798
return;
6899
}
69100

101+
if (!initialParamsSentRef.current && response.parameters?.length > 0) {
102+
sendInitialParameters();
103+
}
104+
70105
setLatestResponse(response);
71106
});
72107

@@ -154,7 +189,7 @@ const WorkspaceParametersPageExperimental: FC = () => {
154189
const error = wsError || updateParameters.error;
155190

156191
if (
157-
originalParametersLoading ||
192+
latestBuildParametersLoading ||
158193
!latestResponse ||
159194
(ws.current && ws.current.readyState === WebSocket.CONNECTING)
160195
) {
@@ -208,8 +243,8 @@ const WorkspaceParametersPageExperimental: FC = () => {
208243
{sortedParams.length > 0 ? (
209244
<WorkspaceParametersPageViewExperimental
210245
workspace={workspace}
246+
autofillParameters={autofillParameters}
211247
canChangeVersions={canChangeVersions}
212-
originalParameters={originalParameters!}
213248
parameters={sortedParams}
214249
diagnostics={latestResponse.diagnostics}
215250
isSubmitting={updateParameters.isPending}

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

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ import {
1616
} from "modules/workspaces/DynamicParameter/DynamicParameter";
1717
import type { FC } from "react";
1818
import { docs } from "utils/docs";
19-
import { AutofillBuildParameter } from "utils/richParameters";
19+
import type { AutofillBuildParameter } from "utils/richParameters";
2020

2121
type WorkspaceParametersPageViewExperimentalProps = {
2222
workspace: Workspace;
23-
originalParameters?: WorkspaceBuildParameter[];
23+
autofillParameters: AutofillBuildParameter[];
2424
parameters: PreviewParameter[];
2525
diagnostics: PreviewParameter["diagnostics"];
2626
canChangeVersions: boolean;
@@ -36,7 +36,7 @@ export const WorkspaceParametersPageViewExperimental: FC<
3636
WorkspaceParametersPageViewExperimentalProps
3737
> = ({
3838
workspace,
39-
originalParameters,
39+
autofillParameters,
4040
parameters,
4141
diagnostics,
4242
canChangeVersions,
@@ -45,16 +45,9 @@ export const WorkspaceParametersPageViewExperimental: FC<
4545
sendMessage,
4646
onCancel,
4747
}) => {
48-
49-
const autoFillValues: AutofillBuildParameter[] = originalParameters!.map((p) => ({
50-
...p,
51-
source: "active_build",
52-
}))
5348
const autofillByName = Object.fromEntries(
54-
autoFillValues.map((param) => [param.name, param]),
49+
autofillParameters.map((param) => [param.name, param]),
5550
);
56-
57-
5851
const initialTouched = parameters.reduce(
5952
(touched, parameter) => {
6053
if (autofillByName[parameter.name] !== undefined) {
@@ -64,19 +57,20 @@ export const WorkspaceParametersPageViewExperimental: FC<
6457
},
6558
{} as Record<string, boolean>,
6659
);
67-
6860
const form = useFormik({
6961
onSubmit,
7062
initialValues: {
71-
rich_parameter_values: getInitialParameterValues(parameters, autoFillValues),
63+
rich_parameter_values: getInitialParameterValues(
64+
parameters,
65+
autofillParameters,
66+
),
7267
},
7368
initialTouched,
7469
validationSchema: useValidationSchemaForDynamicParameters(parameters),
7570
enableReinitialize: false,
7671
validateOnChange: true,
7772
validateOnBlur: true,
7873
});
79-
8074
// Group parameters by ephemeral status
8175
const ephemeralParameters = parameters.filter((p) => p.ephemeral);
8276
const standardParameters = parameters.filter((p) => !p.ephemeral);

0 commit comments

Comments
 (0)