From e97c7d64d0dd28bb92a772007b623ad013292db8 Mon Sep 17 00:00:00 2001 From: Abhi kumar Date: Wed, 23 Jul 2025 11:46:29 +0530 Subject: [PATCH] fix: added fix for logs orderby filter refetching (#8585) * fix: added fix for logs orderby filter refetching * chore: added cleanup for debouncetimer on unmount * chore: added cleanup for debouncetimer on unmount --- .../OrderBy/ListViewOrderBy.styles.scss | 7 ++ .../components/OrderBy/ListViewOrderBy.tsx | 95 ++++++++++++++----- 2 files changed, 78 insertions(+), 24 deletions(-) create mode 100644 frontend/src/components/OrderBy/ListViewOrderBy.styles.scss diff --git a/frontend/src/components/OrderBy/ListViewOrderBy.styles.scss b/frontend/src/components/OrderBy/ListViewOrderBy.styles.scss new file mode 100644 index 000000000000..9210406a5539 --- /dev/null +++ b/frontend/src/components/OrderBy/ListViewOrderBy.styles.scss @@ -0,0 +1,7 @@ +.order-by-loading-container { + padding: 4px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} diff --git a/frontend/src/components/OrderBy/ListViewOrderBy.tsx b/frontend/src/components/OrderBy/ListViewOrderBy.tsx index cf95a209258e..b390aa11077f 100644 --- a/frontend/src/components/OrderBy/ListViewOrderBy.tsx +++ b/frontend/src/components/OrderBy/ListViewOrderBy.tsx @@ -1,6 +1,8 @@ -import { Select } from 'antd'; +import './ListViewOrderBy.styles.scss'; + +import { Select, Spin } from 'antd'; import { getKeySuggestions } from 'api/querySuggestions/getKeySuggestions'; -import { useMemo, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { useQuery } from 'react-query'; import { QueryKeyDataSuggestionsProps } from 'types/api/querySuggestions/types'; import { DataSource } from 'types/common/queryBuilder'; @@ -11,56 +13,101 @@ interface ListViewOrderByProps { dataSource: DataSource; } +// Loader component for the dropdown when loading or no results +function Loader({ isLoading }: { isLoading: boolean }): JSX.Element { + return ( +
+ {isLoading ? : 'No results found'} +
+ ); +} + function ListViewOrderBy({ value, onChange, dataSource, }: ListViewOrderByProps): JSX.Element { - const [searchText, setSearchText] = useState(''); + const [searchInput, setSearchInput] = useState(''); + const [debouncedInput, setDebouncedInput] = useState(''); + const [selectOptions, setSelectOptions] = useState< + { label: string; value: string }[] + >([]); + const debounceTimer = useRef | null>(null); - const { data } = useQuery( - ['orderByKeySuggestions', dataSource, searchText], - async () => { + // Fetch key suggestions based on debounced input + const { data, isLoading } = useQuery({ + queryKey: ['orderByKeySuggestions', dataSource, debouncedInput], + queryFn: async () => { const response = await getKeySuggestions({ signal: dataSource, - searchText, + searchText: debouncedInput, }); return response.data; }, + }); + + useEffect( + () => (): void => { + if (debounceTimer.current) { + clearTimeout(debounceTimer.current); + } + }, + [], ); - const options = useMemo(() => { - const keys: QueryKeyDataSuggestionsProps[] = data?.data.keys + // Update options when API data changes + useEffect(() => { + const rawKeys: QueryKeyDataSuggestionsProps[] = data?.data.keys ? Object.values(data.data.keys).flat() : []; - let displayKeys: string[]; + const keyNames = rawKeys.map((key) => key.name); + const uniqueKeys = [ + ...new Set(searchInput ? keyNames : ['timestamp', ...keyNames]), + ]; - if (searchText) { - displayKeys = [...new Set(keys.map((k) => k.name))]; - } else { - displayKeys = [ - 'timestamp', - ...keys.map((k) => k.name).filter((k) => k !== 'timestamp'), - ]; - } - - return displayKeys.flatMap((key) => [ + const updatedOptions = uniqueKeys.flatMap((key) => [ { label: `${key} (desc)`, value: `${key}:desc` }, { label: `${key} (asc)`, value: `${key}:asc` }, ]); - }, [data, searchText]); + + setSelectOptions(updatedOptions); + }, [data, searchInput]); + + // Handle search input with debounce + const handleSearch = (input: string): void => { + setSearchInput(input); + + // Filter current options for instant client-side match + const filteredOptions = selectOptions.filter((option) => + option.value.toLowerCase().includes(input.trim().toLowerCase()), + ); + + // If no match found or input is empty, trigger debounced fetch + if (filteredOptions.length === 0 || input === '') { + if (debounceTimer.current) { + clearTimeout(debounceTimer.current); + } + + debounceTimer.current = setTimeout(() => { + setDebouncedInput(input); + }, 100); + } + }; return (