mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Variables: Adds new Api that allows proper QueryEditors for Query variables (#28217)
* Initial * WIP * wip * Refactor: fixing types * Refactor: Fixed more typings * Feature: Moves TestData to new API * Feature: Moves CloudMonitoringDatasource to new API * Feature: Moves PrometheusDatasource to new Variables API * Refactor: Clean up comments * Refactor: changes to QueryEditorProps instead * Refactor: cleans up testdata, prometheus and cloud monitoring variable support * Refactor: adds variableQueryRunner * Refactor: adds props to VariableQueryEditor * Refactor: reverted Loki editor * Refactor: refactor queryrunner into smaller pieces * Refactor: adds upgrade query thunk * Tests: Updates old tests * Docs: fixes build errors for exported api * Tests: adds guard tests * Tests: adds QueryRunner tests * Tests: fixes broken tests * Tests: adds variableQueryObserver tests * Test: adds tests for operator functions * Test: adds VariableQueryRunner tests * Refactor: renames dataSource * Refactor: adds definition for standard variable support * Refactor: adds cancellation to OptionPicker * Refactor: changes according to Dominiks suggestion * Refactor:tt * Refactor: adds tests for factories * Refactor: restructuring a bit * Refactor: renames variableQueryRunner.ts * Refactor: adds quick exit when runRequest returns errors * Refactor: using TextArea from grafana/ui * Refactor: changed from interfaces to classes instead * Tests: fixes broken test * Docs: fixes doc issue count * Docs: fixes doc issue count * Refactor: Adds check for self referencing queries * Tests: fixed unused variable * Refactor: Changes comments
This commit is contained in:
@@ -1,15 +1,15 @@
|
||||
import React from 'react';
|
||||
import { LegacyForms } from '@grafana/ui';
|
||||
const { Input } = LegacyForms;
|
||||
|
||||
import { TemplateSrv } from '@grafana/runtime';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
|
||||
import CloudMonitoringDatasource from '../datasource';
|
||||
import { Metrics, LabelFilter, AnnotationsHelp, Project } from './';
|
||||
import { AnnotationsHelp, LabelFilter, Metrics, Project } from './';
|
||||
import { toOption } from '../functions';
|
||||
import { AnnotationTarget, MetricDescriptor } from '../types';
|
||||
|
||||
const { Input } = LegacyForms;
|
||||
|
||||
export interface Props {
|
||||
onQueryChange: (target: AnnotationTarget) => void;
|
||||
target: AnnotationTarget;
|
||||
@@ -52,7 +52,7 @@ export class AnnotationQueryEditor extends React.Component<Props, State> {
|
||||
|
||||
const variableOptionGroup = {
|
||||
label: 'Template Variables',
|
||||
options: datasource.variables.map(toOption),
|
||||
options: datasource.getVariables().map(toOption),
|
||||
};
|
||||
|
||||
const projects = await datasource.getProjects();
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { CoreEvents } from 'app/types';
|
||||
import { MetricQueryEditor, QueryTypeSelector, SLOQueryEditor, Help } from './';
|
||||
import { Help, MetricQueryEditor, QueryTypeSelector, SLOQueryEditor } from './';
|
||||
import { CloudMonitoringQuery, MetricQuery, QueryType, SLOQuery } from '../types';
|
||||
import { defaultQuery } from './MetricQueryEditor';
|
||||
import { defaultQuery as defaultSLOQuery } from './SLOQueryEditor';
|
||||
import { toOption, formatCloudMonitoringError } from '../functions';
|
||||
import { formatCloudMonitoringError, toOption } from '../functions';
|
||||
import CloudMonitoringDatasource from '../datasource';
|
||||
import { ExploreQueryFieldProps } from '@grafana/data';
|
||||
|
||||
@@ -71,7 +71,7 @@ export class QueryEditor extends PureComponent<Props, State> {
|
||||
const variableOptionGroup = {
|
||||
label: 'Template Variables',
|
||||
expanded: false,
|
||||
options: datasource.variables.map(toOption),
|
||||
options: datasource.getVariables().map(toOption),
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,42 +1,38 @@
|
||||
import React from 'react';
|
||||
// @ts-ignore
|
||||
import renderer from 'react-test-renderer';
|
||||
import { CloudMonitoringVariableQueryEditor } from './VariableQueryEditor';
|
||||
import { VariableQueryProps } from 'app/types/plugins';
|
||||
import { MetricFindQueryTypes } from '../types';
|
||||
import { VariableModel } from 'app/features/variables/types';
|
||||
import { CloudMonitoringVariableQueryEditor, Props } from './VariableQueryEditor';
|
||||
import { CloudMonitoringVariableQuery, MetricFindQueryTypes } from '../types';
|
||||
import CloudMonitoringDatasource from '../datasource';
|
||||
import { VariableModel } from '@grafana/data';
|
||||
|
||||
jest.mock('../functions', () => ({
|
||||
getMetricTypes: (): any => ({ metricTypes: [], selectedMetricType: '' }),
|
||||
extractServicesFromMetricDescriptors: (): any[] => [],
|
||||
}));
|
||||
|
||||
jest.mock('../../../../core/config', () => {
|
||||
console.warn('[This test uses old variable system, needs a rewrite]');
|
||||
const original = jest.requireActual('../../../../core/config');
|
||||
const config = original.getConfig();
|
||||
jest.mock('@grafana/runtime', () => {
|
||||
const original = jest.requireActual('@grafana/runtime');
|
||||
return {
|
||||
getConfig: () => ({
|
||||
...config,
|
||||
featureToggles: {
|
||||
...config.featureToggles,
|
||||
newVariables: false,
|
||||
},
|
||||
...original,
|
||||
getTemplateSrv: () => ({
|
||||
replace: (s: string) => s,
|
||||
getVariables: () => ([] as unknown) as VariableModel[],
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
const props: VariableQueryProps = {
|
||||
onChange: (query, definition) => {},
|
||||
query: {},
|
||||
datasource: {
|
||||
const props: Props = {
|
||||
onChange: query => {},
|
||||
query: ({} as unknown) as CloudMonitoringVariableQuery,
|
||||
datasource: ({
|
||||
getDefaultProject: () => '',
|
||||
getProjects: async () => Promise.resolve([]),
|
||||
getMetricTypes: async (projectName: string) => Promise.resolve([]),
|
||||
getSLOServices: async (projectName: string, serviceId: string) => Promise.resolve([]),
|
||||
getSLOServices: async (projectName: string) => Promise.resolve([]),
|
||||
getServiceLevelObjectives: (projectName: string, serviceId: string) => Promise.resolve([]),
|
||||
},
|
||||
templateSrv: { replace: (s: string) => s, getVariables: () => ([] as unknown) as VariableModel[] },
|
||||
} as unknown) as CloudMonitoringDatasource,
|
||||
onRunQuery: () => {},
|
||||
};
|
||||
|
||||
describe('VariableQueryEditor', () => {
|
||||
@@ -46,10 +42,9 @@ describe('VariableQueryEditor', () => {
|
||||
});
|
||||
|
||||
describe('and a new variable is created', () => {
|
||||
// these test need to be updated to reflect the changes from old variables system to new
|
||||
it('should trigger a query using the first query type in the array', done => {
|
||||
props.onChange = (query, definition) => {
|
||||
expect(definition).toBe('Google Cloud Monitoring - Projects');
|
||||
props.onChange = query => {
|
||||
expect(query.selectedQueryType).toBe('projects');
|
||||
done();
|
||||
};
|
||||
renderer.create(<CloudMonitoringVariableQueryEditor {...props} />).toJSON();
|
||||
@@ -57,11 +52,10 @@ describe('VariableQueryEditor', () => {
|
||||
});
|
||||
|
||||
describe('and an existing variable is edited', () => {
|
||||
// these test need to be updated to reflect the changes from old variables system to new
|
||||
it('should trigger new query using the saved query type', done => {
|
||||
props.query = { selectedQueryType: MetricFindQueryTypes.LabelKeys };
|
||||
props.onChange = (query, definition) => {
|
||||
expect(definition).toBe('Google Cloud Monitoring - Label Keys');
|
||||
props.query = ({ selectedQueryType: MetricFindQueryTypes.LabelKeys } as unknown) as CloudMonitoringVariableQuery;
|
||||
props.onChange = query => {
|
||||
expect(query.selectedQueryType).toBe('labelKeys');
|
||||
done();
|
||||
};
|
||||
renderer.create(<CloudMonitoringVariableQueryEditor {...props} />).toJSON();
|
||||
|
||||
@@ -1,10 +1,26 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { VariableQueryProps } from 'app/types/plugins';
|
||||
import { SimpleSelect } from './';
|
||||
import { extractServicesFromMetricDescriptors, getLabelKeys, getMetricTypes } from '../functions';
|
||||
import { MetricFindQueryTypes, VariableQueryData } from '../types';
|
||||
import {
|
||||
CloudMonitoringOptions,
|
||||
CloudMonitoringQuery,
|
||||
CloudMonitoringVariableQuery,
|
||||
MetricDescriptor,
|
||||
MetricFindQueryTypes,
|
||||
VariableQueryData,
|
||||
} from '../types';
|
||||
import CloudMonitoringDatasource from '../datasource';
|
||||
import { getTemplateSrv } from '@grafana/runtime';
|
||||
import { QueryEditorProps } from '@grafana/data';
|
||||
|
||||
export class CloudMonitoringVariableQueryEditor extends PureComponent<VariableQueryProps, VariableQueryData> {
|
||||
export type Props = QueryEditorProps<
|
||||
CloudMonitoringDatasource,
|
||||
CloudMonitoringQuery,
|
||||
CloudMonitoringOptions,
|
||||
CloudMonitoringVariableQuery
|
||||
>;
|
||||
|
||||
export class CloudMonitoringVariableQueryEditor extends PureComponent<Props, VariableQueryData> {
|
||||
queryTypes: Array<{ value: string; name: string }> = [
|
||||
{ value: MetricFindQueryTypes.Projects, name: 'Projects' },
|
||||
{ value: MetricFindQueryTypes.Services, name: 'Services' },
|
||||
@@ -36,7 +52,7 @@ export class CloudMonitoringVariableQueryEditor extends PureComponent<VariableQu
|
||||
loading: true,
|
||||
};
|
||||
|
||||
constructor(props: VariableQueryProps) {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = Object.assign(
|
||||
this.defaults,
|
||||
@@ -46,7 +62,7 @@ export class CloudMonitoringVariableQueryEditor extends PureComponent<VariableQu
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
const projects = await this.props.datasource.getProjects();
|
||||
const projects = (await this.props.datasource.getProjects()) as MetricDescriptor[];
|
||||
const metricDescriptors = await this.props.datasource.getMetricTypes(
|
||||
this.props.query.projectName || this.props.datasource.getDefaultProject()
|
||||
);
|
||||
@@ -56,7 +72,7 @@ export class CloudMonitoringVariableQueryEditor extends PureComponent<VariableQu
|
||||
}));
|
||||
|
||||
let selectedService = '';
|
||||
if (services.some(s => s.value === this.props.templateSrv.replace(this.state.selectedService))) {
|
||||
if (services.some(s => s.value === getTemplateSrv().replace(this.state.selectedService))) {
|
||||
selectedService = this.state.selectedService;
|
||||
} else if (services && services.length > 0) {
|
||||
selectedService = services[0].value;
|
||||
@@ -65,8 +81,8 @@ export class CloudMonitoringVariableQueryEditor extends PureComponent<VariableQu
|
||||
const { metricTypes, selectedMetricType } = getMetricTypes(
|
||||
metricDescriptors,
|
||||
this.state.selectedMetricType,
|
||||
this.props.templateSrv.replace(this.state.selectedMetricType),
|
||||
this.props.templateSrv.replace(selectedService)
|
||||
getTemplateSrv().replace(this.state.selectedMetricType),
|
||||
getTemplateSrv().replace(selectedService)
|
||||
);
|
||||
|
||||
const sloServices = await this.props.datasource.getSLOServices(this.state.projectName);
|
||||
@@ -87,8 +103,7 @@ export class CloudMonitoringVariableQueryEditor extends PureComponent<VariableQu
|
||||
|
||||
onPropsChange = () => {
|
||||
const { metricDescriptors, labels, metricTypes, services, ...queryModel } = this.state;
|
||||
const query = this.queryTypes.find(q => q.value === this.state.selectedQueryType)!;
|
||||
this.props.onChange(queryModel, `Google Cloud Monitoring - ${query.name}`);
|
||||
this.props.onChange({ ...queryModel, refId: 'CloudMonitoringVariableQueryEditor-VariableQuery' });
|
||||
};
|
||||
|
||||
async onQueryTypeChange(queryType: string) {
|
||||
@@ -106,8 +121,8 @@ export class CloudMonitoringVariableQueryEditor extends PureComponent<VariableQu
|
||||
const { metricTypes, selectedMetricType } = getMetricTypes(
|
||||
metricDescriptors,
|
||||
this.state.selectedMetricType,
|
||||
this.props.templateSrv.replace(this.state.selectedMetricType),
|
||||
this.props.templateSrv.replace(this.state.selectedService)
|
||||
getTemplateSrv().replace(this.state.selectedMetricType),
|
||||
getTemplateSrv().replace(this.state.selectedService)
|
||||
);
|
||||
|
||||
const sloServices = await this.props.datasource.getSLOServices(projectName);
|
||||
@@ -126,8 +141,8 @@ export class CloudMonitoringVariableQueryEditor extends PureComponent<VariableQu
|
||||
const { metricTypes, selectedMetricType } = getMetricTypes(
|
||||
this.state.metricDescriptors,
|
||||
this.state.selectedMetricType,
|
||||
this.props.templateSrv.replace(this.state.selectedMetricType),
|
||||
this.props.templateSrv.replace(service)
|
||||
getTemplateSrv().replace(this.state.selectedMetricType),
|
||||
getTemplateSrv().replace(service)
|
||||
);
|
||||
const state: any = {
|
||||
selectedService: service,
|
||||
@@ -150,7 +165,7 @@ export class CloudMonitoringVariableQueryEditor extends PureComponent<VariableQu
|
||||
this.setState({ labelKey }, () => this.onPropsChange());
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: Readonly<VariableQueryProps>, prevState: Readonly<VariableQueryData>) {
|
||||
componentDidUpdate(prevProps: Readonly<Props>, prevState: Readonly<VariableQueryData>) {
|
||||
const selecQueryTypeChanged = prevState.selectedQueryType !== this.state.selectedQueryType;
|
||||
const selectSLOServiceChanged = this.state.selectedSLOService !== prevState.selectedSLOService;
|
||||
if (selecQueryTypeChanged || selectSLOServiceChanged) {
|
||||
@@ -162,7 +177,7 @@ export class CloudMonitoringVariableQueryEditor extends PureComponent<VariableQu
|
||||
let result = { labels: this.state.labels, labelKey: this.state.labelKey };
|
||||
if (selectedMetricType && selectedQueryType === MetricFindQueryTypes.LabelValues) {
|
||||
const labels = await getLabelKeys(this.props.datasource, selectedMetricType, projectName);
|
||||
const labelKey = labels.some(l => l === this.props.templateSrv.replace(this.state.labelKey))
|
||||
const labelKey = labels.some(l => l === getTemplateSrv().replace(this.state.labelKey))
|
||||
? this.state.labelKey
|
||||
: labels[0];
|
||||
result = { labels, labelKey };
|
||||
@@ -171,10 +186,12 @@ export class CloudMonitoringVariableQueryEditor extends PureComponent<VariableQu
|
||||
}
|
||||
|
||||
insertTemplateVariables(options: any) {
|
||||
const templateVariables = this.props.templateSrv.getVariables().map((v: any) => ({
|
||||
name: `$${v.name}`,
|
||||
value: `$${v.name}`,
|
||||
}));
|
||||
const templateVariables = getTemplateSrv()
|
||||
.getVariables()
|
||||
.map((v: any) => ({
|
||||
name: `$${v.name}`,
|
||||
value: `$${v.name}`,
|
||||
}));
|
||||
return [...templateVariables, ...options];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user