mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge branch 'panel-edit-style-changes' into select-refactor
This commit is contained in:
commit
ab31d52b77
@ -1,4 +1,4 @@
|
|||||||
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 {
|
|||||||
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;
|
||||||
|
@ -1,60 +1,157 @@
|
|||||||
// import React, { PureComponent } from 'react';
|
// Libraries
|
||||||
// import Select as ReactSelect from 'react-select';
|
import classNames from 'classnames';
|
||||||
// import DescriptionOption from './DescriptionOption';
|
import React, { PureComponent } from 'react';
|
||||||
// import IndicatorsContainer from './IndicatorsContainer';
|
import { default as ReactSelect } from 'react-select';
|
||||||
// import ResetStyles from './ResetStyles';
|
import { default as ReactAsyncSelect } from 'react-select/lib/Async';
|
||||||
//
|
|
||||||
// export interface OptionType {
|
// Components
|
||||||
// label: string;
|
import { Option, SingleValue } from './PickerOption';
|
||||||
// value: string;
|
import IndicatorsContainer from './IndicatorsContainer';
|
||||||
// }
|
import NoOptionsMessage from './NoOptionsMessage';
|
||||||
//
|
import ResetStyles from './ResetStyles';
|
||||||
// interface Props {
|
|
||||||
// defaultValue?: any;
|
export interface SelectOptionItem {
|
||||||
// getOptionLabel: (item: T) => string;
|
label?: string;
|
||||||
// getOptionValue: (item: T) => string;
|
value?: string;
|
||||||
// onChange: (item: T) => {} | void;
|
imgUrl?: string;
|
||||||
// options: T[];
|
description?: string;
|
||||||
// placeholder?: string;
|
[key: string]: any;
|
||||||
// width?: number;
|
}
|
||||||
// value: T;
|
|
||||||
// className?: string;
|
interface CommonProps {
|
||||||
// }
|
defaultValue?: any;
|
||||||
//
|
getOptionLabel?: (item: SelectOptionItem) => string;
|
||||||
// export class Select<T> extends PureComponent<Props<T>> {
|
getOptionValue?: (item: SelectOptionItem) => string;
|
||||||
// static defaultProps = {
|
onChange: (item: SelectOptionItem) => {} | void;
|
||||||
// width: null,
|
placeholder?: string;
|
||||||
// className: '',
|
width?: number;
|
||||||
// }
|
value?: SelectOptionItem;
|
||||||
//
|
className?: string;
|
||||||
// render() {
|
components: object;
|
||||||
// const { defaultValue, getOptionLabel, getOptionValue, onSelected, options, placeholder, width, value, className } = this.props;
|
}
|
||||||
// let widthClass = '';
|
|
||||||
// if (width) {
|
interface SelectProps {
|
||||||
// widthClass = 'width-'+width;
|
options: SelectOptionItem[];
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// return (
|
interface AsyncProps {
|
||||||
// <ReactSelect
|
defaultOptions: boolean;
|
||||||
// classNamePrefix="gf-form-select-box"
|
loadOptions: (query: string) => Promise<SelectOptionItem[]>;
|
||||||
// className={`gf-form-input gf-form-input--form-dropdown ${widthClass} ${className}`}
|
isLoading: boolean;
|
||||||
// components={{
|
loadingMessage?: () => string;
|
||||||
// Option: DescriptionOption,
|
noOptionsMessage?: () => string;
|
||||||
// IndicatorsContainer,
|
}
|
||||||
// }}
|
|
||||||
// defaultValue={defaultValue}
|
export class Select extends PureComponent<CommonProps & SelectProps> {
|
||||||
// value={value}
|
static defaultProps = {
|
||||||
// getOptionLabel={getOptionLabel}
|
width: null,
|
||||||
// getOptionValue={getOptionValue}
|
className: '',
|
||||||
// menuShouldScrollIntoView={false}
|
components: {},
|
||||||
// isSearchable={false}
|
};
|
||||||
// onChange={onSelected}
|
|
||||||
// options={options}
|
render() {
|
||||||
// placeholder={placeholder || 'Choose'}
|
const {
|
||||||
// styles={ResetStyles}
|
defaultValue,
|
||||||
// />
|
getOptionLabel,
|
||||||
// );
|
getOptionValue,
|
||||||
// }
|
onChange,
|
||||||
// }
|
options,
|
||||||
//
|
placeholder,
|
||||||
// export default Select;
|
width,
|
||||||
|
value,
|
||||||
|
className,
|
||||||
|
} = 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,
|
||||||
|
}}
|
||||||
|
defaultValue={defaultValue}
|
||||||
|
value={value}
|
||||||
|
getOptionLabel={getOptionLabel}
|
||||||
|
getOptionValue={getOptionValue}
|
||||||
|
menuShouldScrollIntoView={false}
|
||||||
|
isSearchable={false}
|
||||||
|
onChange={onChange}
|
||||||
|
options={options}
|
||||||
|
placeholder={placeholder || 'Choose'}
|
||||||
|
styles={ResetStyles}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AsyncSelect extends PureComponent<CommonProps & AsyncProps> {
|
||||||
|
static defaultProps = {
|
||||||
|
width: null,
|
||||||
|
className: '',
|
||||||
|
components: {},
|
||||||
|
loadingMessage: () => 'Loading...',
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
defaultValue,
|
||||||
|
getOptionLabel,
|
||||||
|
getOptionValue,
|
||||||
|
onChange,
|
||||||
|
placeholder,
|
||||||
|
width,
|
||||||
|
value,
|
||||||
|
className,
|
||||||
|
loadOptions,
|
||||||
|
defaultOptions,
|
||||||
|
isLoading,
|
||||||
|
loadingMessage,
|
||||||
|
noOptionsMessage,
|
||||||
|
} = 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}
|
||||||
|
isSearchable={false}
|
||||||
|
onChange={onChange}
|
||||||
|
loadOptions={loadOptions}
|
||||||
|
isLoading={isLoading}
|
||||||
|
defaultOptions={defaultOptions}
|
||||||
|
placeholder={placeholder || 'Choose'}
|
||||||
|
styles={ResetStyles}
|
||||||
|
loadingMessage={loadingMessage}
|
||||||
|
noOptionsMessage={noOptionsMessage}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Select;
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
|
// 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 'app/core/components/Picker/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> {
|
|||||||
.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> {
|
|||||||
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>
|
||||||
);
|
);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
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/Picker/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 {
|
|||||||
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,10 @@ 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
|
||||||
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 +105,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 +117,9 @@ 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
|
||||||
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}
|
||||||
/>
|
/>
|
||||||
|
@ -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;
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
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/Picker/Select';
|
||||||
import UnitPicker from 'app/core/components/Picker/Unit/UnitPicker';
|
import UnitPicker from 'app/core/components/Picker/Unit/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,12 +43,10 @@ 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>
|
||||||
|
Loading…
Reference in New Issue
Block a user