Skip to content

Commit 177bda3

Browse files
jaaydenhEmyrk
andauthored
fix: autofill with workspace build parameters from the latest build (#18091)
Set the form parameters using autofill parameters based on the workspace build parameters for the latest build --------- Co-authored-by: Steven Masley <stevenmasley@gmail.com>
1 parent e4648b6 commit 177bda3

File tree

3 files changed

+78
-6
lines changed

3 files changed

+78
-6
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: 42 additions & 0 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,11 +40,27 @@ const WorkspaceParametersPageExperimental: FC = () => {
3940
const navigate = useNavigate();
4041
const experimentalFormContext = useContext(ExperimentalFormContext);
4142

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"],
49+
queryFn: () => API.getWorkspaceBuildParameters(workspace.latest_build.id),
50+
});
51+
4252
const [latestResponse, setLatestResponse] =
4353
useState<DynamicParametersResponse | null>(null);
4454
const wsResponseId = useRef<number>(-1);
4555
const ws = useRef<WebSocket | null>(null);
4656
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+
})) ?? [];
4764

4865
const sendMessage = useEffectEvent((formValues: Record<string, string>) => {
4966
const request: DynamicParametersRequest = {
@@ -57,11 +74,34 @@ const WorkspaceParametersPageExperimental: FC = () => {
5774
}
5875
});
5976

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+
6096
const onMessage = useEffectEvent((response: DynamicParametersResponse) => {
6197
if (latestResponse && latestResponse?.id >= response.id) {
6298
return;
6399
}
64100

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

@@ -149,6 +189,7 @@ const WorkspaceParametersPageExperimental: FC = () => {
149189
const error = wsError || updateParameters.error;
150190

151191
if (
192+
latestBuildParametersLoading ||
152193
!latestResponse ||
153194
(ws.current && ws.current.readyState === WebSocket.CONNECTING)
154195
) {
@@ -202,6 +243,7 @@ const WorkspaceParametersPageExperimental: FC = () => {
202243
{sortedParams.length > 0 ? (
203244
<WorkspaceParametersPageViewExperimental
204245
workspace={workspace}
246+
autofillParameters={autofillParameters}
205247
canChangeVersions={canChangeVersions}
206248
parameters={sortedParams}
207249
diagnostics={latestResponse.diagnostics}

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

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

2021
type WorkspaceParametersPageViewExperimentalProps = {
2122
workspace: Workspace;
23+
autofillParameters: AutofillBuildParameter[];
2224
parameters: PreviewParameter[];
2325
diagnostics: PreviewParameter["diagnostics"];
2426
canChangeVersions: boolean;
@@ -34,6 +36,7 @@ export const WorkspaceParametersPageViewExperimental: FC<
3436
WorkspaceParametersPageViewExperimentalProps
3537
> = ({
3638
workspace,
39+
autofillParameters,
3740
parameters,
3841
diagnostics,
3942
canChangeVersions,
@@ -42,17 +45,32 @@ export const WorkspaceParametersPageViewExperimental: FC<
4245
sendMessage,
4346
onCancel,
4447
}) => {
48+
const autofillByName = Object.fromEntries(
49+
autofillParameters.map((param) => [param.name, param]),
50+
);
51+
const initialTouched = parameters.reduce(
52+
(touched, parameter) => {
53+
if (autofillByName[parameter.name] !== undefined) {
54+
touched[parameter.name] = true;
55+
}
56+
return touched;
57+
},
58+
{} as Record<string, boolean>,
59+
);
4560
const form = useFormik({
4661
onSubmit,
4762
initialValues: {
48-
rich_parameter_values: getInitialParameterValues(parameters),
63+
rich_parameter_values: getInitialParameterValues(
64+
parameters,
65+
autofillParameters,
66+
),
4967
},
68+
initialTouched,
5069
validationSchema: useValidationSchemaForDynamicParameters(parameters),
5170
enableReinitialize: false,
5271
validateOnChange: true,
5372
validateOnBlur: true,
5473
});
55-
5674
// Group parameters by ephemeral status
5775
const ephemeralParameters = parameters.filter((p) => p.ephemeral);
5876
const standardParameters = parameters.filter((p) => !p.ephemeral);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy