Add on datasource change to optional components -- alt -- (#40239)

* Add onDataSourceChange to optional components

- Fixes a bug where the user can select  twice and overwrite all queries
- Adds handler to control main datasoruce selection to the optional components.

* only pass onDatasource change when necessary
pull/40404/head
Travis Patterson 4 years ago committed by GitHub
parent c4ce7a40af
commit 3fb8b87972
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 30
      public/app/core/utils/query.ts
  2. 1
      public/app/features/query/components/QueryActionComponent.ts
  3. 2
      public/app/features/query/components/QueryEditorRow.tsx
  4. 68
      public/app/features/query/components/QueryGroup.tsx

@ -1,4 +1,4 @@
import { DataQuery } from '@grafana/data'; import { DataQuery, DataSourceInstanceSettings } from '@grafana/data';
export const getNextRefIdChar = (queries: DataQuery[]): string => { export const getNextRefIdChar = (queries: DataQuery[]): string => {
for (let num = 0; ; num++) { for (let num = 0; ; num++) {
@ -9,13 +9,39 @@ export const getNextRefIdChar = (queries: DataQuery[]): string => {
} }
}; };
export function addQuery(queries: DataQuery[], query?: Partial<DataQuery>): DataQuery[] { export function addQuery(queries: DataQuery[], query?: Partial<DataQuery>, datasource?: string): DataQuery[] {
const q = query || {}; const q = query || {};
q.refId = getNextRefIdChar(queries); q.refId = getNextRefIdChar(queries);
q.hide = false; q.hide = false;
if (!q.datasource && datasource) {
q.datasource = datasource;
}
return [...queries, q as DataQuery]; return [...queries, q as DataQuery];
} }
export function updateQueries(
newSettings: DataSourceInstanceSettings,
queries: DataQuery[],
extensionID: string, // pass this in because importing it creates a circular dependency
dsSettings?: DataSourceInstanceSettings
): DataQuery[] {
if (!newSettings.meta.mixed && dsSettings?.meta.mixed) {
return queries.map((q) => {
if (q.datasource !== extensionID) {
q.datasource = newSettings.name;
}
return q;
});
} else if (!newSettings.meta.mixed && dsSettings?.meta.id !== newSettings.meta.id) {
// we are changing data source type, clear queries
return [{ refId: 'A', datasource: newSettings.name }];
}
return queries;
}
export function isDataQuery(url: string): boolean { export function isDataQuery(url: string): boolean {
if ( if (
url.indexOf('api/datasources/proxy') !== -1 || url.indexOf('api/datasources/proxy') !== -1 ||

@ -4,6 +4,7 @@ interface ActionComponentProps {
query?: DataQuery; query?: DataQuery;
queries?: Array<Partial<DataQuery>>; queries?: Array<Partial<DataQuery>>;
onAddQuery?: (q: DataQuery) => void; onAddQuery?: (q: DataQuery) => void;
onChangeDataSource?: (ds: DataSourceInstanceSettings) => void;
timeRange?: TimeRange; timeRange?: TimeRange;
dataSource?: DataSourceInstanceSettings; dataSource?: DataSourceInstanceSettings;
} }

@ -1,7 +1,7 @@
// Libraries // Libraries
import React, { PureComponent, ReactNode } from 'react'; import React, { PureComponent, ReactNode } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { has, cloneDeep } from 'lodash'; import { cloneDeep, has } from 'lodash';
// Utils & Services // Utils & Services
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
import { AngularComponent, getAngularLoader } from '@grafana/runtime'; import { AngularComponent, getAngularLoader } from '@grafana/runtime';

@ -12,7 +12,7 @@ import {
stylesFactory, stylesFactory,
Tooltip, Tooltip,
} from '@grafana/ui'; } from '@grafana/ui';
import { getDataSourceSrv, DataSourcePicker } from '@grafana/runtime'; import { DataSourcePicker, getDataSourceSrv } from '@grafana/runtime';
import { QueryEditorRows } from './QueryEditorRows'; import { QueryEditorRows } from './QueryEditorRows';
// Services // Services
import { backendSrv } from 'app/core/services/backend_srv'; import { backendSrv } from 'app/core/services/backend_srv';
@ -27,12 +27,9 @@ import {
PanelData, PanelData,
} from '@grafana/data'; } from '@grafana/data';
import { PluginHelp } from 'app/core/components/PluginHelp/PluginHelp'; import { PluginHelp } from 'app/core/components/PluginHelp/PluginHelp';
import { addQuery } from 'app/core/utils/query'; import { addQuery, updateQueries } from 'app/core/utils/query';
import { Unsubscribable } from 'rxjs'; import { Unsubscribable } from 'rxjs';
import { import { dataSource as expressionDatasource } from 'app/features/expressions/ExpressionDatasource';
dataSource as expressionDatasource,
ExpressionDatasourceID,
} from 'app/features/expressions/ExpressionDatasource';
import { selectors } from '@grafana/e2e-selectors'; import { selectors } from '@grafana/e2e-selectors';
import { PanelQueryRunner } from '../state/PanelQueryRunner'; import { PanelQueryRunner } from '../state/PanelQueryRunner';
import { QueryGroupOptionsEditor } from './QueryGroupOptions'; import { QueryGroupOptionsEditor } from './QueryGroupOptions';
@ -52,6 +49,7 @@ interface Props {
interface State { interface State {
dataSource?: DataSourceApi; dataSource?: DataSourceApi;
dsSettings?: DataSourceInstanceSettings; dsSettings?: DataSourceInstanceSettings;
queries: DataQuery[];
helpContent: React.ReactNode; helpContent: React.ReactNode;
isLoadingHelp: boolean; isLoadingHelp: boolean;
isPickerOpen: boolean; isPickerOpen: boolean;
@ -74,6 +72,7 @@ export class QueryGroup extends PureComponent<Props, State> {
isAddingMixed: false, isAddingMixed: false,
isHelpOpen: false, isHelpOpen: false,
scrollTop: 0, scrollTop: 0,
queries: [],
data: { data: {
state: LoadingState.NotStarted, state: LoadingState.NotStarted,
series: [], series: [],
@ -92,7 +91,8 @@ export class QueryGroup extends PureComponent<Props, State> {
const ds = await this.dataSourceSrv.get(options.dataSource.name); const ds = await this.dataSourceSrv.get(options.dataSource.name);
const dsSettings = this.dataSourceSrv.getInstanceSettings(options.dataSource.name); const dsSettings = this.dataSourceSrv.getInstanceSettings(options.dataSource.name);
const defaultDataSource = await this.dataSourceSrv.get(); const defaultDataSource = await this.dataSourceSrv.get();
this.setState({ dataSource: ds, dsSettings, defaultDataSource }); const queries = options.queries.map((q) => (q.datasource ? q : { ...q, datasource: dsSettings?.name }));
this.setState({ queries, dataSource: ds, dsSettings, defaultDataSource });
} catch (error) { } catch (error) {
console.log('failed to load data source', error); console.log('failed to load data source', error);
} }
@ -110,36 +110,10 @@ export class QueryGroup extends PureComponent<Props, State> {
} }
onChangeDataSource = async (newSettings: DataSourceInstanceSettings) => { onChangeDataSource = async (newSettings: DataSourceInstanceSettings) => {
let { queries } = this.props.options;
const { dsSettings } = this.state; const { dsSettings } = this.state;
const queries = updateQueries(newSettings, this.state.queries, expressionDatasource.name, dsSettings);
// switching to mixed
if (newSettings.meta.mixed) {
for (const query of queries) {
if (query.datasource !== ExpressionDatasourceID) {
query.datasource = dsSettings?.name;
if (!query.datasource) {
query.datasource = config.defaultDatasource;
}
}
}
} else if (dsSettings) {
// if switching from mixed
if (dsSettings.meta.mixed) {
// Remove the explicit datasource
for (const query of queries) {
if (query.datasource !== ExpressionDatasourceID) {
delete query.datasource;
}
}
} else if (dsSettings.meta.id !== newSettings.meta.id) {
// we are changing data source type, clear queries
queries = [{ refId: 'A' }];
}
}
const dataSource = await this.dataSourceSrv.get(newSettings.name); const dataSource = await this.dataSourceSrv.get(newSettings.name);
this.onChange({ this.onChange({
queries, queries,
dataSource: { dataSource: {
@ -150,14 +124,15 @@ export class QueryGroup extends PureComponent<Props, State> {
}); });
this.setState({ this.setState({
queries,
dataSource: dataSource, dataSource: dataSource,
dsSettings: newSettings, dsSettings: newSettings,
}); });
}; };
onAddQueryClick = () => { onAddQueryClick = () => {
const { options } = this.props; const { queries } = this.state;
this.onChange({ queries: addQuery(options.queries, this.newQuery()) }); this.onQueriesChange(addQuery(queries, this.newQuery()));
this.onScrollBottom(); this.onScrollBottom();
}; };
@ -165,7 +140,7 @@ export class QueryGroup extends PureComponent<Props, State> {
const { dsSettings, defaultDataSource } = this.state; const { dsSettings, defaultDataSource } = this.state;
if (!dsSettings?.meta.mixed) { if (!dsSettings?.meta.mixed) {
return {}; return { datasource: dsSettings?.name };
} }
return { return {
@ -181,9 +156,7 @@ export class QueryGroup extends PureComponent<Props, State> {
} }
onAddExpressionClick = () => { onAddExpressionClick = () => {
this.onChange({ this.onQueriesChange(addQuery(this.state.queries, expressionDatasource.newQuery()));
queries: addQuery(this.props.options.queries, expressionDatasource.newQuery()),
});
this.onScrollBottom(); this.onScrollBottom();
}; };
@ -284,8 +257,8 @@ export class QueryGroup extends PureComponent<Props, State> {
}; };
onAddQuery = (query: Partial<DataQuery>) => { onAddQuery = (query: Partial<DataQuery>) => {
const { queries } = this.props.options; const { dsSettings, queries } = this.state;
this.onChange({ queries: addQuery(queries, query) }); this.onQueriesChange(addQuery(queries, query, dsSettings?.name));
this.onScrollBottom(); this.onScrollBottom();
}; };
@ -295,16 +268,17 @@ export class QueryGroup extends PureComponent<Props, State> {
onQueriesChange = (queries: DataQuery[]) => { onQueriesChange = (queries: DataQuery[]) => {
this.onChange({ queries }); this.onChange({ queries });
this.setState({ queries });
}; };
renderQueries(dsSettings: DataSourceInstanceSettings) { renderQueries(dsSettings: DataSourceInstanceSettings) {
const { options, onRunQueries } = this.props; const { onRunQueries } = this.props;
const { data } = this.state; const { data, queries } = this.state;
if (isSharedDashboardQuery(dsSettings.name)) { if (isSharedDashboardQuery(dsSettings.name)) {
return ( return (
<DashboardQueryEditor <DashboardQueryEditor
queries={options.queries} queries={queries}
panelData={data} panelData={data}
onChange={this.onQueriesChange} onChange={this.onQueriesChange}
onRunQueries={onRunQueries} onRunQueries={onRunQueries}
@ -315,7 +289,7 @@ export class QueryGroup extends PureComponent<Props, State> {
return ( return (
<div aria-label={selectors.components.QueryTab.content}> <div aria-label={selectors.components.QueryTab.content}>
<QueryEditorRows <QueryEditorRows
queries={options.queries} queries={queries}
dsSettings={dsSettings} dsSettings={dsSettings}
onQueriesChange={this.onQueriesChange} onQueriesChange={this.onQueriesChange}
onAddQuery={this.onAddQuery} onAddQuery={this.onAddQuery}
@ -332,7 +306,7 @@ export class QueryGroup extends PureComponent<Props, State> {
renderExtraActions() { renderExtraActions() {
return GroupActionComponents.getAllExtraRenderAction().map((c) => { return GroupActionComponents.getAllExtraRenderAction().map((c) => {
return React.createElement(c, { onAddQuery: this.onAddQuery }); return React.createElement(c, { onAddQuery: this.onAddQuery, onChangeDataSource: this.onChangeDataSource });
}); });
} }

Loading…
Cancel
Save