import { css } from '@emotion/css'; import { useCallback, useEffect, useState } from 'react'; import { SelectableValue, toOption } from '@grafana/data'; import { TemporaryAlert } from '@grafana/o11y-ds-frontend'; import { getTemplateSrv } from '@grafana/runtime'; import { fuzzyMatch, InlineField, InlineFieldRow, Input, Select } from '@grafana/ui'; import { JaegerDatasource } from '../datasource'; import { JaegerQuery } from '../types'; import { transformToLogfmt } from '../util'; const durationPlaceholder = 'e.g. 1.2s, 100ms, 500us'; type Props = { datasource: JaegerDatasource; query: JaegerQuery; onChange: (value: JaegerQuery) => void; }; export const ALL_OPERATIONS_KEY = 'All'; const allOperationsOption: SelectableValue = { label: ALL_OPERATIONS_KEY, value: undefined, }; export function SearchForm({ datasource, query, onChange }: Props) { const [alertText, setAlertText] = useState(''); const [serviceOptions, setServiceOptions] = useState>>(); const [operationOptions, setOperationOptions] = useState>>(); const [isLoading, setIsLoading] = useState<{ services: boolean; operations: boolean; }>({ services: false, operations: false, }); const loadOptions = useCallback( async (url: string, loaderOfType: string, query = ''): Promise>> => { setIsLoading((prevValue) => ({ ...prevValue, [loaderOfType]: true })); try { const values: string[] | null = await datasource.metadataRequest(url); if (!values) { return [{ label: `No ${loaderOfType} found`, value: `No ${loaderOfType} found` }]; } const options: SelectableValue[] = values.sort().map((option) => ({ label: option, value: option, })); const filteredOptions = options.filter((item) => (item.value ? fuzzyMatch(item.value, query).found : false)); setAlertText(''); return filteredOptions; } catch (error) { if (error instanceof Error) { setAlertText(`Error: ${error.message}`); } return []; } finally { setIsLoading((prevValue) => ({ ...prevValue, [loaderOfType]: false })); } }, [datasource] ); useEffect(() => { const getServices = async () => { const services = await loadOptions('services', 'services'); if (query.service && getTemplateSrv().containsTemplate(query.service)) { services.push(toOption(query.service)); } setServiceOptions(services); }; getServices(); }, [datasource, loadOptions, query.service]); useEffect(() => { const getOperations = async () => { const operations = await loadOptions( `services/${encodeURIComponent(getTemplateSrv().replace(query.service!))}/operations`, 'operations' ); if (query.operation && getTemplateSrv().containsTemplate(query.operation)) { operations.push(toOption(query.operation)); } setOperationOptions([allOperationsOption, ...operations]); }; if (query.service) { getOperations(); } }, [datasource, query.service, loadOptions, query.operation]); return ( <>
loadOptions( `services/${encodeURIComponent(getTemplateSrv().replace(query.service!))}/operations`, 'operations' ) } isLoading={isLoading.operations} value={operationOptions?.find((v) => v.value === query.operation) || null} placeholder="Select an operation" onChange={(v) => onChange({ ...query, operation: v?.value! || undefined, }) } menuPlacement="bottom" isClearable aria-label={'select-operation-name'} allowCustomValue={true} /> onChange({ ...query, tags: v.currentTarget.value, }) } /> onChange({ ...query, minDuration: v.currentTarget.value, }) } /> onChange({ ...query, maxDuration: v.currentTarget.value, }) } /> onChange({ ...query, limit: v.currentTarget.value ? parseInt(v.currentTarget.value, 10) : undefined, }) } />
{alertText && } ); } export default SearchForm;