Commit b34281e2 by Tobias Skarhed Committed by GitHub

Forms migration: Old Select to Legacy namespace (#23200)

* Export other components as Legacy

* More Select Legacy

* Add namespacing to more files

* Export new elements

* Move Legacy Select folder

* Let's not forget the scss file

* Move new Select folder

* Move new Select from Forms namespace

* Little oopsie

* Fix errors

* Fix merge issues
parent 15bff311
...@@ -2,7 +2,7 @@ import React from 'react'; ...@@ -2,7 +2,7 @@ import React from 'react';
import { Icon } from '../Icon/Icon'; import { Icon } from '../Icon/Icon';
import RCCascader from 'rc-cascader'; import RCCascader from 'rc-cascader';
import { Select } from '../Forms/Select/Select'; import { Select } from '../Select/Select';
import { FormInputSize } from '../Forms/types'; import { FormInputSize } from '../Forms/types';
import { Input } from '../Forms/Input/Input'; import { Input } from '../Forms/Input/Input';
import { SelectableValue } from '@grafana/data'; import { SelectableValue } from '@grafana/data';
......
...@@ -8,7 +8,7 @@ import { TLSAuthSettings } from './TLSAuthSettings'; ...@@ -8,7 +8,7 @@ import { TLSAuthSettings } from './TLSAuthSettings';
import { DataSourceSettings } from '@grafana/data'; import { DataSourceSettings } from '@grafana/data';
import { HttpSettingsProps } from './types'; import { HttpSettingsProps } from './types';
import { CustomHeadersSettings } from './CustomHeadersSettings'; import { CustomHeadersSettings } from './CustomHeadersSettings';
import { Select } from '../Select/Select'; import { Select } from '../Forms/Legacy/Select/Select';
import { Input } from '../Input/Input'; import { Input } from '../Input/Input';
import { FormField } from '../FormField/FormField'; import { FormField } from '../FormField/FormField';
import { FormLabel } from '../FormLabel/FormLabel'; import { FormLabel } from '../FormLabel/FormLabel';
......
...@@ -11,7 +11,7 @@ import { Switch } from './Switch'; ...@@ -11,7 +11,7 @@ import { Switch } from './Switch';
import { Checkbox } from './Checkbox'; import { Checkbox } from './Checkbox';
import { RadioButtonGroup } from './RadioButtonGroup/RadioButtonGroup'; import { RadioButtonGroup } from './RadioButtonGroup/RadioButtonGroup';
import { Select } from './Select/Select'; import { Select } from '../Select/Select';
import Forms from './index'; import Forms from './index';
import mdx from './Form.mdx'; import mdx from './Form.mdx';
import { ValidateResult } from 'react-hook-form'; import { ValidateResult } from 'react-hook-form';
......
...@@ -2,8 +2,8 @@ import React from 'react'; ...@@ -2,8 +2,8 @@ import React from 'react';
import { storiesOf } from '@storybook/react'; import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions'; import { action } from '@storybook/addon-actions';
import { withKnobs, object, text } from '@storybook/addon-knobs'; import { withKnobs, object, text } from '@storybook/addon-knobs';
import { withCenteredStory } from '../../utils/storybook/withCenteredStory'; import { withCenteredStory } from '../../../../utils/storybook/withCenteredStory';
import { UseState } from '../../utils/storybook/UseState'; import { UseState } from '../../../../utils/storybook/UseState';
import { SelectableValue } from '@grafana/data'; import { SelectableValue } from '@grafana/data';
import { ButtonSelect } from './ButtonSelect'; import { ButtonSelect } from './ButtonSelect';
......
import React, { PureComponent, ReactElement } from 'react';
import Select from './Select';
import { PopoverContent } from '../../../Tooltip/Tooltip';
import { SelectableValue } from '@grafana/data';
interface ButtonComponentProps {
label: ReactElement | string | undefined;
className: string | undefined;
iconClass?: string;
}
const ButtonComponent = (buttonProps: ButtonComponentProps) => (props: any) => {
const { label, className, iconClass } = buttonProps;
return (
<div // changed to div because of FireFox on MacOs issue below
ref={props.innerRef}
className={`btn navbar-button navbar-button--tight ${className}`}
onClick={props.selectProps.menuIsOpen ? props.selectProps.onMenuClose : props.selectProps.onMenuOpen}
onBlur={props.selectProps.onMenuClose}
tabIndex={0} // necessary to get onBlur to work https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#Clicking_and_focus
>
<div className="select-button">
{iconClass && <i className={`select-button-icon ${iconClass}`} />}
<span className="select-button-value">{label ? label : ''}</span>
{!props.menuIsOpen && <i className="fa fa-caret-down fa-fw" />}
{props.menuIsOpen && <i className="fa fa-caret-up fa-fw" />}
</div>
</div>
);
};
export interface Props<T> {
className: string | undefined;
options: Array<SelectableValue<T>>;
value?: SelectableValue<T>;
label?: ReactElement | string;
iconClass?: string;
components?: any;
maxMenuHeight?: number;
onChange: (item: SelectableValue<T>) => void;
tooltipContent?: PopoverContent;
isMenuOpen?: boolean;
onOpenMenu?: () => void;
onCloseMenu?: () => void;
tabSelectsValue?: boolean;
autoFocus?: boolean;
}
export class ButtonSelect<T> extends PureComponent<Props<T>> {
onChange = (item: SelectableValue<T>) => {
const { onChange } = this.props;
onChange(item);
};
render() {
const {
className,
options,
value,
label,
iconClass,
components,
maxMenuHeight,
tooltipContent,
isMenuOpen,
onOpenMenu,
onCloseMenu,
tabSelectsValue,
autoFocus = true,
} = this.props;
const combinedComponents = {
...components,
Control: ButtonComponent({ label, className, iconClass }),
};
return (
<Select
autoFocus={autoFocus}
backspaceRemovesValue={false}
isClearable={false}
isSearchable={false}
options={options}
onChange={this.onChange}
value={value}
isOpen={isMenuOpen}
onOpenMenu={onOpenMenu}
onCloseMenu={onCloseMenu}
maxMenuHeight={maxMenuHeight}
components={combinedComponents}
className="gf-form-select-box-button-select"
tooltipContent={tooltipContent}
tabSelectsValue={tabSelectsValue}
/>
);
}
}
import React from 'react';
// Ignoring because I couldn't get @types/react-select work wih Torkel's fork
// @ts-ignore
import { components } from '@torkelo/react-select';
export const IndicatorsContainer = (props: any) => {
const isOpen = props.selectProps.menuIsOpen;
return (
<components.IndicatorsContainer {...props}>
<span
className={`gf-form-select-box__select-arrow ${isOpen ? `gf-form-select-box__select-arrow--reversed` : ''}`}
/>
</components.IndicatorsContainer>
);
};
export default IndicatorsContainer;
import React, { useState, useCallback } from 'react';
import { action } from '@storybook/addon-actions';
import { withKnobs, object } from '@storybook/addon-knobs';
import { withCenteredStory } from '../../../../utils/storybook/withCenteredStory';
import { UseState } from '../../../../utils/storybook/UseState';
import { SelectableValue } from '@grafana/data';
import { Select, AsyncSelect } from './Select';
export default {
title: 'General/Select/Select',
component: Select,
decorators: [withCenteredStory, withKnobs],
};
const intialState: SelectableValue<string> = { label: 'A label', value: 'A value' };
const options = object<Array<SelectableValue<string>>>('Options:', [
intialState,
{ label: 'Another label', value: 'Another value 1' },
{ label: 'Another label', value: 'Another value 2' },
{ label: 'Another label', value: 'Another value 3' },
{ label: 'Another label', value: 'Another value 4' },
{ label: 'Another label', value: 'Another value 5' },
{ label: 'Another label', value: 'Another value ' },
]);
export const basic = () => {
const value = object<SelectableValue<string>>('Selected Value:', intialState);
return (
<UseState initialState={value}>
{(value, updateValue) => {
return (
<Select
placeholder="Choose..."
options={options}
width={20}
onChange={value => {
action('onChanged fired')(value);
updateValue(value);
}}
/>
);
}}
</UseState>
);
};
export const withAllowCustomValue = () => {
// @ts-ignore
const value = object<SelectableValue<string>>('Selected Value:', null);
return (
<UseState initialState={value}>
{(value, updateValue) => {
return (
<Select
// value={value}
placeholder="Choose..."
options={options}
width={20}
allowCustomValue={true}
onChange={value => {
action('onChanged fired')(value);
updateValue(value);
}}
/>
);
}}
</UseState>
);
};
export const asyncSelect = () => {
const [isLoading, setIsLoading] = useState<boolean>(true);
const [value, setValue] = useState();
const loadAsyncOptions = useCallback(
inputValue => {
return new Promise<Array<SelectableValue<string>>>(resolve => {
setTimeout(() => {
setIsLoading(false);
resolve(options.filter(option => option.label && option.label.includes(inputValue)));
}, 1000);
});
},
[value]
);
return (
<AsyncSelect
value={value}
defaultOptions
width={20}
isLoading={isLoading}
loadOptions={loadAsyncOptions}
onChange={value => {
action('onChange')(value);
setValue(value);
}}
/>
);
};
// Libraries
import classNames from 'classnames';
import React, { PureComponent } from 'react';
// Ignoring because I couldn't get @types/react-select work wih Torkel's fork
// @ts-ignore
import { default as ReactSelect } from '@torkelo/react-select';
// @ts-ignore
import Creatable from '@torkelo/react-select/creatable';
// @ts-ignore
import { CreatableProps } from 'react-select';
// @ts-ignore
import { default as ReactAsyncSelect } from '@torkelo/react-select/async';
// @ts-ignore
import { components } from '@torkelo/react-select';
// Components
import { SelectOption } from './SelectOption';
import { SelectOptionGroup } from '../../../Select/SelectOptionGroup';
import { SingleValue } from '../../../Select/SingleValue';
import { SelectCommonProps, SelectAsyncProps } from '../../../Select/types';
import IndicatorsContainer from './IndicatorsContainer';
import NoOptionsMessage from './NoOptionsMessage';
import resetSelectStyles from '../../../Select/resetSelectStyles';
import { CustomScrollbar } from '../../../CustomScrollbar/CustomScrollbar';
import { PopoverContent } from '../../../Tooltip/Tooltip';
import { Tooltip } from '../../../Tooltip/Tooltip';
import { SelectableValue } from '@grafana/data';
/**
* Changes in new selects:
* - noOptionsMessage & loadingMessage is of string type
* - isDisabled is renamed to disabled
*/
type LegacyCommonProps<T> = Omit<SelectCommonProps<T>, 'noOptionsMessage' | 'disabled' | 'value'>;
interface AsyncProps<T> extends LegacyCommonProps<T>, Omit<SelectAsyncProps<T>, 'loadingMessage'> {
loadingMessage?: () => string;
noOptionsMessage?: () => string;
tooltipContent?: PopoverContent;
isDisabled?: boolean;
value?: SelectableValue<T>;
}
interface LegacySelectProps<T> extends LegacyCommonProps<T> {
tooltipContent?: PopoverContent;
noOptionsMessage?: () => string;
isDisabled?: boolean;
value?: SelectableValue<T>;
}
export const MenuList = (props: any) => {
return (
<components.MenuList {...props}>
<CustomScrollbar autoHide={false} autoHeightMax="inherit">
{props.children}
</CustomScrollbar>
</components.MenuList>
);
};
export class Select<T> extends PureComponent<LegacySelectProps<T>> {
static defaultProps: Partial<LegacySelectProps<any>> = {
className: '',
isDisabled: false,
isSearchable: true,
isClearable: false,
isMulti: false,
openMenuOnFocus: false,
autoFocus: false,
isLoading: false,
backspaceRemovesValue: true,
maxMenuHeight: 300,
tabSelectsValue: true,
allowCustomValue: false,
components: {
Option: SelectOption,
SingleValue,
IndicatorsContainer,
MenuList,
Group: SelectOptionGroup,
},
};
render() {
const {
defaultValue,
getOptionLabel,
getOptionValue,
onChange,
options,
placeholder,
width,
value,
className,
isDisabled,
isLoading,
isSearchable,
isClearable,
backspaceRemovesValue,
isMulti,
autoFocus,
openMenuOnFocus,
onBlur,
maxMenuHeight,
noOptionsMessage,
isOpen,
components,
tooltipContent,
tabSelectsValue,
onCloseMenu,
onOpenMenu,
allowCustomValue,
formatCreateLabel,
} = this.props;
let widthClass = '';
if (width) {
widthClass = 'width-' + width;
}
let SelectComponent: ReactSelect | Creatable = ReactSelect;
const creatableOptions: any = {};
if (allowCustomValue) {
SelectComponent = Creatable;
creatableOptions.formatCreateLabel = formatCreateLabel ?? ((input: string) => input);
}
const selectClassNames = classNames('gf-form-input', 'gf-form-input--form-dropdown', widthClass, className);
const selectComponents = { ...Select.defaultProps.components, ...components };
return (
<WrapInTooltip onCloseMenu={onCloseMenu} onOpenMenu={onOpenMenu} tooltipContent={tooltipContent} isOpen={isOpen}>
{(onOpenMenuInternal, onCloseMenuInternal) => {
return (
<SelectComponent
captureMenuScroll={false}
classNamePrefix="gf-form-select-box"
className={selectClassNames}
components={selectComponents}
defaultValue={defaultValue}
value={value}
getOptionLabel={getOptionLabel}
getOptionValue={getOptionValue}
menuShouldScrollIntoView={false}
isSearchable={isSearchable}
onChange={onChange}
options={options}
placeholder={placeholder || 'Choose'}
styles={resetSelectStyles()}
isDisabled={isDisabled}
isLoading={isLoading}
isClearable={isClearable}
autoFocus={autoFocus}
onBlur={onBlur}
openMenuOnFocus={openMenuOnFocus}
maxMenuHeight={maxMenuHeight}
noOptionsMessage={() => noOptionsMessage}
isMulti={isMulti}
backspaceRemovesValue={backspaceRemovesValue}
menuIsOpen={isOpen}
onMenuOpen={onOpenMenuInternal}
onMenuClose={onCloseMenuInternal}
tabSelectsValue={tabSelectsValue}
{...creatableOptions}
/>
);
}}
</WrapInTooltip>
);
}
}
export class AsyncSelect<T> extends PureComponent<AsyncProps<T>> {
static defaultProps: Partial<AsyncProps<any>> = {
className: '',
components: {},
loadingMessage: () => 'Loading...',
isDisabled: false,
isClearable: false,
isMulti: false,
isSearchable: true,
backspaceRemovesValue: true,
autoFocus: false,
openMenuOnFocus: false,
maxMenuHeight: 300,
};
render() {
const {
defaultValue,
getOptionLabel,
getOptionValue,
onChange,
placeholder,
width,
value,
className,
loadOptions,
defaultOptions,
isLoading,
loadingMessage,
noOptionsMessage,
isDisabled,
isSearchable,
isClearable,
backspaceRemovesValue,
autoFocus,
onBlur,
openMenuOnFocus,
maxMenuHeight,
isMulti,
tooltipContent,
onCloseMenu,
onOpenMenu,
isOpen,
} = this.props;
let widthClass = '';
if (width) {
widthClass = 'width-' + width;
}
const selectClassNames = classNames('gf-form-input', 'gf-form-input--form-dropdown', widthClass, className);
return (
<WrapInTooltip onCloseMenu={onCloseMenu} onOpenMenu={onOpenMenu} tooltipContent={tooltipContent} isOpen={isOpen}>
{(onOpenMenuInternal, onCloseMenuInternal) => {
return (
<ReactAsyncSelect
captureMenuScroll={false}
classNamePrefix="gf-form-select-box"
className={selectClassNames}
components={{
Option: SelectOption,
SingleValue,
IndicatorsContainer,
NoOptionsMessage,
}}
defaultValue={defaultValue}
value={value}
getOptionLabel={getOptionLabel}
getOptionValue={getOptionValue}
menuShouldScrollIntoView={false}
onChange={onChange}
loadOptions={loadOptions}
isLoading={isLoading}
defaultOptions={defaultOptions}
placeholder={placeholder || 'Choose'}
styles={resetSelectStyles()}
loadingMessage={() => loadingMessage}
noOptionsMessage={noOptionsMessage}
isDisabled={isDisabled}
isSearchable={isSearchable}
isClearable={isClearable}
autoFocus={autoFocus}
onBlur={onBlur}
openMenuOnFocus={openMenuOnFocus}
maxMenuHeight={maxMenuHeight}
isMulti={isMulti}
backspaceRemovesValue={backspaceRemovesValue}
/>
);
}}
</WrapInTooltip>
);
}
}
export interface TooltipWrapperProps {
children: (onOpenMenu: () => void, onCloseMenu: () => void) => React.ReactNode;
onOpenMenu?: () => void;
onCloseMenu?: () => void;
isOpen?: boolean;
tooltipContent?: PopoverContent;
}
export interface TooltipWrapperState {
isOpenInternal: boolean;
}
export class WrapInTooltip extends PureComponent<TooltipWrapperProps, TooltipWrapperState> {
state: TooltipWrapperState = {
isOpenInternal: false,
};
onOpenMenu = () => {
const { onOpenMenu } = this.props;
if (onOpenMenu) {
onOpenMenu();
}
this.setState({ isOpenInternal: true });
};
onCloseMenu = () => {
const { onCloseMenu } = this.props;
if (onCloseMenu) {
onCloseMenu();
}
this.setState({ isOpenInternal: false });
};
render() {
const { children, isOpen, tooltipContent } = this.props;
const { isOpenInternal } = this.state;
let showTooltip: boolean | undefined = undefined;
if (isOpenInternal || isOpen) {
showTooltip = false;
}
if (tooltipContent) {
return (
<Tooltip show={showTooltip} content={tooltipContent} placement="bottom">
<div>
{/* div needed for tooltip */}
{children(this.onOpenMenu, this.onCloseMenu)}
</div>
</Tooltip>
);
} else {
return <div>{children(this.onOpenMenu, this.onCloseMenu)}</div>;
}
}
}
export default Select;
import React from 'react';
import { css } from 'emotion';
import { GrafanaTheme } from '@grafana/data';
import { Button, ButtonVariant, ButtonProps } from '../../Button';
import { ComponentSize } from '../../../types/size';
import { SelectCommonProps, CustomControlProps } from './types';
import { SelectBase } from './SelectBase';
import { stylesFactory, useTheme } from '../../../themes';
import { Icon } from '../../Icon/Icon';
import { IconType } from '../../Icon/types';
interface ButtonSelectProps<T> extends Omit<SelectCommonProps<T>, 'renderControl' | 'size' | 'prefix'> {
icon?: IconType;
variant?: ButtonVariant;
size?: ComponentSize;
}
interface SelectButtonProps extends Omit<ButtonProps, 'icon'> {
icon?: IconType;
isOpen?: boolean;
}
const SelectButton = React.forwardRef<HTMLButtonElement, SelectButtonProps>(
({ icon, children, isOpen, ...buttonProps }, ref) => {
const getStyles = stylesFactory((theme: GrafanaTheme) => ({
wrapper: css`
display: flex;
align-items: center;
justify-content: space-between;
max-width: 200px;
text-overflow: ellipsis;
`,
iconWrap: css`
padding: 0 15px 0 0;
`,
caretWrap: css`
padding-left: ${theme.spacing.sm};
margin-left: ${theme.spacing.sm};
margin-right: -${theme.spacing.sm};
height: 100%;
`,
}));
const styles = getStyles(useTheme());
const buttonIcon = `fa fa-${icon}`;
const caretIcon = isOpen ? 'caret-up' : 'caret-down';
return (
<Button {...buttonProps} ref={ref} icon={buttonIcon}>
<span className={styles.wrapper}>
<span>{children}</span>
<span className={styles.caretWrap}>
<Icon name={caretIcon} />
</span>
</span>
</Button>
);
}
);
export function ButtonSelect<T>({
placeholder,
icon,
variant = 'primary',
size = 'md',
className,
disabled,
...selectProps
}: ButtonSelectProps<T>) {
const buttonProps = {
icon,
variant,
size,
className,
disabled,
};
return (
<SelectBase
{...selectProps}
renderControl={React.forwardRef<any, CustomControlProps<T>>(({ onBlur, onClick, value, isOpen }, ref) => {
return (
<SelectButton {...buttonProps} ref={ref} onBlur={onBlur} onClick={onClick} isOpen={isOpen}>
{value ? value.label : placeholder}
</SelectButton>
);
})}
/>
);
}
import React from 'react';
import { useTheme } from '../../../themes/ThemeContext';
import { getInputStyles } from '../Input/Input';
import { cx, css } from 'emotion';
export const IndicatorsContainer = React.forwardRef<HTMLDivElement, React.PropsWithChildren<any>>((props, ref) => {
const { children } = props;
const theme = useTheme();
const styles = getInputStyles({ theme, invalid: false });
return (
<div
className={cx(
styles.suffix,
css`
position: relative;
`
)}
ref={ref}
>
{children}
</div>
);
});
import React, { useState } from 'react';
import { Select, AsyncSelect, MultiSelect, AsyncMultiSelect } from './Select';
import { withCenteredStory, withHorizontallyCenteredStory } from '../../../utils/storybook/withCenteredStory';
import { SelectableValue } from '@grafana/data';
import { getAvailableIcons, IconType } from '../../Icon/types';
import { select, boolean } from '@storybook/addon-knobs';
import { Icon } from '../../Icon/Icon';
import { Button } from '../../Button';
import { ButtonSelect } from './ButtonSelect';
import { getIconKnob } from '../../../utils/storybook/knobs';
import kebabCase from 'lodash/kebabCase';
import { generateOptions } from './mockOptions';
export default {
title: 'Forms/Select',
component: Select,
decorators: [withCenteredStory, withHorizontallyCenteredStory],
};
const loadAsyncOptions = () => {
return new Promise<Array<SelectableValue<string>>>(resolve => {
setTimeout(() => {
resolve(generateOptions());
}, 2000);
});
};
const getKnobs = () => {
const BEHAVIOUR_GROUP = 'Behaviour props';
const disabled = boolean('Disabled', false, BEHAVIOUR_GROUP);
const invalid = boolean('Invalid', false, BEHAVIOUR_GROUP);
const loading = boolean('Loading', false, BEHAVIOUR_GROUP);
const prefixSuffixOpts = {
None: null,
Text: '$',
...getAvailableIcons().reduce<Record<string, string>>((prev, c) => {
return {
...prev,
[`Icon: ${c}`]: `icon-${c}`,
};
}, {}),
};
const VISUAL_GROUP = 'Visual options';
// ---
const prefix = select('Prefix', prefixSuffixOpts, null, VISUAL_GROUP);
let prefixEl: any = prefix;
if (prefix && prefix.match(/icon-/g)) {
prefixEl = <Icon name={prefix.replace(/icon-/g, '') as IconType} />;
}
return {
disabled,
invalid,
loading,
prefixEl,
};
};
const getDynamicProps = () => {
const knobs = getKnobs();
return {
disabled: knobs.disabled,
isLoading: knobs.loading,
invalid: knobs.invalid,
prefix: knobs.prefixEl,
};
};
export const basic = () => {
const [value, setValue] = useState<SelectableValue<string>>();
return (
<>
<Select
options={generateOptions()}
value={value}
onChange={v => {
setValue(v);
}}
size="md"
{...getDynamicProps()}
/>
</>
);
};
/**
* Uses plain values instead of SelectableValue<T>
*/
export const basicSelectPlainValue = () => {
const [value, setValue] = useState<string>();
return (
<>
<Select
options={generateOptions()}
value={value}
onChange={v => {
setValue(v.value);
}}
size="md"
{...getDynamicProps()}
/>
</>
);
};
/**
* Uses plain values instead of SelectableValue<T>
*/
export const SelectWithOptionDescriptions = () => {
// TODO this is not working with new Select
const [value, setValue] = useState<number>();
const options = [
{ label: 'Basic option', value: 0 },
{ label: 'Option with description', value: 1, description: 'this is a description' },
{
label: 'Option with description and image',
value: 2,
description: 'This is a very elaborate description, describing all the wonders in the world.',
imgUrl: 'https://placekitten.com/40/40',
},
];
return (
<>
<Select
options={options}
value={value}
onChange={v => {
setValue(v.value);
}}
size="md"
{...getDynamicProps()}
/>
</>
);
};
/**
* Uses plain values instead of SelectableValue<T>
*/
export const multiPlainValue = () => {
const [value, setValue] = useState<string[]>();
return (
<>
<MultiSelect
options={generateOptions()}
value={value}
onChange={v => {
setValue(v.map((v: any) => v.value));
}}
size="md"
{...getDynamicProps()}
/>
</>
);
};
export const multiSelect = () => {
const [value, setValue] = useState<Array<SelectableValue<string>>>([]);
return (
<>
<MultiSelect
options={generateOptions()}
value={value}
onChange={v => {
setValue(v);
}}
size="md"
{...getDynamicProps()}
/>
</>
);
};
export const multiSelectAsync = () => {
const [value, setValue] = useState<Array<SelectableValue<string>>>();
return (
<AsyncMultiSelect
loadOptions={loadAsyncOptions}
defaultOptions
value={value}
onChange={v => {
setValue(v);
}}
size="md"
allowCustomValue
{...getDynamicProps()}
/>
);
};
export const buttonSelect = () => {
const [value, setValue] = useState<SelectableValue<string>>();
const icon = getIconKnob();
return (
<ButtonSelect
placeholder="Select all the things..."
value={value}
options={generateOptions()}
onChange={v => {
setValue(v);
}}
size="md"
allowCustomValue
icon={icon}
{...getDynamicProps()}
/>
);
};
export const basicSelectAsync = () => {
const [value, setValue] = useState<SelectableValue<string>>();
return (
<AsyncSelect
loadOptions={loadAsyncOptions}
defaultOptions
value={value}
onChange={v => {
setValue(v);
}}
size="md"
{...getDynamicProps()}
/>
);
};
export const customizedControl = () => {
const [value, setValue] = useState<SelectableValue<string>>();
return (
<Select
options={generateOptions()}
value={value}
onChange={v => {
setValue(v);
}}
size="md"
renderControl={React.forwardRef(({ isOpen, value, ...otherProps }, ref) => {
return (
<Button {...otherProps} ref={ref}>
{' '}
{isOpen ? 'Open' : 'Closed'}
</Button>
);
})}
{...getDynamicProps()}
/>
);
};
export const autoMenuPlacement = () => {
const [value, setValue] = useState<SelectableValue<string>>();
return (
<>
<div style={{ height: '95vh', display: 'flex', alignItems: 'flex-end' }}>
<Select
options={generateOptions()}
value={value}
onChange={v => {
setValue(v);
}}
size="md"
{...getDynamicProps()}
/>
</div>
</>
);
};
export const customValueCreation = () => {
const [value, setValue] = useState<SelectableValue<string>>();
const [customOptions, setCustomOptions] = useState<Array<SelectableValue<string>>>([]);
const options = generateOptions();
return (
<>
<Select
options={[...options, ...customOptions]}
value={value}
onChange={v => {
setValue(v);
}}
size="md"
allowCustomValue
onCreateOption={v => {
const customValue: SelectableValue<string> = { value: kebabCase(v), label: v };
setCustomOptions([...customOptions, customValue]);
setValue(customValue);
}}
{...getDynamicProps()}
/>
</>
);
};
import React from 'react';
import { SelectableValue } from '@grafana/data';
import { SelectCommonProps, MultiSelectCommonProps, SelectAsyncProps } from './types';
import { SelectBase } from './SelectBase';
export function Select<T>(props: SelectCommonProps<T>) {
return <SelectBase {...props} />;
}
export function MultiSelect<T>(props: MultiSelectCommonProps<T>) {
// @ts-ignore
return <SelectBase {...props} isMulti />;
}
interface AsyncSelectProps<T> extends Omit<SelectCommonProps<T>, 'options'>, SelectAsyncProps<T> {
// AsyncSelect has options stored internally. We cannot enable plain values as we don't have access to the fetched options
value?: SelectableValue<T>;
invalid?: boolean;
}
export function AsyncSelect<T>(props: AsyncSelectProps<T>) {
return <SelectBase {...props} />;
}
interface AsyncMultiSelectProps<T> extends Omit<MultiSelectCommonProps<T>, 'options'>, SelectAsyncProps<T> {
// AsyncSelect has options stored internally. We cannot enable plain values as we don't have access to the fetched options
value?: Array<SelectableValue<T>>;
}
export function AsyncMultiSelect<T>(props: AsyncMultiSelectProps<T>) {
// @ts-ignore
return <SelectBase {...props} isMulti />;
}
...@@ -2,15 +2,15 @@ import { Controller as InputControl } from 'react-hook-form'; ...@@ -2,15 +2,15 @@ import { Controller as InputControl } from 'react-hook-form';
import { getFormStyles } from './getFormStyles'; import { getFormStyles } from './getFormStyles';
import { Label } from './Label'; import { Label } from './Label';
import { Input } from './Input/Input'; import { Input } from './Input/Input';
import { ButtonSelect } from './Select/ButtonSelect';
import { RadioButtonGroup } from './RadioButtonGroup/RadioButtonGroup'; import { RadioButtonGroup } from './RadioButtonGroup/RadioButtonGroup';
import { AsyncSelect, Select } from './Select/Select';
import { Form } from './Form'; import { Form } from './Form';
import { Field } from './Field'; import { Field } from './Field';
import { Switch } from './Switch'; import { Switch } from './Switch';
import { Legend } from './Legend'; import { Legend } from './Legend';
import { TextArea } from './TextArea/TextArea'; import { TextArea } from './TextArea/TextArea';
import { Checkbox } from './Checkbox'; import { Checkbox } from './Checkbox';
//Remove after Enterprise migrations have been merged
import { Select } from '../Select/Select';
const Forms = { const Forms = {
RadioButtonGroup, RadioButtonGroup,
...@@ -20,13 +20,11 @@ const Forms = { ...@@ -20,13 +20,11 @@ const Forms = {
Input, Input,
Form, Form,
Field, Field,
Select,
ButtonSelect,
InputControl, InputControl,
AsyncSelect,
TextArea, TextArea,
Checkbox, Checkbox,
Legend, Legend,
Select,
}; };
export default Forms; export default Forms;
import React from 'react'; import React from 'react';
import { MatcherUIProps, FieldMatcherUIRegistryItem } from './types'; import { MatcherUIProps, FieldMatcherUIRegistryItem } from './types';
import { FieldMatcherID, fieldMatchers } from '@grafana/data'; import { FieldMatcherID, fieldMatchers } from '@grafana/data';
import Forms from '../Forms'; import { Select } from '../Select/Select';
export class FieldNameMatcherEditor extends React.PureComponent<MatcherUIProps<string>> { export class FieldNameMatcherEditor extends React.PureComponent<MatcherUIProps<string>> {
render() { render() {
...@@ -23,12 +23,7 @@ export class FieldNameMatcherEditor extends React.PureComponent<MatcherUIProps<s ...@@ -23,12 +23,7 @@ export class FieldNameMatcherEditor extends React.PureComponent<MatcherUIProps<s
const selectedOption = selectOptions.find(v => v.value === options); const selectedOption = selectOptions.find(v => v.value === options);
return ( return (
<Forms.Select <Select allowCustomValue value={selectedOption} options={selectOptions} onChange={o => onChange(o.value!)} />
allowCustomValue
value={selectedOption}
options={selectOptions}
onChange={o => onChange(o.value!)}
/>
); );
} }
} }
......
import React from 'react'; import React from 'react';
import { FieldConfigEditorProps, SelectFieldConfigSettings } from '@grafana/data'; import { FieldConfigEditorProps, SelectFieldConfigSettings } from '@grafana/data';
import Forms from '../Forms'; import { Select } from '../Select/Select';
export function SelectValueEditor<T>({ export function SelectValueEditor<T>({
value, value,
onChange, onChange,
item, item,
}: FieldConfigEditorProps<T, SelectFieldConfigSettings<T>>) { }: FieldConfigEditorProps<T, SelectFieldConfigSettings<T>>) {
return <Forms.Select<T> defaultValue={value} onChange={e => onChange(e.value)} options={item.settings?.options} />; return <Select<T> defaultValue={value} onChange={e => onChange(e.value)} options={item.settings?.options} />;
} }
...@@ -3,7 +3,7 @@ import classNames from 'classnames'; ...@@ -3,7 +3,7 @@ import classNames from 'classnames';
import { SelectableValue } from '@grafana/data'; import { SelectableValue } from '@grafana/data';
import { css } from 'emotion'; import { css } from 'emotion';
import { Tooltip } from '../Tooltip/Tooltip'; import { Tooltip } from '../Tooltip/Tooltip';
import { ButtonSelect } from '../Select/ButtonSelect'; import { ButtonSelect } from '../Forms/Legacy/Select/ButtonSelect';
import memoizeOne from 'memoize-one'; import memoizeOne from 'memoize-one';
import { GrafanaTheme } from '@grafana/data'; import { GrafanaTheme } from '@grafana/data';
import { withTheme } from '../../themes'; import { withTheme } from '../../themes';
......
...@@ -2,7 +2,7 @@ import React, { useRef } from 'react'; ...@@ -2,7 +2,7 @@ import React, { useRef } from 'react';
import { css, cx } from 'emotion'; import { css, cx } from 'emotion';
import useClickAway from 'react-use/lib/useClickAway'; import useClickAway from 'react-use/lib/useClickAway';
import { SelectableValue } from '@grafana/data'; import { SelectableValue } from '@grafana/data';
import { Select } from '../Select/Select'; import { Select } from '../Forms/Legacy/Select/Select';
export interface Props<T> { export interface Props<T> {
value?: SelectableValue<T>; value?: SelectableValue<T>;
......
import React, { PureComponent, ReactElement } from 'react'; import React from 'react';
import Select from './Select'; import { css } from 'emotion';
import { PopoverContent } from '../Tooltip/Tooltip'; import { GrafanaTheme } from '@grafana/data';
import { SelectableValue } from '@grafana/data';
interface ButtonComponentProps { import { Button, ButtonVariant, ButtonProps } from '../Button';
label: ReactElement | string | undefined; import { ComponentSize } from '../../types/size';
className: string | undefined; import { SelectCommonProps, CustomControlProps } from './types';
iconClass?: string; import { SelectBase } from './SelectBase';
} import { stylesFactory, useTheme } from '../../themes';
import { Icon } from '../Icon/Icon';
const ButtonComponent = (buttonProps: ButtonComponentProps) => (props: any) => { import { IconType } from '../Icon/types';
const { label, className, iconClass } = buttonProps;
return ( interface ButtonSelectProps<T> extends Omit<SelectCommonProps<T>, 'renderControl' | 'size' | 'prefix'> {
<div // changed to div because of FireFox on MacOs issue below icon?: IconType;
ref={props.innerRef} variant?: ButtonVariant;
className={`btn navbar-button navbar-button--tight ${className}`} size?: ComponentSize;
onClick={props.selectProps.menuIsOpen ? props.selectProps.onMenuClose : props.selectProps.onMenuOpen}
onBlur={props.selectProps.onMenuClose}
tabIndex={0} // necessary to get onBlur to work https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#Clicking_and_focus
>
<div className="select-button">
{iconClass && <i className={`select-button-icon ${iconClass}`} />}
<span className="select-button-value">{label ? label : ''}</span>
{!props.menuIsOpen && <i className="fa fa-caret-down fa-fw" />}
{props.menuIsOpen && <i className="fa fa-caret-up fa-fw" />}
</div>
</div>
);
};
export interface Props<T> {
className: string | undefined;
options: Array<SelectableValue<T>>;
value?: SelectableValue<T>;
label?: ReactElement | string;
iconClass?: string;
components?: any;
maxMenuHeight?: number;
onChange: (item: SelectableValue<T>) => void;
tooltipContent?: PopoverContent;
isMenuOpen?: boolean;
onOpenMenu?: () => void;
onCloseMenu?: () => void;
tabSelectsValue?: boolean;
autoFocus?: boolean;
} }
export class ButtonSelect<T> extends PureComponent<Props<T>> { interface SelectButtonProps extends Omit<ButtonProps, 'icon'> {
onChange = (item: SelectableValue<T>) => { icon?: IconType;
const { onChange } = this.props; isOpen?: boolean;
onChange(item); }
};
render() {
const {
className,
options,
value,
label,
iconClass,
components,
maxMenuHeight,
tooltipContent,
isMenuOpen,
onOpenMenu,
onCloseMenu,
tabSelectsValue,
autoFocus = true,
} = this.props;
const combinedComponents = {
...components,
Control: ButtonComponent({ label, className, iconClass }),
};
const SelectButton = React.forwardRef<HTMLButtonElement, SelectButtonProps>(
({ icon, children, isOpen, ...buttonProps }, ref) => {
const getStyles = stylesFactory((theme: GrafanaTheme) => ({
wrapper: css`
display: flex;
align-items: center;
justify-content: space-between;
max-width: 200px;
text-overflow: ellipsis;
`,
iconWrap: css`
padding: 0 15px 0 0;
`,
caretWrap: css`
padding-left: ${theme.spacing.sm};
margin-left: ${theme.spacing.sm};
margin-right: -${theme.spacing.sm};
height: 100%;
`,
}));
const styles = getStyles(useTheme());
const buttonIcon = `fa fa-${icon}`;
const caretIcon = isOpen ? 'caret-up' : 'caret-down';
return ( return (
<Select <Button {...buttonProps} ref={ref} icon={buttonIcon}>
autoFocus={autoFocus} <span className={styles.wrapper}>
backspaceRemovesValue={false} <span>{children}</span>
isClearable={false} <span className={styles.caretWrap}>
isSearchable={false} <Icon name={caretIcon} />
options={options} </span>
onChange={this.onChange} </span>
value={value} </Button>
isOpen={isMenuOpen}
onOpenMenu={onOpenMenu}
onCloseMenu={onCloseMenu}
maxMenuHeight={maxMenuHeight}
components={combinedComponents}
className="gf-form-select-box-button-select"
tooltipContent={tooltipContent}
tabSelectsValue={tabSelectsValue}
/>
); );
} }
);
export function ButtonSelect<T>({
placeholder,
icon,
variant = 'primary',
size = 'md',
className,
disabled,
...selectProps
}: ButtonSelectProps<T>) {
const buttonProps = {
icon,
variant,
size,
className,
disabled,
};
return (
<SelectBase
{...selectProps}
renderControl={React.forwardRef<any, CustomControlProps<T>>(({ onBlur, onClick, value, isOpen }, ref) => {
return (
<SelectButton {...buttonProps} ref={ref} onBlur={onBlur} onClick={onClick} isOpen={isOpen}>
{value ? value.label : placeholder}
</SelectButton>
);
})}
/>
);
} }
import React from 'react'; import React from 'react';
import { Icon } from '../../Icon/Icon'; import { Icon } from '../Icon/Icon';
interface DropdownIndicatorProps { interface DropdownIndicatorProps {
isOpen: boolean; isOpen: boolean;
......
import React from 'react'; import React from 'react';
import { useTheme } from '../../themes/ThemeContext';
import { getInputStyles } from '../Forms/Input/Input';
import { cx, css } from 'emotion';
// Ignoring because I couldn't get @types/react-select work wih Torkel's fork export const IndicatorsContainer = React.forwardRef<HTMLDivElement, React.PropsWithChildren<any>>((props, ref) => {
// @ts-ignore const { children } = props;
import { components } from '@torkelo/react-select'; const theme = useTheme();
const styles = getInputStyles({ theme, invalid: false });
export const IndicatorsContainer = (props: any) => {
const isOpen = props.selectProps.menuIsOpen;
return ( return (
<components.IndicatorsContainer {...props}> <div
<span className={cx(
className={`gf-form-select-box__select-arrow ${isOpen ? `gf-form-select-box__select-arrow--reversed` : ''}`} styles.suffix,
/> css`
</components.IndicatorsContainer> position: relative;
`
)}
ref={ref}
>
{children}
</div>
); );
}; });
export default IndicatorsContainer;
import React from 'react'; import React from 'react';
import { useTheme } from '../../../themes/ThemeContext'; import { useTheme } from '../../themes/ThemeContext';
import { getFocusCss, sharedInputStyle } from '../commonStyles'; import { getFocusCss, sharedInputStyle } from '../Forms/commonStyles';
import { getInputStyles } from '../Input/Input'; import { getInputStyles } from '../Forms/Input/Input';
import { cx, css } from 'emotion'; import { cx, css } from 'emotion';
import { stylesFactory } from '../../../themes'; import { stylesFactory } from '../../themes';
import { GrafanaTheme } from '@grafana/data'; import { GrafanaTheme } from '@grafana/data';
interface InputControlProps { interface InputControlProps {
......
import React from 'react'; import React from 'react';
import { useTheme } from '../../../themes'; import { useTheme } from '../../themes';
import { getSelectStyles } from './getSelectStyles'; import { getSelectStyles } from './getSelectStyles';
import { Icon } from '../../Icon/Icon'; import { Icon } from '../Icon/Icon';
interface MultiValueContainerProps { interface MultiValueContainerProps {
innerProps: any; innerProps: any;
......
import React, { useState, useCallback } from 'react'; import React, { useState } from 'react';
import { action } from '@storybook/addon-actions'; import { Select, AsyncSelect, MultiSelect, AsyncMultiSelect } from './Select';
import { withKnobs, object } from '@storybook/addon-knobs'; import { withCenteredStory, withHorizontallyCenteredStory } from '../../utils/storybook/withCenteredStory';
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
import { UseState } from '../../utils/storybook/UseState';
import { SelectableValue } from '@grafana/data'; import { SelectableValue } from '@grafana/data';
import { Select, AsyncSelect } from './Select'; import { getAvailableIcons, IconType } from '../Icon/types';
import { select, boolean } from '@storybook/addon-knobs';
import { Icon } from '../Icon/Icon';
import { Button } from '../Button';
import { ButtonSelect } from './ButtonSelect';
import { getIconKnob } from '../../utils/storybook/knobs';
import kebabCase from 'lodash/kebabCase';
import { generateOptions } from './mockOptions';
export default { export default {
title: 'General/Select/Select', title: 'Forms/Select',
component: Select, component: Select,
decorators: [withCenteredStory, withKnobs], decorators: [withCenteredStory, withHorizontallyCenteredStory],
}; };
const intialState: SelectableValue<string> = { label: 'A label', value: 'A value' }; const loadAsyncOptions = () => {
return new Promise<Array<SelectableValue<string>>>(resolve => {
setTimeout(() => {
resolve(generateOptions());
}, 2000);
});
};
const getKnobs = () => {
const BEHAVIOUR_GROUP = 'Behaviour props';
const disabled = boolean('Disabled', false, BEHAVIOUR_GROUP);
const invalid = boolean('Invalid', false, BEHAVIOUR_GROUP);
const loading = boolean('Loading', false, BEHAVIOUR_GROUP);
const prefixSuffixOpts = {
None: null,
Text: '$',
...getAvailableIcons().reduce<Record<string, string>>((prev, c) => {
return {
...prev,
[`Icon: ${c}`]: `icon-${c}`,
};
}, {}),
};
const VISUAL_GROUP = 'Visual options';
// ---
const prefix = select('Prefix', prefixSuffixOpts, null, VISUAL_GROUP);
const options = object<Array<SelectableValue<string>>>('Options:', [ let prefixEl: any = prefix;
intialState, if (prefix && prefix.match(/icon-/g)) {
{ label: 'Another label', value: 'Another value 1' }, prefixEl = <Icon name={prefix.replace(/icon-/g, '') as IconType} />;
{ label: 'Another label', value: 'Another value 2' }, }
{ label: 'Another label', value: 'Another value 3' },
{ label: 'Another label', value: 'Another value 4' }, return {
{ label: 'Another label', value: 'Another value 5' }, disabled,
{ label: 'Another label', value: 'Another value ' }, invalid,
]); loading,
prefixEl,
};
};
const getDynamicProps = () => {
const knobs = getKnobs();
return {
disabled: knobs.disabled,
isLoading: knobs.loading,
invalid: knobs.invalid,
prefix: knobs.prefixEl,
};
};
export const basic = () => { export const basic = () => {
const value = object<SelectableValue<string>>('Selected Value:', intialState); const [value, setValue] = useState<SelectableValue<string>>();
return ( return (
<UseState initialState={value}> <>
{(value, updateValue) => { <Select
return ( options={generateOptions()}
<Select value={value}
placeholder="Choose..." onChange={v => {
options={options} setValue(v);
width={20} }}
onChange={value => { size="md"
action('onChanged fired')(value); {...getDynamicProps()}
updateValue(value); />
}} </>
/>
);
}}
</UseState>
); );
}; };
export const withAllowCustomValue = () => { /**
// @ts-ignore * Uses plain values instead of SelectableValue<T>
const value = object<SelectableValue<string>>('Selected Value:', null); */
export const basicSelectPlainValue = () => {
const [value, setValue] = useState<string>();
return ( return (
<UseState initialState={value}> <>
{(value, updateValue) => { <Select
return ( options={generateOptions()}
<Select value={value}
// value={value} onChange={v => {
placeholder="Choose..." setValue(v.value);
options={options} }}
width={20} size="md"
allowCustomValue={true} {...getDynamicProps()}
onChange={value => { />
action('onChanged fired')(value); </>
updateValue(value);
}}
/>
);
}}
</UseState>
); );
}; };
export const asyncSelect = () => { /**
const [isLoading, setIsLoading] = useState<boolean>(true); * Uses plain values instead of SelectableValue<T>
const [value, setValue] = useState(); */
const loadAsyncOptions = useCallback( export const SelectWithOptionDescriptions = () => {
inputValue => { // TODO this is not working with new Select
return new Promise<Array<SelectableValue<string>>>(resolve => {
setTimeout(() => { const [value, setValue] = useState<number>();
setIsLoading(false); const options = [
resolve(options.filter(option => option.label && option.label.includes(inputValue))); { label: 'Basic option', value: 0 },
}, 1000); { label: 'Option with description', value: 1, description: 'this is a description' },
}); {
label: 'Option with description and image',
value: 2,
description: 'This is a very elaborate description, describing all the wonders in the world.',
imgUrl: 'https://placekitten.com/40/40',
}, },
[value] ];
return (
<>
<Select
options={options}
value={value}
onChange={v => {
setValue(v.value);
}}
size="md"
{...getDynamicProps()}
/>
</>
);
};
/**
* Uses plain values instead of SelectableValue<T>
*/
export const multiPlainValue = () => {
const [value, setValue] = useState<string[]>();
return (
<>
<MultiSelect
options={generateOptions()}
value={value}
onChange={v => {
setValue(v.map((v: any) => v.value));
}}
size="md"
{...getDynamicProps()}
/>
</>
); );
};
export const multiSelect = () => {
const [value, setValue] = useState<Array<SelectableValue<string>>>([]);
return ( return (
<AsyncSelect <>
value={value} <MultiSelect
options={generateOptions()}
value={value}
onChange={v => {
setValue(v);
}}
size="md"
{...getDynamicProps()}
/>
</>
);
};
export const multiSelectAsync = () => {
const [value, setValue] = useState<Array<SelectableValue<string>>>();
return (
<AsyncMultiSelect
loadOptions={loadAsyncOptions}
defaultOptions defaultOptions
width={20} value={value}
isLoading={isLoading} onChange={v => {
setValue(v);
}}
size="md"
allowCustomValue
{...getDynamicProps()}
/>
);
};
export const buttonSelect = () => {
const [value, setValue] = useState<SelectableValue<string>>();
const icon = getIconKnob();
return (
<ButtonSelect
placeholder="Select all the things..."
value={value}
options={generateOptions()}
onChange={v => {
setValue(v);
}}
size="md"
allowCustomValue
icon={icon}
{...getDynamicProps()}
/>
);
};
export const basicSelectAsync = () => {
const [value, setValue] = useState<SelectableValue<string>>();
return (
<AsyncSelect
loadOptions={loadAsyncOptions} loadOptions={loadAsyncOptions}
onChange={value => { defaultOptions
action('onChange')(value); value={value}
setValue(value); onChange={v => {
setValue(v);
}}
size="md"
{...getDynamicProps()}
/>
);
};
export const customizedControl = () => {
const [value, setValue] = useState<SelectableValue<string>>();
return (
<Select
options={generateOptions()}
value={value}
onChange={v => {
setValue(v);
}} }}
size="md"
renderControl={React.forwardRef(({ isOpen, value, ...otherProps }, ref) => {
return (
<Button {...otherProps} ref={ref}>
{' '}
{isOpen ? 'Open' : 'Closed'}
</Button>
);
})}
{...getDynamicProps()}
/> />
); );
}; };
export const autoMenuPlacement = () => {
const [value, setValue] = useState<SelectableValue<string>>();
return (
<>
<div style={{ height: '95vh', display: 'flex', alignItems: 'flex-end' }}>
<Select
options={generateOptions()}
value={value}
onChange={v => {
setValue(v);
}}
size="md"
{...getDynamicProps()}
/>
</div>
</>
);
};
export const customValueCreation = () => {
const [value, setValue] = useState<SelectableValue<string>>();
const [customOptions, setCustomOptions] = useState<Array<SelectableValue<string>>>([]);
const options = generateOptions();
return (
<>
<Select
options={[...options, ...customOptions]}
value={value}
onChange={v => {
setValue(v);
}}
size="md"
allowCustomValue
onCreateOption={v => {
const customValue: SelectableValue<string> = { value: kebabCase(v), label: v };
setCustomOptions([...customOptions, customValue]);
setValue(customValue);
}}
{...getDynamicProps()}
/>
</>
);
};
...@@ -9,9 +9,9 @@ import { default as ReactAsyncSelect } from '@torkelo/react-select/async'; ...@@ -9,9 +9,9 @@ import { default as ReactAsyncSelect } from '@torkelo/react-select/async';
// @ts-ignore // @ts-ignore
import { default as AsyncCreatable } from '@torkelo/react-select/async-creatable'; import { default as AsyncCreatable } from '@torkelo/react-select/async-creatable';
import { Icon } from '../../Icon/Icon'; import { Icon } from '../Icon/Icon';
import { css, cx } from 'emotion'; import { css, cx } from 'emotion';
import { inputSizesPixels } from '../commonStyles'; import { inputSizesPixels } from '../Forms/commonStyles';
import resetSelectStyles from './resetSelectStyles'; import resetSelectStyles from './resetSelectStyles';
import { SelectMenu, SelectMenuOptions } from './SelectMenu'; import { SelectMenu, SelectMenuOptions } from './SelectMenu';
import { IndicatorsContainer } from './IndicatorsContainer'; import { IndicatorsContainer } from './IndicatorsContainer';
...@@ -21,7 +21,7 @@ import { DropdownIndicator } from './DropdownIndicator'; ...@@ -21,7 +21,7 @@ import { DropdownIndicator } from './DropdownIndicator';
import { SelectOptionGroup } from './SelectOptionGroup'; import { SelectOptionGroup } from './SelectOptionGroup';
import { SingleValue } from './SingleValue'; import { SingleValue } from './SingleValue';
import { MultiValueContainer, MultiValueRemove } from './MultiValue'; import { MultiValueContainer, MultiValueRemove } from './MultiValue';
import { useTheme } from '../../../themes'; import { useTheme } from '../../themes';
import { getSelectStyles } from './getSelectStyles'; import { getSelectStyles } from './getSelectStyles';
import { cleanValue } from './utils'; import { cleanValue } from './utils';
import { SelectBaseProps, SelectValue } from './types'; import { SelectBaseProps, SelectValue } from './types';
......
import React from 'react'; import React from 'react';
import { useTheme } from '../../../themes/ThemeContext'; import { useTheme } from '../../themes/ThemeContext';
import { getSelectStyles } from './getSelectStyles'; import { getSelectStyles } from './getSelectStyles';
import { cx } from 'emotion'; import { cx } from 'emotion';
import { SelectableValue } from '@grafana/data'; import { SelectableValue } from '@grafana/data';
import { Icon } from '../../Icon/Icon'; import { Icon } from '../Icon/Icon';
import { CustomScrollbar } from '../../CustomScrollbar/CustomScrollbar'; import { CustomScrollbar } from '../CustomScrollbar/CustomScrollbar';
interface SelectMenuProps { interface SelectMenuProps {
maxHeight: number; maxHeight: number;
......
...@@ -2,8 +2,8 @@ import React, { PureComponent } from 'react'; ...@@ -2,8 +2,8 @@ import React, { PureComponent } from 'react';
import { css, cx } from 'emotion'; import { css, cx } from 'emotion';
import { GrafanaTheme } from '@grafana/data'; import { GrafanaTheme } from '@grafana/data';
import { GroupProps } from 'react-select'; import { GroupProps } from 'react-select';
import { stylesFactory, withTheme, selectThemeVariant } from '../../../themes'; import { stylesFactory, withTheme, selectThemeVariant } from '../../themes';
import { Themeable } from '../../../types'; import { Themeable } from '../../types';
interface ExtendedGroupProps extends GroupProps<any>, Themeable { interface ExtendedGroupProps extends GroupProps<any>, Themeable {
data: { data: {
......
...@@ -4,11 +4,11 @@ import { css, cx } from 'emotion'; ...@@ -4,11 +4,11 @@ import { css, cx } from 'emotion';
// Ignoring because I couldn't get @types/react-select work wih Torkel's fork // Ignoring because I couldn't get @types/react-select work wih Torkel's fork
// @ts-ignore // @ts-ignore
import { components } from '@torkelo/react-select'; import { components } from '@torkelo/react-select';
import { useDelayedSwitch } from '../../../utils/useDelayedSwitch'; import { useDelayedSwitch } from '../../utils/useDelayedSwitch';
import { stylesFactory, useTheme } from '../../../themes'; import { stylesFactory, useTheme } from '../../themes';
import { SlideOutTransition } from '../../transitions/SlideOutTransition'; import { SlideOutTransition } from '../transitions/SlideOutTransition';
import { FadeTransition } from '../../transitions/FadeTransition'; import { FadeTransition } from '../transitions/FadeTransition';
import { Spinner } from '../../Spinner/Spinner'; import { Spinner } from '../Spinner/Spinner';
import { GrafanaTheme } from '@grafana/data'; import { GrafanaTheme } from '@grafana/data';
const getStyles = stylesFactory((theme: GrafanaTheme) => { const getStyles = stylesFactory((theme: GrafanaTheme) => {
......
import React from 'react'; import React from 'react';
import { cx } from 'emotion'; import { cx } from 'emotion';
import { useTheme } from '../../../themes/ThemeContext'; import { useTheme } from '../../themes/ThemeContext';
import { getSelectStyles } from './getSelectStyles'; import { getSelectStyles } from './getSelectStyles';
export const ValueContainer = (props: any) => { export const ValueContainer = (props: any) => {
......
import { stylesFactory } from '../../../themes/stylesFactory'; import { stylesFactory } from '../../themes/stylesFactory';
import { selectThemeVariant as stv } from '../../../themes/selectThemeVariant'; import { selectThemeVariant as stv } from '../../themes/selectThemeVariant';
import { css } from 'emotion'; import { css } from 'emotion';
import { GrafanaTheme } from '@grafana/data'; import { GrafanaTheme } from '@grafana/data';
......
import { SelectableValue } from '@grafana/data'; import { SelectableValue } from '@grafana/data';
import React from 'react'; import React from 'react';
import { FormInputSize } from '../types'; import { FormInputSize } from '../Forms/types';
export type SelectValue<T> = T | SelectableValue<T> | T[] | Array<SelectableValue<T>>; export type SelectValue<T> = T | SelectableValue<T> | T[] | Array<SelectableValue<T>>;
...@@ -18,6 +18,8 @@ export interface SelectCommonProps<T> { ...@@ -18,6 +18,8 @@ export interface SelectCommonProps<T> {
onKeyDown?: (event: React.KeyboardEvent) => void; onKeyDown?: (event: React.KeyboardEvent) => void;
placeholder?: string; placeholder?: string;
disabled?: boolean; disabled?: boolean;
//To be removed, is here to make Enterprise mergable
isDisabled?: boolean;
isSearchable?: boolean; isSearchable?: boolean;
isClearable?: boolean; isClearable?: boolean;
autoFocus?: boolean; autoFocus?: boolean;
......
...@@ -42,7 +42,7 @@ const options: SelectableValue[] = [ ...@@ -42,7 +42,7 @@ const options: SelectableValue[] = [
{ label: 'Option 6', value: 6 }, { label: 'Option 6', value: 6 },
]; ];
describe('Forms.Select utils', () => { describe('Select utils', () => {
describe('findSelected value', () => { describe('findSelected value', () => {
it('should find value of type number in array of optgroups', () => { it('should find value of type number in array of optgroups', () => {
expect(findSelectedValue(11, optGroup)).toEqual({ label: 'Group 2 - Option 1', value: 11 }); expect(findSelectedValue(11, optGroup)).toEqual({ label: 'Group 2 - Option 1', value: 11 });
......
...@@ -7,7 +7,7 @@ import { FormField } from '../FormField/FormField'; ...@@ -7,7 +7,7 @@ import { FormField } from '../FormField/FormField';
import { StatsPicker } from '../StatsPicker/StatsPicker'; import { StatsPicker } from '../StatsPicker/StatsPicker';
// Types // Types
import Select from '../Select/Select'; import Select from '../Forms/Legacy/Select/Select';
import { import {
ReduceDataOptions, ReduceDataOptions,
DEFAULT_FIELD_DISPLAY_VALUES_LIMIT, DEFAULT_FIELD_DISPLAY_VALUES_LIMIT,
......
...@@ -3,7 +3,7 @@ import React, { PureComponent } from 'react'; ...@@ -3,7 +3,7 @@ import React, { PureComponent } from 'react';
import isArray from 'lodash/isArray'; import isArray from 'lodash/isArray';
import difference from 'lodash/difference'; import difference from 'lodash/difference';
import { Select } from '../Forms/Select/Select'; import { Select } from '../Select/Select';
import { fieldReducers, SelectableValue } from '@grafana/data'; import { fieldReducers, SelectableValue } from '@grafana/data';
......
import { DataTransformerID, DataTransformerConfig, DataFrame, transformDataFrame } from '@grafana/data'; import { DataTransformerID, DataTransformerConfig, DataFrame, transformDataFrame } from '@grafana/data';
import { Select } from '../Select/Select'; import { Select } from '../Forms/Legacy/Select/Select';
import { transformersUIRegistry } from './transformers'; import { transformersUIRegistry } from './transformers';
import React from 'react'; import React from 'react';
import { TransformationRow } from './TransformationRow'; import { TransformationRow } from './TransformationRow';
......
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { Select } from '../Select/Select'; import { Select } from '../Forms/Legacy/Select/Select';
import { Cascader, CascaderOption } from '../Cascader/Cascader'; import { Cascader, CascaderOption } from '../Cascader/Cascader';
import { getValueFormats, SelectableValue } from '@grafana/data'; import { getValueFormats, SelectableValue } from '@grafana/data';
......
...@@ -3,7 +3,7 @@ import React, { ChangeEvent, PureComponent } from 'react'; ...@@ -3,7 +3,7 @@ import React, { ChangeEvent, PureComponent } from 'react';
import { FormField } from '../FormField/FormField'; import { FormField } from '../FormField/FormField';
import { FormLabel } from '../FormLabel/FormLabel'; import { FormLabel } from '../FormLabel/FormLabel';
import { Input } from '../Input/Input'; import { Input } from '../Input/Input';
import { Select } from '../Select/Select'; import { Select } from '../Forms/Legacy/Select/Select';
import { MappingType, ValueMapping } from '@grafana/data'; import { MappingType, ValueMapping } from '@grafana/data';
......
import React, { ChangeEvent } from 'react'; import React, { ChangeEvent } from 'react';
import { HorizontalGroup } from '../Layout/Layout'; import { HorizontalGroup } from '../Layout/Layout';
import { Select } from '../index';
import Forms from '../Forms'; import Forms from '../Forms';
import { MappingType, RangeMap, ValueMap, ValueMapping } from '@grafana/data'; import { MappingType, RangeMap, ValueMap, ValueMapping } from '@grafana/data';
import * as styleMixins from '../../themes/mixins'; import * as styleMixins from '../../themes/mixins';
...@@ -80,7 +81,7 @@ export const MappingRow: React.FC<Props> = ({ valueMapping, updateValueMapping, ...@@ -80,7 +81,7 @@ export const MappingRow: React.FC<Props> = ({ valueMapping, updateValueMapping,
<div className={styles.wrapper}> <div className={styles.wrapper}>
<FieldConfigItemHeaderTitle title="Mapping type" onRemove={removeValueMapping}> <FieldConfigItemHeaderTitle title="Mapping type" onRemove={removeValueMapping}>
<div className={styles.itemContent}> <div className={styles.itemContent}>
<Forms.Select <Select
placeholder="Choose type" placeholder="Choose type"
isSearchable={false} isSearchable={false}
options={MAPPING_OPTIONS} options={MAPPING_OPTIONS}
......
...@@ -2,7 +2,7 @@ import { text } from '@storybook/addon-knobs'; ...@@ -2,7 +2,7 @@ import { text } from '@storybook/addon-knobs';
import { withCenteredStory } from '../../utils/storybook/withCenteredStory'; import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
import { ValuePicker } from './ValuePicker'; import { ValuePicker } from './ValuePicker';
import React from 'react'; import React from 'react';
import { generateOptions } from '../Forms/Select/mockOptions'; import { generateOptions } from '../Select/mockOptions';
export default { export default {
title: 'General/ValuePicker', title: 'General/ValuePicker',
......
...@@ -2,7 +2,7 @@ import React, { useState } from 'react'; ...@@ -2,7 +2,7 @@ import React, { useState } from 'react';
import { IconType } from '../Icon/types'; import { IconType } from '../Icon/types';
import { SelectableValue } from '@grafana/data'; import { SelectableValue } from '@grafana/data';
import { Button, ButtonVariant } from '../Button'; import { Button, ButtonVariant } from '../Button';
import { Select } from '../Forms/Select/Select'; import { Select } from '../Select/Select';
import { FullWidthButtonContainer } from '../Button/FullWidthButtonContainer'; import { FullWidthButtonContainer } from '../Button/FullWidthButtonContainer';
interface ValuePickerProps<T> { interface ValuePickerProps<T> {
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
@import 'PanelOptionsGrid/PanelOptionsGrid'; @import 'PanelOptionsGrid/PanelOptionsGrid';
@import 'PanelOptionsGroup/PanelOptionsGroup'; @import 'PanelOptionsGroup/PanelOptionsGroup';
@import 'RefreshPicker/RefreshPicker'; @import 'RefreshPicker/RefreshPicker';
@import 'Select/Select'; @import 'Forms/Legacy/Select/Select';
@import 'TableInputCSV/TableInputCSV'; @import 'TableInputCSV/TableInputCSV';
@import 'ThresholdsEditor/ThresholdsEditor'; @import 'ThresholdsEditor/ThresholdsEditor';
@import 'TimePicker/TimeOfDayPicker'; @import 'TimePicker/TimeOfDayPicker';
......
...@@ -7,15 +7,8 @@ export { Portal } from './Portal/Portal'; ...@@ -7,15 +7,8 @@ export { Portal } from './Portal/Portal';
export { CustomScrollbar } from './CustomScrollbar/CustomScrollbar'; export { CustomScrollbar } from './CustomScrollbar/CustomScrollbar';
export { ClipboardButton } from './ClipboardButton/ClipboardButton'; export { ClipboardButton } from './ClipboardButton/ClipboardButton';
// Select
export { Select, AsyncSelect } from './Select/Select';
export { IndicatorsContainer } from './Select/IndicatorsContainer';
export { NoOptionsMessage } from './Select/NoOptionsMessage';
export { default as resetSelectStyles } from './Forms/Select/resetSelectStyles';
export { ButtonSelect } from './Select/ButtonSelect';
export { ButtonCascader } from './ButtonCascader/ButtonCascader';
export { Cascader, CascaderOption } from './Cascader/Cascader'; export { Cascader, CascaderOption } from './Cascader/Cascader';
export { ButtonCascader } from './ButtonCascader/ButtonCascader';
// Forms // Forms
export { FormLabel } from './FormLabel/FormLabel'; export { FormLabel } from './FormLabel/FormLabel';
...@@ -140,5 +133,27 @@ export * from './Button'; ...@@ -140,5 +133,27 @@ export * from './Button';
export { ValuePicker } from './ValuePicker/ValuePicker'; export { ValuePicker } from './ValuePicker/ValuePicker';
export { fieldMatchersUI } from './MatchersUI/fieldMatchersUI'; export { fieldMatchersUI } from './MatchersUI/fieldMatchersUI';
export { default as resetSelectStyles } from './Select/resetSelectStyles';
export * from './Select/Select';
export { ButtonSelect } from './Select/ButtonSelect';
export { HorizontalGroup, VerticalGroup, Container } from './Layout/Layout'; export { HorizontalGroup, VerticalGroup, Container } from './Layout/Layout';
export { RadioButtonGroup } from './Forms/RadioButtonGroup/RadioButtonGroup'; export { RadioButtonGroup } from './Forms/RadioButtonGroup/RadioButtonGroup';
// Legacy forms
// Select
import { Select, AsyncSelect } from './Forms/Legacy/Select/Select';
import { IndicatorsContainer } from './Forms/Legacy/Select/IndicatorsContainer';
import { NoOptionsMessage } from './Forms/Legacy/Select/NoOptionsMessage';
import { ButtonSelect } from './Forms/Legacy/Select/ButtonSelect';
const LegacyForms = {
Select,
AsyncSelect,
IndicatorsContainer,
NoOptionsMessage,
ButtonSelect,
};
export { LegacyForms };
...@@ -18,7 +18,7 @@ import { ...@@ -18,7 +18,7 @@ import {
ValueMappingFieldConfigSettings, ValueMappingFieldConfigSettings,
valueMappingsOverrideProcessor, valueMappingsOverrideProcessor,
} from '@grafana/data'; } from '@grafana/data';
import { NumberValueEditor, Forms, StringValueEditor } from '../components'; import { NumberValueEditor, Forms, StringValueEditor, Select } from '../components';
import { ValueMappingsValueEditor } from '../components/OptionsUI/mappings'; import { ValueMappingsValueEditor } from '../components/OptionsUI/mappings';
import { ThresholdsValueEditor } from '../components/OptionsUI/thresholds'; import { ThresholdsValueEditor } from '../components/OptionsUI/thresholds';
import { UnitValueEditor } from '../components/OptionsUI/units'; import { UnitValueEditor } from '../components/OptionsUI/units';
...@@ -216,11 +216,7 @@ export const getStandardOptionEditors = () => { ...@@ -216,11 +216,7 @@ export const getStandardOptionEditors = () => {
name: 'Select', name: 'Select',
description: 'Allows option selection', description: 'Allows option selection',
editor: props => ( editor: props => (
<Forms.Select <Select value={props.value} onChange={e => props.onChange(e.value)} options={props.item.settings?.options} />
value={props.value}
onChange={e => props.onChange(e.value)}
options={props.item.settings?.options}
/>
), ),
}; };
......
import React, { Component } from 'react'; import React, { Component } from 'react';
import { UserPicker } from 'app/core/components/Select/UserPicker'; import { UserPicker } from 'app/core/components/Select/UserPicker';
import { TeamPicker, Team } from 'app/core/components/Select/TeamPicker'; import { TeamPicker, Team } from 'app/core/components/Select/TeamPicker';
import { Select } from '@grafana/ui'; import { LegacyForms } from '@grafana/ui';
import { SelectableValue } from '@grafana/data'; import { SelectableValue } from '@grafana/data';
import { User } from 'app/types'; import { User } from 'app/types';
import { import {
...@@ -12,6 +12,7 @@ import { ...@@ -12,6 +12,7 @@ import {
NewDashboardAclItem, NewDashboardAclItem,
OrgRole, OrgRole,
} from 'app/types/acl'; } from 'app/types/acl';
const { Select } = LegacyForms;
export interface Props { export interface Props {
onAddPermission: (item: NewDashboardAclItem) => void; onAddPermission: (item: NewDashboardAclItem) => void;
......
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Select } from '@grafana/ui'; import { LegacyForms } from '@grafana/ui';
import { dashboardPermissionLevels } from 'app/types/acl'; import { dashboardPermissionLevels } from 'app/types/acl';
const { Select } = LegacyForms;
export interface Props { export interface Props {
item: any; item: any;
......
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { Select } from '@grafana/ui'; import { LegacyForms } from '@grafana/ui';
import { SelectableValue } from '@grafana/data'; import { SelectableValue } from '@grafana/data';
import { dashboardPermissionLevels, DashboardAcl, PermissionLevel } from 'app/types/acl'; import { dashboardPermissionLevels, DashboardAcl, PermissionLevel } from 'app/types/acl';
import { FolderInfo } from 'app/types'; import { FolderInfo } from 'app/types';
const { Select } = LegacyForms;
const setClassNameHelper = (inherited: boolean) => { const setClassNameHelper = (inherited: boolean) => {
return inherited ? 'gf-form-disabled' : ''; return inherited ? 'gf-form-disabled' : '';
......
...@@ -2,7 +2,7 @@ import React, { FC } from 'react'; ...@@ -2,7 +2,7 @@ import React, { FC } from 'react';
import { debounce } from 'lodash'; import { debounce } from 'lodash';
import { useAsyncFn } from 'react-use'; import { useAsyncFn } from 'react-use';
import { SelectableValue } from '@grafana/data'; import { SelectableValue } from '@grafana/data';
import { Forms } from '@grafana/ui'; import { AsyncSelect } from '@grafana/ui';
import { FormInputSize } from '@grafana/ui/src/components/Forms/types'; import { FormInputSize } from '@grafana/ui/src/components/Forms/types';
import { backendSrv } from 'app/core/services/backend_srv'; import { backendSrv } from 'app/core/services/backend_srv';
import { DashboardSearchHit, DashboardDTO } from 'app/types'; import { DashboardSearchHit, DashboardDTO } from 'app/types';
...@@ -42,7 +42,7 @@ export const DashboardPicker: FC<Props> = ({ ...@@ -42,7 +42,7 @@ export const DashboardPicker: FC<Props> = ({
const [state, searchDashboards] = useAsyncFn(debouncedSearch, []); const [state, searchDashboards] = useAsyncFn(debouncedSearch, []);
return ( return (
<Forms.AsyncSelect <AsyncSelect
size={size} size={size}
isLoading={state.loading} isLoading={state.loading}
isClearable={isClearable} isClearable={isClearable}
......
...@@ -2,8 +2,9 @@ ...@@ -2,8 +2,9 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
// Components // Components
import { Select } from '@grafana/ui'; import { LegacyForms } from '@grafana/ui';
import { SelectableValue, DataSourceSelectItem } from '@grafana/data'; import { SelectableValue, DataSourceSelectItem } from '@grafana/data';
const { Select } = LegacyForms;
export interface Props { export interface Props {
onChange: (ds: DataSourceSelectItem) => void; onChange: (ds: DataSourceSelectItem) => void;
......
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { Forms } from '@grafana/ui'; import { AsyncSelect } from '@grafana/ui';
import { AppEvents, SelectableValue } from '@grafana/data'; import { AppEvents, SelectableValue } from '@grafana/data';
import { debounce } from 'lodash'; import { debounce } from 'lodash';
import appEvents from '../../app_events'; import appEvents from '../../app_events';
...@@ -150,7 +150,7 @@ export class FolderPicker extends PureComponent<Props, State> { ...@@ -150,7 +150,7 @@ export class FolderPicker extends PureComponent<Props, State> {
return ( return (
<> <>
{useNewForms && ( {useNewForms && (
<Forms.AsyncSelect <AsyncSelect
loadingMessage="Loading folders..." loadingMessage="Loading folders..."
defaultOptions defaultOptions
defaultValue={folder} defaultValue={folder}
...@@ -167,7 +167,7 @@ export class FolderPicker extends PureComponent<Props, State> { ...@@ -167,7 +167,7 @@ export class FolderPicker extends PureComponent<Props, State> {
<div className="gf-form-inline"> <div className="gf-form-inline">
<div className="gf-form"> <div className="gf-form">
<label className="gf-form-label width-7">Folder</label> <label className="gf-form-label width-7">Folder</label>
<Forms.AsyncSelect <AsyncSelect
loadingMessage="Loading folders..." loadingMessage="Loading folders..."
defaultOptions defaultOptions
defaultValue={folder} defaultValue={folder}
......
import React from 'react'; import React from 'react';
import _ from 'lodash'; import _ from 'lodash';
import { Select } from '@grafana/ui'; import { LegacyForms } from '@grafana/ui';
import { SelectableValue } from '@grafana/data'; import { SelectableValue } from '@grafana/data';
import { Variable } from 'app/types/templates'; import { Variable } from 'app/types/templates';
const { Select } = LegacyForms;
export interface Props { export interface Props {
onChange: (value: string) => void; onChange: (value: string) => void;
......
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { Forms } from '@grafana/ui'; import { AsyncSelect } from '@grafana/ui';
import { getBackendSrv } from 'app/core/services/backend_srv'; import { getBackendSrv } from 'app/core/services/backend_srv';
import { Organization } from 'app/types'; import { Organization } from 'app/types';
import { SelectableValue } from '@grafana/data'; import { SelectableValue } from '@grafana/data';
...@@ -54,7 +54,7 @@ export class OrgPicker extends PureComponent<Props, State> { ...@@ -54,7 +54,7 @@ export class OrgPicker extends PureComponent<Props, State> {
const { isLoading } = this.state; const { isLoading } = this.state;
return ( return (
<Forms.AsyncSelect <AsyncSelect
className={className} className={className}
isLoading={isLoading} isLoading={isLoading}
defaultOptions={true} defaultOptions={true}
......
import React, { Component } from 'react'; import React, { Component } from 'react';
import _ from 'lodash'; import _ from 'lodash';
import { AsyncSelect } from '@grafana/ui'; import { LegacyForms } from '@grafana/ui';
import { debounce } from 'lodash'; import { debounce } from 'lodash';
import { getBackendSrv } from '@grafana/runtime'; import { getBackendSrv } from '@grafana/runtime';
const { AsyncSelect } = LegacyForms;
export interface Team { export interface Team {
id: number; id: number;
......
...@@ -3,7 +3,8 @@ import React, { Component } from 'react'; ...@@ -3,7 +3,8 @@ import React, { Component } from 'react';
import _ from 'lodash'; import _ from 'lodash';
// Components // Components
import { AsyncSelect } from '@grafana/ui'; import { LegacyForms } from '@grafana/ui';
const { AsyncSelect } = LegacyForms;
// Utils & Services // Utils & Services
import { debounce } from 'lodash'; import { debounce } from 'lodash';
......
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { FormLabel, Select } from '@grafana/ui'; import { FormLabel, LegacyForms } from '@grafana/ui';
const { Select } = LegacyForms;
import { DashboardSearchHit, DashboardSearchHitType } from 'app/types'; import { DashboardSearchHit, DashboardSearchHitType } from 'app/types';
import { backendSrv } from 'app/core/services/backend_srv'; import { backendSrv } from 'app/core/services/backend_srv';
......
...@@ -8,7 +8,8 @@ import { escapeStringForRegex } from '@grafana/data'; ...@@ -8,7 +8,8 @@ import { escapeStringForRegex } from '@grafana/data';
// Components // Components
import { TagOption } from './TagOption'; import { TagOption } from './TagOption';
import { TagBadge } from './TagBadge'; import { TagBadge } from './TagBadge';
import { IndicatorsContainer, NoOptionsMessage, resetSelectStyles } from '@grafana/ui'; import { resetSelectStyles, LegacyForms } from '@grafana/ui';
const { IndicatorsContainer, NoOptionsMessage } = LegacyForms;
export interface TermCount { export interface TermCount {
term: string; term: string;
......
...@@ -6,7 +6,17 @@ import { css } from 'emotion'; ...@@ -6,7 +6,17 @@ import { css } from 'emotion';
import { InspectHeader } from './InspectHeader'; import { InspectHeader } from './InspectHeader';
import { DashboardModel, PanelModel } from 'app/features/dashboard/state'; import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
import { JSONFormatter, Drawer, Select, Table, TabContent, stylesFactory, CustomScrollbar, Button } from '@grafana/ui'; import {
JSONFormatter,
Drawer,
LegacyForms,
Table,
TabContent,
stylesFactory,
CustomScrollbar,
Button,
} from '@grafana/ui';
const { Select } = LegacyForms;
import { getLocationSrv, getDataSourceSrv } from '@grafana/runtime'; import { getLocationSrv, getDataSourceSrv } from '@grafana/runtime';
import { import {
DataFrame, DataFrame,
......
import React, { FC, useMemo } from 'react'; import React, { FC, useMemo } from 'react';
import { PanelModel } from '../../state'; import { PanelModel } from '../../state';
import { SelectableValue } from '@grafana/data'; import { SelectableValue } from '@grafana/data';
import { DataLinksInlineEditor, Forms } from '@grafana/ui'; import { Forms, Select, DataLinksInlineEditor } from '@grafana/ui';
import { OptionsGroup } from './OptionsGroup'; import { OptionsGroup } from './OptionsGroup';
import { getPanelLinksVariableSuggestions } from '../../../panel/panellinks/link_srv'; import { getPanelLinksVariableSuggestions } from '../../../panel/panellinks/link_srv';
import { getVariables } from '../../../variables/state/selectors'; import { getVariables } from '../../../variables/state/selectors';
...@@ -54,7 +54,7 @@ export const GeneralPanelOptions: FC<{ ...@@ -54,7 +54,7 @@ export const GeneralPanelOptions: FC<{
This is not visible while in edit mode. You need to go back to dashboard and then update the variable or This is not visible while in edit mode. You need to go back to dashboard and then update the variable or
reload the dashboard." reload the dashboard."
> >
<Forms.Select <Select
value={panel.repeat} value={panel.repeat}
onChange={value => onPanelConfigChange('repeat', value.value)} onChange={value => onPanelConfigChange('repeat', value.value)}
options={variableOptions} options={variableOptions}
...@@ -72,7 +72,7 @@ export const GeneralPanelOptions: FC<{ ...@@ -72,7 +72,7 @@ export const GeneralPanelOptions: FC<{
{panel.repeat && panel.repeatDirection === 'h' && ( {panel.repeat && panel.repeatDirection === 'h' && (
<Forms.Field label="Max per row"> <Forms.Field label="Max per row">
<Forms.Select <Select
options={maxPerRowOptions} options={maxPerRowOptions}
value={panel.maxPerRow} value={panel.maxPerRow}
onChange={value => onPanelConfigChange('maxPerRow', value.value)} onChange={value => onPanelConfigChange('maxPerRow', value.value)}
......
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { FieldConfigSource, GrafanaTheme, PanelData, PanelPlugin, SelectableValue } from '@grafana/data'; import { FieldConfigSource, GrafanaTheme, PanelData, PanelPlugin, SelectableValue } from '@grafana/data';
import { Forms, stylesFactory, Icon } from '@grafana/ui'; import { Select, stylesFactory, Icon } from '@grafana/ui';
import { css, cx } from 'emotion'; import { css, cx } from 'emotion';
import config from 'app/core/config'; import config from 'app/core/config';
import AutoSizer from 'react-virtualized-auto-sizer'; import AutoSizer from 'react-virtualized-auto-sizer';
...@@ -205,7 +205,7 @@ export class PanelEditorUnconnected extends PureComponent<Props> { ...@@ -205,7 +205,7 @@ export class PanelEditorUnconnected extends PureComponent<Props> {
</DashNavButton> </DashNavButton>
</div> </div>
<div className={styles.toolbarItem}> <div className={styles.toolbarItem}>
<Forms.Select <Select
value={displayModes.find(v => v.value === uiState.mode)} value={displayModes.find(v => v.value === uiState.mode)}
options={displayModes} options={displayModes}
onChange={this.onDiplayModeChange} onChange={this.onDiplayModeChange}
......
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { Switch, Select } from '@grafana/ui'; import { Switch, LegacyForms } from '@grafana/ui';
const { Select } = LegacyForms;
import { SelectableValue } from '@grafana/data'; import { SelectableValue } from '@grafana/data';
import { DashboardModel, PanelModel } from 'app/features/dashboard/state'; import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
import { buildIframeHtml } from './utils'; import { buildIframeHtml } from './utils';
......
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { e2e } from '@grafana/e2e'; import { e2e } from '@grafana/e2e';
import { Switch, Select, ClipboardButton } from '@grafana/ui'; import { Switch, LegacyForms, ClipboardButton } from '@grafana/ui';
const { Select } = LegacyForms;
import { SelectableValue, PanelModel, AppEvents } from '@grafana/data'; import { SelectableValue, PanelModel, AppEvents } from '@grafana/data';
import { DashboardModel } from 'app/features/dashboard/state'; import { DashboardModel } from 'app/features/dashboard/state';
import { buildImageUrl, buildShareUrl } from './utils'; import { buildImageUrl, buildShareUrl } from './utils';
......
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { Button, ClipboardButton, Input, LinkButton, Select } from '@grafana/ui'; import { Button, ClipboardButton, Input, LinkButton, LegacyForms } from '@grafana/ui';
const { Select } = LegacyForms;
import { AppEvents, SelectableValue } from '@grafana/data'; import { AppEvents, SelectableValue } from '@grafana/data';
import { getBackendSrv } from '@grafana/runtime'; import { getBackendSrv } from '@grafana/runtime';
import { DashboardModel, PanelModel } from 'app/features/dashboard/state'; import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
......
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { Select, ThemeContext } from '@grafana/ui'; import { LegacyForms, ThemeContext } from '@grafana/ui';
const { Select } = LegacyForms;
import { css, cx } from 'emotion'; import { css, cx } from 'emotion';
import { GrafanaTheme, SelectableValue } from '@grafana/data'; import { GrafanaTheme, SelectableValue } from '@grafana/data';
......
...@@ -7,7 +7,8 @@ import classNames from 'classnames'; ...@@ -7,7 +7,8 @@ import classNames from 'classnames';
import { css } from 'emotion'; import { css } from 'emotion';
import { ExploreId, ExploreItemState } from 'app/types/explore'; import { ExploreId, ExploreItemState } from 'app/types/explore';
import { ToggleButtonGroup, ToggleButton, Tooltip, ButtonSelect, SetInterval } from '@grafana/ui'; import { ToggleButtonGroup, ToggleButton, Tooltip, LegacyForms, SetInterval } from '@grafana/ui';
const { ButtonSelect } = LegacyForms;
import { RawTimeRange, TimeZone, TimeRange, DataQuery, ExploreMode } from '@grafana/data'; import { RawTimeRange, TimeZone, TimeRange, DataQuery, ExploreMode } from '@grafana/data';
import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker'; import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker';
import { StoreState } from 'app/types/store'; import { StoreState } from 'app/types/store';
......
...@@ -21,7 +21,8 @@ import { ...@@ -21,7 +21,8 @@ import {
// Components // Components
import RichHistoryCard from './RichHistoryCard'; import RichHistoryCard from './RichHistoryCard';
import { sortOrderOptions } from './RichHistory'; import { sortOrderOptions } from './RichHistory';
import { Select, Slider } from '@grafana/ui'; import { LegacyForms, Slider } from '@grafana/ui';
const { Select } = LegacyForms;
export interface Props { export interface Props {
queries: RichHistoryQuery[]; queries: RichHistoryQuery[];
......
import React from 'react'; import React from 'react';
import { mount } from 'enzyme'; import { mount } from 'enzyme';
import { RichHistorySettings, RichHistorySettingsProps } from './RichHistorySettings'; import { RichHistorySettings, RichHistorySettingsProps } from './RichHistorySettings';
import { Forms } from '@grafana/ui'; import { Forms, Select } from '@grafana/ui';
const setup = (propOverrides?: Partial<RichHistorySettingsProps>) => { const setup = (propOverrides?: Partial<RichHistorySettingsProps>) => {
const props: RichHistorySettingsProps = { const props: RichHistorySettingsProps = {
...@@ -23,7 +23,7 @@ const setup = (propOverrides?: Partial<RichHistorySettingsProps>) => { ...@@ -23,7 +23,7 @@ const setup = (propOverrides?: Partial<RichHistorySettingsProps>) => {
describe('RichHistorySettings', () => { describe('RichHistorySettings', () => {
it('should render component with correct retention period', () => { it('should render component with correct retention period', () => {
const wrapper = setup(); const wrapper = setup();
expect(wrapper.find(Forms.Select).text()).toEqual('2 weeks'); expect(wrapper.find(Select).text()).toEqual('2 weeks');
}); });
it('should render component with correctly checked starredTabAsFirstTab settings', () => { it('should render component with correctly checked starredTabAsFirstTab settings', () => {
const wrapper = setup(); const wrapper = setup();
......
import React from 'react'; import React from 'react';
import { css } from 'emotion'; import { css } from 'emotion';
import { stylesFactory, useTheme, Forms, Button } from '@grafana/ui'; import { stylesFactory, useTheme, Forms, Select, Button } from '@grafana/ui';
import { GrafanaTheme, AppEvents } from '@grafana/data'; import { GrafanaTheme, AppEvents } from '@grafana/data';
import appEvents from 'app/core/app_events'; import appEvents from 'app/core/app_events';
import { CoreEvents } from 'app/types'; import { CoreEvents } from 'app/types';
...@@ -79,11 +79,7 @@ export function RichHistorySettings(props: RichHistorySettingsProps) { ...@@ -79,11 +79,7 @@ export function RichHistorySettings(props: RichHistorySettingsProps) {
className="space-between" className="space-between"
> >
<div className={styles.input}> <div className={styles.input}>
<Forms.Select <Select value={selectedOption} options={retentionPeriodOptions} onChange={onChangeRetentionPeriod}></Select>
value={selectedOption}
options={retentionPeriodOptions}
onChange={onChangeRetentionPeriod}
></Forms.Select>
</div> </div>
</Forms.Field> </Forms.Field>
<Forms.Field label="Default active tab" description=" " className="space-between"> <Forms.Field label="Default active tab" description=" " className="space-between">
......
...@@ -15,7 +15,8 @@ import { sortQueries, createDatasourcesList } from '../../../core/utils/richHist ...@@ -15,7 +15,8 @@ import { sortQueries, createDatasourcesList } from '../../../core/utils/richHist
// Components // Components
import RichHistoryCard from './RichHistoryCard'; import RichHistoryCard from './RichHistoryCard';
import { sortOrderOptions } from './RichHistory'; import { sortOrderOptions } from './RichHistory';
import { Select } from '@grafana/ui'; import { LegacyForms } from '@grafana/ui';
const { Select } = LegacyForms;
export interface Props { export interface Props {
queries: RichHistoryQuery[]; queries: RichHistoryQuery[];
......
// Libraries // Libraries
import React, { PureComponent, ChangeEvent } from 'react'; import React, { PureComponent, ChangeEvent } from 'react';
import { FormLabel, Select, FormField } from '@grafana/ui'; import { FormLabel, LegacyForms, FormField } from '@grafana/ui';
const { Select } = LegacyForms;
import { SelectableValue, ReducerID, QueryEditorProps } from '@grafana/data'; import { SelectableValue, ReducerID, QueryEditorProps } from '@grafana/data';
// Types // Types
......
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { Select, DeleteButton } from '@grafana/ui'; import { LegacyForms, DeleteButton } from '@grafana/ui';
const { Select } = LegacyForms;
import { SelectableValue } from '@grafana/data'; import { SelectableValue } from '@grafana/data';
import { TeamMember, teamsPermissionLevels, TeamPermissionLevel } from 'app/types'; import { TeamMember, teamsPermissionLevels, TeamPermissionLevel } from 'app/types';
......
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { FormLabel, Select, Input, Button } from '@grafana/ui'; import { FormLabel, LegacyForms, Input, Button } from '@grafana/ui';
const { Select } = LegacyForms;
import { import {
DataSourcePluginOptionsEditorProps, DataSourcePluginOptionsEditorProps,
onUpdateDatasourceJsonDataOptionSelect, onUpdateDatasourceJsonDataOptionSelect,
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
// Types // Types
import { Select } from '@grafana/ui'; import { LegacyForms } from '@grafana/ui';
import { DataQuery, DataQueryError, PanelData, DataFrame, SelectableValue } from '@grafana/data'; import { DataQuery, DataQueryError, PanelData, DataFrame, SelectableValue } from '@grafana/data';
import { DashboardQuery } from './types'; import { DashboardQuery } from './types';
import config from 'app/core/config'; import config from 'app/core/config';
...@@ -12,6 +12,7 @@ import { PanelModel } from 'app/features/dashboard/state'; ...@@ -12,6 +12,7 @@ import { PanelModel } from 'app/features/dashboard/state';
import { SHARED_DASHBODARD_QUERY } from './types'; import { SHARED_DASHBODARD_QUERY } from './types';
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv'; import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
import { filterPanelDataToQuery } from 'app/features/dashboard/panel_editor/QueryEditorRow'; import { filterPanelDataToQuery } from 'app/features/dashboard/panel_editor/QueryEditorRow';
const { Select } = LegacyForms;
type ResultInfo = { type ResultInfo = {
img: string; // The Datasource img: string; // The Datasource
......
...@@ -3,7 +3,8 @@ import { last } from 'lodash'; ...@@ -3,7 +3,8 @@ import { last } from 'lodash';
import { mount } from 'enzyme'; import { mount } from 'enzyme';
import { ElasticDetails } from './ElasticDetails'; import { ElasticDetails } from './ElasticDetails';
import { createDefaultConfigOptions } from './mocks'; import { createDefaultConfigOptions } from './mocks';
import { Select } from '@grafana/ui'; import { LegacyForms } from '@grafana/ui';
const { Select } = LegacyForms;
describe('ElasticDetails', () => { describe('ElasticDetails', () => {
it('should render without error', () => { it('should render without error', () => {
......
import React from 'react'; import React from 'react';
import { EventsWithValidation, FormField, Input, regexValidation, Select } from '@grafana/ui'; import { EventsWithValidation, FormField, Input, regexValidation, LegacyForms } from '@grafana/ui';
const { Select } = LegacyForms;
import { ElasticsearchOptions } from '../types'; import { ElasticsearchOptions } from '../types';
import { DataSourceSettings, SelectableValue } from '@grafana/data'; import { DataSourceSettings, SelectableValue } from '@grafana/data';
......
import React, { PureComponent, ChangeEvent } from 'react'; import React, { PureComponent, ChangeEvent } from 'react';
import { SelectableValue } from '@grafana/data'; import { SelectableValue } from '@grafana/data';
import { AzureCredentialsForm } from './AzureCredentialsForm'; import { AzureCredentialsForm } from './AzureCredentialsForm';
import { Switch, FormLabel, Select, Button } from '@grafana/ui'; import { Switch, FormLabel, LegacyForms, Button } from '@grafana/ui';
const { Select } = LegacyForms;
import { AzureDataSourceSettings } from '../types'; import { AzureDataSourceSettings } from '../types';
export interface State { export interface State {
......
import React, { ChangeEvent, PureComponent } from 'react'; import React, { ChangeEvent, PureComponent } from 'react';
import { SelectableValue } from '@grafana/data'; import { SelectableValue } from '@grafana/data';
import { Input, FormLabel, Select, Button } from '@grafana/ui'; import { Input, FormLabel, LegacyForms, Button } from '@grafana/ui';
const { Select } = LegacyForms;
export interface Props { export interface Props {
selectedAzureCloud?: string; selectedAzureCloud?: string;
......
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { DataSourceHttpSettings, FormLabel, Select, Switch } from '@grafana/ui'; import { DataSourceHttpSettings, FormLabel, LegacyForms, Switch } from '@grafana/ui';
const { Select } = LegacyForms;
import { import {
DataSourcePluginOptionsEditorProps, DataSourcePluginOptionsEditorProps,
onUpdateDatasourceJsonDataOptionSelect, onUpdateDatasourceJsonDataOptionSelect,
......
...@@ -8,7 +8,8 @@ import { ...@@ -8,7 +8,8 @@ import {
onUpdateDatasourceJsonDataOptionSelect, onUpdateDatasourceJsonDataOptionSelect,
onUpdateDatasourceSecureJsonDataOption, onUpdateDatasourceSecureJsonDataOption,
} from '@grafana/data'; } from '@grafana/data';
import { DataSourceHttpSettings, FormLabel, Input, SecretFormField, Select } from '@grafana/ui'; import { DataSourceHttpSettings, FormLabel, Input, SecretFormField, LegacyForms } from '@grafana/ui';
const { Select } = LegacyForms;
import { InfluxOptions, InfluxSecureJsonData } from '../types'; import { InfluxOptions, InfluxSecureJsonData } from '../types';
const httpModes = [ const httpModes = [
......
...@@ -5,7 +5,8 @@ import React, { PureComponent } from 'react'; ...@@ -5,7 +5,8 @@ import React, { PureComponent } from 'react';
import { InputDatasource, describeDataFrame } from './InputDatasource'; import { InputDatasource, describeDataFrame } from './InputDatasource';
import { InputQuery, InputOptions } from './types'; import { InputQuery, InputOptions } from './types';
import { FormLabel, Select, TableInputCSV } from '@grafana/ui'; import { FormLabel, LegacyForms, TableInputCSV } from '@grafana/ui';
const { Select } = LegacyForms;
import { DataFrame, toCSV, SelectableValue, MutableDataFrame, QueryEditorProps } from '@grafana/data'; import { DataFrame, toCSV, SelectableValue, MutableDataFrame, QueryEditorProps } from '@grafana/data';
import { dataFrameToCSV } from './utils'; import { dataFrameToCSV } from './utils';
......
import React, { SyntheticEvent } from 'react'; import React, { SyntheticEvent } from 'react';
import { FormLabel, Select, Input } from '@grafana/ui'; import { FormLabel, LegacyForms, Input } from '@grafana/ui';
const { Select } = LegacyForms;
import { DataSourceSettings, SelectableValue } from '@grafana/data'; import { DataSourceSettings, SelectableValue } from '@grafana/data';
import { OpenTsdbOptions } from '../types'; import { OpenTsdbOptions } from '../types';
......
...@@ -2,9 +2,11 @@ import _ from 'lodash'; ...@@ -2,9 +2,11 @@ import _ from 'lodash';
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
// Types // Types
import { FormLabel, Select, Switch } from '@grafana/ui'; import { FormLabel, LegacyForms, Switch } from '@grafana/ui';
import { SelectableValue, QueryEditorProps } from '@grafana/data'; import { SelectableValue, QueryEditorProps } from '@grafana/data';
const { Select } = LegacyForms;
import { PrometheusDatasource } from '../datasource'; import { PrometheusDatasource } from '../datasource';
import { PromQuery, PromOptions } from '../types'; import { PromQuery, PromOptions } from '../types';
......
import React, { SyntheticEvent } from 'react'; import React, { SyntheticEvent } from 'react';
import { EventsWithValidation, FormField, FormLabel, Input, regexValidation, Select } from '@grafana/ui'; import { EventsWithValidation, FormField, FormLabel, Input, regexValidation, LegacyForms } from '@grafana/ui';
const { Select } = LegacyForms;
import { DataSourceSettings, SelectableValue } from '@grafana/data'; import { DataSourceSettings, SelectableValue } from '@grafana/data';
import { PromOptions } from '../types'; import { PromOptions } from '../types';
......
...@@ -6,7 +6,8 @@ import _ from 'lodash'; ...@@ -6,7 +6,8 @@ import _ from 'lodash';
import { getBackendSrv } from '@grafana/runtime'; import { getBackendSrv } from '@grafana/runtime';
// Components // Components
import { FormLabel, Select } from '@grafana/ui'; import { FormLabel, LegacyForms } from '@grafana/ui';
const { Select } = LegacyForms;
import { QueryEditorProps, SelectableValue } from '@grafana/data'; import { QueryEditorProps, SelectableValue } from '@grafana/data';
// Types // Types
......
...@@ -6,13 +6,14 @@ import { ...@@ -6,13 +6,14 @@ import {
FieldDisplayEditor, FieldDisplayEditor,
PanelOptionsGroup, PanelOptionsGroup,
FormLabel, FormLabel,
Select, LegacyForms,
Switch, Switch,
FieldPropertiesEditor, FieldPropertiesEditor,
ThresholdsEditor, ThresholdsEditor,
LegacyValueMappingsEditor, LegacyValueMappingsEditor,
DataLinksEditor, DataLinksEditor,
} from '@grafana/ui'; } from '@grafana/ui';
const { Select } = LegacyForms;
import { import {
DataLink, DataLink,
FieldConfig, FieldConfig,
......
...@@ -10,9 +10,10 @@ import { ...@@ -10,9 +10,10 @@ import {
GraphTooltipOptions, GraphTooltipOptions,
PanelOptionsGrid, PanelOptionsGrid,
PanelOptionsGroup, PanelOptionsGroup,
Select, LegacyForms,
FieldPropertiesEditor, FieldPropertiesEditor,
} from '@grafana/ui'; } from '@grafana/ui';
const { Select } = LegacyForms;
import { Options, GraphOptions } from './types'; import { Options, GraphOptions } from './types';
import { GraphLegendEditor } from './GraphLegendEditor'; import { GraphLegendEditor } from './GraphLegendEditor';
import { NewPanelEditorContext } from 'app/features/dashboard/components/PanelEditor/PanelEditor'; import { NewPanelEditorContext } from 'app/features/dashboard/components/PanelEditor/PanelEditor';
......
// Libraries // Libraries
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { Switch, PanelOptionsGrid, PanelOptionsGroup, FormLabel, Select } from '@grafana/ui'; import { Switch, PanelOptionsGrid, PanelOptionsGroup, FormLabel, LegacyForms } from '@grafana/ui';
const { Select } = LegacyForms;
// Types // Types
import { Options } from './types'; import { Options } from './types';
......
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
// Components // Components
import { Select, FormLabel, PanelOptionsGroup } from '@grafana/ui'; import { LegacyForms, FormLabel, PanelOptionsGroup } from '@grafana/ui';
const { Select } = LegacyForms;
// Types // Types
import { PanelEditorProps } from '@grafana/data'; import { PanelEditorProps } from '@grafana/data';
......
...@@ -6,13 +6,15 @@ import { ...@@ -6,13 +6,15 @@ import {
FieldDisplayEditor, FieldDisplayEditor,
PanelOptionsGroup, PanelOptionsGroup,
FormLabel, FormLabel,
Select, LegacyForms,
FieldPropertiesEditor, FieldPropertiesEditor,
ThresholdsEditor, ThresholdsEditor,
LegacyValueMappingsEditor, LegacyValueMappingsEditor,
DataLinksEditor, DataLinksEditor,
} from '@grafana/ui'; } from '@grafana/ui';
const { Select } = LegacyForms;
import { import {
PanelEditorProps, PanelEditorProps,
ReduceDataOptions, ReduceDataOptions,
......
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
import React, { PureComponent, ChangeEvent } from 'react'; import React, { PureComponent, ChangeEvent } from 'react';
// Components // Components
import { PanelOptionsGroup, Select } from '@grafana/ui'; import { PanelOptionsGroup, LegacyForms } from '@grafana/ui';
const { Select } = LegacyForms;
import { PanelEditorProps, SelectableValue } from '@grafana/data'; import { PanelEditorProps, SelectableValue } from '@grafana/data';
// Types // Types
......
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