Commit cf1cd4d6 by Torkel Ödegaard Committed by GitHub

Merge pull request #14500 from grafana/select-refactor

Select refactor
parents b9a05a85 6e2f6701
...@@ -28,8 +28,8 @@ class CustomScrollbar extends PureComponent<Props> { ...@@ -28,8 +28,8 @@ class CustomScrollbar extends PureComponent<Props> {
<Scrollbars <Scrollbars
className={customClassName} className={customClassName}
autoHeight={true} autoHeight={true}
autoHeightMin={'100%'} autoHeightMin={'inherit'}
autoHeightMax={'100%'} autoHeightMax={'inherit'}
renderTrackHorizontal={props => <div {...props} className="track-horizontal" />} renderTrackHorizontal={props => <div {...props} className="track-horizontal" />}
renderTrackVertical={props => <div {...props} className="track-vertical" />} renderTrackVertical={props => <div {...props} className="track-vertical" />}
renderThumbHorizontal={props => <div {...props} className="thumb-horizontal" />} renderThumbHorizontal={props => <div {...props} className="thumb-horizontal" />}
......
...@@ -6,8 +6,8 @@ exports[`CustomScrollbar renders correctly 1`] = ` ...@@ -6,8 +6,8 @@ exports[`CustomScrollbar renders correctly 1`] = `
style={ style={
Object { Object {
"height": "auto", "height": "auto",
"maxHeight": "100%", "maxHeight": "inherit",
"minHeight": "100%", "minHeight": "inherit",
"overflow": "hidden", "overflow": "hidden",
"position": "relative", "position": "relative",
"width": "100%", "width": "100%",
...@@ -23,8 +23,8 @@ exports[`CustomScrollbar renders correctly 1`] = ` ...@@ -23,8 +23,8 @@ exports[`CustomScrollbar renders correctly 1`] = `
"left": undefined, "left": undefined,
"marginBottom": 0, "marginBottom": 0,
"marginRight": 0, "marginRight": 0,
"maxHeight": "calc(100% + 0px)", "maxHeight": "calc(inherit + 0px)",
"minHeight": "calc(100% + 0px)", "minHeight": "calc(inherit + 0px)",
"overflow": "scroll", "overflow": "scroll",
"position": "relative", "position": "relative",
"right": undefined, "right": undefined,
......
import React, { Component } from 'react'; import React, { Component } from 'react';
import { UserPicker } from 'app/core/components/Picker/UserPicker'; import { UserPicker } from 'app/core/components/Select/UserPicker';
import { TeamPicker, Team } from 'app/core/components/Picker/TeamPicker'; import { TeamPicker, Team } from 'app/core/components/Select/TeamPicker';
import DescriptionPicker, { OptionWithDescription } from 'app/core/components/Picker/DescriptionPicker'; import { Select, SelectOptionItem } from 'app/core/components/Select/Select';
import { User } from 'app/types'; import { User } from 'app/types';
import { import {
dashboardPermissionLevels, dashboardPermissionLevels,
...@@ -61,7 +61,7 @@ class AddPermissions extends Component<Props, NewDashboardAclItem> { ...@@ -61,7 +61,7 @@ class AddPermissions extends Component<Props, NewDashboardAclItem> {
this.setState({ teamId: team && !Array.isArray(team) ? team.id : 0 }); this.setState({ teamId: team && !Array.isArray(team) ? team.id : 0 });
}; };
onPermissionChanged = (permission: OptionWithDescription) => { onPermissionChanged = (permission: SelectOptionItem) => {
this.setState({ permission: permission.value }); this.setState({ permission: permission.value });
}; };
...@@ -121,11 +121,11 @@ class AddPermissions extends Component<Props, NewDashboardAclItem> { ...@@ -121,11 +121,11 @@ class AddPermissions extends Component<Props, NewDashboardAclItem> {
) : null} ) : null}
<div className="gf-form"> <div className="gf-form">
<DescriptionPicker <Select
optionsWithDesc={dashboardPermissionLevels} isSearchable={false}
onSelected={this.onPermissionChanged} options={dashboardPermissionLevels}
disabled={false} onChange={this.onPermissionChanged}
className={'gf-form-select-box__control--menu-right'} className="gf-form-select-box__control--menu-right"
/> />
</div> </div>
......
import React, { Component } from 'react'; import React, { Component } from 'react';
import DescriptionPicker from 'app/core/components/Picker/DescriptionPicker'; import Select from 'app/core/components/Select/Select';
import { dashboardPermissionLevels } from 'app/types/acl'; import { dashboardPermissionLevels } from 'app/types/acl';
export interface Props { export interface Props {
...@@ -9,6 +9,7 @@ export interface Props { ...@@ -9,6 +9,7 @@ export interface Props {
export default class DisabledPermissionListItem extends Component<Props, any> { export default class DisabledPermissionListItem extends Component<Props, any> {
render() { render() {
const { item } = this.props; const { item } = this.props;
const currentPermissionLevel = dashboardPermissionLevels.find(dp => dp.value === item.permission);
return ( return (
<tr className="gf-form-disabled"> <tr className="gf-form-disabled">
...@@ -23,12 +24,12 @@ export default class DisabledPermissionListItem extends Component<Props, any> { ...@@ -23,12 +24,12 @@ export default class DisabledPermissionListItem extends Component<Props, any> {
<td className="query-keyword">Can</td> <td className="query-keyword">Can</td>
<td> <td>
<div className="gf-form"> <div className="gf-form">
<DescriptionPicker <Select
optionsWithDesc={dashboardPermissionLevels} options={dashboardPermissionLevels}
onSelected={() => {}} onChange={() => {}}
disabled={true} isDisabled={true}
className={'gf-form-select-box__control--menu-right'} className="gf-form-select-box__control--menu-right"
value={item.permission} value={currentPermissionLevel}
/> />
</div> </div>
</td> </td>
......
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import DescriptionPicker from 'app/core/components/Picker/DescriptionPicker'; import { Select } from 'app/core/components/Select/Select';
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';
...@@ -50,6 +50,7 @@ export default class PermissionsListItem extends PureComponent<Props> { ...@@ -50,6 +50,7 @@ export default class PermissionsListItem extends PureComponent<Props> {
render() { render() {
const { item, folderInfo } = this.props; const { item, folderInfo } = this.props;
const inheritedFromRoot = item.dashboardId === -1 && !item.inherited; const inheritedFromRoot = item.dashboardId === -1 && !item.inherited;
const currentPermissionLevel = dashboardPermissionLevels.find(dp => dp.value === item.permission);
return ( return (
<tr className={setClassNameHelper(item.inherited)}> <tr className={setClassNameHelper(item.inherited)}>
...@@ -74,12 +75,13 @@ export default class PermissionsListItem extends PureComponent<Props> { ...@@ -74,12 +75,13 @@ export default class PermissionsListItem extends PureComponent<Props> {
<td className="query-keyword">Can</td> <td className="query-keyword">Can</td>
<td> <td>
<div className="gf-form"> <div className="gf-form">
<DescriptionPicker <Select
optionsWithDesc={dashboardPermissionLevels} isSearchable={false}
onSelected={this.onPermissionChanged} options={dashboardPermissionLevels}
disabled={item.inherited} onChange={this.onPermissionChanged}
className={'gf-form-select-box__control--menu-right'} isDisabled={item.inherited}
value={item.permission} className="gf-form-select-box__control--menu-right"
value={currentPermissionLevel}
/> />
</div> </div>
</td> </td>
......
import React from 'react';
import { components } from 'react-select';
import { OptionProps } from 'react-select/lib/components/Option';
// https://github.com/JedWatson/react-select/issues/3038
interface ExtendedOptionProps extends OptionProps<any> {
data: any;
}
export const Option = (props: ExtendedOptionProps) => {
const { children, isSelected, data } = props;
return (
<components.Option {...props}>
<div className="gf-form-select-box__desc-option">
<div className="gf-form-select-box__desc-option__body">
<div>{children}</div>
{data.description && <div className="gf-form-select-box__desc-option__desc">{data.description}</div>}
</div>
{isSelected && <i className="fa fa-check" aria-hidden="true" />}
</div>
</components.Option>
);
};
export default Option;
import React, { Component } from 'react';
import Select from 'react-select';
import DescriptionOption from './DescriptionOption';
import IndicatorsContainer from './IndicatorsContainer';
import ResetStyles from './ResetStyles';
import NoOptionsMessage from './NoOptionsMessage';
export interface OptionWithDescription {
value: any;
label: string;
description: string;
}
export interface Props {
optionsWithDesc: OptionWithDescription[];
onSelected: (permission) => void;
disabled: boolean;
className?: string;
value?: any;
}
const getSelectedOption = (optionsWithDesc, value) => optionsWithDesc.find(option => option.value === value);
class DescriptionPicker extends Component<Props, any> {
render() {
const { optionsWithDesc, onSelected, disabled, className, value } = this.props;
const selectedOption = getSelectedOption(optionsWithDesc, value);
return (
<div className="permissions-picker">
<Select
placeholder="Choose"
classNamePrefix={`gf-form-select-box`}
className={`width-7 gf-form-input gf-form-input--form-dropdown ${className || ''}`}
options={optionsWithDesc}
components={{
Option: DescriptionOption,
IndicatorsContainer,
NoOptionsMessage,
}}
styles={ResetStyles}
isDisabled={disabled}
onChange={onSelected}
getOptionValue={i => i.value}
getOptionLabel={i => i.label}
value={selectedOption}
/>
</div>
);
}
}
export default DescriptionPicker;
// import React, { PureComponent } from 'react';
// import Select as ReactSelect from 'react-select';
// import DescriptionOption from './DescriptionOption';
// import IndicatorsContainer from './IndicatorsContainer';
// import ResetStyles from './ResetStyles';
//
// export interface OptionType {
// label: string;
// value: string;
// }
//
// interface Props {
// defaultValue?: any;
// getOptionLabel: (item: T) => string;
// getOptionValue: (item: T) => string;
// onChange: (item: T) => {} | void;
// options: T[];
// placeholder?: string;
// width?: number;
// value: T;
// className?: string;
// }
//
// export class Select<T> extends PureComponent<Props<T>> {
// static defaultProps = {
// width: null,
// className: '',
// }
//
// render() {
// const { defaultValue, getOptionLabel, getOptionValue, onSelected, options, placeholder, width, value, className } = this.props;
// let widthClass = '';
// if (width) {
// widthClass = 'width-'+width;
// }
//
// return (
// <ReactSelect
// classNamePrefix="gf-form-select-box"
// className={`gf-form-input gf-form-input--form-dropdown ${widthClass} ${className}`}
// components={{
// Option: DescriptionOption,
// IndicatorsContainer,
// }}
// defaultValue={defaultValue}
// value={value}
// getOptionLabel={getOptionLabel}
// getOptionValue={getOptionValue}
// menuShouldScrollIntoView={false}
// isSearchable={false}
// onChange={onSelected}
// options={options}
// placeholder={placeholder || 'Choose'}
// styles={ResetStyles}
// />
// );
// }
// }
//
// export default Select;
import React, { SFC } from 'react';
import Select from 'react-select';
import DescriptionOption from './DescriptionOption';
import IndicatorsContainer from './IndicatorsContainer';
import ResetStyles from './ResetStyles';
interface Props {
className?: string;
defaultValue?: any;
getOptionLabel: (item: any) => string;
getOptionValue: (item: any) => string;
onSelected: (item: any) => {} | void;
options: any[];
placeholder?: string;
width?: number;
value: any;
}
const SimplePicker: SFC<Props> = ({
className,
defaultValue,
getOptionLabel,
getOptionValue,
onSelected,
options,
placeholder,
width,
value,
}) => {
return (
<Select
classNamePrefix="gf-form-select-box"
className={`${width ? 'width-' + width : ''} gf-form-input gf-form-input--form-dropdown ${className || ''}`}
components={{
Option: DescriptionOption,
IndicatorsContainer,
}}
defaultValue={defaultValue}
value={value}
getOptionLabel={getOptionLabel}
getOptionValue={getOptionValue}
menuShouldScrollIntoView={false}
isSearchable={false}
onChange={onSelected}
options={options}
placeholder={placeholder || 'Choose'}
styles={ResetStyles}
/>
);
};
export default SimplePicker;
import React, { SFC } from 'react';
import { components } from 'react-select';
import { OptionProps } from 'react-select/lib/components/Option';
interface ExtendedOptionProps extends OptionProps<any> {
data: any;
}
const UnitOption: SFC<ExtendedOptionProps> = props => {
const { children, isSelected, className } = props;
return (
<components.Option {...props}>
<div className={`unit-picker-option__button btn btn-link ${className}`}>
{isSelected && <i className="fa fa-check pull-right" aria-hidden="true" />}
<div className="gf-form">{children}</div>
</div>
</components.Option>
);
};
export default UnitOption;
...@@ -3,16 +3,13 @@ import React, { PureComponent } from 'react'; ...@@ -3,16 +3,13 @@ import React, { PureComponent } from 'react';
import _ from 'lodash'; import _ from 'lodash';
// Components // Components
import ResetStyles from 'app/core/components/Picker/ResetStyles'; import Select from './Select';
import { Option, SingleValue } from 'app/core/components/Picker/PickerOption';
import IndicatorsContainer from 'app/core/components/Picker/IndicatorsContainer';
import Select from 'react-select';
// Types // Types
import { DataSourceSelectItem } from 'app/types'; import { DataSourceSelectItem } from 'app/types';
export interface Props { export interface Props {
onChangeDataSource: (ds: DataSourceSelectItem) => void; onChange: (ds: DataSourceSelectItem) => void;
datasources: DataSourceSelectItem[]; datasources: DataSourceSelectItem[];
current: DataSourceSelectItem; current: DataSourceSelectItem;
onBlur?: () => void; onBlur?: () => void;
...@@ -32,7 +29,7 @@ export class DataSourcePicker extends PureComponent<Props> { ...@@ -32,7 +29,7 @@ export class DataSourcePicker extends PureComponent<Props> {
onChange = item => { onChange = item => {
const ds = this.props.datasources.find(ds => ds.name === item.value); const ds = this.props.datasources.find(ds => ds.name === item.value);
this.props.onChangeDataSource(ds); this.props.onChange(ds);
}; };
render() { render() {
...@@ -53,27 +50,19 @@ export class DataSourcePicker extends PureComponent<Props> { ...@@ -53,27 +50,19 @@ export class DataSourcePicker extends PureComponent<Props> {
return ( return (
<div className="gf-form-inline"> <div className="gf-form-inline">
<Select <Select
classNamePrefix={`gf-form-select-box`} className="ds-picker"
isMulti={false} isMulti={false}
menuShouldScrollIntoView={false}
isClearable={false} isClearable={false}
className="gf-form-input gf-form-input--form-dropdown ds-picker" backspaceRemovesValue={false}
onChange={item => this.onChange(item)} onChange={this.onChange}
options={options} options={options}
styles={ResetStyles}
autoFocus={autoFocus} autoFocus={autoFocus}
onBlur={onBlur} onBlur={onBlur}
openMenuOnFocus={true} openMenuOnFocus={true}
maxMenuHeight={500} maxMenuHeight={500}
placeholder="Select datasource" placeholder="Select datasource"
loadingMessage={() => 'Loading datasources...'}
noOptionsMessage={() => 'No datasources found'} noOptionsMessage={() => 'No datasources found'}
value={value} value={value}
components={{
Option,
SingleValue,
IndicatorsContainer,
}}
/> />
</div> </div>
); );
......
import React from 'react'; import React from 'react';
import { components } from 'react-select'; import { components } from 'react-select';
import { OptionProps } from 'react-select/lib/components/Option'; import { OptionProps } from 'react-select/lib/components/Option';
...@@ -6,13 +6,15 @@ export interface Props { ...@@ -6,13 +6,15 @@ export interface Props {
children: Element; children: Element;
} }
export const PickerOption = (props: OptionProps<any>) => { export const NoOptionsMessage = (props: OptionProps<any>) => {
const { children, className } = props; const { children } = props;
return ( return (
<components.Option {...props}> <components.Option {...props}>
<div className={`description-picker-option__button btn btn-link ${className}`}>{children}</div> <div className="gf-form-select-box__desc-option">
<div className="gf-form-select-box__desc-option__body">{children}</div>
</div>
</components.Option> </components.Option>
); );
}; };
export default PickerOption; export default NoOptionsMessage;
...@@ -9,7 +9,7 @@ interface State { ...@@ -9,7 +9,7 @@ interface State {
expanded: boolean; expanded: boolean;
} }
export default class UnitGroup extends PureComponent<ExtendedGroupProps, State> { export default class OptionGroup extends PureComponent<ExtendedGroupProps, State> {
state = { state = {
expanded: false, expanded: false,
}; };
...@@ -41,10 +41,10 @@ export default class UnitGroup extends PureComponent<ExtendedGroupProps, State> ...@@ -41,10 +41,10 @@ export default class UnitGroup extends PureComponent<ExtendedGroupProps, State>
const { expanded } = this.state; const { expanded } = this.state;
return ( return (
<div className="width-21 unit-picker-group" style={{ marginBottom: '5px' }}> <div className="gf-form-select-box__option-group">
<div className="unit-picker-group-item" onClick={this.onToggleChildren}> <div className="gf-form-select-box__option-group__header" onClick={this.onToggleChildren}>
<span style={{ textTransform: 'capitalize' }}>{label}</span> <span className="flex-grow">{label}</span>
<i className={`fa ${expanded ? 'fa-minus' : 'fa-plus'}`} />{' '} <i className={`fa ${expanded ? 'fa-caret-left' : 'fa-caret-down'}`} />{' '}
</div> </div>
{expanded && children} {expanded && children}
</div> </div>
......
// Libraries
import classNames from 'classnames';
import React, { PureComponent } from 'react';
import { default as ReactSelect } from 'react-select';
import { default as ReactAsyncSelect } from 'react-select/lib/Async';
import { components } from 'react-select';
// Components
import { Option, SingleValue } from './PickerOption';
import OptionGroup from './OptionGroup';
import IndicatorsContainer from './IndicatorsContainer';
import NoOptionsMessage from './NoOptionsMessage';
import ResetStyles from './ResetStyles';
import CustomScrollbar from '../CustomScrollbar/CustomScrollbar';
export interface SelectOptionItem {
label?: string;
value?: any;
imgUrl?: string;
description?: string;
[key: string]: any;
}
interface CommonProps {
defaultValue?: any;
getOptionLabel?: (item: SelectOptionItem) => string;
getOptionValue?: (item: SelectOptionItem) => string;
onChange: (item: SelectOptionItem) => {} | void;
placeholder?: string;
width?: number;
value?: SelectOptionItem;
className?: string;
isDisabled?: boolean;
isSearchable?: boolean;
isClearable?: boolean;
autoFocus?: boolean;
openMenuOnFocus?: boolean;
onBlur?: () => void;
maxMenuHeight?: number;
isLoading: boolean;
noOptionsMessage?: () => string;
isMulti?: boolean;
backspaceRemovesValue: boolean;
}
interface SelectProps {
options: SelectOptionItem[];
}
interface AsyncProps {
defaultOptions: boolean;
loadOptions: (query: string) => Promise<SelectOptionItem[]>;
loadingMessage?: () => string;
}
export const MenuList = props => {
return (
<components.MenuList {...props}>
<CustomScrollbar autoHide={false}>{props.children}</CustomScrollbar>
</components.MenuList>
);
};
export class Select extends PureComponent<CommonProps & SelectProps> {
static defaultProps = {
width: null,
className: '',
isDisabled: false,
isSearchable: true,
isClearable: false,
isMulti: false,
openMenuOnFocus: false,
autoFocus: false,
isLoading: false,
backspaceRemovesValue: true,
maxMenuHeight: 300,
};
render() {
const {
defaultValue,
getOptionLabel,
getOptionValue,
onChange,
options,
placeholder,
width,
value,
className,
isDisabled,
isLoading,
isSearchable,
isClearable,
backspaceRemovesValue,
isMulti,
autoFocus,
openMenuOnFocus,
onBlur,
maxMenuHeight,
noOptionsMessage,
} = this.props;
let widthClass = '';
if (width) {
widthClass = 'width-' + width;
}
const selectClassNames = classNames('gf-form-input', 'gf-form-input--form-dropdown', widthClass, className);
return (
<ReactSelect
classNamePrefix="gf-form-select-box"
className={selectClassNames}
components={{
Option,
SingleValue,
IndicatorsContainer,
MenuList,
Group: OptionGroup,
}}
defaultValue={defaultValue}
value={value}
getOptionLabel={getOptionLabel}
getOptionValue={getOptionValue}
menuShouldScrollIntoView={false}
isSearchable={isSearchable}
onChange={onChange}
options={options}
placeholder={placeholder || 'Choose'}
styles={ResetStyles}
isDisabled={isDisabled}
isLoading={isLoading}
isClearable={isClearable}
autoFocus={autoFocus}
onBlur={onBlur}
openMenuOnFocus={openMenuOnFocus}
maxMenuHeight={maxMenuHeight}
noOptionsMessage={noOptionsMessage}
isMulti={isMulti}
backspaceRemovesValue={backspaceRemovesValue}
/>
);
}
}
export class AsyncSelect extends PureComponent<CommonProps & AsyncProps> {
static defaultProps = {
width: null,
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,
} = this.props;
let widthClass = '';
if (width) {
widthClass = 'width-' + width;
}
const selectClassNames = classNames('gf-form-input', 'gf-form-input--form-dropdown', widthClass, className);
return (
<ReactAsyncSelect
classNamePrefix="gf-form-select-box"
className={selectClassNames}
components={{
Option,
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={ResetStyles}
loadingMessage={loadingMessage}
noOptionsMessage={noOptionsMessage}
isDisabled={isDisabled}
isSearchable={isSearchable}
isClearable={isClearable}
autoFocus={autoFocus}
onBlur={onBlur}
openMenuOnFocus={openMenuOnFocus}
maxMenuHeight={maxMenuHeight}
isMulti={isMulti}
backspaceRemovesValue={backspaceRemovesValue}
/>
);
}
}
export default Select;
import React, { Component } from 'react'; import React, { Component } from 'react';
import AsyncSelect from 'react-select/lib/Async'; import { AsyncSelect } from './Select';
import PickerOption from './PickerOption';
import { debounce } from 'lodash'; import { debounce } from 'lodash';
import { getBackendSrv } from 'app/core/services/backend_srv'; import { getBackendSrv } from 'app/core/services/backend_srv';
import ResetStyles from './ResetStyles';
import IndicatorsContainer from './IndicatorsContainer';
import NoOptionsMessage from './NoOptionsMessage';
export interface Team { export interface Team {
id: number; id: number;
...@@ -45,6 +41,7 @@ export class TeamPicker extends Component<Props, State> { ...@@ -45,6 +41,7 @@ export class TeamPicker extends Component<Props, State> {
const teams = result.teams.map(team => { const teams = result.teams.map(team => {
return { return {
id: team.id, id: team.id,
value: team.id,
label: team.name, label: team.name,
name: team.name, name: team.name,
imgUrl: team.avatarUrl, imgUrl: team.avatarUrl,
...@@ -62,24 +59,13 @@ export class TeamPicker extends Component<Props, State> { ...@@ -62,24 +59,13 @@ export class TeamPicker extends Component<Props, State> {
return ( return (
<div className="user-picker"> <div className="user-picker">
<AsyncSelect <AsyncSelect
classNamePrefix={`gf-form-select-box`}
isMulti={false}
isLoading={isLoading} isLoading={isLoading}
defaultOptions={true} defaultOptions={true}
loadOptions={this.debouncedSearch} loadOptions={this.debouncedSearch}
onChange={onSelected} onChange={onSelected}
className={`gf-form-input gf-form-input--form-dropdown ${className || ''}`} className={className}
styles={ResetStyles}
components={{
Option: PickerOption,
IndicatorsContainer,
NoOptionsMessage,
}}
placeholder="Select a team" placeholder="Select a team"
loadingMessage={() => 'Loading...'}
noOptionsMessage={() => 'No teams found'} noOptionsMessage={() => 'No teams found'}
getOptionValue={i => i.id}
getOptionLabel={i => i.label}
/> />
</div> </div>
); );
......
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import Select from 'react-select'; import Select from './Select';
import UnitGroup from './UnitGroup'; import kbn from 'app/core/utils/kbn';
import UnitOption from './UnitOption';
import ResetStyles from '../ResetStyles';
import kbn from '../../../utils/kbn';
interface Props { interface Props {
onSelected: (item: any) => {} | void; onChange: (item: any) => {} | void;
defaultValue?: string; defaultValue?: string;
width?: number; width?: number;
} }
...@@ -17,7 +14,7 @@ export default class UnitPicker extends PureComponent<Props> { ...@@ -17,7 +14,7 @@ export default class UnitPicker extends PureComponent<Props> {
}; };
render() { render() {
const { defaultValue, onSelected, width } = this.props; const { defaultValue, onChange, width } = this.props;
const unitGroups = kbn.getUnitFormats(); const unitGroups = kbn.getUnitFormats();
...@@ -36,45 +33,18 @@ export default class UnitPicker extends PureComponent<Props> { ...@@ -36,45 +33,18 @@ export default class UnitPicker extends PureComponent<Props> {
}; };
}); });
// const styles = {
// ...ResetStyles,
// menu: () => ({
// maxHeight: '75%',
// overflow: 'scroll',
// }),
// menuList: () =>
// ({
// overflowY: 'auto',
// position: 'relative',
// } as React.CSSProperties),
// valueContainer: () =>
// ({
// overflow: 'hidden',
// textOverflow: 'ellipsis',
// maxWidth: '90px',
// whiteSpace: 'nowrap',
// } as React.CSSProperties),
// };
const value = groupOptions.map(group => { const value = groupOptions.map(group => {
return group.options.find(option => option.value === defaultValue); return group.options.find(option => option.value === defaultValue);
}); });
return ( return (
<Select <Select
classNamePrefix="gf-form-select-box" width={width}
className={`width-${width} gf-form-input gf-form-input--form-dropdown`}
defaultValue={value} defaultValue={value}
isSearchable={true} isSearchable={true}
menuShouldScrollIntoView={false}
options={groupOptions} options={groupOptions}
placeholder="Choose" placeholder="Choose"
onChange={onSelected} onChange={onChange}
components={{
Group: UnitGroup,
Option: UnitOption,
}}
styles={ResetStyles}
/> />
); );
} }
......
// Libraries
import React, { Component } from 'react'; import React, { Component } from 'react';
import AsyncSelect from 'react-select/lib/Async';
import PickerOption from './PickerOption'; // Components
import { AsyncSelect } from './Select';
// Utils & Services
import { debounce } from 'lodash'; import { debounce } from 'lodash';
import { getBackendSrv } from 'app/core/services/backend_srv'; import { getBackendSrv } from 'app/core/services/backend_srv';
// Types
import { User } from 'app/types'; import { User } from 'app/types';
import ResetStyles from './ResetStyles';
import IndicatorsContainer from './IndicatorsContainer';
import NoOptionsMessage from './NoOptionsMessage';
export interface Props { export interface Props {
onSelected: (user: User) => void; onSelected: (user: User) => void;
...@@ -40,6 +43,7 @@ export class UserPicker extends Component<Props, State> { ...@@ -40,6 +43,7 @@ export class UserPicker extends Component<Props, State> {
.then(result => { .then(result => {
return result.map(user => ({ return result.map(user => ({
id: user.userId, id: user.userId,
value: user.userId,
label: user.login === user.email ? user.login : `${user.login} - ${user.email}`, label: user.login === user.email ? user.login : `${user.login} - ${user.email}`,
imgUrl: user.avatarUrl, imgUrl: user.avatarUrl,
login: user.login, login: user.login,
...@@ -57,24 +61,13 @@ export class UserPicker extends Component<Props, State> { ...@@ -57,24 +61,13 @@ export class UserPicker extends Component<Props, State> {
return ( return (
<div className="user-picker"> <div className="user-picker">
<AsyncSelect <AsyncSelect
classNamePrefix={`gf-form-select-box`} className={className}
isMulti={false}
isLoading={isLoading} isLoading={isLoading}
defaultOptions={true} defaultOptions={true}
loadOptions={this.debouncedSearch} loadOptions={this.debouncedSearch}
onChange={onSelected} onChange={onSelected}
className={`gf-form-input gf-form-input--form-dropdown ${className || ''}`}
styles={ResetStyles}
components={{
Option: PickerOption,
IndicatorsContainer,
NoOptionsMessage,
}}
placeholder="Select user" placeholder="Select user"
loadingMessage={() => 'Loading...'}
noOptionsMessage={() => 'No users found'} noOptionsMessage={() => 'No users found'}
getOptionValue={i => i.id}
getOptionLabel={i => i.label}
/> />
</div> </div>
); );
......
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { Label } from 'app/core/components/Label/Label'; import { Label } from 'app/core/components/Label/Label';
import SimplePicker from 'app/core/components/Picker/SimplePicker'; import Select from 'app/core/components/Select/Select';
import { getBackendSrv, BackendSrv } from 'app/core/services/backend_srv'; import { getBackendSrv, BackendSrv } from 'app/core/services/backend_srv';
import { DashboardSearchHit } from 'app/types'; import { DashboardSearchHit } from 'app/types';
...@@ -17,12 +17,12 @@ export interface State { ...@@ -17,12 +17,12 @@ export interface State {
dashboards: DashboardSearchHit[]; dashboards: DashboardSearchHit[];
} }
const themes = [{ value: '', text: 'Default' }, { value: 'dark', text: 'Dark' }, { value: 'light', text: 'Light' }]; const themes = [{ value: '', label: 'Default' }, { value: 'dark', label: 'Dark' }, { value: 'light', label: 'Light' }];
const timezones = [ const timezones = [
{ value: '', text: 'Default' }, { value: '', label: 'Default' },
{ value: 'browser', text: 'Local browser time' }, { value: 'browser', label: 'Local browser time' },
{ value: 'utc', text: 'UTC' }, { value: 'utc', label: 'UTC' },
]; ];
export class SharedPreferences extends PureComponent<Props, State> { export class SharedPreferences extends PureComponent<Props, State> {
...@@ -91,12 +91,11 @@ export class SharedPreferences extends PureComponent<Props, State> { ...@@ -91,12 +91,11 @@ export class SharedPreferences extends PureComponent<Props, State> {
<h3 className="page-heading">Preferences</h3> <h3 className="page-heading">Preferences</h3>
<div className="gf-form"> <div className="gf-form">
<span className="gf-form-label width-11">UI Theme</span> <span className="gf-form-label width-11">UI Theme</span>
<SimplePicker <Select
isSearchable={false}
value={themes.find(item => item.value === theme)} value={themes.find(item => item.value === theme)}
options={themes} options={themes}
getOptionValue={i => i.value} onChange={theme => this.onThemeChanged(theme.value)}
getOptionLabel={i => i.text}
onSelected={theme => this.onThemeChanged(theme.value)}
width={20} width={20}
/> />
</div> </div>
...@@ -107,11 +106,11 @@ export class SharedPreferences extends PureComponent<Props, State> { ...@@ -107,11 +106,11 @@ export class SharedPreferences extends PureComponent<Props, State> {
> >
Home Dashboard Home Dashboard
</Label> </Label>
<SimplePicker <Select
value={dashboards.find(dashboard => dashboard.id === homeDashboardId)} value={dashboards.find(dashboard => dashboard.id === homeDashboardId)}
getOptionValue={i => i.id} getOptionValue={i => i.id}
getOptionLabel={i => i.title} getOptionLabel={i => i.title}
onSelected={(dashboard: DashboardSearchHit) => this.onHomeDashboardChanged(dashboard.id)} onChange={(dashboard: DashboardSearchHit) => this.onHomeDashboardChanged(dashboard.id)}
options={dashboards} options={dashboards}
placeholder="Chose default dashboard" placeholder="Chose default dashboard"
width={20} width={20}
...@@ -119,11 +118,10 @@ export class SharedPreferences extends PureComponent<Props, State> { ...@@ -119,11 +118,10 @@ export class SharedPreferences extends PureComponent<Props, State> {
</div> </div>
<div className="gf-form"> <div className="gf-form">
<label className="gf-form-label width-11">Timezone</label> <label className="gf-form-label width-11">Timezone</label>
<SimplePicker <Select
isSearchable={false}
value={timezones.find(item => item.value === timezone)} value={timezones.find(item => item.value === timezone)}
getOptionValue={i => i.value} onChange={timezone => this.onTimeZoneChanged(timezone.value)}
getOptionLabel={i => i.text}
onSelected={timezone => this.onTimeZoneChanged(timezone.value)}
options={timezones} options={timezones}
width={20} width={20}
/> />
......
...@@ -2,10 +2,10 @@ import React from 'react'; ...@@ -2,10 +2,10 @@ import React from 'react';
import AsyncSelect from 'react-select/lib/Async'; import AsyncSelect from 'react-select/lib/Async';
import { TagOption } from './TagOption'; import { TagOption } from './TagOption';
import { TagBadge } from './TagBadge'; import { TagBadge } from './TagBadge';
import IndicatorsContainer from 'app/core/components/Picker/IndicatorsContainer'; import IndicatorsContainer from 'app/core/components/Select/IndicatorsContainer';
import NoOptionsMessage from 'app/core/components/Picker/NoOptionsMessage'; import NoOptionsMessage from 'app/core/components/Select/NoOptionsMessage';
import { components } from 'react-select'; import { components } from 'react-select';
import ResetStyles from 'app/core/components/Picker/ResetStyles'; import ResetStyles from 'app/core/components/Select/ResetStyles';
export interface Props { export interface Props {
tags: string[]; tags: string[];
......
...@@ -84,7 +84,7 @@ function link(scope, elem, attrs) { ...@@ -84,7 +84,7 @@ function link(scope, elem, attrs) {
// disable depreacation warning // disable depreacation warning
codeEditor.$blockScrolling = Infinity; codeEditor.$blockScrolling = Infinity;
// Padding hacks // Padding hacks
(codeEditor.renderer as any).setScrollMargin(15, 15); (codeEditor.renderer as any).setScrollMargin(10, 10);
codeEditor.renderer.setPadding(10); codeEditor.renderer.setPadding(10);
setThemeMode(); setThemeMode();
......
...@@ -6,7 +6,7 @@ import _ from 'lodash'; ...@@ -6,7 +6,7 @@ import _ from 'lodash';
// Components // Components
import './../../panel/metrics_tab'; import './../../panel/metrics_tab';
import { EditorTabBody } from './EditorTabBody'; import { EditorTabBody } from './EditorTabBody';
import { DataSourcePicker } from './DataSourcePicker'; import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker';
import { QueryInspector } from './QueryInspector'; import { QueryInspector } from './QueryInspector';
import { QueryOptions } from './QueryOptions'; import { QueryOptions } from './QueryOptions';
import { AngularQueryComponentScope } from 'app/features/panel/metrics_tab'; import { AngularQueryComponentScope } from 'app/features/panel/metrics_tab';
...@@ -205,20 +205,14 @@ export class QueriesTab extends PureComponent<Props, State> { ...@@ -205,20 +205,14 @@ export class QueriesTab extends PureComponent<Props, State> {
renderToolbar = () => { renderToolbar = () => {
const { currentDS } = this.state; const { currentDS } = this.state;
return ( return <DataSourcePicker datasources={this.datasources} onChange={this.onChangeDataSource} current={currentDS} />;
<DataSourcePicker
datasources={this.datasources}
onChangeDataSource={this.onChangeDataSource}
current={currentDS}
/>
);
}; };
renderMixedPicker = () => { renderMixedPicker = () => {
return ( return (
<DataSourcePicker <DataSourcePicker
datasources={this.datasources} datasources={this.datasources}
onChangeDataSource={this.onAddMixedQuery} onChange={this.onAddMixedQuery}
current={null} current={null}
autoFocus={true} autoFocus={true}
onBlur={this.onMixedPickerBlur} onBlur={this.onMixedPickerBlur}
......
import React from 'react'; import React from 'react';
import { hot } from 'react-hot-loader'; import { hot } from 'react-hot-loader';
import Select from 'react-select';
import _ from 'lodash'; import _ from 'lodash';
import { DataSource } from 'app/types/datasources'; import { DataSource } from 'app/types/datasources';
...@@ -25,10 +24,7 @@ import { ...@@ -25,10 +24,7 @@ import {
makeTimeSeriesList, makeTimeSeriesList,
updateHistory, updateHistory,
} from 'app/core/utils/explore'; } from 'app/core/utils/explore';
import ResetStyles from 'app/core/components/Picker/ResetStyles'; import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker';
import PickerOption from 'app/core/components/Picker/PickerOption';
import IndicatorsContainer from 'app/core/components/Picker/IndicatorsContainer';
import NoOptionsMessage from 'app/core/components/Picker/NoOptionsMessage';
import TableModel from 'app/core/table_model'; import TableModel from 'app/core/table_model';
import { DatasourceSrv } from 'app/features/plugins/datasource_srv'; import { DatasourceSrv } from 'app/features/plugins/datasource_srv';
import { Emitter } from 'app/core/utils/emitter'; import { Emitter } from 'app/core/utils/emitter';
...@@ -158,10 +154,12 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> { ...@@ -158,10 +154,12 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
if (!datasourceSrv) { if (!datasourceSrv) {
throw new Error('No datasource service passed as props.'); throw new Error('No datasource service passed as props.');
} }
const datasources = datasourceSrv.getExternal(); const datasources = datasourceSrv.getExternal();
const exploreDatasources = datasources.map(ds => ({ const exploreDatasources = datasources.map(ds => ({
value: ds.name, value: ds.name,
label: ds.name, name: ds.name,
meta: ds.meta,
})); }));
if (datasources.length > 0) { if (datasources.length > 0) {
...@@ -885,7 +883,7 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> { ...@@ -885,7 +883,7 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
} = this.state; } = this.state;
const graphHeight = showingGraph && showingTable ? '200px' : '400px'; const graphHeight = showingGraph && showingTable ? '200px' : '400px';
const exploreClass = split ? 'explore explore-split' : 'explore'; const exploreClass = split ? 'explore explore-split' : 'explore';
const selectedDatasource = datasource ? exploreDatasources.find(d => d.label === datasource.name) : undefined; const selectedDatasource = datasource ? exploreDatasources.find(d => d.name === datasource.name) : undefined;
const graphLoading = queryTransactions.some(qt => qt.resultType === 'Graph' && !qt.done); const graphLoading = queryTransactions.some(qt => qt.resultType === 'Graph' && !qt.done);
const tableLoading = queryTransactions.some(qt => qt.resultType === 'Table' && !qt.done); const tableLoading = queryTransactions.some(qt => qt.resultType === 'Table' && !qt.done);
const logsLoading = queryTransactions.some(qt => qt.resultType === 'Logs' && !qt.done); const logsLoading = queryTransactions.some(qt => qt.resultType === 'Logs' && !qt.done);
...@@ -910,26 +908,10 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> { ...@@ -910,26 +908,10 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
)} )}
{!datasourceMissing ? ( {!datasourceMissing ? (
<div className="navbar-buttons"> <div className="navbar-buttons">
<Select <DataSourcePicker
classNamePrefix={`gf-form-select-box`}
isMulti={false}
menuShouldScrollIntoView={false}
isLoading={datasourceLoading}
isClearable={false}
className="gf-form-input gf-form-input--form-dropdown datasource-picker"
onChange={this.onChangeDatasource} onChange={this.onChangeDatasource}
options={exploreDatasources} datasources={exploreDatasources}
styles={ResetStyles} current={selectedDatasource}
maxMenuHeight={500}
placeholder="Select datasource"
loadingMessage={() => 'Loading datasources...'}
noOptionsMessage={() => 'No datasources found'}
value={selectedDatasource}
components={{
Option: PickerOption,
IndicatorsContainer,
NoOptionsMessage,
}}
/> />
</div> </div>
) : null} ) : null}
......
...@@ -111,11 +111,11 @@ function panelHeader($compile) { ...@@ -111,11 +111,11 @@ function panelHeader($compile) {
*/ */
function togglePanelStackPosition() { function togglePanelStackPosition() {
const menuOpenClass = 'dropdown-menu-open'; const menuOpenClass = 'dropdown-menu-open';
const panelGridClass = '.react-grid-item.panel'; const panelGridClass = '.react-grid-item';
let panelElem = elem let panelElem = elem
.find('[data-toggle=dropdown]') .find('[data-toggle=dropdown]')
.parentsUntil('.panel') .parentsUntil(panelGridClass)
.parent(); .parent();
const menuElem = elem.find('[data-toggle=dropdown]').parent(); const menuElem = elem.find('[data-toggle=dropdown]').parent();
panelElem = panelElem && panelElem.length ? panelElem[0] : undefined; panelElem = panelElem && panelElem.length ? panelElem[0] : undefined;
......
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import SlideDown from 'app/core/components/Animations/SlideDown'; import SlideDown from 'app/core/components/Animations/SlideDown';
import { UserPicker } from 'app/core/components/Picker/UserPicker'; import { UserPicker } from 'app/core/components/Select/UserPicker';
import DeleteButton from 'app/core/components/DeleteButton/DeleteButton'; import DeleteButton from 'app/core/components/DeleteButton/DeleteButton';
import { TagBadge } from 'app/core/components/TagFilter/TagBadge'; import { TagBadge } from 'app/core/components/TagFilter/TagBadge';
import { TeamMember, User } from 'app/types'; import { TeamMember, User } from 'app/types';
......
...@@ -2,21 +2,6 @@ import angular from 'angular'; ...@@ -2,21 +2,6 @@ import angular from 'angular';
import coreModule from 'app/core/core_module'; import coreModule from 'app/core/core_module';
import _ from 'lodash'; import _ from 'lodash';
export class CloudWatchQueryParameter {
constructor() {
return {
templateUrl: 'public/app/plugins/datasource/cloudwatch/partials/query.parameter.html',
controller: 'CloudWatchQueryParameterCtrl',
restrict: 'E',
scope: {
target: '=',
datasource: '=',
onChange: '&',
},
};
}
}
export class CloudWatchQueryParameterCtrl { export class CloudWatchQueryParameterCtrl {
/** @ngInject */ /** @ngInject */
constructor($scope, templateSrv, uiSegmentSrv, datasourceSrv, $q) { constructor($scope, templateSrv, uiSegmentSrv, datasourceSrv, $q) {
...@@ -240,5 +225,17 @@ export class CloudWatchQueryParameterCtrl { ...@@ -240,5 +225,17 @@ export class CloudWatchQueryParameterCtrl {
} }
} }
coreModule.directive('cloudwatchQueryParameter', CloudWatchQueryParameter); export function cloudWatchQueryParameter() {
coreModule.controller('CloudWatchQueryParameterCtrl', CloudWatchQueryParameterCtrl); return {
templateUrl: 'public/app/plugins/datasource/cloudwatch/partials/query.parameter.html',
controller: CloudWatchQueryParameterCtrl,
restrict: 'E',
scope: {
target: '=',
datasource: '=',
onChange: '&',
},
};
}
coreModule.directive('cloudwatchQueryParameter', cloudWatchQueryParameter);
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { Label } from 'app/core/components/Label/Label'; import { Label } from 'app/core/components/Label/Label';
import SimplePicker from 'app/core/components/Picker/SimplePicker'; import { Select } from 'app/core/components/Select/Select';
import { MappingType, RangeMap, ValueMap } from 'app/types'; import { MappingType, RangeMap, ValueMap } from 'app/types';
interface Props { interface Props {
...@@ -135,13 +135,12 @@ export default class MappingRow extends PureComponent<Props, State> { ...@@ -135,13 +135,12 @@ export default class MappingRow extends PureComponent<Props, State> {
<div className="mapping-row"> <div className="mapping-row">
<div className="gf-form-inline mapping-row-type"> <div className="gf-form-inline mapping-row-type">
<Label width={5}>Type</Label> <Label width={5}>Type</Label>
<SimplePicker <Select
placeholder="Choose type" placeholder="Choose type"
isSearchable={false}
options={mappingOptions} options={mappingOptions}
value={mappingOptions.find(o => o.value === type)} value={mappingOptions.find(o => o.value === type)}
getOptionLabel={i => i.label} onChange={type => this.onMappingTypeChange(type.value)}
getOptionValue={i => i.value}
onSelected={type => this.onMappingTypeChange(type.value)}
width={7} width={7}
/> />
</div> </div>
......
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { Label } from 'app/core/components/Label/Label'; import { Label } from 'app/core/components/Label/Label';
import SimplePicker from 'app/core/components/Picker/SimplePicker'; import Select from 'app/core/components/Select/Select';
import UnitPicker from 'app/core/components/Picker/Unit/UnitPicker'; import UnitPicker from 'app/core/components/Select/UnitPicker';
import { OptionModuleProps } from './module'; import { OptionModuleProps } from './module';
const statOptions = [ const statOptions = [
{ value: 'min', text: 'Min' }, { value: 'min', label: 'Min' },
{ value: 'max', text: 'Max' }, { value: 'max', label: 'Max' },
{ value: 'avg', text: 'Average' }, { value: 'avg', label: 'Average' },
{ value: 'current', text: 'Current' }, { value: 'current', label: 'Current' },
{ value: 'total', text: 'Total' }, { value: 'total', label: 'Total' },
{ value: 'name', text: 'Name' }, { value: 'name', label: 'Name' },
{ value: 'first', text: 'First' }, { value: 'first', label: 'First' },
{ value: 'delta', text: 'Delta' }, { value: 'delta', label: 'Delta' },
{ value: 'diff', text: 'Difference' }, { value: 'diff', label: 'Difference' },
{ value: 'range', text: 'Range' }, { value: 'range', label: 'Range' },
{ value: 'last_time', text: 'Time of last point' }, { value: 'last_time', label: 'Time of last point' },
]; ];
const labelWidth = 6; const labelWidth = 6;
...@@ -43,18 +43,16 @@ export default class ValueOptions extends PureComponent<OptionModuleProps> { ...@@ -43,18 +43,16 @@ export default class ValueOptions extends PureComponent<OptionModuleProps> {
<h5 className="page-heading">Value</h5> <h5 className="page-heading">Value</h5>
<div className="gf-form-inline"> <div className="gf-form-inline">
<Label width={labelWidth}>Stat</Label> <Label width={labelWidth}>Stat</Label>
<SimplePicker <Select
width={12} width={12}
options={statOptions} options={statOptions}
getOptionLabel={i => i.text} onChange={this.onStatChange}
getOptionValue={i => i.value}
onSelected={this.onStatChange}
value={statOptions.find(option => option.value === stat)} value={statOptions.find(option => option.value === stat)}
/> />
</div> </div>
<div className="gf-form-inline"> <div className="gf-form-inline">
<Label width={labelWidth}>Unit</Label> <Label width={labelWidth}>Unit</Label>
<UnitPicker defaultValue={unit} onSelected={value => this.onUnitChange(value)} /> <UnitPicker defaultValue={unit} onChange={this.onUnitChange} />
</div> </div>
<div className="gf-form-inline"> <div className="gf-form-inline">
<Label width={labelWidth}>Decimals</Label> <Label width={labelWidth}>Decimals</Label>
......
...@@ -3,6 +3,7 @@ import { Value } from 'slate'; ...@@ -3,6 +3,7 @@ import { Value } from 'slate';
import { DataQuery, RawTimeRange } from './series'; import { DataQuery, RawTimeRange } from './series';
import TableModel from 'app/core/table_model'; import TableModel from 'app/core/table_model';
import { LogsModel } from 'app/core/logs_model'; import { LogsModel } from 'app/core/logs_model';
import { DataSourceSelectItem } from 'app/types/datasources';
export interface CompletionItem { export interface CompletionItem {
/** /**
...@@ -74,11 +75,6 @@ export interface CompletionItemGroup { ...@@ -74,11 +75,6 @@ export interface CompletionItemGroup {
skipSort?: boolean; skipSort?: boolean;
} }
interface ExploreDatasource {
value: string;
label: string;
}
export interface HistoryItem { export interface HistoryItem {
ts: number; ts: number;
query: DataQuery; query: DataQuery;
...@@ -159,7 +155,7 @@ export interface ExploreState { ...@@ -159,7 +155,7 @@ export interface ExploreState {
datasourceLoading: boolean | null; datasourceLoading: boolean | null;
datasourceMissing: boolean; datasourceMissing: boolean;
datasourceName?: string; datasourceName?: string;
exploreDatasources: ExploreDatasource[]; exploreDatasources: DataSourceSelectItem[];
graphInterval: number; // in ms graphInterval: number; // in ms
graphResult?: any[]; graphResult?: any[];
history: HistoryItem[]; history: HistoryItem[];
......
...@@ -101,7 +101,6 @@ ...@@ -101,7 +101,6 @@
@import 'components/delete_button'; @import 'components/delete_button';
@import 'components/add_data_source.scss'; @import 'components/add_data_source.scss';
@import 'components/page_loader'; @import 'components/page_loader';
@import 'components/unit-picker';
@import 'components/thresholds'; @import 'components/thresholds';
@import 'components/toggle_button_group'; @import 'components/toggle_button_group';
@import 'components/value-mappings'; @import 'components/value-mappings';
......
...@@ -79,6 +79,7 @@ $select-input-bg-disabled: $input-bg-disabled; ...@@ -79,6 +79,7 @@ $select-input-bg-disabled: $input-bg-disabled;
.gf-form-select-box__option { .gf-form-select-box__option {
border-left: 2px solid transparent; border-left: 2px solid transparent;
white-space: nowrap; white-space: nowrap;
background-color: $input-bg;
&.gf-form-select-box__option--is-focused { &.gf-form-select-box__option--is-focused {
color: $dropdownLinkColorHover; color: $dropdownLinkColorHover;
...@@ -116,7 +117,7 @@ $select-input-bg-disabled: $input-bg-disabled; ...@@ -116,7 +117,7 @@ $select-input-bg-disabled: $input-bg-disabled;
.gf-form-select-box__select-arrow { .gf-form-select-box__select-arrow {
border-color: $input-color-select-arrow transparent transparent; border-color: $input-color-select-arrow transparent transparent;
border-style: solid; border-style: solid;
border-width: 5px 5px 2.5px; border-width: 4px 4px 2.5px;
display: inline-block; display: inline-block;
height: 0; height: 0;
width: 0; width: 0;
...@@ -125,7 +126,7 @@ $select-input-bg-disabled: $input-bg-disabled; ...@@ -125,7 +126,7 @@ $select-input-bg-disabled: $input-bg-disabled;
&.gf-form-select-box__select-arrow--reversed { &.gf-form-select-box__select-arrow--reversed {
border-color: transparent transparent $input-color-select-arrow; border-color: transparent transparent $input-color-select-arrow;
top: -2px; top: -2px;
border-width: 0 5px 5px; border-width: 0 4px 4px;
} }
} }
...@@ -170,3 +171,19 @@ $select-input-bg-disabled: $input-bg-disabled; ...@@ -170,3 +171,19 @@ $select-input-bg-disabled: $input-bg-disabled;
width: 16px; width: 16px;
margin-right: 10px; margin-right: 10px;
} }
.gf-form-select-box__option-group__header {
display: flex;
align-items: center;
justify-content: flex-start;
justify-items: center;
cursor: pointer;
padding: 7px 10px;
width: 100%;
border-bottom: 1px solid $hr-border-color;
text-transform: capitalize;
.fa {
padding-right: 2px;
}
}
...@@ -59,6 +59,8 @@ ...@@ -59,6 +59,8 @@
} }
.gf-form-query-letter-cell { .gf-form-query-letter-cell {
flex-shrink: 0;
.gf-form-query-letter-cell-carret { .gf-form-query-letter-cell-carret {
display: inline-block; display: inline-block;
width: 0.7rem; width: 0.7rem;
......
...@@ -97,10 +97,10 @@ input:checked + .gf-form-switch__slider::before { ...@@ -97,10 +97,10 @@ input:checked + .gf-form-switch__slider::before {
&--transparent { &--transparent {
background: transparent; background: transparent;
border: none; border: none;
width: 20px; width: 23px;
height: auto; height: auto;
position: relative; position: relative;
padding-left: 7px; padding-left: 8px;
} }
&--table-cell { &--table-cell {
......
.unit-picker-option {
position: relative;
width: 100%;
display: block;
border-radius: 0;
white-space: normal;
i.fa-check {
padding-left: 2px;
}
}
.unit-picker-group {
margin-bottom: 5px;
}
.unit-picker-group-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px;
font-size: 14px;
border-bottom: 1px solid #555;
}
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