diff --git a/packages/grafana-ui/src/components/Combobox/Combobox.story.tsx b/packages/grafana-ui/src/components/Combobox/Combobox.story.tsx index 309a3028098..23c8f30032b 100644 --- a/packages/grafana-ui/src/components/Combobox/Combobox.story.tsx +++ b/packages/grafana-ui/src/components/Combobox/Combobox.story.tsx @@ -273,6 +273,14 @@ const AsyncStory: StoryFn = (args) => { ); }, []); + const loadOptionsWithErrors = useCallback((inputValue: string) => { + if (inputValue.length % 2 === 0) { + return fakeSearchAPI(`http://example.com/search?query=${inputValue}`); + } else { + throw new Error('Could not retrieve options'); + } + }, []); + return ( <> = (args) => { /> + + { + action('onChange')(val); + setSelectedOption(val); + }} + /> + { expect(customItem).toBeInTheDocument(); }); + + it('should display message when there is an error loading async options', async () => { + const asyncOptions = jest.fn(() => { + throw new Error('Could not retrieve options'); + }); + + render(); + + const input = screen.getByRole('combobox'); + await user.click(input); + await user.type(input, 'test'); + + await act(async () => { + jest.advanceTimersToNextTimer(); + }); + + const emptyMessage = screen.queryByText('An error occurred while loading options.'); + + expect(emptyMessage).toBeInTheDocument(); + }); }); }); diff --git a/packages/grafana-ui/src/components/Combobox/Combobox.tsx b/packages/grafana-ui/src/components/Combobox/Combobox.tsx index f2e439946aa..933cee2d8c0 100644 --- a/packages/grafana-ui/src/components/Combobox/Combobox.tsx +++ b/packages/grafana-ui/src/components/Combobox/Combobox.tsx @@ -9,6 +9,8 @@ import { t } from '../../utils/i18n'; import { Icon } from '../Icon/Icon'; import { AutoSizeInput } from '../Input/AutoSizeInput'; import { Input, Props as InputProps } from '../Input/Input'; +import { Stack } from '../Layout/Stack/Stack'; +import { Text } from '../Text/Text'; import { getComboboxStyles } from './getComboboxStyles'; import { useComboboxFloat, OPTION_HEIGHT } from './useComboboxFloat'; @@ -94,6 +96,7 @@ export const Combobox = ({ const isAsync = typeof options === 'function'; const loadOptions = useLatestAsyncCall(isAsync ? options : asyncNoop); // loadOptions isn't called at all if not async const [asyncLoading, setAsyncLoading] = useState(false); + const [asyncError, setAsyncError] = useState(false); const [items, setItems] = useState(isAsync ? [] : options); @@ -143,10 +146,11 @@ export const Combobox = ({ .then((opts) => { setItems(customValueOption ? [customValueOption, ...opts] : opts); setAsyncLoading(false); + setAsyncError(false); }) .catch((err) => { if (!(err instanceof StaleResultError)) { - // TODO: handle error + setAsyncError(true); setAsyncLoading(false); } }); @@ -217,12 +221,12 @@ export const Combobox = ({ .then((options) => { setItems(options); setAsyncLoading(false); + setAsyncError(false); }) .catch((err) => { if (!(err instanceof StaleResultError)) { - // TODO: handle error + setAsyncError(true); setAsyncLoading(false); - throw err; } }); return; @@ -307,7 +311,7 @@ export const Combobox = ({ 'aria-labelledby': ariaLabelledBy, })} > - {isOpen && ( + {isOpen && !asyncError && (
    {rowVirtualizer.getVirtualItems().map((virtualRow) => { return ( @@ -341,6 +345,12 @@ export const Combobox = ({ })}
)} + {asyncError && ( + + + {t('combobox.async.error', 'An error occurred while loading options.')} + + )} ); diff --git a/packages/grafana-ui/src/components/Combobox/getComboboxStyles.ts b/packages/grafana-ui/src/components/Combobox/getComboboxStyles.ts index 9c24efae0ea..95ceef76a7e 100644 --- a/packages/grafana-ui/src/components/Combobox/getComboboxStyles.ts +++ b/packages/grafana-ui/src/components/Combobox/getComboboxStyles.ts @@ -98,5 +98,9 @@ export const getComboboxStyles = (theme: GrafanaTheme2) => { color: theme.colors.text.primary, }, }), + warningIcon: css({ + label: 'grafana-select-warning-icon', + color: theme.colors.text.secondary, + }), }; }; diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index 43faff4dc65..526c5f9aace 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -448,6 +448,9 @@ } }, "combobox": { + "async": { + "error": "An error occurred while loading options." + }, "clear": { "title": "Clear value" }, diff --git a/public/locales/pseudo-LOCALE/grafana.json b/public/locales/pseudo-LOCALE/grafana.json index d1ac1ff091a..859c47639f7 100644 --- a/public/locales/pseudo-LOCALE/grafana.json +++ b/public/locales/pseudo-LOCALE/grafana.json @@ -448,6 +448,9 @@ } }, "combobox": { + "async": { + "error": "Åʼn ęřřőř őččūřřęđ ŵĥįľę ľőäđįʼnģ őpŧįőʼnş." + }, "clear": { "title": "Cľęäř väľūę" },