Commit e0229045 by Erik Sundell Committed by GitHub

UI: Use SelectableValue as Segment value (#20867)

* Use SelectableValue for segment value

* Update cloudwatch components to use new segment props
parent b111fee6
......@@ -18,8 +18,9 @@ const toOption = (value: any) => ({ label: value, value: value });
SegmentStories.add('Array Options', () => {
const options = ['Option1', 'Option2', 'OptionWithLooongLabel', 'Option4'].map(toOption);
options[0].label = 'Option1 Label';
return (
<UseState initialState={options[0].value}>
<UseState initialState={options[0] as SelectableValue}>
{(value, updateValue) => (
<>
<div className="gf-form-inline">
......@@ -29,9 +30,9 @@ SegmentStories.add('Array Options', () => {
<Segment
value={value}
options={options}
onChange={(value: SelectableValue<string>) => {
updateValue(value);
action('Segment value changed')(value);
onChange={item => {
updateValue(item);
action('Segment value changed')(item.value);
}}
/>
<Segment
......@@ -53,7 +54,7 @@ const groupedOptions = [
SegmentStories.add('Grouped Array Options', () => {
return (
<UseState initialState={groupedOptions[0].options[0].value}>
<UseState initialState={groupedOptions[0].options[0] as SelectableValue}>
{(value, updateValue) => (
<>
<div className="gf-form-inline">
......@@ -63,9 +64,9 @@ SegmentStories.add('Grouped Array Options', () => {
<Segment
value={value}
options={groupedOptions}
onChange={(value: SelectableValue<string>) => {
updateValue(value);
action('Segment value changed')(value);
onChange={item => {
updateValue(item);
action('Segment value changed')(item.value);
}}
/>
<Segment
......@@ -83,7 +84,7 @@ SegmentStories.add('Grouped Array Options', () => {
SegmentStories.add('With custom options allowed', () => {
const options = ['Option1', 'Option2', 'OptionWithLooongLabel', 'Option4'].map(toOption);
return (
<UseState initialState={options[0].value}>
<UseState initialState={options[0] as SelectableValue}>
{(value, updateValue) => (
<>
<div className="gf-form-inline">
......@@ -94,9 +95,9 @@ SegmentStories.add('With custom options allowed', () => {
allowCustomValue
value={value}
options={options}
onChange={(value: SelectableValue<string>) => {
updateValue(value);
action('Segment value changed')(value);
onChange={item => {
updateValue(item);
action('Segment value changed')(item.value);
}}
/>
<Segment
......@@ -112,11 +113,11 @@ SegmentStories.add('With custom options allowed', () => {
);
});
const CustomLabelComponent = ({ value }: any) => <div className="gf-form-label">custom({value})</div>;
const CustomLabelComponent = ({ value: { value } }: any) => <div className="gf-form-label">custom({value})</div>;
SegmentStories.add('Custom Label Field', () => {
return (
<UseState initialState={groupedOptions[0].options[0].value}>
<UseState initialState={groupedOptions[0].options[0] as SelectableValue}>
{(value, setValue) => (
<>
<div className="gf-form-inline">
......@@ -126,9 +127,9 @@ SegmentStories.add('Custom Label Field', () => {
<Segment
Component={<CustomLabelComponent value={value} />}
options={groupedOptions}
onChange={(value: SelectableValue<string>) => {
setValue(value);
action('Segment value changed')(value);
onChange={item => {
setValue(item);
action('Segment value changed')(item.value);
}}
/>
<Segment
......
......@@ -18,18 +18,23 @@ export function Segment<T>({
const [Label, width, expanded, setExpanded] = useExpandableLabel(false);
if (!expanded) {
return <Label Component={Component || <a className={cx('gf-form-label', 'query-part', className)}>{value}</a>} />;
return (
<Label
Component={Component || <a className={cx('gf-form-label', 'query-part', className)}>{value && value.label}</a>}
/>
);
}
return (
<SegmentSelect
width={width}
value={value}
options={options}
width={width}
onClickOutside={() => setExpanded(false)}
allowCustomValue={allowCustomValue}
onChange={value => {
onChange={item => {
setExpanded(false);
onChange(value);
onChange(item);
}}
/>
);
......
......@@ -20,7 +20,7 @@ const loadOptions = (options: any): Promise<Array<SelectableValue<string>>> =>
SegmentStories.add('Array Options', () => {
const options = ['Option1', 'Option2', 'OptionWithLooongLabel', 'Option4'].map(toOption);
return (
<UseState initialState={options[0].value}>
<UseState initialState={options[0] as SelectableValue}>
{(value, updateValue) => (
<>
<div className="gf-form-inline">
......@@ -30,9 +30,9 @@ SegmentStories.add('Array Options', () => {
<SegmentAsync
value={value}
loadOptions={() => loadOptions(options)}
onChange={value => {
updateValue(value);
action('Segment value changed')(value);
onChange={item => {
updateValue(item);
action('Segment value changed')(item.value);
}}
/>
<SegmentAsync
......@@ -54,7 +54,7 @@ const groupedOptions = [
SegmentStories.add('Grouped Array Options', () => {
return (
<UseState initialState={groupedOptions[0].options[0].value}>
<UseState initialState={groupedOptions[0].options[0] as SelectableValue}>
{(value, updateValue) => (
<>
<div className="gf-form-inline">
......@@ -64,9 +64,9 @@ SegmentStories.add('Grouped Array Options', () => {
<SegmentAsync
value={value}
loadOptions={() => loadOptions(groupedOptions)}
onChange={value => {
updateValue(value);
action('Segment value changed')(value);
onChange={item => {
updateValue(item);
action('Segment value changed')(item.value);
}}
/>
<SegmentAsync
......@@ -84,7 +84,7 @@ SegmentStories.add('Grouped Array Options', () => {
SegmentStories.add('With custom options allowed', () => {
const options = ['Option1', 'Option2', 'OptionWithLooongLabel', 'Option4'].map(toOption);
return (
<UseState initialState={options[0].value}>
<UseState initialState={options[0] as SelectableValue}>
{(value, updateValue) => (
<>
<div className="gf-form-inline">
......@@ -95,9 +95,9 @@ SegmentStories.add('With custom options allowed', () => {
allowCustomValue
value={value}
loadOptions={() => loadOptions(options)}
onChange={value => {
updateValue(value);
action('Segment value changed')(value);
onChange={item => {
updateValue(item);
action('Segment value changed')(item.value);
}}
/>
<SegmentAsync
......@@ -113,10 +113,10 @@ SegmentStories.add('With custom options allowed', () => {
);
});
const CustomLabelComponent = ({ value }: any) => <div className="gf-form-label">custom({value})</div>;
const CustomLabelComponent = ({ value: { value } }: any) => <div className="gf-form-label">custom({value})</div>;
SegmentStories.add('Custom Label Field', () => {
return (
<UseState initialState={groupedOptions[0].options[0].value}>
<UseState initialState={groupedOptions[0].options[0] as SelectableValue}>
{(value, updateValue) => (
<>
<div className="gf-form-inline">
......@@ -126,9 +126,9 @@ SegmentStories.add('Custom Label Field', () => {
<SegmentAsync
Component={<CustomLabelComponent value={value} />}
loadOptions={() => loadOptions(groupedOptions)}
onChange={value => {
updateValue(value);
action('Segment value changed')(value);
onChange={item => {
updateValue(item);
action('Segment value changed')(item.value);
}}
/>
<SegmentAsync
......
......@@ -29,15 +29,16 @@ export function SegmentAsync<T>({
setLoadedOptions(opts);
setSelectPlaceholder(opts.length ? '' : 'No options found');
}}
Component={Component || <a className={cx('gf-form-label', 'query-part', className)}>{value}</a>}
Component={Component || <a className={cx('gf-form-label', 'query-part', className)}>{value && value.label}</a>}
/>
);
}
return (
<SegmentSelect
width={width}
value={value}
options={loadedOptions}
width={width}
noOptionsMessage={selectPlaceholder}
allowCustomValue={allowCustomValue}
onClickOutside={() => {
......@@ -45,11 +46,11 @@ export function SegmentAsync<T>({
setLoadedOptions([]);
setExpanded(false);
}}
onChange={value => {
onChange={item => {
setSelectPlaceholder('');
setLoadedOptions([]);
setExpanded(false);
onChange(value);
onChange(item);
}}
/>
);
......
......@@ -5,8 +5,9 @@ import { SelectableValue } from '@grafana/data';
import { Select } from '../Select/Select';
export interface Props<T> {
value?: SelectableValue<T>;
options: Array<SelectableValue<T>>;
onChange: (value: T) => void;
onChange: (item: SelectableValue<T>) => void;
onClickOutside: () => void;
width: number;
noOptionsMessage?: string;
......@@ -14,6 +15,7 @@ export interface Props<T> {
}
export function SegmentSelect<T>({
value,
options = [],
onChange,
onClickOutside,
......@@ -39,8 +41,9 @@ export function SegmentSelect<T>({
placeholder=""
autoFocus={true}
isOpen={true}
onChange={({ value }) => onChange(value!)}
onChange={onChange}
options={options}
value={value}
allowCustomValue={allowCustomValue}
/>
</div>
......
import { ReactElement } from 'react';
import { SelectableValue } from '@grafana/data';
export interface SegmentProps<T> {
onChange: (item: T) => void;
value?: T;
onChange: (item: SelectableValue<T>) => void;
value?: SelectableValue<T>;
Component?: ReactElement;
className?: string;
allowCustomValue?: boolean;
......
......@@ -34,15 +34,17 @@ export const Dimensions: FunctionComponent<Props> = ({ dimensions, loadValues, l
return options.filter(({ value }) => !Object.keys(data).includes(value));
};
const toOption = (value: any) => ({ label: value, value });
return (
<>
{Object.entries(data).map(([key, value], index) => (
<Fragment key={index}>
<SegmentAsync
allowCustomValue
value={key}
value={toOption(key)}
loadOptions={() => loadKeys().then(keys => [removeOption, ...excludeUsedKeys(keys)])}
onChange={newKey => {
onChange={({ value: newKey }) => {
const { [key]: value, ...newDimensions } = data;
if (newKey === removeText) {
setData({ ...newDimensions });
......@@ -54,9 +56,9 @@ export const Dimensions: FunctionComponent<Props> = ({ dimensions, loadValues, l
<label className="gf-form-label query-segment-operator">=</label>
<SegmentAsync
allowCustomValue
value={value || 'select dimension value'}
value={toOption(value || 'select dimension value')}
loadOptions={() => loadValues(key)}
onChange={newValue => setData({ ...data, [key]: newValue })}
onChange={({ value: newValue }) => setData({ ...data, [key]: newValue })}
/>
{Object.values(data).length > 1 && index + 1 !== Object.values(data).length && (
<label className="gf-form-label query-keyword">AND</label>
......@@ -72,7 +74,7 @@ export const Dimensions: FunctionComponent<Props> = ({ dimensions, loadValues, l
</a>
}
loadOptions={() => loadKeys().then(excludeUsedKeys)}
onChange={(newKey: string) => setData({ ...data, [newKey]: '' })}
onChange={({ value: newKey }) => setData({ ...data, [newKey]: '' })}
/>
)}
</>
......
......@@ -112,10 +112,10 @@ export class QueryEditor extends PureComponent<Props, State> {
<>
<QueryInlineField label="Region">
<Segment
value={query.region || 'Select region'}
value={this.toOption(query.region || 'Select region')}
options={regions}
allowCustomValue
onChange={region => this.onChange({ ...query, region })}
onChange={({ value: region }) => this.onChange({ ...query, region })}
/>
</QueryInlineField>
......@@ -123,19 +123,19 @@ export class QueryEditor extends PureComponent<Props, State> {
<>
<QueryInlineField label="Namespace">
<Segment
value={query.namespace || 'Select namespace'}
value={this.toOption(query.namespace || 'Select namespace')}
allowCustomValue
options={namespaces}
onChange={namespace => this.onChange({ ...query, namespace })}
onChange={({ value: namespace }) => this.onChange({ ...query, namespace })}
/>
</QueryInlineField>
<QueryInlineField label="Metric Name">
<SegmentAsync
value={query.metricName || 'Select metric name'}
value={this.toOption(query.metricName || 'Select metric name')}
allowCustomValue
loadOptions={this.loadMetricNames}
onChange={metricName => this.onChange({ ...query, metricName })}
onChange={({ value: metricName }) => this.onChange({ ...query, metricName })}
/>
</QueryInlineField>
......
......@@ -12,6 +12,7 @@ export interface Props {
const removeText = '-- remove stat --';
const removeOption: SelectableValue<string> = { label: removeText, value: removeText };
const toOption = (value: any) => ({ label: value, value });
export const Stats: FunctionComponent<Props> = ({ stats, values, onChange, variableOptionGroup }) => (
<>
......@@ -20,9 +21,9 @@ export const Stats: FunctionComponent<Props> = ({ stats, values, onChange, varia
<Segment
allowCustomValue
key={value + index}
value={value}
value={toOption(value)}
options={[removeOption, ...stats, variableOptionGroup]}
onChange={value =>
onChange={({ value }) =>
onChange(
value === removeText
? values.filter((_, i) => i !== index)
......@@ -39,7 +40,7 @@ export const Stats: FunctionComponent<Props> = ({ stats, values, onChange, varia
</a>
}
allowCustomValue
onChange={(value: string) => onChange([...values, value])}
onChange={({ value }) => onChange([...values, value])}
options={[...stats.filter(({ value }) => !values.includes(value)), variableOptionGroup]}
/>
)}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment