QueryGroup & DataSourceSrv & DataSourcePicker changes simplify usage, error handling and reduce duplication, support for uid (#29542)

* Starting moving more stuff into data source picker

* WIP progress

* Progress on datasource picker rethink

* Things are working now some details to figure out

* Removed commented part

* Complex work on getting data source lists

* Fixed variable support showing correct data sources

* Tried fixing dashboard import but failed

* Fixes

* Fixed import dashboard

* Fixed unit test

* Fixed explore test

* Fixed test

* Fix

* fixed more tests

* fixed more tests

* fixed showing which option is default in picker

* Changed query variable to use data source picker, updated tests and e2e

* Fixed more tests

* Updated snapshots, had wrong typescript version
This commit is contained in:
Torkel Ödegaard
2020-12-04 14:24:55 +01:00
committed by GitHub
parent c62a0aa4d0
commit 3d6380a0aa
45 changed files with 707 additions and 807 deletions

View File

@@ -3,72 +3,119 @@ import React, { PureComponent } from 'react';
// Components
import { HorizontalGroup, Select } from '@grafana/ui';
import { SelectableValue, DataSourceSelectItem } from '@grafana/data';
import { SelectableValue, DataSourceInstanceSettings } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { isUnsignedPluginSignature, PluginSignatureBadge } from '../../../features/plugins/PluginSignatureBadge';
import { getDataSourceSrv } from '@grafana/runtime';
export interface Props {
onChange: (ds: DataSourceSelectItem) => void;
datasources: DataSourceSelectItem[];
current?: DataSourceSelectItem | null;
onChange: (ds: DataSourceInstanceSettings) => void;
current: string | null;
hideTextValue?: boolean;
onBlur?: () => void;
autoFocus?: boolean;
openMenuOnFocus?: boolean;
showLoading?: boolean;
placeholder?: string;
invalid?: boolean;
tracing?: boolean;
mixed?: boolean;
dashboard?: boolean;
metrics?: boolean;
annotations?: boolean;
variables?: boolean;
pluginId?: string;
noDefault?: boolean;
}
export class DataSourcePicker extends PureComponent<Props> {
export interface State {
error?: string;
}
export class DataSourcePicker extends PureComponent<Props, State> {
dataSourceSrv = getDataSourceSrv();
static defaultProps: Partial<Props> = {
autoFocus: false,
openMenuOnFocus: false,
placeholder: 'Select datasource',
};
searchInput: HTMLElement;
state: State = {};
constructor(props: Props) {
super(props);
}
onChange = (item: SelectableValue<string>) => {
const ds = this.props.datasources.find(ds => ds.name === item.value);
componentDidMount() {
const { current } = this.props;
const dsSettings = this.dataSourceSrv.getInstanceSettings(current);
if (!dsSettings) {
this.setState({ error: 'Could not find data source ' + current });
}
}
if (ds) {
this.props.onChange(ds);
onChange = (item: SelectableValue<string>) => {
const dsSettings = this.dataSourceSrv.getInstanceSettings(item.value);
if (dsSettings) {
this.props.onChange(dsSettings);
this.setState({ error: undefined });
}
};
render() {
const {
datasources,
current,
autoFocus,
hideTextValue,
onBlur,
openMenuOnFocus,
showLoading,
placeholder,
invalid,
} = this.props;
private getCurrentValue() {
const { current, hideTextValue, noDefault } = this.props;
const options = datasources.map(ds => ({
value: ds.name,
label: ds.name,
imgUrl: ds.meta.info.logos.small,
meta: ds.meta,
}));
if (!current && noDefault) {
return null;
}
const value = current && {
label: current.name.substr(0, 37),
value: current.name,
imgUrl: current.meta.info.logos.small,
loading: showLoading,
const ds = this.dataSourceSrv.getInstanceSettings(current);
if (ds) {
return {
label: ds.name.substr(0, 37),
value: ds.name,
imgUrl: ds.meta.info.logos.small,
hideText: hideTextValue,
meta: ds.meta,
};
}
return {
label: (current ?? 'no name') + ' - not found',
value: current,
imgUrl: '',
hideText: hideTextValue,
meta: current.meta,
};
}
getDataSourceOptions() {
const { tracing, metrics, mixed, dashboard, variables, annotations, pluginId } = this.props;
const options = this.dataSourceSrv
.getList({
tracing,
metrics,
dashboard,
mixed,
variables,
annotations,
pluginId,
})
.map(ds => ({
value: ds.name,
label: `${ds.name}${ds.isDefault ? ' (default)' : ''}`,
imgUrl: ds.meta.info.logos.small,
meta: ds.meta,
}));
return options;
}
render() {
const { autoFocus, onBlur, openMenuOnFocus, placeholder } = this.props;
const { error } = this.state;
const options = this.getDataSourceOptions();
const value = this.getCurrentValue();
return (
<div aria-label={selectors.components.DataSourcePicker.container}>
@@ -87,9 +134,9 @@ export class DataSourcePicker extends PureComponent<Props> {
placeholder={placeholder}
noOptionsMessage="No datasources found"
value={value}
invalid={invalid}
invalid={!!error}
getOptionLabel={o => {
if (isUnsignedPluginSignature(o.meta.signature) && o !== value) {
if (o.meta && isUnsignedPluginSignature(o.meta.signature) && o !== value) {
return (
<HorizontalGroup align="center" justify="space-between">
<span>{o.label}</span> <PluginSignatureBadge status={o.meta.signature} />
@@ -103,5 +150,3 @@ export class DataSourcePicker extends PureComponent<Props> {
);
}
}
export default DataSourcePicker;