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';
import { Icon } from '../Icon/Icon';
import RCCascader from 'rc-cascader';
import { Select } from '../Forms/Select/Select';
import { Select } from '../Select/Select';
import { FormInputSize } from '../Forms/types';
import { Input } from '../Forms/Input/Input';
import { SelectableValue } from '@grafana/data';
......
......@@ -8,7 +8,7 @@ import { TLSAuthSettings } from './TLSAuthSettings';
import { DataSourceSettings } from '@grafana/data';
import { HttpSettingsProps } from './types';
import { CustomHeadersSettings } from './CustomHeadersSettings';
import { Select } from '../Select/Select';
import { Select } from '../Forms/Legacy/Select/Select';
import { Input } from '../Input/Input';
import { FormField } from '../FormField/FormField';
import { FormLabel } from '../FormLabel/FormLabel';
......
......@@ -11,7 +11,7 @@ import { Switch } from './Switch';
import { Checkbox } from './Checkbox';
import { RadioButtonGroup } from './RadioButtonGroup/RadioButtonGroup';
import { Select } from './Select/Select';
import { Select } from '../Select/Select';
import Forms from './index';
import mdx from './Form.mdx';
import { ValidateResult } from 'react-hook-form';
......
......@@ -2,8 +2,8 @@ import React from 'react';
import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';
import { withKnobs, object, text } from '@storybook/addon-knobs';
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
import { UseState } from '../../utils/storybook/UseState';
import { withCenteredStory } from '../../../../utils/storybook/withCenteredStory';
import { UseState } from '../../../../utils/storybook/UseState';
import { SelectableValue } from '@grafana/data';
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';
import { getFormStyles } from './getFormStyles';
import { Label } from './Label';
import { Input } from './Input/Input';
import { ButtonSelect } from './Select/ButtonSelect';
import { RadioButtonGroup } from './RadioButtonGroup/RadioButtonGroup';
import { AsyncSelect, Select } from './Select/Select';
import { Form } from './Form';
import { Field } from './Field';
import { Switch } from './Switch';
import { Legend } from './Legend';
import { TextArea } from './TextArea/TextArea';
import { Checkbox } from './Checkbox';
//Remove after Enterprise migrations have been merged
import { Select } from '../Select/Select';
const Forms = {
RadioButtonGroup,
......@@ -20,13 +20,11 @@ const Forms = {
Input,
Form,
Field,
Select,
ButtonSelect,
InputControl,
AsyncSelect,
TextArea,
Checkbox,
Legend,
Select,
};
export default Forms;
import React from 'react';
import { MatcherUIProps, FieldMatcherUIRegistryItem } from './types';
import { FieldMatcherID, fieldMatchers } from '@grafana/data';
import Forms from '../Forms';
import { Select } from '../Select/Select';
export class FieldNameMatcherEditor extends React.PureComponent<MatcherUIProps<string>> {
render() {
......@@ -23,12 +23,7 @@ export class FieldNameMatcherEditor extends React.PureComponent<MatcherUIProps<s
const selectedOption = selectOptions.find(v => v.value === options);
return (
<Forms.Select
allowCustomValue
value={selectedOption}
options={selectOptions}
onChange={o => onChange(o.value!)}
/>
<Select allowCustomValue value={selectedOption} options={selectOptions} onChange={o => onChange(o.value!)} />
);
}
}
......
import React from 'react';
import { FieldConfigEditorProps, SelectFieldConfigSettings } from '@grafana/data';
import Forms from '../Forms';
import { Select } from '../Select/Select';
export function SelectValueEditor<T>({
value,
onChange,
item,
}: 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';
import { SelectableValue } from '@grafana/data';
import { css } from 'emotion';
import { Tooltip } from '../Tooltip/Tooltip';
import { ButtonSelect } from '../Select/ButtonSelect';
import { ButtonSelect } from '../Forms/Legacy/Select/ButtonSelect';
import memoizeOne from 'memoize-one';
import { GrafanaTheme } from '@grafana/data';
import { withTheme } from '../../themes';
......
......@@ -2,7 +2,7 @@ import React, { useRef } from 'react';
import { css, cx } from 'emotion';
import useClickAway from 'react-use/lib/useClickAway';
import { SelectableValue } from '@grafana/data';
import { Select } from '../Select/Select';
import { Select } from '../Forms/Legacy/Select/Select';
export interface Props<T> {
value?: SelectableValue<T>;
......
import React, { PureComponent, ReactElement } from 'react';
import Select from './Select';
import { PopoverContent } from '../Tooltip/Tooltip';
import { SelectableValue } from '@grafana/data';
import React from 'react';
import { css } from 'emotion';
import { GrafanaTheme } 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;
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';
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;
interface ButtonSelectProps<T> extends Omit<SelectCommonProps<T>, 'renderControl' | 'size' | 'prefix'> {
icon?: IconType;
variant?: ButtonVariant;
size?: ComponentSize;
}
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 }),
};
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 (
<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}
/>
<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 { Icon } from '../../Icon/Icon';
import { Icon } from '../Icon/Icon';
interface DropdownIndicatorProps {
isOpen: boolean;
......
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
// @ts-ignore
import { components } from '@torkelo/react-select';
export const IndicatorsContainer = React.forwardRef<HTMLDivElement, React.PropsWithChildren<any>>((props, ref) => {
const { children } = props;
const theme = useTheme();
const styles = getInputStyles({ theme, invalid: false });
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>
<div
className={cx(
styles.suffix,
css`
position: relative;
`
)}
ref={ref}
>
{children}
</div>
);
};
export default IndicatorsContainer;
});
import React from 'react';
import { useTheme } from '../../../themes/ThemeContext';
import { getFocusCss, sharedInputStyle } from '../commonStyles';
import { getInputStyles } from '../Input/Input';
import { useTheme } from '../../themes/ThemeContext';
import { getFocusCss, sharedInputStyle } from '../Forms/commonStyles';
import { getInputStyles } from '../Forms/Input/Input';
import { cx, css } from 'emotion';
import { stylesFactory } from '../../../themes';
import { stylesFactory } from '../../themes';
import { GrafanaTheme } from '@grafana/data';
interface InputControlProps {
......
import React from 'react';
import { useTheme } from '../../../themes';
import { useTheme } from '../../themes';
import { getSelectStyles } from './getSelectStyles';
import { Icon } from '../../Icon/Icon';
import { Icon } from '../Icon/Icon';
interface MultiValueContainerProps {
innerProps: any;
......
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 React, { useState } from 'react';
import { Select, AsyncSelect, MultiSelect, AsyncMultiSelect } from './Select';
import { withCenteredStory, withHorizontallyCenteredStory } from '../../utils/storybook/withCenteredStory';
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 {
title: 'General/Select/Select',
title: 'Forms/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:', [
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 ' },
]);
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 = object<SelectableValue<string>>('Selected Value:', intialState);
const [value, setValue] = useState<SelectableValue<string>>();
return (
<UseState initialState={value}>
{(value, updateValue) => {
return (
<Select
placeholder="Choose..."
options={options}
width={20}
onChange={value => {
action('onChanged fired')(value);
updateValue(value);
}}
/>
);
}}
</UseState>
<>
<Select
options={generateOptions()}
value={value}
onChange={v => {
setValue(v);
}}
size="md"
{...getDynamicProps()}
/>
</>
);
};
export const withAllowCustomValue = () => {
// @ts-ignore
const value = object<SelectableValue<string>>('Selected Value:', null);
/**
* Uses plain values instead of SelectableValue<T>
*/
export const basicSelectPlainValue = () => {
const [value, setValue] = useState<string>();
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>
<>
<Select
options={generateOptions()}
value={value}
onChange={v => {
setValue(v.value);
}}
size="md"
{...getDynamicProps()}
/>
</>
);
};
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);
});
/**
* 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',
},
[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 (
<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
width={20}
isLoading={isLoading}
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}
onChange={value => {
action('onChange')(value);
setValue(value);
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()}
/>
</>
);
};
......@@ -9,9 +9,9 @@ import { default as ReactAsyncSelect } from '@torkelo/react-select/async';
// @ts-ignore
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 { inputSizesPixels } from '../commonStyles';
import { inputSizesPixels } from '../Forms/commonStyles';
import resetSelectStyles from './resetSelectStyles';
import { SelectMenu, SelectMenuOptions } from './SelectMenu';
import { IndicatorsContainer } from './IndicatorsContainer';
......@@ -21,7 +21,7 @@ import { DropdownIndicator } from './DropdownIndicator';
import { SelectOptionGroup } from './SelectOptionGroup';
import { SingleValue } from './SingleValue';
import { MultiValueContainer, MultiValueRemove } from './MultiValue';
import { useTheme } from '../../../themes';
import { useTheme } from '../../themes';
import { getSelectStyles } from './getSelectStyles';
import { cleanValue } from './utils';
import { SelectBaseProps, SelectValue } from './types';
......
import React from 'react';
import { useTheme } from '../../../themes/ThemeContext';
import { useTheme } from '../../themes/ThemeContext';
import { getSelectStyles } from './getSelectStyles';
import { cx } from 'emotion';
import { SelectableValue } from '@grafana/data';
import { Icon } from '../../Icon/Icon';
import { CustomScrollbar } from '../../CustomScrollbar/CustomScrollbar';
import { Icon } from '../Icon/Icon';
import { CustomScrollbar } from '../CustomScrollbar/CustomScrollbar';
interface SelectMenuProps {
maxHeight: number;
......
......@@ -2,8 +2,8 @@ import React, { PureComponent } from 'react';
import { css, cx } from 'emotion';
import { GrafanaTheme } from '@grafana/data';
import { GroupProps } from 'react-select';
import { stylesFactory, withTheme, selectThemeVariant } from '../../../themes';
import { Themeable } from '../../../types';
import { stylesFactory, withTheme, selectThemeVariant } from '../../themes';
import { Themeable } from '../../types';
interface ExtendedGroupProps extends GroupProps<any>, Themeable {
data: {
......
......@@ -4,11 +4,11 @@ import { css, cx } from 'emotion';
// Ignoring because I couldn't get @types/react-select work wih Torkel's fork
// @ts-ignore
import { components } from '@torkelo/react-select';
import { useDelayedSwitch } from '../../../utils/useDelayedSwitch';
import { stylesFactory, useTheme } from '../../../themes';
import { SlideOutTransition } from '../../transitions/SlideOutTransition';
import { FadeTransition } from '../../transitions/FadeTransition';
import { Spinner } from '../../Spinner/Spinner';
import { useDelayedSwitch } from '../../utils/useDelayedSwitch';
import { stylesFactory, useTheme } from '../../themes';
import { SlideOutTransition } from '../transitions/SlideOutTransition';
import { FadeTransition } from '../transitions/FadeTransition';
import { Spinner } from '../Spinner/Spinner';
import { GrafanaTheme } from '@grafana/data';
const getStyles = stylesFactory((theme: GrafanaTheme) => {
......
import React from 'react';
import { cx } from 'emotion';
import { useTheme } from '../../../themes/ThemeContext';
import { useTheme } from '../../themes/ThemeContext';
import { getSelectStyles } from './getSelectStyles';
export const ValueContainer = (props: any) => {
......
import { stylesFactory } from '../../../themes/stylesFactory';
import { selectThemeVariant as stv } from '../../../themes/selectThemeVariant';
import { stylesFactory } from '../../themes/stylesFactory';
import { selectThemeVariant as stv } from '../../themes/selectThemeVariant';
import { css } from 'emotion';
import { GrafanaTheme } from '@grafana/data';
......
import { SelectableValue } from '@grafana/data';
import React from 'react';
import { FormInputSize } from '../types';
import { FormInputSize } from '../Forms/types';
export type SelectValue<T> = T | SelectableValue<T> | T[] | Array<SelectableValue<T>>;
......@@ -18,6 +18,8 @@ export interface SelectCommonProps<T> {
onKeyDown?: (event: React.KeyboardEvent) => void;
placeholder?: string;
disabled?: boolean;
//To be removed, is here to make Enterprise mergable
isDisabled?: boolean;
isSearchable?: boolean;
isClearable?: boolean;
autoFocus?: boolean;
......
......@@ -42,7 +42,7 @@ const options: SelectableValue[] = [
{ label: 'Option 6', value: 6 },
];
describe('Forms.Select utils', () => {
describe('Select utils', () => {
describe('findSelected value', () => {
it('should find value of type number in array of optgroups', () => {
expect(findSelectedValue(11, optGroup)).toEqual({ label: 'Group 2 - Option 1', value: 11 });
......
......@@ -7,7 +7,7 @@ import { FormField } from '../FormField/FormField';
import { StatsPicker } from '../StatsPicker/StatsPicker';
// Types
import Select from '../Select/Select';
import Select from '../Forms/Legacy/Select/Select';
import {
ReduceDataOptions,
DEFAULT_FIELD_DISPLAY_VALUES_LIMIT,
......
......@@ -3,7 +3,7 @@ import React, { PureComponent } from 'react';
import isArray from 'lodash/isArray';
import difference from 'lodash/difference';
import { Select } from '../Forms/Select/Select';
import { Select } from '../Select/Select';
import { fieldReducers, SelectableValue } 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 React from 'react';
import { TransformationRow } from './TransformationRow';
......
import React, { PureComponent } from 'react';
import { Select } from '../Select/Select';
import { Select } from '../Forms/Legacy/Select/Select';
import { Cascader, CascaderOption } from '../Cascader/Cascader';
import { getValueFormats, SelectableValue } from '@grafana/data';
......
......@@ -3,7 +3,7 @@ import React, { ChangeEvent, PureComponent } from 'react';
import { FormField } from '../FormField/FormField';
import { FormLabel } from '../FormLabel/FormLabel';
import { Input } from '../Input/Input';
import { Select } from '../Select/Select';
import { Select } from '../Forms/Legacy/Select/Select';
import { MappingType, ValueMapping } from '@grafana/data';
......
import React, { ChangeEvent } from 'react';
import { HorizontalGroup } from '../Layout/Layout';
import { Select } from '../index';
import Forms from '../Forms';
import { MappingType, RangeMap, ValueMap, ValueMapping } from '@grafana/data';
import * as styleMixins from '../../themes/mixins';
......@@ -80,7 +81,7 @@ export const MappingRow: React.FC<Props> = ({ valueMapping, updateValueMapping,
<div className={styles.wrapper}>
<FieldConfigItemHeaderTitle title="Mapping type" onRemove={removeValueMapping}>
<div className={styles.itemContent}>
<Forms.Select
<Select
placeholder="Choose type"
isSearchable={false}
options={MAPPING_OPTIONS}
......
......@@ -2,7 +2,7 @@ import { text } from '@storybook/addon-knobs';
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
import { ValuePicker } from './ValuePicker';
import React from 'react';
import { generateOptions } from '../Forms/Select/mockOptions';
import { generateOptions } from '../Select/mockOptions';
export default {
title: 'General/ValuePicker',
......
......@@ -2,7 +2,7 @@ import React, { useState } from 'react';
import { IconType } from '../Icon/types';
import { SelectableValue } from '@grafana/data';
import { Button, ButtonVariant } from '../Button';
import { Select } from '../Forms/Select/Select';
import { Select } from '../Select/Select';
import { FullWidthButtonContainer } from '../Button/FullWidthButtonContainer';
interface ValuePickerProps<T> {
......
......@@ -8,7 +8,7 @@
@import 'PanelOptionsGrid/PanelOptionsGrid';
@import 'PanelOptionsGroup/PanelOptionsGroup';
@import 'RefreshPicker/RefreshPicker';
@import 'Select/Select';
@import 'Forms/Legacy/Select/Select';
@import 'TableInputCSV/TableInputCSV';
@import 'ThresholdsEditor/ThresholdsEditor';
@import 'TimePicker/TimeOfDayPicker';
......
......@@ -7,15 +7,8 @@ export { Portal } from './Portal/Portal';
export { CustomScrollbar } from './CustomScrollbar/CustomScrollbar';
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 { ButtonCascader } from './ButtonCascader/ButtonCascader';
// Forms
export { FormLabel } from './FormLabel/FormLabel';
......@@ -140,5 +133,27 @@ export * from './Button';
export { ValuePicker } from './ValuePicker/ValuePicker';
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 { 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 {
ValueMappingFieldConfigSettings,
valueMappingsOverrideProcessor,
} from '@grafana/data';
import { NumberValueEditor, Forms, StringValueEditor } from '../components';
import { NumberValueEditor, Forms, StringValueEditor, Select } from '../components';
import { ValueMappingsValueEditor } from '../components/OptionsUI/mappings';
import { ThresholdsValueEditor } from '../components/OptionsUI/thresholds';
import { UnitValueEditor } from '../components/OptionsUI/units';
......@@ -216,11 +216,7 @@ export const getStandardOptionEditors = () => {
name: 'Select',
description: 'Allows option selection',
editor: props => (
<Forms.Select
value={props.value}
onChange={e => props.onChange(e.value)}
options={props.item.settings?.options}
/>
<Select value={props.value} onChange={e => props.onChange(e.value)} options={props.item.settings?.options} />
),
};
......
import React, { Component } from 'react';
import { UserPicker } from 'app/core/components/Select/UserPicker';
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 { User } from 'app/types';
import {
......@@ -12,6 +12,7 @@ import {
NewDashboardAclItem,
OrgRole,
} from 'app/types/acl';
const { Select } = LegacyForms;
export interface Props {
onAddPermission: (item: NewDashboardAclItem) => void;
......
import React, { Component } from 'react';
import { Select } from '@grafana/ui';
import { LegacyForms } from '@grafana/ui';
import { dashboardPermissionLevels } from 'app/types/acl';
const { Select } = LegacyForms;
export interface Props {
item: any;
......
import React, { PureComponent } from 'react';
import { Select } from '@grafana/ui';
import { LegacyForms } from '@grafana/ui';
import { SelectableValue } from '@grafana/data';
import { dashboardPermissionLevels, DashboardAcl, PermissionLevel } from 'app/types/acl';
import { FolderInfo } from 'app/types';
const { Select } = LegacyForms;
const setClassNameHelper = (inherited: boolean) => {
return inherited ? 'gf-form-disabled' : '';
......
......@@ -2,7 +2,7 @@ import React, { FC } from 'react';
import { debounce } from 'lodash';
import { useAsyncFn } from 'react-use';
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 { backendSrv } from 'app/core/services/backend_srv';
import { DashboardSearchHit, DashboardDTO } from 'app/types';
......@@ -42,7 +42,7 @@ export const DashboardPicker: FC<Props> = ({
const [state, searchDashboards] = useAsyncFn(debouncedSearch, []);
return (
<Forms.AsyncSelect
<AsyncSelect
size={size}
isLoading={state.loading}
isClearable={isClearable}
......
......@@ -2,8 +2,9 @@
import React, { PureComponent } from 'react';
// Components
import { Select } from '@grafana/ui';
import { LegacyForms } from '@grafana/ui';
import { SelectableValue, DataSourceSelectItem } from '@grafana/data';
const { Select } = LegacyForms;
export interface Props {
onChange: (ds: DataSourceSelectItem) => void;
......
import React, { PureComponent } from 'react';
import { Forms } from '@grafana/ui';
import { AsyncSelect } from '@grafana/ui';
import { AppEvents, SelectableValue } from '@grafana/data';
import { debounce } from 'lodash';
import appEvents from '../../app_events';
......@@ -150,7 +150,7 @@ export class FolderPicker extends PureComponent<Props, State> {
return (
<>
{useNewForms && (
<Forms.AsyncSelect
<AsyncSelect
loadingMessage="Loading folders..."
defaultOptions
defaultValue={folder}
......@@ -167,7 +167,7 @@ export class FolderPicker extends PureComponent<Props, State> {
<div className="gf-form-inline">
<div className="gf-form">
<label className="gf-form-label width-7">Folder</label>
<Forms.AsyncSelect
<AsyncSelect
loadingMessage="Loading folders..."
defaultOptions
defaultValue={folder}
......
import React from 'react';
import _ from 'lodash';
import { Select } from '@grafana/ui';
import { LegacyForms } from '@grafana/ui';
import { SelectableValue } from '@grafana/data';
import { Variable } from 'app/types/templates';
const { Select } = LegacyForms;
export interface Props {
onChange: (value: string) => void;
......
import React, { PureComponent } from 'react';
import { Forms } from '@grafana/ui';
import { AsyncSelect } from '@grafana/ui';
import { getBackendSrv } from 'app/core/services/backend_srv';
import { Organization } from 'app/types';
import { SelectableValue } from '@grafana/data';
......@@ -54,7 +54,7 @@ export class OrgPicker extends PureComponent<Props, State> {
const { isLoading } = this.state;
return (
<Forms.AsyncSelect
<AsyncSelect
className={className}
isLoading={isLoading}
defaultOptions={true}
......
import React, { Component } from 'react';
import _ from 'lodash';
import { AsyncSelect } from '@grafana/ui';
import { LegacyForms } from '@grafana/ui';
import { debounce } from 'lodash';
import { getBackendSrv } from '@grafana/runtime';
const { AsyncSelect } = LegacyForms;
export interface Team {
id: number;
......
......@@ -3,7 +3,8 @@ import React, { Component } from 'react';
import _ from 'lodash';
// Components
import { AsyncSelect } from '@grafana/ui';
import { LegacyForms } from '@grafana/ui';
const { AsyncSelect } = LegacyForms;
// Utils & Services
import { debounce } from 'lodash';
......
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 { backendSrv } from 'app/core/services/backend_srv';
......
......@@ -8,7 +8,8 @@ import { escapeStringForRegex } from '@grafana/data';
// Components
import { TagOption } from './TagOption';
import { TagBadge } from './TagBadge';
import { IndicatorsContainer, NoOptionsMessage, resetSelectStyles } from '@grafana/ui';
import { resetSelectStyles, LegacyForms } from '@grafana/ui';
const { IndicatorsContainer, NoOptionsMessage } = LegacyForms;
export interface TermCount {
term: string;
......
......@@ -6,7 +6,17 @@ import { css } from 'emotion';
import { InspectHeader } from './InspectHeader';
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 {
DataFrame,
......
import React, { FC, useMemo } from 'react';
import { PanelModel } from '../../state';
import { SelectableValue } from '@grafana/data';
import { DataLinksInlineEditor, Forms } from '@grafana/ui';
import { Forms, Select, DataLinksInlineEditor } from '@grafana/ui';
import { OptionsGroup } from './OptionsGroup';
import { getPanelLinksVariableSuggestions } from '../../../panel/panellinks/link_srv';
import { getVariables } from '../../../variables/state/selectors';
......@@ -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
reload the dashboard."
>
<Forms.Select
<Select
value={panel.repeat}
onChange={value => onPanelConfigChange('repeat', value.value)}
options={variableOptions}
......@@ -72,7 +72,7 @@ export const GeneralPanelOptions: FC<{
{panel.repeat && panel.repeatDirection === 'h' && (
<Forms.Field label="Max per row">
<Forms.Select
<Select
options={maxPerRowOptions}
value={panel.maxPerRow}
onChange={value => onPanelConfigChange('maxPerRow', value.value)}
......
import React, { PureComponent } from 'react';
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 config from 'app/core/config';
import AutoSizer from 'react-virtualized-auto-sizer';
......@@ -205,7 +205,7 @@ export class PanelEditorUnconnected extends PureComponent<Props> {
</DashNavButton>
</div>
<div className={styles.toolbarItem}>
<Forms.Select
<Select
value={displayModes.find(v => v.value === uiState.mode)}
options={displayModes}
onChange={this.onDiplayModeChange}
......
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 { DashboardModel, PanelModel } from 'app/features/dashboard/state';
import { buildIframeHtml } from './utils';
......
import React, { PureComponent } from 'react';
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 { DashboardModel } from 'app/features/dashboard/state';
import { buildImageUrl, buildShareUrl } from './utils';
......
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 { getBackendSrv } from '@grafana/runtime';
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
......
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 { GrafanaTheme, SelectableValue } from '@grafana/data';
......
......@@ -7,7 +7,8 @@ import classNames from 'classnames';
import { css } from 'emotion';
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 { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker';
import { StoreState } from 'app/types/store';
......
......@@ -21,7 +21,8 @@ import {
// Components
import RichHistoryCard from './RichHistoryCard';
import { sortOrderOptions } from './RichHistory';
import { Select, Slider } from '@grafana/ui';
import { LegacyForms, Slider } from '@grafana/ui';
const { Select } = LegacyForms;
export interface Props {
queries: RichHistoryQuery[];
......
import React from 'react';
import { mount } from 'enzyme';
import { RichHistorySettings, RichHistorySettingsProps } from './RichHistorySettings';
import { Forms } from '@grafana/ui';
import { Forms, Select } from '@grafana/ui';
const setup = (propOverrides?: Partial<RichHistorySettingsProps>) => {
const props: RichHistorySettingsProps = {
......@@ -23,7 +23,7 @@ const setup = (propOverrides?: Partial<RichHistorySettingsProps>) => {
describe('RichHistorySettings', () => {
it('should render component with correct retention period', () => {
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', () => {
const wrapper = setup();
......
import React from 'react';
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 appEvents from 'app/core/app_events';
import { CoreEvents } from 'app/types';
......@@ -79,11 +79,7 @@ export function RichHistorySettings(props: RichHistorySettingsProps) {
className="space-between"
>
<div className={styles.input}>
<Forms.Select
value={selectedOption}
options={retentionPeriodOptions}
onChange={onChangeRetentionPeriod}
></Forms.Select>
<Select value={selectedOption} options={retentionPeriodOptions} onChange={onChangeRetentionPeriod}></Select>
</div>
</Forms.Field>
<Forms.Field label="Default active tab" description=" " className="space-between">
......
......@@ -15,7 +15,8 @@ import { sortQueries, createDatasourcesList } from '../../../core/utils/richHist
// Components
import RichHistoryCard from './RichHistoryCard';
import { sortOrderOptions } from './RichHistory';
import { Select } from '@grafana/ui';
import { LegacyForms } from '@grafana/ui';
const { Select } = LegacyForms;
export interface Props {
queries: RichHistoryQuery[];
......
// Libraries
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';
// Types
......
import React, { PureComponent } from 'react';
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 { TeamMember, teamsPermissionLevels, TeamPermissionLevel } from 'app/types';
......
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 {
DataSourcePluginOptionsEditorProps,
onUpdateDatasourceJsonDataOptionSelect,
......
......@@ -2,7 +2,7 @@
import React, { PureComponent } from 'react';
// Types
import { Select } from '@grafana/ui';
import { LegacyForms } from '@grafana/ui';
import { DataQuery, DataQueryError, PanelData, DataFrame, SelectableValue } from '@grafana/data';
import { DashboardQuery } from './types';
import config from 'app/core/config';
......@@ -12,6 +12,7 @@ import { PanelModel } from 'app/features/dashboard/state';
import { SHARED_DASHBODARD_QUERY } from './types';
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
import { filterPanelDataToQuery } from 'app/features/dashboard/panel_editor/QueryEditorRow';
const { Select } = LegacyForms;
type ResultInfo = {
img: string; // The Datasource
......
......@@ -3,7 +3,8 @@ import { last } from 'lodash';
import { mount } from 'enzyme';
import { ElasticDetails } from './ElasticDetails';
import { createDefaultConfigOptions } from './mocks';
import { Select } from '@grafana/ui';
import { LegacyForms } from '@grafana/ui';
const { Select } = LegacyForms;
describe('ElasticDetails', () => {
it('should render without error', () => {
......
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 { DataSourceSettings, SelectableValue } from '@grafana/data';
......
import React, { PureComponent, ChangeEvent } from 'react';
import { SelectableValue } from '@grafana/data';
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';
export interface State {
......
import React, { ChangeEvent, PureComponent } from 'react';
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 {
selectedAzureCloud?: string;
......
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 {
DataSourcePluginOptionsEditorProps,
onUpdateDatasourceJsonDataOptionSelect,
......
......@@ -8,7 +8,8 @@ import {
onUpdateDatasourceJsonDataOptionSelect,
onUpdateDatasourceSecureJsonDataOption,
} 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';
const httpModes = [
......
......@@ -5,7 +5,8 @@ import React, { PureComponent } from 'react';
import { InputDatasource, describeDataFrame } from './InputDatasource';
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 { dataFrameToCSV } from './utils';
......
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 { OpenTsdbOptions } from '../types';
......
......@@ -2,9 +2,11 @@ import _ from 'lodash';
import React, { PureComponent } from 'react';
// Types
import { FormLabel, Select, Switch } from '@grafana/ui';
import { FormLabel, LegacyForms, Switch } from '@grafana/ui';
import { SelectableValue, QueryEditorProps } from '@grafana/data';
const { Select } = LegacyForms;
import { PrometheusDatasource } from '../datasource';
import { PromQuery, PromOptions } from '../types';
......
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 { PromOptions } from '../types';
......
......@@ -6,7 +6,8 @@ import _ from 'lodash';
import { getBackendSrv } from '@grafana/runtime';
// Components
import { FormLabel, Select } from '@grafana/ui';
import { FormLabel, LegacyForms } from '@grafana/ui';
const { Select } = LegacyForms;
import { QueryEditorProps, SelectableValue } from '@grafana/data';
// Types
......
......@@ -6,13 +6,14 @@ import {
FieldDisplayEditor,
PanelOptionsGroup,
FormLabel,
Select,
LegacyForms,
Switch,
FieldPropertiesEditor,
ThresholdsEditor,
LegacyValueMappingsEditor,
DataLinksEditor,
} from '@grafana/ui';
const { Select } = LegacyForms;
import {
DataLink,
FieldConfig,
......
......@@ -10,9 +10,10 @@ import {
GraphTooltipOptions,
PanelOptionsGrid,
PanelOptionsGroup,
Select,
LegacyForms,
FieldPropertiesEditor,
} from '@grafana/ui';
const { Select } = LegacyForms;
import { Options, GraphOptions } from './types';
import { GraphLegendEditor } from './GraphLegendEditor';
import { NewPanelEditorContext } from 'app/features/dashboard/components/PanelEditor/PanelEditor';
......
// Libraries
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
import { Options } from './types';
......
......@@ -2,7 +2,8 @@
import React, { PureComponent } from 'react';
// Components
import { Select, FormLabel, PanelOptionsGroup } from '@grafana/ui';
import { LegacyForms, FormLabel, PanelOptionsGroup } from '@grafana/ui';
const { Select } = LegacyForms;
// Types
import { PanelEditorProps } from '@grafana/data';
......
......@@ -6,13 +6,15 @@ import {
FieldDisplayEditor,
PanelOptionsGroup,
FormLabel,
Select,
LegacyForms,
FieldPropertiesEditor,
ThresholdsEditor,
LegacyValueMappingsEditor,
DataLinksEditor,
} from '@grafana/ui';
const { Select } = LegacyForms;
import {
PanelEditorProps,
ReduceDataOptions,
......
......@@ -2,7 +2,8 @@
import React, { PureComponent, ChangeEvent } from 'react';
// Components
import { PanelOptionsGroup, Select } from '@grafana/ui';
import { PanelOptionsGroup, LegacyForms } from '@grafana/ui';
const { Select } = LegacyForms;
import { PanelEditorProps, SelectableValue } from '@grafana/data';
// 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