AsyncSegment: Allow custom "no options" messages (#32674)

* Added support for custom user function for mapping custom noOptions messages

* Added new scenario in SegmentAsync.story.tsx

Co-authored-by: Hugo Häggmark <hugo.haggmark@gmail.com>
This commit is contained in:
Villena Guillaume 2021-04-14 08:15:15 +02:00 committed by GitHub
parent 567a6a09bd
commit e533e5fe2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 64 additions and 1 deletions

View File

@ -1,4 +1,5 @@
import React, { useState } from 'react';
import { AsyncState } from 'react-use/lib/useAsync';
import { action } from '@storybook/addon-actions';
import { SelectableValue } from '@grafana/data';
import { SegmentAsync, Icon } from '@grafana/ui';
@ -15,6 +16,9 @@ const options = ['Option1', 'Option2', 'OptionWithLooongLabel', 'Option4'].map(t
const loadOptions = (options: any): Promise<Array<SelectableValue<string>>> =>
new Promise((res) => setTimeout(() => res(options), 2000));
const loadOptionsErr = (): Promise<Array<SelectableValue<string>>> =>
new Promise((_, rej) => setTimeout(() => rej(Error('Could not find data')), 2000));
const SegmentFrame = ({ loadOptions, children }: any) => (
<>
<div className="gf-form-inline">
@ -124,6 +128,63 @@ export const CustomLabel = () => {
);
};
export const CustomStateMessageHandler = () => {
const stateToTextFunction = (state: AsyncState<Array<SelectableValue<string>>>) => {
if (state.loading) {
return "You're going too fast for me, please wait...";
}
if (state.error) {
return 'Outch ! We encountered an error...';
}
if (!Array.isArray(state.value) || state.value.length === 0) {
return 'It is empty :)';
}
return '';
};
const [value, setValue] = useState<any>(options[0]);
return (
<>
<SegmentFrame loadOptions={() => loadOptions(groupedOptions)}>
<SegmentAsync
value={value}
noOptionMessageHandler={stateToTextFunction}
loadOptions={() => loadOptions(groupedOptions)}
onChange={({ value }) => {
setValue(value);
action('Segment value changed')(value);
}}
/>
</SegmentFrame>
<SegmentFrame loadOptions={() => loadOptions([])}>
<SegmentAsync
value={value}
noOptionMessageHandler={stateToTextFunction}
loadOptions={() => loadOptions([])}
onChange={({ value }) => {
setValue(value);
action('Segment value changed')(value);
}}
/>
</SegmentFrame>
<SegmentFrame loadOptions={() => loadOptionsErr()}>
<SegmentAsync
value={value}
noOptionMessageHandler={stateToTextFunction}
loadOptions={() => loadOptionsErr()}
onChange={({ value }) => {
setValue(value);
action('Segment value changed')(value);
}}
/>
</SegmentFrame>
</>
);
};
export const HtmlAttributes = () => {
const [value, setValue] = useState<any>(options[0]);
return (

View File

@ -14,6 +14,7 @@ export interface SegmentAsyncProps<T> extends SegmentProps<T>, Omit<HTMLProps<HT
value?: T | SelectableValue<T>;
loadOptions: (query?: string) => Promise<Array<SelectableValue<T>>>;
onChange: (item: SelectableValue<T>) => void;
noOptionMessageHandler?: (state: AsyncState<Array<SelectableValue<T>>>) => string;
}
export function SegmentAsync<T>({
@ -25,6 +26,7 @@ export function SegmentAsync<T>({
allowCustomValue,
disabled,
placeholder,
noOptionMessageHandler = mapStateToNoOptionsMessage,
...rest
}: React.PropsWithChildren<SegmentAsyncProps<T>>) {
const [state, fetchOptions] = useAsyncFn(loadOptions, [loadOptions]);
@ -64,7 +66,7 @@ export function SegmentAsync<T>({
value={value && !_.isObject(value) ? { value } : value}
options={state.value ?? []}
width={width}
noOptionsMessage={mapStateToNoOptionsMessage(state)}
noOptionsMessage={noOptionMessageHandler(state)}
allowCustomValue={allowCustomValue}
onClickOutside={() => {
setExpanded(false);