Commit 0e4850f2 by Erik Sundell Committed by GitHub

UI: Segment fixes (#20947)

* Add support for primitive values/onchange

* Fix segment clickaway bug

* Fix onchange

* Use primitive in cloudwatch

* Add placeholder

* Use placeholder in cloudwatch editor

* Fix lint error

* Fix lodash import

* Use new component story format

* Add support for autofocus

* Use selectable value for onchange event

* Fix lint error
parent 26789d1e
import React from 'react'; import React, { useState } from 'react';
import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions'; import { action } from '@storybook/addon-actions';
import { SelectableValue } from '@grafana/data';
import { Segment } from './'; import { Segment } from './';
import { UseState } from '../../utils/storybook/UseState';
const SegmentStories = storiesOf('UI/Segment/SegmentSync', module);
const AddButton = ( const AddButton = (
<a className="gf-form-label query-part"> <a className="gf-form-label query-part">
...@@ -15,131 +9,125 @@ const AddButton = ( ...@@ -15,131 +9,125 @@ const AddButton = (
); );
const toOption = (value: any) => ({ label: value, value: value }); const toOption = (value: any) => ({ label: value, value: value });
const options = ['Option1', 'Option2', 'OptionWithLooongLabel', 'Option4'].map(toOption);
SegmentStories.add('Array Options', () => {
const options = ['Option1', 'Option2', 'OptionWithLooongLabel', 'Option4'].map(toOption);
options[0].label = 'Option1 Label';
return (
<UseState initialState={options[0] as SelectableValue}>
{(value, updateValue) => (
<>
<div className="gf-form-inline">
<div className="gf-form">
<span className="gf-form-label width-8 query-keyword">Segment Name</span>
</div>
<Segment
value={value}
options={options}
onChange={item => {
updateValue(item);
action('Segment value changed')(item.value);
}}
/>
<Segment
Component={AddButton}
onChange={(value: SelectableValue<string>) => action('New value added')(value)}
options={options}
/>
</div>
</>
)}
</UseState>
);
});
const groupedOptions = [ const groupedOptions = [
{ label: 'Names', options: ['Jane', 'Tom', 'Lisa'].map(toOption) }, { label: 'Names', options: ['Jane', 'Tom', 'Lisa'].map(toOption) },
{ label: 'Prime', options: [2, 3, 5, 7, 11, 13].map(toOption) }, { label: 'Prime', options: [2, 3, 5, 7, 11, 13].map(toOption) },
]; ];
SegmentStories.add('Grouped Array Options', () => { const SegmentFrame = ({ options, children }: any) => (
<>
<div className="gf-form-inline">
<div className="gf-form">
<span className="gf-form-label width-8 query-keyword">Segment Name</span>
</div>
{children}
<Segment Component={AddButton} onChange={({ value }) => action('New value added')(value)} options={options} />
</div>
</>
);
export const ArrayOptions = () => {
const [value, setValue] = useState<any>(options[0]);
return (
<SegmentFrame options={options}>
<Segment
value={value}
options={options}
onChange={item => {
setValue(item);
action('Segment value changed')(item.value);
}}
/>
</SegmentFrame>
);
};
export default {
title: 'UI/Segment/SegmentSync',
component: ArrayOptions,
};
export const ArrayOptionsWithPrimitiveValue = () => {
const [value, setValue] = useState('Option1');
return (
<SegmentFrame options={options}>
<Segment
value={value}
options={options}
onChange={({ value }) => {
setValue(value);
action('Segment value changed')(value);
}}
/>
</SegmentFrame>
);
};
export const ArrayOptionsWithPlaceholder = () => {
const [value, setValue] = useState<any>(undefined);
return (
<SegmentFrame options={options}>
<Segment
value={value}
options={options}
placeholder="Enter a value"
onChange={item => {
setValue(item);
action('Segment value changed')(item.value);
}}
/>
</SegmentFrame>
);
};
export const GroupedArrayOptions = () => {
const [value, setValue] = useState<any>(groupedOptions[0].options[0]);
return ( return (
<UseState initialState={groupedOptions[0].options[0] as SelectableValue}> <SegmentFrame options={options}>
{(value, updateValue) => ( <Segment
<> value={value}
<div className="gf-form-inline"> options={groupedOptions}
<div className="gf-form"> onChange={item => {
<span className="gf-form-label width-8 query-keyword">Segment Name</span> setValue(item);
</div> action('Segment value changed')(item.value);
<Segment }}
value={value} />
options={groupedOptions} </SegmentFrame>
onChange={item => {
updateValue(item);
action('Segment value changed')(item.value);
}}
/>
<Segment
Component={AddButton}
onChange={value => action('New value added')(value)}
options={groupedOptions}
/>
</div>
</>
)}
</UseState>
); );
}); };
SegmentStories.add('With custom options allowed', () => { export const CustomOptionsAllowed = () => {
const options = ['Option1', 'Option2', 'OptionWithLooongLabel', 'Option4'].map(toOption); const [value, setValue] = useState(options[0]);
return ( return (
<UseState initialState={options[0] as SelectableValue}> <SegmentFrame options={options}>
{(value, updateValue) => ( <Segment
<> allowCustomValue
<div className="gf-form-inline"> value={value}
<div className="gf-form"> options={options}
<span className="gf-form-label width-8 query-keyword">Segment Name</span> onChange={({ value }) => {
</div> setValue(value);
<Segment action('Segment value changed')(value);
allowCustomValue }}
value={value} />
options={options} </SegmentFrame>
onChange={item => {
updateValue(item);
action('Segment value changed')(item.value);
}}
/>
<Segment
allowCustomValue
Component={AddButton}
onChange={(value: SelectableValue<string>) => action('New value added')(value)}
options={options}
/>
</div>
</>
)}
</UseState>
); );
}); };
const CustomLabelComponent = ({ value: { value } }: any) => <div className="gf-form-label">custom({value})</div>; const CustomLabelComponent = ({ value }: any) => <div className="gf-form-label">custom({value})</div>;
SegmentStories.add('Custom Label Field', () => { export const CustomLabelField = () => {
const [value, setValue] = useState<any>(groupedOptions[0].options[0].value);
return ( return (
<UseState initialState={groupedOptions[0].options[0] as SelectableValue}> <SegmentFrame options={options}>
{(value, setValue) => ( <Segment
<> Component={<CustomLabelComponent value={value} />}
<div className="gf-form-inline"> options={groupedOptions}
<div className="gf-form"> onChange={({ value }) => {
<span className="gf-form-label width-8 query-keyword">Segment Name</span> setValue(value);
</div> action('Segment value changed')(value);
<Segment }}
Component={<CustomLabelComponent value={value} />} />
options={groupedOptions} </SegmentFrame>
onChange={item => {
setValue(item);
action('Segment value changed')(item.value);
}}
/>
<Segment
Component={AddButton}
onChange={value => action('New value added')(value)}
options={groupedOptions}
/>
</div>
</>
)}
</UseState>
); );
}); };
import React from 'react'; import React from 'react';
import { cx } from 'emotion'; import { cx } from 'emotion';
import _ from 'lodash';
import { SelectableValue } from '@grafana/data'; import { SelectableValue } from '@grafana/data';
import { SegmentSelect, useExpandableLabel, SegmentProps } from './'; import { SegmentSelect, useExpandableLabel, SegmentProps } from './';
export interface SegmentSyncProps<T> extends SegmentProps<T> { export interface SegmentSyncProps<T> extends SegmentProps<T> {
value?: SelectableValue<T>; value?: T | SelectableValue<T>;
onChange: (item: SelectableValue<T>) => void; onChange: (item: SelectableValue<T>) => void;
options: Array<SelectableValue<T>>; options: Array<SelectableValue<T>>;
} }
...@@ -16,20 +17,28 @@ export function Segment<T>({ ...@@ -16,20 +17,28 @@ export function Segment<T>({
Component, Component,
className, className,
allowCustomValue, allowCustomValue,
placeholder,
}: React.PropsWithChildren<SegmentSyncProps<T>>) { }: React.PropsWithChildren<SegmentSyncProps<T>>) {
const [Label, width, expanded, setExpanded] = useExpandableLabel(false); const [Label, width, expanded, setExpanded] = useExpandableLabel(false);
if (!expanded) { if (!expanded) {
const label = _.isObject(value) ? value.label : value;
return ( return (
<Label <Label
Component={Component || <a className={cx('gf-form-label', 'query-part', className)}>{value && value.label}</a>} Component={
Component || (
<a className={cx('gf-form-label', 'query-part', !value && placeholder && 'query-placeholder', className)}>
{label || placeholder}
</a>
)
}
/> />
); );
} }
return ( return (
<SegmentSelect <SegmentSelect
value={value} value={value && !_.isObject(value) ? { value } : value}
options={options} options={options}
width={width} width={width}
onClickOutside={() => setExpanded(false)} onClickOutside={() => setExpanded(false)}
......
import React from 'react'; import React, { useState } from 'react';
import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions'; import { action } from '@storybook/addon-actions';
import { SelectableValue } from '@grafana/data'; import { SelectableValue } from '@grafana/data';
const SegmentStories = storiesOf('UI/Segment/SegmentAsync', module);
import { SegmentAsync } from './'; import { SegmentAsync } from './';
import { UseState } from '../../utils/storybook/UseState';
const AddButton = ( const AddButton = (
<a className="gf-form-label query-part"> <a className="gf-form-label query-part">
...@@ -13,132 +10,116 @@ const AddButton = ( ...@@ -13,132 +10,116 @@ const AddButton = (
); );
const toOption = (value: any) => ({ label: value, value: value }); const toOption = (value: any) => ({ label: value, value: value });
const options = ['Option1', 'Option2', 'OptionWithLooongLabel', 'Option4'].map(toOption);
const loadOptions = (options: any): Promise<Array<SelectableValue<string>>> => const loadOptions = (options: any): Promise<Array<SelectableValue<string>>> =>
new Promise(res => setTimeout(() => res(options), 2000)); new Promise(res => setTimeout(() => res(options), 2000));
SegmentStories.add('Array Options', () => { const SegmentFrame = ({ loadOptions, children }: any) => (
const options = ['Option1', 'Option2', 'OptionWithLooongLabel', 'Option4'].map(toOption); <>
<div className="gf-form-inline">
<div className="gf-form">
<span className="gf-form-label width-8 query-keyword">Segment Name</span>
</div>
{children}
<SegmentAsync
Component={AddButton}
onChange={value => action('New value added')(value)}
loadOptions={() => loadOptions(options)}
/>
</div>
</>
);
export const ArrayOptions = () => {
const [value, setValue] = useState<any>(options[0]);
return ( return (
<UseState initialState={options[0] as SelectableValue}> <SegmentFrame loadOptions={() => loadOptions(options)}>
{(value, updateValue) => ( <SegmentAsync
<> value={value}
<div className="gf-form-inline"> loadOptions={() => loadOptions(options)}
<div className="gf-form"> onChange={item => {
<span className="gf-form-label width-8 query-keyword">Segment Name</span> setValue(item);
</div> action('Segment value changed')(item.value);
<SegmentAsync }}
value={value} />
loadOptions={() => loadOptions(options)} </SegmentFrame>
onChange={item => {
updateValue(item);
action('Segment value changed')(item.value);
}}
/>
<SegmentAsync
Component={AddButton}
onChange={value => action('New value added')(value)}
loadOptions={() => loadOptions(options)}
/>
</div>
</>
)}
</UseState>
); );
}); };
const groupedOptions = [ export default {
title: 'UI/Segment/SegmentAsync',
component: ArrayOptions,
};
export const ArrayOptionsWithPrimitiveValue = () => {
const [value, setValue] = useState(options[0].value);
return (
<SegmentFrame loadOptions={() => loadOptions(options)}>
<SegmentAsync
value={value}
loadOptions={() => loadOptions(options)}
onChange={({ value }) => {
setValue(value);
action('Segment value changed')(value);
}}
/>
</SegmentFrame>
);
};
const groupedOptions: any = [
{ label: 'Names', options: ['Jane', 'Tom', 'Lisa'].map(toOption) }, { label: 'Names', options: ['Jane', 'Tom', 'Lisa'].map(toOption) },
{ label: 'Prime', options: [2, 3, 5, 7, 11, 13].map(toOption) }, { label: 'Prime', options: [2, 3, 5, 7, 11, 13].map(toOption) },
]; ];
SegmentStories.add('Grouped Array Options', () => { export const GroupedArrayOptions = () => {
const [value, setValue] = useState(groupedOptions[0].options[0]);
return ( return (
<UseState initialState={groupedOptions[0].options[0] as SelectableValue}> <SegmentFrame loadOptions={() => loadOptions(groupedOptions)}>
{(value, updateValue) => ( <SegmentAsync
<> value={value}
<div className="gf-form-inline"> loadOptions={() => loadOptions(groupedOptions)}
<div className="gf-form"> onChange={item => {
<span className="gf-form-label width-8 query-keyword">Segment Name</span> setValue(item);
</div> action('Segment value changed')(item.value);
<SegmentAsync }}
value={value} />
loadOptions={() => loadOptions(groupedOptions)} </SegmentFrame>
onChange={item => {
updateValue(item);
action('Segment value changed')(item.value);
}}
/>
<SegmentAsync
Component={AddButton}
onChange={value => action('New value added')(value)}
loadOptions={() => loadOptions(groupedOptions)}
/>
</div>
</>
)}
</UseState>
); );
}); };
SegmentStories.add('With custom options allowed', () => { export const CustomOptionsAllowed = () => {
const options = ['Option1', 'Option2', 'OptionWithLooongLabel', 'Option4'].map(toOption); const [value, setValue] = useState(groupedOptions[0].options[0]);
return ( return (
<UseState initialState={options[0] as SelectableValue}> <SegmentFrame loadOptions={() => loadOptions(groupedOptions)}>
{(value, updateValue) => ( <SegmentAsync
<> allowCustomValue
<div className="gf-form-inline"> value={value}
<div className="gf-form"> loadOptions={() => loadOptions(options)}
<span className="gf-form-label width-8 query-keyword">Segment Name</span> onChange={item => {
</div> setValue(item);
<SegmentAsync action('Segment value changed')(item.value);
allowCustomValue }}
value={value} />
loadOptions={() => loadOptions(options)} </SegmentFrame>
onChange={item => {
updateValue(item);
action('Segment value changed')(item.value);
}}
/>
<SegmentAsync
allowCustomValue
Component={AddButton}
onChange={value => action('New value added')(value)}
loadOptions={() => loadOptions(options)}
/>
</div>
</>
)}
</UseState>
); );
}); };
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>; export const CustomLabel = () => {
SegmentStories.add('Custom Label Field', () => { const [value, setValue] = useState(groupedOptions[0].options[0].value);
return ( return (
<UseState initialState={groupedOptions[0].options[0] as SelectableValue}> <SegmentFrame loadOptions={() => loadOptions(groupedOptions)}>
{(value, updateValue) => ( <SegmentAsync
<> Component={<CustomLabelComponent value={value} />}
<div className="gf-form-inline"> loadOptions={() => loadOptions(groupedOptions)}
<div className="gf-form"> onChange={({ value }) => {
<span className="gf-form-label width-8 query-keyword">Segment Name</span> setValue(value);
</div> action('Segment value changed')(value);
<SegmentAsync }}
Component={<CustomLabelComponent value={value} />} />
loadOptions={() => loadOptions(groupedOptions)} </SegmentFrame>
onChange={item => {
updateValue(item);
action('Segment value changed')(item.value);
}}
/>
<SegmentAsync
Component={AddButton}
onChange={value => action('New value added')(value)}
loadOptions={() => loadOptions(groupedOptions)}
/>
</div>
</>
)}
</UseState>
); );
}); };
import React, { useState } from 'react'; import React, { useState } from 'react';
import { cx } from 'emotion'; import { cx } from 'emotion';
import _ from 'lodash';
import { SegmentSelect } from './SegmentSelect'; import { SegmentSelect } from './SegmentSelect';
import { SelectableValue } from '@grafana/data'; import { SelectableValue } from '@grafana/data';
import { useExpandableLabel, SegmentProps } from '.'; import { useExpandableLabel, SegmentProps } from '.';
export interface SegmentAsyncProps<T> extends SegmentProps<T> { export interface SegmentAsyncProps<T> extends SegmentProps<T> {
value?: SelectableValue<T>; value?: T | SelectableValue<T>;
loadOptions: (query?: string) => Promise<Array<SelectableValue<T>>>; loadOptions: (query?: string) => Promise<Array<SelectableValue<T>>>;
onChange: (item: SelectableValue<T>) => void; onChange: (item: SelectableValue<T>) => void;
} }
...@@ -17,12 +18,14 @@ export function SegmentAsync<T>({ ...@@ -17,12 +18,14 @@ export function SegmentAsync<T>({
Component, Component,
className, className,
allowCustomValue, allowCustomValue,
placeholder,
}: React.PropsWithChildren<SegmentAsyncProps<T>>) { }: React.PropsWithChildren<SegmentAsyncProps<T>>) {
const [selectPlaceholder, setSelectPlaceholder] = useState<string>(''); const [selectPlaceholder, setSelectPlaceholder] = useState<string>('');
const [loadedOptions, setLoadedOptions] = useState<Array<SelectableValue<T>>>([]); const [loadedOptions, setLoadedOptions] = useState<Array<SelectableValue<T>>>([]);
const [Label, width, expanded, setExpanded] = useExpandableLabel(false); const [Label, width, expanded, setExpanded] = useExpandableLabel(false);
if (!expanded) { if (!expanded) {
const label = _.isObject(value) ? value.label : value;
return ( return (
<Label <Label
onClick={async () => { onClick={async () => {
...@@ -31,14 +34,20 @@ export function SegmentAsync<T>({ ...@@ -31,14 +34,20 @@ export function SegmentAsync<T>({
setLoadedOptions(opts); setLoadedOptions(opts);
setSelectPlaceholder(opts.length ? '' : 'No options found'); setSelectPlaceholder(opts.length ? '' : 'No options found');
}} }}
Component={Component || <a className={cx('gf-form-label', 'query-part', className)}>{value && value.label}</a>} Component={
Component || (
<a className={cx('gf-form-label', 'query-part', !value && placeholder && 'query-placeholder', className)}>
{label || placeholder}
</a>
)
}
/> />
); );
} }
return ( return (
<SegmentSelect <SegmentSelect
value={value} value={value && !_.isObject(value) ? { value } : value}
options={loadedOptions} options={loadedOptions}
width={width} width={width}
noOptionsMessage={selectPlaceholder} noOptionsMessage={selectPlaceholder}
......
import React from 'react'; import React, { useState } from 'react';
import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions'; import { action } from '@storybook/addon-actions';
const SegmentStories = storiesOf('UI/Segment/SegmentInput', module);
import { SegmentInput } from '.'; import { SegmentInput } from '.';
import { UseState } from '../../utils/storybook/UseState';
SegmentStories.add('Segment Input', () => { const SegmentFrame = ({ children }: any) => (
<>
<div className="gf-form-inline">
<div className="gf-form">
<span className="gf-form-label width-8 query-keyword">Segment Name</span>
</div>
{children}
</div>
</>
);
export const BasicInput = () => {
const [value, setValue] = useState('some text');
return (
<SegmentFrame>
<SegmentInput
value={value}
onChange={text => {
setValue(text as string);
action('Segment value changed')(text);
}}
/>
</SegmentFrame>
);
};
export default {
title: 'UI/Segment/SegmentInput',
component: BasicInput,
};
export const BasicInputWithPlaceholder = () => {
const [value, setValue] = useState('');
return (
<SegmentFrame>
<SegmentInput
placeholder="add text"
value={value}
onChange={text => {
setValue(text as string);
action('Segment value changed')(text);
}}
/>
</SegmentFrame>
);
};
const InputComponent = ({ initialValue }: any) => {
const [value, setValue] = useState(initialValue);
return (
<SegmentInput
placeholder="add text"
autofocus
value={value}
onChange={text => {
setValue(text as string);
action('Segment value changed')(text);
}}
/>
);
};
export const InputWithAutoFocus = () => {
const [inputComponents, setInputComponents] = useState<any>([]);
return ( return (
<UseState initialState={'some text'}> <SegmentFrame>
{(value, updateValue) => ( {inputComponents.map((InputComponent: any) => (
<> <InputComponent intitialValue="test"></InputComponent>
<div className="gf-form-inline"> ))}
<div className="gf-form"> <a
<span className="gf-form-label width-8 query-keyword">Segment Name</span> className="gf-form-label query-part"
</div> onClick={() => {
<SegmentInput setInputComponents([...inputComponents, InputComponent]);
value={value} }}
onChange={text => { >
updateValue(text as string); <i className="fa fa-plus" />
action('Segment value changed')(text); </a>
}} </SegmentFrame>
/>
</div>
</>
)}
</UseState>
); );
}); };
...@@ -7,6 +7,7 @@ import { useExpandableLabel, SegmentProps } from '.'; ...@@ -7,6 +7,7 @@ import { useExpandableLabel, SegmentProps } from '.';
export interface SegmentInputProps<T> extends SegmentProps<T> { export interface SegmentInputProps<T> extends SegmentProps<T> {
value: string | number; value: string | number;
onChange: (text: string | number) => void; onChange: (text: string | number) => void;
autofocus?: boolean;
} }
const FONT_SIZE = 14; const FONT_SIZE = 14;
...@@ -16,16 +17,30 @@ export function SegmentInput<T>({ ...@@ -16,16 +17,30 @@ export function SegmentInput<T>({
onChange, onChange,
Component, Component,
className, className,
placeholder,
autofocus = false,
}: React.PropsWithChildren<SegmentInputProps<T>>) { }: React.PropsWithChildren<SegmentInputProps<T>>) {
const ref = useRef(null); const ref = useRef<HTMLInputElement>(null);
const [value, setValue] = useState<number | string>(initialValue); const [value, setValue] = useState<number | string>(initialValue);
const [inputWidth, setInputWidth] = useState<number>(measureText(initialValue.toString(), FONT_SIZE).width); const [inputWidth, setInputWidth] = useState<number>(measureText((initialValue || '').toString(), FONT_SIZE).width);
const [Label, , expanded, setExpanded] = useExpandableLabel(false); const [Label, , expanded, setExpanded] = useExpandableLabel(autofocus);
useClickAway(ref, () => setExpanded(false));
useClickAway(ref, () => {
setExpanded(false);
onChange(value);
});
if (!expanded) { if (!expanded) {
return ( return (
<Label Component={Component || <a className={cx('gf-form-label', 'query-part', className)}>{initialValue}</a>} /> <Label
Component={
Component || (
<a className={cx('gf-form-label', 'query-part', !value && placeholder && 'query-placeholder', className)}>
{initialValue || placeholder}
</a>
)
}
/>
); );
} }
......
...@@ -4,4 +4,5 @@ export interface SegmentProps<T> { ...@@ -4,4 +4,5 @@ export interface SegmentProps<T> {
Component?: ReactElement; Component?: ReactElement;
className?: string; className?: string;
allowCustomValue?: boolean; allowCustomValue?: boolean;
placeholder?: string;
} }
...@@ -34,15 +34,13 @@ export const Dimensions: FunctionComponent<Props> = ({ dimensions, loadValues, l ...@@ -34,15 +34,13 @@ export const Dimensions: FunctionComponent<Props> = ({ dimensions, loadValues, l
return options.filter(({ value }) => !Object.keys(data).includes(value)); return options.filter(({ value }) => !Object.keys(data).includes(value));
}; };
const toOption = (value: any) => ({ label: value, value });
return ( return (
<> <>
{Object.entries(data).map(([key, value], index) => ( {Object.entries(data).map(([key, value], index) => (
<Fragment key={index}> <Fragment key={index}>
<SegmentAsync <SegmentAsync
allowCustomValue allowCustomValue
value={toOption(key)} value={key}
loadOptions={() => loadKeys().then(keys => [removeOption, ...excludeUsedKeys(keys)])} loadOptions={() => loadKeys().then(keys => [removeOption, ...excludeUsedKeys(keys)])}
onChange={({ value: newKey }) => { onChange={({ value: newKey }) => {
const { [key]: value, ...newDimensions } = data; const { [key]: value, ...newDimensions } = data;
...@@ -56,7 +54,8 @@ export const Dimensions: FunctionComponent<Props> = ({ dimensions, loadValues, l ...@@ -56,7 +54,8 @@ export const Dimensions: FunctionComponent<Props> = ({ dimensions, loadValues, l
<label className="gf-form-label query-segment-operator">=</label> <label className="gf-form-label query-segment-operator">=</label>
<SegmentAsync <SegmentAsync
allowCustomValue allowCustomValue
value={toOption(value || 'select dimension value')} value={value}
placeholder="select dimension value"
loadOptions={() => loadValues(key)} loadOptions={() => loadValues(key)}
onChange={({ value: newValue }) => setData({ ...data, [key]: newValue })} onChange={({ value: newValue }) => setData({ ...data, [key]: newValue })}
/> />
......
...@@ -112,7 +112,8 @@ export class QueryEditor extends PureComponent<Props, State> { ...@@ -112,7 +112,8 @@ export class QueryEditor extends PureComponent<Props, State> {
<> <>
<QueryInlineField label="Region"> <QueryInlineField label="Region">
<Segment <Segment
value={this.toOption(query.region || 'Select region')} value={query.region}
placeholder="Select region"
options={regions} options={regions}
allowCustomValue allowCustomValue
onChange={({ value: region }) => this.onChange({ ...query, region })} onChange={({ value: region }) => this.onChange({ ...query, region })}
...@@ -123,7 +124,8 @@ export class QueryEditor extends PureComponent<Props, State> { ...@@ -123,7 +124,8 @@ export class QueryEditor extends PureComponent<Props, State> {
<> <>
<QueryInlineField label="Namespace"> <QueryInlineField label="Namespace">
<Segment <Segment
value={this.toOption(query.namespace || 'Select namespace')} value={query.namespace}
placeholder="Select namespace"
allowCustomValue allowCustomValue
options={namespaces} options={namespaces}
onChange={({ value: namespace }) => this.onChange({ ...query, namespace })} onChange={({ value: namespace }) => this.onChange({ ...query, namespace })}
...@@ -132,7 +134,8 @@ export class QueryEditor extends PureComponent<Props, State> { ...@@ -132,7 +134,8 @@ export class QueryEditor extends PureComponent<Props, State> {
<QueryInlineField label="Metric Name"> <QueryInlineField label="Metric Name">
<SegmentAsync <SegmentAsync
value={this.toOption(query.metricName || 'Select metric name')} value={query.metricName}
placeholder="Select metric name"
allowCustomValue allowCustomValue
loadOptions={this.loadMetricNames} loadOptions={this.loadMetricNames}
onChange={({ value: metricName }) => this.onChange({ ...query, metricName })} onChange={({ value: metricName }) => this.onChange({ ...query, metricName })}
......
...@@ -12,7 +12,6 @@ export interface Props { ...@@ -12,7 +12,6 @@ export interface Props {
const removeText = '-- remove stat --'; const removeText = '-- remove stat --';
const removeOption: SelectableValue<string> = { label: removeText, value: removeText }; const removeOption: SelectableValue<string> = { label: removeText, value: removeText };
const toOption = (value: any) => ({ label: value, value });
export const Stats: FunctionComponent<Props> = ({ stats, values, onChange, variableOptionGroup }) => ( export const Stats: FunctionComponent<Props> = ({ stats, values, onChange, variableOptionGroup }) => (
<> <>
...@@ -21,7 +20,7 @@ export const Stats: FunctionComponent<Props> = ({ stats, values, onChange, varia ...@@ -21,7 +20,7 @@ export const Stats: FunctionComponent<Props> = ({ stats, values, onChange, varia
<Segment <Segment
allowCustomValue allowCustomValue
key={value + index} key={value + index}
value={toOption(value)} value={value}
options={[removeOption, ...stats, variableOptionGroup]} options={[removeOption, ...stats, variableOptionGroup]}
onChange={({ value }) => onChange={({ value }) =>
onChange( onChange(
......
...@@ -7,6 +7,10 @@ ...@@ -7,6 +7,10 @@
color: $orange; color: $orange;
} }
.query-placeholder {
color: $gray-2;
}
.query-editor-rows { .query-editor-rows {
margin: 20px 0; margin: 20px 0;
} }
......
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