From 982739f3bfdad51909736752c27cb672b8d79acc Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Sat, 11 Apr 2026 15:12:03 +1000 Subject: [PATCH] feat: add a debounce to menu filtering (#24048) This pull-request implements a small debounce to ensure we aren't constantly pinging the backend on each keystroke of an input. image https://github.com/user-attachments/assets/5787310a-2c1e-448a-a4b7-123eb9d50124 --- site/src/components/Combobox/Combobox.stories.tsx | 7 ++++++- site/src/components/Combobox/Combobox.tsx | 1 + site/src/components/Filter/SelectFilter.tsx | 2 ++ site/src/components/Filter/menu.ts | 13 +++++++++++-- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/site/src/components/Combobox/Combobox.stories.tsx b/site/src/components/Combobox/Combobox.stories.tsx index 6e52ec3141..2356010cb8 100644 --- a/site/src/components/Combobox/Combobox.stories.tsx +++ b/site/src/components/Combobox/Combobox.stories.tsx @@ -37,6 +37,7 @@ const ComboboxWithHooks = ({ optionsList?: SelectFilterOption[]; }) => { const [value, setValue] = useState(undefined); + const [inputValue, setInputValue] = useState(""); const selectedOption = optionsList.find((opt) => opt.value === value); return ( @@ -48,7 +49,11 @@ const ComboboxWithHooks = ({ /> - + {optionsList.map((option) => ( diff --git a/site/src/components/Combobox/Combobox.tsx b/site/src/components/Combobox/Combobox.tsx index 20fb0ecf82..0cbca4ea35 100644 --- a/site/src/components/Combobox/Combobox.tsx +++ b/site/src/components/Combobox/Combobox.tsx @@ -127,6 +127,7 @@ export const ComboboxContent = ({ }; export const ComboboxInput = CommandInput; + export const ComboboxList = CommandList; export const ComboboxItem = ({ diff --git a/site/src/components/Filter/SelectFilter.tsx b/site/src/components/Filter/SelectFilter.tsx index fbf8d78b5b..339e8aa7e8 100644 --- a/site/src/components/Filter/SelectFilter.tsx +++ b/site/src/components/Filter/SelectFilter.tsx @@ -71,6 +71,8 @@ export const SelectFilter: FC = ({ minWidth: width, }} align="end" + // We want the backend to handle the filtering, not the client. + shouldFilter={false} > {selectFilterSearch} { @@ -44,11 +48,15 @@ export const useFilterMenu = ({ }); const selectedOption = selectedOptionQuery.data; const searchOptionsQuery = useQuery({ - queryKey: [id, "autocomplete", "search", query], - queryFn: () => getOptions(query), + queryKey: [id, "autocomplete", "search", debouncedQuery], + queryFn: () => getOptions(debouncedQuery), enabled, }); const searchOptions = useMemo(() => { + if (searchOptionsQuery.isFetching) { + return undefined; + } + const isDataLoaded = searchOptionsQuery.isFetched && selectedOptionQuery.isFetched; @@ -77,6 +85,7 @@ export const useFilterMenu = ({ query, searchOptionsQuery.data, searchOptionsQuery.isFetched, + searchOptionsQuery.isFetching, selectedOption, ]);