mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
explore using data source picker
This commit is contained in:
parent
24825dc899
commit
ae76ddcc3b
@ -75,6 +75,7 @@ export default class PermissionsListItem extends PureComponent<Props> {
|
|||||||
<td>
|
<td>
|
||||||
<div className="gf-form">
|
<div className="gf-form">
|
||||||
<Select
|
<Select
|
||||||
|
isSearchable={false}
|
||||||
options={dashboardPermissionLevels}
|
options={dashboardPermissionLevels}
|
||||||
onChange={this.onPermissionChanged}
|
onChange={this.onPermissionChanged}
|
||||||
isDisabled={item.inherited}
|
isDisabled={item.inherited}
|
||||||
|
@ -3,16 +3,13 @@ import React, { PureComponent } from 'react';
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
import ResetStyles from 'app/core/components/Select/ResetStyles';
|
import Select from './Select';
|
||||||
import { Option, SingleValue } from 'app/core/components/Select/PickerOption';
|
|
||||||
import IndicatorsContainer from 'app/core/components/Select/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> {
|
|||||||
|
|
||||||
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,18 @@ 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`}
|
|
||||||
isMulti={false}
|
isMulti={false}
|
||||||
menuShouldScrollIntoView={false}
|
backspaceRemovesValue={false}
|
||||||
isClearable={false}
|
isClearable={false}
|
||||||
className="gf-form-input gf-form-input--form-dropdown ds-picker"
|
onChange={this.onChange}
|
||||||
onChange={item => this.onChange(item)}
|
|
||||||
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>
|
||||||
);
|
);
|
@ -29,7 +29,16 @@ interface CommonProps {
|
|||||||
className?: string;
|
className?: string;
|
||||||
components: object;
|
components: object;
|
||||||
isDisabled?: boolean;
|
isDisabled?: boolean;
|
||||||
isSearchable: boolean;
|
isSearchable?: boolean;
|
||||||
|
isClearable?: boolean;
|
||||||
|
autoFocus?: boolean;
|
||||||
|
openMenuOnFocus?: boolean;
|
||||||
|
onBlur?: () => void;
|
||||||
|
maxMenuHeight?: number;
|
||||||
|
isLoading: boolean;
|
||||||
|
noOptionsMessage?: () => string;
|
||||||
|
isMulti?: boolean;
|
||||||
|
backspaceRemovesValue: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SelectProps {
|
interface SelectProps {
|
||||||
@ -39,9 +48,7 @@ interface SelectProps {
|
|||||||
interface AsyncProps {
|
interface AsyncProps {
|
||||||
defaultOptions: boolean;
|
defaultOptions: boolean;
|
||||||
loadOptions: (query: string) => Promise<SelectOptionItem[]>;
|
loadOptions: (query: string) => Promise<SelectOptionItem[]>;
|
||||||
isLoading: boolean;
|
|
||||||
loadingMessage?: () => string;
|
loadingMessage?: () => string;
|
||||||
noOptionsMessage?: () => string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Select extends PureComponent<CommonProps & SelectProps> {
|
export class Select extends PureComponent<CommonProps & SelectProps> {
|
||||||
@ -51,6 +58,13 @@ export class Select extends PureComponent<CommonProps & SelectProps> {
|
|||||||
components: {},
|
components: {},
|
||||||
isDisabled: false,
|
isDisabled: false,
|
||||||
isSearchable: true,
|
isSearchable: true,
|
||||||
|
isClearable: false,
|
||||||
|
isMulti: false,
|
||||||
|
openMenuOnFocus: false,
|
||||||
|
autoFocus: false,
|
||||||
|
isLoading: false,
|
||||||
|
backspaceRemovesValue: true,
|
||||||
|
maxMenuHeight: 300,
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -65,7 +79,16 @@ export class Select extends PureComponent<CommonProps & SelectProps> {
|
|||||||
value,
|
value,
|
||||||
className,
|
className,
|
||||||
isDisabled,
|
isDisabled,
|
||||||
isSearchable
|
isLoading,
|
||||||
|
isSearchable,
|
||||||
|
isClearable,
|
||||||
|
backspaceRemovesValue,
|
||||||
|
isMulti,
|
||||||
|
autoFocus,
|
||||||
|
openMenuOnFocus,
|
||||||
|
onBlur,
|
||||||
|
maxMenuHeight,
|
||||||
|
noOptionsMessage,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
let widthClass = '';
|
let widthClass = '';
|
||||||
@ -95,6 +118,15 @@ export class Select extends PureComponent<CommonProps & SelectProps> {
|
|||||||
placeholder={placeholder || 'Choose'}
|
placeholder={placeholder || 'Choose'}
|
||||||
styles={ResetStyles}
|
styles={ResetStyles}
|
||||||
isDisabled={isDisabled}
|
isDisabled={isDisabled}
|
||||||
|
isLoading={isLoading}
|
||||||
|
isClearable={isClearable}
|
||||||
|
autoFocus={autoFocus}
|
||||||
|
onBlur={onBlur}
|
||||||
|
openMenuOnFocus={openMenuOnFocus}
|
||||||
|
maxMenuHeight={maxMenuHeight}
|
||||||
|
noOptionsMessage={noOptionsMessage}
|
||||||
|
isMulti={isMulti}
|
||||||
|
backspaceRemovesValue={backspaceRemovesValue}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -107,7 +139,13 @@ export class AsyncSelect extends PureComponent<CommonProps & AsyncProps> {
|
|||||||
components: {},
|
components: {},
|
||||||
loadingMessage: () => 'Loading...',
|
loadingMessage: () => 'Loading...',
|
||||||
isDisabled: false,
|
isDisabled: false,
|
||||||
|
isClearable: false,
|
||||||
|
isMulti: false,
|
||||||
isSearchable: true,
|
isSearchable: true,
|
||||||
|
backspaceRemovesValue: true,
|
||||||
|
autoFocus: false,
|
||||||
|
openMenuOnFocus: false,
|
||||||
|
maxMenuHeight: 300,
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -127,6 +165,13 @@ export class AsyncSelect extends PureComponent<CommonProps & AsyncProps> {
|
|||||||
noOptionsMessage,
|
noOptionsMessage,
|
||||||
isDisabled,
|
isDisabled,
|
||||||
isSearchable,
|
isSearchable,
|
||||||
|
isClearable,
|
||||||
|
backspaceRemovesValue,
|
||||||
|
autoFocus,
|
||||||
|
onBlur,
|
||||||
|
openMenuOnFocus,
|
||||||
|
maxMenuHeight,
|
||||||
|
isMulti,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
let widthClass = '';
|
let widthClass = '';
|
||||||
@ -161,6 +206,13 @@ export class AsyncSelect extends PureComponent<CommonProps & AsyncProps> {
|
|||||||
noOptionsMessage={noOptionsMessage}
|
noOptionsMessage={noOptionsMessage}
|
||||||
isDisabled={isDisabled}
|
isDisabled={isDisabled}
|
||||||
isSearchable={isSearchable}
|
isSearchable={isSearchable}
|
||||||
|
isClearable={isClearable}
|
||||||
|
autoFocus={autoFocus}
|
||||||
|
onBlur={onBlur}
|
||||||
|
openMenuOnFocus={openMenuOnFocus}
|
||||||
|
maxMenuHeight={maxMenuHeight}
|
||||||
|
isMulti={isMulti}
|
||||||
|
backspaceRemovesValue={backspaceRemovesValue}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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> {
|
|||||||
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}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
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 {
|
|||||||
makeTimeSeriesList,
|
makeTimeSeriesList,
|
||||||
updateHistory,
|
updateHistory,
|
||||||
} from 'app/core/utils/explore';
|
} from 'app/core/utils/explore';
|
||||||
import ResetStyles from 'app/core/components/Select/ResetStyles';
|
import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker';
|
||||||
import PickerOption from 'app/core/components/Select/PickerOption';
|
|
||||||
import IndicatorsContainer from 'app/core/components/Select/IndicatorsContainer';
|
|
||||||
import NoOptionsMessage from 'app/core/components/Select/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> {
|
|||||||
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> {
|
|||||||
} = 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> {
|
|||||||
)}
|
)}
|
||||||
{!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}
|
||||||
|
@ -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 {
|
|||||||
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 {
|
|||||||
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[];
|
||||||
|
@ -116,7 +116,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 +125,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user