fix: disallow deselecting dynamic dropdown value (#22931)

This was accomplished by switching from the comboxbox (which has
deselection logic) to a select (which does not).

As a side effect, the dropdowns are wider now, which seems to match
better with other inputs anyway.  And, it seems it uses the `combobox`
role instead of `button` which also seems to make more sense.  Lastly, 
they lose some bolding.
This commit is contained in:
Asher
2026-03-11 17:08:52 -08:00
committed by GitHub
parent d495a4eddb
commit 53304df70d
3 changed files with 25 additions and 41 deletions
@@ -191,7 +191,7 @@ describe("DynamicParameter", () => {
/>,
);
const select = screen.getByRole("button");
const select = screen.getByRole("combobox");
await waitFor(async () => {
await userEvent.click(select);
});
@@ -211,7 +211,7 @@ describe("DynamicParameter", () => {
/>,
);
const select = screen.getByRole("button");
const select = screen.getByRole("combobox");
await waitFor(async () => {
await userEvent.click(select);
});
@@ -703,7 +703,7 @@ describe("DynamicParameter", () => {
/>,
);
expect(screen.getByRole("button")).toBeInTheDocument();
expect(screen.getByRole("combobox")).toBeInTheDocument();
});
it("handles null/undefined values", () => {
@@ -7,14 +7,6 @@ import type {
import { Badge } from "components/Badge/Badge";
import { Button } from "components/Button/Button";
import { Checkbox } from "components/Checkbox/Checkbox";
import {
Combobox,
ComboboxButton,
ComboboxContent,
ComboboxItem,
ComboboxList,
ComboboxTrigger,
} from "components/Combobox/Combobox";
import { ExternalImage } from "components/ExternalImage/ExternalImage";
import { Input } from "components/Input/Input";
import { Label } from "components/Label/Label";
@@ -24,6 +16,13 @@ import {
type Option,
} from "components/MultiSelectCombobox/MultiSelectCombobox";
import { RadioGroup, RadioGroupItem } from "components/RadioGroup/RadioGroup";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "components/Select/Select";
import { Slider } from "components/Slider/Slider";
import { Stack } from "components/Stack/Stack";
import { Switch } from "components/Switch/Switch";
@@ -335,41 +334,25 @@ const ParameterField: FC<ParameterFieldProps> = ({
}
case "dropdown": {
const selectedOption = parameter.options.find(
(opt) => opt.value.value === value,
);
return (
<Combobox
<Select
value={value}
onValueChange={(newValue) => onChange(newValue ?? "")}
disabled={disabled}
>
<ComboboxTrigger asChild>
<ComboboxButton
selectedOption={
selectedOption
? {
label: selectedOption.name,
value: selectedOption.value.value,
}
: undefined
}
<SelectTrigger>
<SelectValue
placeholder={parameter.styling?.placeholder || "Select option"}
disabled={disabled}
/>
</ComboboxTrigger>
<ComboboxContent>
<ComboboxList>
{parameter.options.map((option) => (
<ComboboxItem
key={option.value.value}
value={option.value.value}
>
{option.name}
</ComboboxItem>
))}
</ComboboxList>
</ComboboxContent>
</Combobox>
</SelectTrigger>
<SelectContent>
{parameter.options.map((option) => (
<SelectItem key={option.value.value} value={option.value.value}>
{option.name}
</SelectItem>
))}
</SelectContent>
</Select>
);
}
@@ -140,7 +140,8 @@ describe("CreateWorkspacePage", () => {
const instanceTypeField = screen.getByTestId(
"parameter-field-instance_type",
);
const instanceTypeSelect = within(instanceTypeField).getByRole("button");
const instanceTypeSelect =
within(instanceTypeField).getByRole("combobox");
expect(instanceTypeSelect).toBeInTheDocument();
jest.useFakeTimers();