diff --git a/public/app/core/components/Select/DataSourcePicker.tsx b/public/app/core/components/Select/DataSourcePicker.tsx index 3086d4fb1f3..d54941e003b 100644 --- a/public/app/core/components/Select/DataSourcePicker.tsx +++ b/public/app/core/components/Select/DataSourcePicker.tsx @@ -15,6 +15,7 @@ export interface Props { openMenuOnFocus?: boolean; showLoading?: boolean; placeholder?: string; + invalid?: boolean; } export class DataSourcePicker extends PureComponent { @@ -48,6 +49,7 @@ export class DataSourcePicker extends PureComponent { openMenuOnFocus, showLoading, placeholder, + invalid, } = this.props; const options = datasources.map(ds => ({ @@ -80,6 +82,7 @@ export class DataSourcePicker extends PureComponent { placeholder={placeholder} noOptionsMessage="No datasources found" value={value} + invalid={invalid} /> ); } diff --git a/public/app/features/dashboard/panel_editor/QueriesTab.tsx b/public/app/features/dashboard/panel_editor/QueriesTab.tsx index cbb374c3682..e2ccc3f35b3 100644 --- a/public/app/features/dashboard/panel_editor/QueriesTab.tsx +++ b/public/app/features/dashboard/panel_editor/QueriesTab.tsx @@ -3,7 +3,7 @@ import React, { PureComponent } from 'react'; // Components import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker'; import { QueryOptions } from './QueryOptions'; -import { Button, CustomScrollbar, HorizontalGroup, Modal, stylesFactory } from '@grafana/ui'; +import { Button, CustomScrollbar, HorizontalGroup, Modal, stylesFactory, Field } from '@grafana/ui'; import { getLocationSrv, getDataSourceSrv } from '@grafana/runtime'; import { QueryEditorRows } from './QueryEditorRows'; // Services @@ -37,6 +37,7 @@ interface Props { interface State { dataSource?: DataSourceApi; dataSourceItem: DataSourceSelectItem; + dataSourceError?: string; helpContent: JSX.Element; isLoadingHelp: boolean; isPickerOpen: boolean; @@ -74,8 +75,14 @@ export class QueriesTab extends PureComponent { next: (data: PanelData) => this.onPanelDataUpdate(data), }); - const ds = await getDataSourceSrv().get(panel.datasource); - this.setState({ dataSource: ds }); + try { + const ds = await getDataSourceSrv().get(panel.datasource); + this.setState({ dataSource: ds }); + } catch (error) { + const ds = await getDataSourceSrv().get(); + const dataSourceItem = this.findCurrentDataSource(ds.name); + this.setState({ dataSource: ds, dataSourceError: error?.message, dataSourceItem }); + } } componentWillUnmount() { @@ -89,9 +96,8 @@ export class QueriesTab extends PureComponent { this.setState({ data }); } - findCurrentDataSource(): DataSourceSelectItem { - const { panel } = this.props; - return this.datasources.find(datasource => datasource.value === panel.datasource) || this.datasources[0]; + findCurrentDataSource(dataSourceName: string = this.props.panel.datasource): DataSourceSelectItem { + return this.datasources.find(datasource => datasource.value === dataSourceName) || this.datasources[0]; } onChangeDataSource = async (newDsItem: DataSourceSelectItem) => { @@ -132,6 +138,7 @@ export class QueriesTab extends PureComponent { { dataSourceItem: newDsItem, dataSource: dataSource, + dataSourceError: undefined, }, () => panel.refresh() ); @@ -179,7 +186,7 @@ export class QueriesTab extends PureComponent { renderTopSection(styles: QueriesTabStyls) { const { panel } = this.props; - const { dataSourceItem, data, dataSource } = this.state; + const { dataSourceItem, data, dataSource, dataSourceError } = this.state; if (!dataSource) { return null; @@ -189,11 +196,13 @@ export class QueriesTab extends PureComponent {
- + + +