|
|
|
@ -1,9 +1,8 @@ |
|
|
|
|
import { css } from '@emotion/css'; |
|
|
|
|
import { debounce } from 'lodash'; |
|
|
|
|
import React, { useCallback, useEffect, useState } from 'react'; |
|
|
|
|
|
|
|
|
|
import { SelectableValue } from '@grafana/data'; |
|
|
|
|
import { AsyncSelect, fuzzyMatch, InlineField, InlineFieldRow, Input } from '@grafana/ui'; |
|
|
|
|
import { fuzzyMatch, InlineField, InlineFieldRow, Input, Select } from '@grafana/ui'; |
|
|
|
|
import { notifyApp } from 'app/core/actions'; |
|
|
|
|
import { createErrorNotification } from 'app/core/copy/appNotification'; |
|
|
|
|
import { dispatch } from 'app/store/store'; |
|
|
|
@ -37,7 +36,7 @@ export function SearchForm({ datasource, query, onChange }: Props) { |
|
|
|
|
operations: false, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
const loadServices = useCallback( |
|
|
|
|
const loadOptions = useCallback( |
|
|
|
|
async (url: string, loaderOfType: string, query = ''): Promise<Array<SelectableValue<string>>> => { |
|
|
|
|
setIsLoading((prevValue) => ({ ...prevValue, [loaderOfType]: true })); |
|
|
|
|
|
|
|
|
@ -47,14 +46,12 @@ export function SearchForm({ datasource, query, onChange }: Props) { |
|
|
|
|
return [{ label: `No ${loaderOfType} found`, value: `No ${loaderOfType} found` }]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const serviceOptions: SelectableValue[] = values.sort().map((service) => ({ |
|
|
|
|
label: service, |
|
|
|
|
value: service, |
|
|
|
|
const options: SelectableValue[] = values.sort().map((option) => ({ |
|
|
|
|
label: option, |
|
|
|
|
value: option, |
|
|
|
|
})); |
|
|
|
|
|
|
|
|
|
const filteredOptions = serviceOptions.filter((item) => |
|
|
|
|
item.value ? fuzzyMatch(item.value, query).found : false |
|
|
|
|
); |
|
|
|
|
const filteredOptions = options.filter((item) => (item.value ? fuzzyMatch(item.value, query).found : false)); |
|
|
|
|
return filteredOptions; |
|
|
|
|
} catch (error) { |
|
|
|
|
dispatch(notifyApp(createErrorNotification('Error', error))); |
|
|
|
@ -66,28 +63,17 @@ export function SearchForm({ datasource, query, onChange }: Props) { |
|
|
|
|
[datasource] |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
const getServiceOptions = (userQuery: string) => { |
|
|
|
|
return loadServices('/api/services', 'services', userQuery); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const getOperationOptions = (userQuery: string) => { |
|
|
|
|
return loadServices(`/api/services/${encodeURIComponent(query.service!)}/operations`, 'operations', userQuery); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const serviceSearch = debounce(getServiceOptions, 500, { leading: true, trailing: true }); |
|
|
|
|
const operationSearch = debounce(getOperationOptions, 500, { leading: true, trailing: true }); |
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
const getServices = async () => { |
|
|
|
|
const services = await loadServices('/api/services', 'services'); |
|
|
|
|
const services = await loadOptions('/api/services', 'services'); |
|
|
|
|
setServiceOptions(services); |
|
|
|
|
}; |
|
|
|
|
getServices(); |
|
|
|
|
}, [datasource, loadServices]); |
|
|
|
|
}, [datasource, loadOptions]); |
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
const getOperations = async () => { |
|
|
|
|
const operations = await loadServices( |
|
|
|
|
const operations = await loadOptions( |
|
|
|
|
`/api/services/${encodeURIComponent(query.service!)}/operations`, |
|
|
|
|
'operations' |
|
|
|
|
); |
|
|
|
@ -96,17 +82,16 @@ export function SearchForm({ datasource, query, onChange }: Props) { |
|
|
|
|
if (query.service) { |
|
|
|
|
getOperations(); |
|
|
|
|
} |
|
|
|
|
}, [datasource, query.service, loadServices]); |
|
|
|
|
}, [datasource, query.service, loadOptions]); |
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
<div className={css({ maxWidth: '500px' })}> |
|
|
|
|
<InlineFieldRow> |
|
|
|
|
<InlineField label="Service" labelWidth={14} grow> |
|
|
|
|
<AsyncSelect |
|
|
|
|
<Select |
|
|
|
|
inputId="service" |
|
|
|
|
cacheOptions={false} |
|
|
|
|
loadOptions={serviceSearch} |
|
|
|
|
onOpenMenu={() => loadServices('/api/services', 'services')} |
|
|
|
|
options={serviceOptions} |
|
|
|
|
onOpenMenu={() => loadOptions('/api/services', 'services')} |
|
|
|
|
isLoading={isLoading.services} |
|
|
|
|
value={serviceOptions?.find((v) => v?.value === query.service) || undefined} |
|
|
|
|
onChange={(v) => |
|
|
|
@ -118,19 +103,17 @@ export function SearchForm({ datasource, query, onChange }: Props) { |
|
|
|
|
} |
|
|
|
|
menuPlacement="bottom" |
|
|
|
|
isClearable |
|
|
|
|
defaultOptions |
|
|
|
|
aria-label={'select-service-name'} |
|
|
|
|
/> |
|
|
|
|
</InlineField> |
|
|
|
|
</InlineFieldRow> |
|
|
|
|
<InlineFieldRow> |
|
|
|
|
<InlineField label="Operation" labelWidth={14} grow disabled={!query.service}> |
|
|
|
|
<AsyncSelect |
|
|
|
|
<Select |
|
|
|
|
inputId="operation" |
|
|
|
|
cacheOptions={false} |
|
|
|
|
loadOptions={operationSearch} |
|
|
|
|
options={operationOptions} |
|
|
|
|
onOpenMenu={() => |
|
|
|
|
loadServices(`/api/services/${encodeURIComponent(query.service!)}/operations`, 'operations') |
|
|
|
|
loadOptions(`/api/services/${encodeURIComponent(query.service!)}/operations`, 'operations') |
|
|
|
|
} |
|
|
|
|
isLoading={isLoading.operations} |
|
|
|
|
value={operationOptions?.find((v) => v.value === query.operation) || null} |
|
|
|
@ -142,7 +125,6 @@ export function SearchForm({ datasource, query, onChange }: Props) { |
|
|
|
|
} |
|
|
|
|
menuPlacement="bottom" |
|
|
|
|
isClearable |
|
|
|
|
defaultOptions |
|
|
|
|
aria-label={'select-operation-name'} |
|
|
|
|
/> |
|
|
|
|
</InlineField> |
|
|
|
|