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