Skip to content

Commit ec003b7

Browse files
authored
fix: update default value handling for dynamic defaults (#17609)
resolves coder/preview#102
1 parent 4587082 commit ec003b7

File tree

2 files changed

+68
-41
lines changed

2 files changed

+68
-41
lines changed

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

Lines changed: 54 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import {
3232
TooltipTrigger,
3333
} from "components/Tooltip/Tooltip";
3434
import { Info, Settings, TriangleAlert } from "lucide-react";
35-
import { type FC, useId } from "react";
35+
import { type FC, useEffect, useId, useState } from "react";
3636
import type { AutofillBuildParameter } from "utils/richParameters";
3737
import * as Yup from "yup";
3838

@@ -164,14 +164,18 @@ const ParameterField: FC<ParameterFieldProps> = ({
164164
id,
165165
}) => {
166166
const value = validValue(parameter.value);
167-
const defaultValue = validValue(parameter.default_value);
167+
const [localValue, setLocalValue] = useState(value);
168+
169+
useEffect(() => {
170+
setLocalValue(value);
171+
}, [value]);
168172

169173
switch (parameter.form_type) {
170174
case "dropdown":
171175
return (
172176
<Select
173177
onValueChange={onChange}
174-
defaultValue={defaultValue}
178+
value={value}
175179
disabled={disabled}
176180
required={parameter.required}
177181
>
@@ -194,31 +198,48 @@ const ParameterField: FC<ParameterFieldProps> = ({
194198
);
195199

196200
case "multi-select": {
201+
let values: string[] = [];
202+
203+
if (value) {
204+
try {
205+
const parsed = JSON.parse(value);
206+
if (Array.isArray(parsed)) {
207+
values = parsed;
208+
}
209+
} catch (e) {
210+
console.error(
211+
"Error parsing parameter value with form_type multi-select",
212+
e,
213+
);
214+
}
215+
}
216+
197217
// Map parameter options to MultiSelectCombobox options format
198-
const comboboxOptions: Option[] = parameter.options.map((opt) => ({
218+
const options: Option[] = parameter.options.map((opt) => ({
199219
value: opt.value.value,
200220
label: opt.name,
201221
disable: false,
202222
}));
203223

204-
const defaultOptions: Option[] = JSON.parse(defaultValue).map(
205-
(val: string) => {
206-
const option = parameter.options.find((o) => o.value.value === val);
207-
return {
208-
value: val,
209-
label: option?.name || val,
210-
disable: false,
211-
};
212-
},
224+
const optionMap = new Map(
225+
parameter.options.map((opt) => [opt.value.value, opt.name]),
213226
);
214227

228+
const selectedOptions: Option[] = values.map((val) => {
229+
return {
230+
value: val,
231+
label: optionMap.get(val) || val,
232+
disable: false,
233+
};
234+
});
235+
215236
return (
216237
<MultiSelectCombobox
217238
inputProps={{
218239
id: `${id}-${parameter.name}`,
219240
}}
220-
options={comboboxOptions}
221-
defaultOptions={defaultOptions}
241+
options={options}
242+
defaultOptions={selectedOptions}
222243
onChange={(newValues) => {
223244
const values = newValues.map((option) => option.value);
224245
onChange(JSON.stringify(values));
@@ -251,11 +272,7 @@ const ParameterField: FC<ParameterFieldProps> = ({
251272

252273
case "radio":
253274
return (
254-
<RadioGroup
255-
onValueChange={onChange}
256-
disabled={disabled}
257-
defaultValue={defaultValue}
258-
>
275+
<RadioGroup onValueChange={onChange} disabled={disabled} value={value}>
259276
{parameter.options.map((option) => (
260277
<div
261278
key={option.value.value}
@@ -282,7 +299,6 @@ const ParameterField: FC<ParameterFieldProps> = ({
282299
<Checkbox
283300
id={parameter.name}
284301
checked={value === "true"}
285-
defaultChecked={defaultValue === "true"} // TODO: defaultChecked is always overridden by checked
286302
onCheckedChange={(checked) => {
287303
onChange(checked ? "true" : "false");
288304
}}
@@ -299,14 +315,11 @@ const ParameterField: FC<ParameterFieldProps> = ({
299315
<div className="flex flex-row items-baseline gap-3">
300316
<Slider
301317
className="mt-2"
302-
defaultValue={[
303-
Number(
304-
parameter.default_value.valid
305-
? parameter.default_value.value
306-
: 0,
307-
),
308-
]}
309-
onValueChange={([value]) => onChange(value.toString())}
318+
value={[Number(localValue ?? 0)]}
319+
onValueChange={([value]) => {
320+
setLocalValue(value.toString());
321+
onChange(value.toString());
322+
}}
310323
min={parameter.validations[0]?.validation_min ?? 0}
311324
max={parameter.validations[0]?.validation_max ?? 100}
312325
disabled={disabled}
@@ -319,8 +332,11 @@ const ParameterField: FC<ParameterFieldProps> = ({
319332
return (
320333
<Textarea
321334
className="max-w-2xl"
322-
defaultValue={defaultValue}
323-
onChange={(e) => onChange(e.target.value)}
335+
value={localValue}
336+
onChange={(e) => {
337+
setLocalValue(e.target.value);
338+
onChange(e.target.value);
339+
}}
324340
onInput={(e) => {
325341
const target = e.currentTarget;
326342
target.style.maxHeight = "700px";
@@ -354,8 +370,11 @@ const ParameterField: FC<ParameterFieldProps> = ({
354370
return (
355371
<Input
356372
type={inputType}
357-
defaultValue={defaultValue}
358-
onChange={(e) => onChange(e.target.value)}
373+
value={localValue}
374+
onChange={(e) => {
375+
setLocalValue(e.target.value);
376+
onChange(e.target.value);
377+
}}
359378
disabled={disabled}
360379
required={parameter.required}
361380
placeholder={
@@ -435,7 +454,7 @@ export const getInitialParameterValues = (
435454
if (parameter.ephemeral) {
436455
return {
437456
name: parameter.name,
438-
value: validValue(parameter.default_value),
457+
value: validValue(parameter.value),
439458
};
440459
}
441460

@@ -450,7 +469,7 @@ export const getInitialParameterValues = (
450469
isValidParameterOption(parameter, autofillParam) &&
451470
autofillParam.value
452471
? autofillParam.value
453-
: validValue(parameter.default_value),
472+
: validValue(parameter.value),
454473
};
455474
});
456475
};

site/src/pages/CreateWorkspacePage/CreateWorkspacePageViewExperimental.tsx

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -213,17 +213,23 @@ export const CreateWorkspacePageViewExperimental: FC<
213213
parameters,
214214
]);
215215

216+
// send the last user modified parameter and all touched parameters to the websocket
216217
const sendDynamicParamsRequest = (
217218
parameter: PreviewParameter,
218219
value: string,
219220
) => {
220-
const formInputs = Object.fromEntries(
221-
form.values.rich_parameter_values?.map((value) => {
222-
return [value.name, value.value];
223-
}) ?? [],
224-
);
225-
// Update the input for the changed parameter
221+
const formInputs: { [k: string]: string } = {};
226222
formInputs[parameter.name] = value;
223+
const parameters = form.values.rich_parameter_values ?? [];
224+
225+
for (const [fieldName, isTouched] of Object.entries(form.touched)) {
226+
if (isTouched && fieldName !== parameter.name) {
227+
const param = parameters.find((p) => p.name === fieldName);
228+
if (param?.value) {
229+
formInputs[fieldName] = param.value;
230+
}
231+
}
232+
}
227233

228234
sendMessage(formInputs);
229235
};
@@ -238,6 +244,7 @@ export const CreateWorkspacePageViewExperimental: FC<
238244
name: parameter.name,
239245
value,
240246
});
247+
form.setFieldTouched(parameter.name, true);
241248
sendDynamicParamsRequest(parameter, value);
242249
},
243250
500,
@@ -255,6 +262,7 @@ export const CreateWorkspacePageViewExperimental: FC<
255262
name: parameter.name,
256263
value,
257264
});
265+
form.setFieldTouched(parameter.name, true);
258266
sendDynamicParamsRequest(parameter, value);
259267
}
260268
};

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