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
This commit is contained in:
Abhi kumar 2025-07-23 11:46:29 +05:30 committed by GitHub
parent d6383a722e
commit e97c7d64d0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 78 additions and 24 deletions

View File

@ -0,0 +1,7 @@
.order-by-loading-container {
padding: 4px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}

View File

@ -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 (
<div className="order-by-loading-container">
{isLoading ? <Spin size="default" /> : 'No results found'}
</div>
);
}
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<ReturnType<typeof setTimeout> | 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 (
<Select
showSearch
value={value}
onChange={onChange}
onSearch={setSearchText}
onSearch={handleSearch}
notFoundContent={<Loader isLoading={isLoading} />}
placeholder="Select an attribute"
style={{ width: 200 }}
options={options}
filterOption={false}
options={selectOptions}
filterOption={(input, option): boolean =>
(option?.value ?? '').toLowerCase().includes(input.trim().toLowerCase())
}
/>
);
}