diff --git a/public/app/plugins/datasource/tempo/QueryEditor/NativeSearch.test.tsx b/public/app/plugins/datasource/tempo/QueryEditor/NativeSearch.test.tsx
index 21ae2466c0c..dc01b7262f4 100644
--- a/public/app/plugins/datasource/tempo/QueryEditor/NativeSearch.test.tsx
+++ b/public/app/plugins/datasource/tempo/QueryEditor/NativeSearch.test.tsx
@@ -35,6 +35,7 @@ const mockQuery = {
queryType: 'nativeSearch',
key: 'Q-595a9bbc-2a25-49a7-9249-a52a0a475d83-0',
serviceName: 'driver',
+ spanName: 'customer',
} as TempoQuery;
describe('NativeSearch', () => {
@@ -56,9 +57,9 @@ describe('NativeSearch', () => {
);
- const asyncServiceSelect = screen.getByRole('combobox', { name: 'select-span-name' });
+ const select = screen.getByRole('combobox', { name: 'select-service-name' });
- await user.click(asyncServiceSelect);
+ await user.click(select);
const loader = screen.getByText('Loading options...');
expect(loader).toBeInTheDocument();
@@ -76,7 +77,7 @@ describe('NativeSearch', () => {
queryType: 'nativeSearch',
refId: 'A',
serviceName: 'driver',
- spanName: 'driver',
+ spanName: 'customer',
};
render(
@@ -88,12 +89,13 @@ describe('NativeSearch', () => {
/>
);
- const asyncServiceSelect = await screen.findByRole('combobox', { name: 'select-span-name' });
+ const select = await screen.findByRole('combobox', { name: 'select-service-name' });
- expect(asyncServiceSelect).toBeInTheDocument();
- await user.click(asyncServiceSelect);
+ expect(select).toBeInTheDocument();
+ await user.click(select);
jest.advanceTimersByTime(1000);
+ await user.type(select, 'd');
const driverOption = await screen.findByText('driver');
await user.click(driverOption);
@@ -105,19 +107,16 @@ describe('NativeSearch', () => {
{}} onRunQuery={() => {}} />
);
- const asyncServiceSelect = await screen.findByRole('combobox', { name: 'select-span-name' });
-
- expect(asyncServiceSelect).toBeInTheDocument();
- await user.click(asyncServiceSelect);
+ const select = await screen.findByRole('combobox', { name: 'select-service-name' });
+ await user.click(select);
jest.advanceTimersByTime(1000);
+ expect(select).toBeInTheDocument();
- await user.type(asyncServiceSelect, 'd');
- jest.advanceTimersByTime(1000);
+ await user.type(select, 'd');
var option = await screen.findByText('driver');
expect(option).toBeDefined();
- await user.type(asyncServiceSelect, 'a');
- jest.advanceTimersByTime(1000);
+ await user.type(select, 'a');
option = await screen.findByText('No options found');
expect(option).toBeDefined();
});
diff --git a/public/app/plugins/datasource/tempo/QueryEditor/NativeSearch.tsx b/public/app/plugins/datasource/tempo/QueryEditor/NativeSearch.tsx
index 232c86aed93..4e83d2808b5 100644
--- a/public/app/plugins/datasource/tempo/QueryEditor/NativeSearch.tsx
+++ b/public/app/plugins/datasource/tempo/QueryEditor/NativeSearch.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import { debounce } from 'lodash';
import Prism from 'prismjs';
import React, { useCallback, useState, useEffect, useMemo } from 'react';
import { Node } from 'slate';
@@ -15,10 +14,10 @@ import {
BracesPlugin,
TypeaheadInput,
TypeaheadOutput,
- AsyncSelect,
Alert,
useStyles2,
fuzzyMatch,
+ Select,
} from '@grafana/ui';
import { notifyApp } from 'app/core/actions';
import { createErrorNotification } from 'app/core/copy/appNotification';
@@ -52,12 +51,8 @@ const NativeSearch = ({ datasource, query, onChange, onBlur, onRunQuery }: Props
const styles = useStyles2(getStyles);
const languageProvider = useMemo(() => new TempoLanguageProvider(datasource), [datasource]);
const [hasSyntaxLoaded, setHasSyntaxLoaded] = useState(false);
- const [asyncServiceNameValue, setAsyncServiceNameValue] = useState>({
- value: '',
- });
- const [asyncSpanNameValue, setAsyncSpanNameValue] = useState>({
- value: '',
- });
+ const [serviceOptions, setServiceOptions] = useState>>();
+ const [spanOptions, setSpanOptions] = useState>>();
const [error, setError] = useState(null);
const [inputErrors, setInputErrors] = useState<{ [key: string]: boolean }>({});
const [isLoading, setIsLoading] = useState<{
@@ -68,60 +63,35 @@ const NativeSearch = ({ datasource, query, onChange, onBlur, onRunQuery }: Props
spanName: false,
});
- async function fetchOptionsCallback(name: string, lp: TempoLanguageProvider, query = '') {
- try {
- setIsLoading((prevValue) => ({ ...prevValue, [name]: false }));
- const options = await lp.getOptions(name);
- const filteredOptions = options.filter((item) => (item.value ? fuzzyMatch(item.value, query).found : false));
- return filteredOptions;
- } catch (error) {
- if (error?.status === 404) {
- setIsLoading((prevValue) => ({ ...prevValue, [name]: false }));
- } else {
- dispatch(notifyApp(createErrorNotification('Error', error)));
+ const loadOptions = useCallback(
+ async (name: string, query = '') => {
+ const lpName = name === 'serviceName' ? 'service.name' : 'name';
+ setIsLoading((prevValue) => ({ ...prevValue, [name]: true }));
+
+ try {
+ const options = await languageProvider.getOptions(lpName);
+ const filteredOptions = options.filter((item) => (item.value ? fuzzyMatch(item.value, query).found : false));
+ return filteredOptions;
+ } catch (error) {
+ if (error?.status === 404) {
+ setError(error);
+ } else {
+ dispatch(notifyApp(createErrorNotification('Error', error)));
+ }
+ return [];
+ } finally {
setIsLoading((prevValue) => ({ ...prevValue, [name]: false }));
}
- setError(error);
- return [];
- }
- }
-
- const loadOptionsOfType = useCallback(
- (name: string) => {
- setIsLoading((prevValue) => ({ ...prevValue, [name]: true }));
- return fetchOptionsCallback(name, languageProvider);
},
[languageProvider]
);
- const fetchOptionsOfType = useCallback(
- (name: string) => debounce(() => loadOptionsOfType(name), 500, { leading: true, trailing: true }),
- [loadOptionsOfType]
- );
-
- const getNameOptions = (query: string, name: string) => {
- setIsLoading((prevValue) => ({ ...prevValue, [name]: true }));
- return fetchOptionsCallback(name, languageProvider, query);
- };
-
- const getServiceNameOptions = (query: string) => {
- return getNameOptions(query, 'service.name');
- };
-
- const getSpanNameOptions = (query: string) => {
- return getNameOptions(query, 'name');
- };
-
- const serviceNameSearch = debounce(getServiceNameOptions, 500, { leading: true, trailing: true });
- const spanNameSearch = debounce(getSpanNameOptions, 500, { leading: true, trailing: true });
-
useEffect(() => {
const fetchOptions = async () => {
try {
- await languageProvider.start();
- fetchOptionsCallback('service.name', languageProvider);
- fetchOptionsCallback('name', languageProvider);
- setHasSyntaxLoaded(true);
+ const [services, spans] = await Promise.all([loadOptions('serviceName'), loadOptions('spanName')]);
+ setServiceOptions(services);
+ setSpanOptions(spans);
} catch (error) {
// Display message if Tempo is connected but search 404's
if (error?.status === 404) {
@@ -129,11 +99,22 @@ const NativeSearch = ({ datasource, query, onChange, onBlur, onRunQuery }: Props
} else {
dispatch(notifyApp(createErrorNotification('Error', error)));
}
- setHasSyntaxLoaded(true);
}
};
fetchOptions();
- }, [languageProvider, fetchOptionsOfType]);
+ }, [languageProvider, loadOptions]);
+
+ useEffect(() => {
+ const fetchTags = async () => {
+ try {
+ await languageProvider.start();
+ setHasSyntaxLoaded(true);
+ } catch (error) {
+ dispatch(notifyApp(createErrorNotification('Error', error)));
+ }
+ };
+ fetchTags();
+ }, [languageProvider]);
const onTypeahead = async (typeahead: TypeaheadInput): Promise => {
return await languageProvider.provideCompletionItems(typeahead);
@@ -160,17 +141,15 @@ const NativeSearch = ({ datasource, query, onChange, onBlur, onRunQuery }: Props
- {
+ loadOptions('serviceName');
+ }}
isLoading={isLoading.serviceName}
- value={asyncServiceNameValue.value}
+ value={serviceOptions?.find((v) => v?.value === query.serviceName) || undefined}
onChange={(v) => {
- setAsyncServiceNameValue({
- value: v,
- });
onChange({
...query,
serviceName: v?.value || undefined,
@@ -178,7 +157,6 @@ const NativeSearch = ({ datasource, query, onChange, onBlur, onRunQuery }: Props
}}
placeholder="Select a service"
isClearable
- defaultOptions
onKeyDown={onKeyDown}
aria-label={'select-service-name'}
/>
@@ -186,15 +164,15 @@ const NativeSearch = ({ datasource, query, onChange, onBlur, onRunQuery }: Props
- {
+ loadOptions('spanName');
+ }}
isLoading={isLoading.spanName}
- value={asyncSpanNameValue.value}
+ value={spanOptions?.find((v) => v?.value === query.spanName) || undefined}
onChange={(v) => {
- setAsyncSpanNameValue({ value: v });
onChange({
...query,
spanName: v?.value || undefined,
@@ -202,7 +180,6 @@ const NativeSearch = ({ datasource, query, onChange, onBlur, onRunQuery }: Props
}}
placeholder="Select a span"
isClearable
- defaultOptions
onKeyDown={onKeyDown}
aria-label={'select-span-name'}
/>