UNPKG

@grafana/ui

Version:
116 lines (113 loc) 3.9 kB
import { debounce } from 'lodash'; import { useMemo, useState, useCallback } from 'react'; import { t } from '@grafana/i18n'; import { itemToString, fuzzyFind } from './filter.mjs'; import { useLatestAsyncCall, StaleResultError } from './useLatestAsyncCall.mjs'; const asyncNoop = () => Promise.resolve([]); function useOptions(rawOptions, createCustomValue) { const isAsync = typeof rawOptions === "function"; const loadOptions = useLatestAsyncCall(isAsync ? rawOptions : asyncNoop); const debouncedLoadOptions = useMemo( () => debounce((searchTerm) => { return loadOptions(searchTerm).then((options) => { setAsyncOptions(options); setAsyncLoading(false); setAsyncError(false); }).catch((error) => { if (!(error instanceof StaleResultError)) { setAsyncError(true); setAsyncLoading(false); if (error) { console.error("Error loading async options for Combobox", error); } } }); }, 200), [loadOptions] ); const [asyncOptions, setAsyncOptions] = useState([]); const [asyncLoading, setAsyncLoading] = useState(false); const [asyncError, setAsyncError] = useState(false); const [userTypedSearch, setUserTypedSearch] = useState(""); const addCustomValue = useCallback( (opts) => { let currentOptions = opts; if (createCustomValue && userTypedSearch) { const customValueExists = opts.some((opt) => opt.value === userTypedSearch); if (!customValueExists) { currentOptions = currentOptions.slice(); currentOptions.unshift({ label: userTypedSearch, value: userTypedSearch, description: t("combobox.custom-value.description", "Use custom value") }); } } return currentOptions; }, [createCustomValue, userTypedSearch] ); const updateOptions = useCallback( (inputValue) => { setUserTypedSearch(inputValue); if (isAsync) { setAsyncLoading(true); debouncedLoadOptions(inputValue); } }, [debouncedLoadOptions, isAsync] ); const stringifiedOptions = useMemo(() => { return isAsync ? [] : rawOptions.map(itemToString); }, [isAsync, rawOptions]); const filteredOptions = useMemo(() => { if (isAsync) { return asyncOptions; } return fuzzyFind(rawOptions, stringifiedOptions, userTypedSearch); }, [asyncOptions, isAsync, rawOptions, stringifiedOptions, userTypedSearch]); const [finalOptions, groupStartIndices] = useMemo(() => { const { options, groupStartIndices: groupStartIndices2 } = sortByGroup(filteredOptions); return [addCustomValue(options), groupStartIndices2]; }, [filteredOptions, addCustomValue]); return { options: finalOptions, groupStartIndices, updateOptions, asyncLoading, asyncError }; } function sortByGroup(options) { var _a, _b; const groupedOptions = /* @__PURE__ */ new Map(); const groupStartIndices = /* @__PURE__ */ new Map(); for (const option of options) { const group = option.group; const existing = groupedOptions.get(group); if (existing) { existing.push(option); } else { groupedOptions.set(group, [option]); } } if (groupedOptions.size <= 1) { if ((_a = options[0]) == null ? void 0 : _a.group) { groupStartIndices.set((_b = options[0]) == null ? void 0 : _b.group, 0); } return { options, groupStartIndices }; } const result = new Array(options.length); let currentIndex = 0; for (const [group, groupOptions] of groupedOptions) { if (group) { groupStartIndices.set(group, currentIndex); } for (const option of groupOptions) { result[currentIndex++] = option; } } return { options: result, groupStartIndices }; } export { sortByGroup, useOptions }; //# sourceMappingURL=useOptions.mjs.map