Skip to content

Commit c0e88b0

Browse files
committed
explicit useEffect for clearing query whenever value is cleared
1 parent a79be2e commit c0e88b0

File tree

3 files changed

+33
-5
lines changed

3 files changed

+33
-5
lines changed

app/forms/firewall-rules-common.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,6 @@ const DynamicTypeAndValueFields = ({
125125
{/* In the firewall rules form, a few types get comboboxes instead of text fields */}
126126
{valueType === 'vpc' || valueType === 'subnet' || valueType === 'instance' ? (
127127
<ComboboxField
128-
// key means we nuke the entire field when we change types. this fixes
129-
// a bug where the firewall rule host filter combobox would keep an
130-
// custom value query around when you change types
131-
key={valueType}
132128
disabled={disabled}
133129
name="value"
134130
{...getFilterValueProps(valueType)}

app/ui/lib/Combobox.tsx

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
} from '@headlessui/react'
1616
import cn from 'classnames'
1717
import { matchSorter } from 'match-sorter'
18-
import { useId, useState, type ReactNode, type Ref } from 'react'
18+
import { useEffect, useId, useState, type ReactNode, type Ref } from 'react'
1919

2020
import { SelectArrows6Icon } from '@oxide/design-system/icons/react'
2121

@@ -97,6 +97,26 @@ export const Combobox = ({
9797
keys: ['selectedLabel', 'label'],
9898
sorter: (items) => items, // preserve original order, don't sort by match
9999
})
100+
101+
// In the arbitraryValues case, clear the query whenever the value is cleared.
102+
// this is necessary, e.g., for the firewall rules form when you submit the
103+
// targets subform and clear the field. Two possible changes we might want to make
104+
// here if we run into issues:
105+
//
106+
// 1. do it all the time, not just in the arbitraryValues case
107+
// 2. do it on all value changes, not just on clear
108+
//
109+
// Currently, I don't think there are any arbitraryValues=false cases where we
110+
// set the value from outside. There is an arbitraryvalues=true case where we
111+
// setValue to something other than empty string, but we don't need the
112+
// sync because that setValue is done in onInputChange and we already are
113+
// doing setQuery in here along with it.
114+
useEffect(() => {
115+
if (allowArbitraryValues && !selectedItemValue) {
116+
setQuery('')
117+
}
118+
}, [allowArbitraryValues, selectedItemValue])
119+
100120
// If the user has typed in a value that isn't in the list,
101121
// add it as an option if `allowArbitraryValues` is true
102122
if (

test/e2e/firewall-rules.e2e.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,18 @@ async function expectOptions(page: Page, options: string[]) {
580580
test('arbitrary values combobox', async ({ page }) => {
581581
await page.goto('/projects/mock-project/vpcs/mock-vpc/firewall-rules-new')
582582

583+
// test for bug where we'd persist the d after add and only show 'Custom: d'
584+
const vpcInput = page.getByRole('combobox', { name: 'VPC name' }).first()
585+
await vpcInput.focus()
586+
await expectOptions(page, ['mock-vpc'])
587+
await vpcInput.fill('d')
588+
await expectOptions(page, ['Custom: d'])
589+
await vpcInput.blur()
590+
page.getByRole('button', { name: 'Add target' }).click()
591+
await expect(vpcInput).toHaveValue('')
592+
await vpcInput.focus()
593+
await expectOptions(page, ['mock-vpc']) // bug cause failure here
594+
583595
await selectOption(page, 'Target type', 'Instance')
584596
const input = page.getByRole('combobox', { name: 'Instance name' })
585597

0 commit comments

Comments
 (0)