mirror of https://github.com/grafana/grafana.git
stackdriver: add support for template variables
This commit is contained in:
parent
26b1cc5dcf
commit
0aeaec1ac6
|
|
@ -14,7 +14,7 @@ async function loadComponent(module) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @ngInject */
|
/** @ngInject */
|
||||||
function variableQueryEditorLoader() {
|
function variableQueryEditorLoader(templateSrv) {
|
||||||
return {
|
return {
|
||||||
restrict: 'E',
|
restrict: 'E',
|
||||||
link: async (scope, elem) => {
|
link: async (scope, elem) => {
|
||||||
|
|
@ -23,6 +23,7 @@ function variableQueryEditorLoader() {
|
||||||
datasource: scope.currentDatasource,
|
datasource: scope.currentDatasource,
|
||||||
query: scope.current.query,
|
query: scope.current.query,
|
||||||
onChange: scope.onQueryChange,
|
onChange: scope.onQueryChange,
|
||||||
|
templateSrv,
|
||||||
};
|
};
|
||||||
ReactDOM.render(<Component {...props} />, elem[0]);
|
ReactDOM.render(<Component {...props} />, elem[0]);
|
||||||
scope.$on('$destroy', () => {
|
scope.$on('$destroy', () => {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,12 @@
|
||||||
import isString from 'lodash/isString';
|
import isString from 'lodash/isString';
|
||||||
import { alignmentPeriods } from './constants';
|
import { alignmentPeriods } from './constants';
|
||||||
import { MetricFindQueryTypes } from './types';
|
import { MetricFindQueryTypes } from './types';
|
||||||
import { getMetricTypesByService, getAlignmentOptionsByMetric, getAggregationOptionsByMetric } from './functions';
|
import {
|
||||||
|
getMetricTypesByService,
|
||||||
|
getAlignmentOptionsByMetric,
|
||||||
|
getAggregationOptionsByMetric,
|
||||||
|
getLabelKeys,
|
||||||
|
} from './functions';
|
||||||
|
|
||||||
export default class StackdriverMetricFindQuery {
|
export default class StackdriverMetricFindQuery {
|
||||||
constructor(private datasource) {}
|
constructor(private datasource) {}
|
||||||
|
|
@ -37,37 +42,34 @@ export default class StackdriverMetricFindQuery {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const metricDescriptors = await this.datasource.getMetricTypes(this.datasource.projectName);
|
const metricDescriptors = await this.datasource.getMetricTypes(this.datasource.projectName);
|
||||||
return getMetricTypesByService(metricDescriptors, selectedService).map(s => ({
|
return getMetricTypesByService(metricDescriptors, this.datasource.templateSrv.replace(selectedService)).map(s => ({
|
||||||
text: s.displayName,
|
text: s.displayName,
|
||||||
value: s.type,
|
value: s.type,
|
||||||
expandable: true,
|
expandable: true,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleLabelKeysQuery({ selectedQueryType, selectedMetricType, labelKey }) {
|
async handleLabelKeysQuery({ selectedMetricType }) {
|
||||||
if (!selectedMetricType) {
|
if (!selectedMetricType) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const refId = 'handleLabelKeysQuery';
|
const labelKeys = await getLabelKeys(this.datasource, selectedMetricType);
|
||||||
const response = await this.datasource.getLabels(selectedMetricType, refId);
|
|
||||||
const labelKeys = response.meta
|
|
||||||
? [...Object.keys(response.meta.resourceLabels), ...Object.keys(response.meta.metricLabels)]
|
|
||||||
: [];
|
|
||||||
return labelKeys.map(this.toFindQueryResult);
|
return labelKeys.map(this.toFindQueryResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleLabelValuesQuery({ selectedQueryType, selectedMetricType, labelKey }) {
|
async handleLabelValuesQuery({ selectedMetricType, labelKey }) {
|
||||||
if (!selectedMetricType) {
|
if (!selectedMetricType) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const refId = 'handleLabelValuesQuery';
|
const refId = 'handleLabelValuesQuery';
|
||||||
const response = await this.datasource.getLabels(selectedMetricType, refId);
|
const response = await this.datasource.getLabels(selectedMetricType, refId);
|
||||||
|
const interpolatedKey = this.datasource.templateSrv.replace(labelKey);
|
||||||
|
const [name] = interpolatedKey.split('.').reverse();
|
||||||
let values = [];
|
let values = [];
|
||||||
if (response.meta && response.meta.metricLabels && response.meta.metricLabels.hasOwnProperty(labelKey)) {
|
if (response.meta && response.meta.metricLabels && response.meta.metricLabels.hasOwnProperty(name)) {
|
||||||
values = response.meta.metricLabels[labelKey];
|
values = response.meta.metricLabels[name];
|
||||||
} else if (response.meta && response.meta.resourceLabels && response.meta.resourceLabels.hasOwnProperty(labelKey)) {
|
} else if (response.meta && response.meta.resourceLabels && response.meta.resourceLabels.hasOwnProperty(name)) {
|
||||||
values = response.meta.resourceLabels[labelKey];
|
values = response.meta.resourceLabels[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
return values.map(this.toFindQueryResult);
|
return values.map(this.toFindQueryResult);
|
||||||
|
|
@ -87,7 +89,9 @@ export default class StackdriverMetricFindQuery {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const metricDescriptors = await this.datasource.getMetricTypes(this.datasource.projectName);
|
const metricDescriptors = await this.datasource.getMetricTypes(this.datasource.projectName);
|
||||||
const { valueType, metricKind } = metricDescriptors.find(m => m.type === selectedMetricType);
|
const { valueType, metricKind } = metricDescriptors.find(
|
||||||
|
m => m.type === this.datasource.templateSrv.replace(selectedMetricType)
|
||||||
|
);
|
||||||
return getAlignmentOptionsByMetric(valueType, metricKind).map(this.toFindQueryResult);
|
return getAlignmentOptionsByMetric(valueType, metricKind).map(this.toFindQueryResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,7 +100,9 @@ export default class StackdriverMetricFindQuery {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const metricDescriptors = await this.datasource.getMetricTypes(this.datasource.projectName);
|
const metricDescriptors = await this.datasource.getMetricTypes(this.datasource.projectName);
|
||||||
const { valueType, metricKind } = metricDescriptors.find(m => m.type === selectedMetricType);
|
const { valueType, metricKind } = metricDescriptors.find(
|
||||||
|
m => m.type === this.datasource.templateSrv.replace(selectedMetricType)
|
||||||
|
);
|
||||||
return getAggregationOptionsByMetric(valueType, metricKind).map(this.toFindQueryResult);
|
return getAggregationOptionsByMetric(valueType, metricKind).map(this.toFindQueryResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ const props: VariableQueryProps = {
|
||||||
datasource: {
|
datasource: {
|
||||||
getMetricTypes: async p => [],
|
getMetricTypes: async p => [],
|
||||||
},
|
},
|
||||||
|
templateSrv: { replace: s => s },
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('VariableQueryEditor', () => {
|
describe('VariableQueryEditor', () => {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import React, { PureComponent } from 'react';
|
||||||
import uniqBy from 'lodash/uniqBy';
|
import uniqBy from 'lodash/uniqBy';
|
||||||
import { VariableQueryProps } from 'app/types/plugins';
|
import { VariableQueryProps } from 'app/types/plugins';
|
||||||
import SimpleSelect from './SimpleSelect';
|
import SimpleSelect from './SimpleSelect';
|
||||||
import { getMetricTypes } from '../functions';
|
import { getMetricTypes, getLabelKeys } from '../functions';
|
||||||
import { MetricFindQueryTypes, VariableQueryData } from '../types';
|
import { MetricFindQueryTypes, VariableQueryData } from '../types';
|
||||||
|
|
||||||
export class StackdriverVariableQueryEditor extends PureComponent<VariableQueryProps, VariableQueryData> {
|
export class StackdriverVariableQueryEditor extends PureComponent<VariableQueryProps, VariableQueryData> {
|
||||||
|
|
@ -40,7 +40,7 @@ export class StackdriverVariableQueryEditor extends PureComponent<VariableQueryP
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let selectedService = '';
|
let selectedService = '';
|
||||||
if (services.some(s => s.value === this.state.selectedService)) {
|
if (services.some(s => s.value === this.props.templateSrv.replace(this.state.selectedService))) {
|
||||||
selectedService = this.state.selectedService;
|
selectedService = this.state.selectedService;
|
||||||
} else if (services && services.length > 0) {
|
} else if (services && services.length > 0) {
|
||||||
selectedService = services[0].value;
|
selectedService = services[0].value;
|
||||||
|
|
@ -49,6 +49,7 @@ export class StackdriverVariableQueryEditor extends PureComponent<VariableQueryP
|
||||||
const { metricTypes, selectedMetricType } = getMetricTypes(
|
const { metricTypes, selectedMetricType } = getMetricTypes(
|
||||||
metricDescriptors,
|
metricDescriptors,
|
||||||
this.state.selectedMetricType,
|
this.state.selectedMetricType,
|
||||||
|
this.props.templateSrv.replace(this.state.selectedMetricType),
|
||||||
selectedService
|
selectedService
|
||||||
);
|
);
|
||||||
const state: any = {
|
const state: any = {
|
||||||
|
|
@ -57,7 +58,7 @@ export class StackdriverVariableQueryEditor extends PureComponent<VariableQueryP
|
||||||
metricTypes,
|
metricTypes,
|
||||||
selectedMetricType,
|
selectedMetricType,
|
||||||
metricDescriptors,
|
metricDescriptors,
|
||||||
...await this.getLabelValues(selectedMetricType),
|
...await this.getLabels(selectedMetricType),
|
||||||
};
|
};
|
||||||
this.setState(state);
|
this.setState(state);
|
||||||
}
|
}
|
||||||
|
|
@ -65,7 +66,7 @@ export class StackdriverVariableQueryEditor extends PureComponent<VariableQueryP
|
||||||
async handleQueryTypeChange(event) {
|
async handleQueryTypeChange(event) {
|
||||||
const state: any = {
|
const state: any = {
|
||||||
selectedQueryType: event.target.value,
|
selectedQueryType: event.target.value,
|
||||||
...await this.getLabelValues(this.state.selectedMetricType, event.target.value),
|
...await this.getLabels(this.state.selectedMetricType, event.target.value),
|
||||||
};
|
};
|
||||||
this.setState(state);
|
this.setState(state);
|
||||||
}
|
}
|
||||||
|
|
@ -74,19 +75,20 @@ export class StackdriverVariableQueryEditor extends PureComponent<VariableQueryP
|
||||||
const { metricTypes, selectedMetricType } = getMetricTypes(
|
const { metricTypes, selectedMetricType } = getMetricTypes(
|
||||||
this.state.metricDescriptors,
|
this.state.metricDescriptors,
|
||||||
this.state.selectedMetricType,
|
this.state.selectedMetricType,
|
||||||
|
this.props.templateSrv.replace(this.state.selectedMetricType),
|
||||||
event.target.value
|
event.target.value
|
||||||
);
|
);
|
||||||
const state: any = {
|
const state: any = {
|
||||||
selectedService: event.target.value,
|
selectedService: event.target.value,
|
||||||
metricTypes,
|
metricTypes,
|
||||||
selectedMetricType,
|
selectedMetricType,
|
||||||
...await this.getLabelValues(selectedMetricType),
|
...await this.getLabels(selectedMetricType),
|
||||||
};
|
};
|
||||||
this.setState(state);
|
this.setState(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
async onMetricTypeChange(event) {
|
async onMetricTypeChange(event) {
|
||||||
const state: any = { selectedMetricType: event.target.value, ...await this.getLabelValues(event.target.value) };
|
const state: any = { selectedMetricType: event.target.value, ...await this.getLabels(event.target.value) };
|
||||||
this.setState(state);
|
this.setState(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -100,18 +102,23 @@ export class StackdriverVariableQueryEditor extends PureComponent<VariableQueryP
|
||||||
this.props.onChange(queryModel, `Stackdriver - ${query.name}`);
|
this.props.onChange(queryModel, `Stackdriver - ${query.name}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getLabelValues(selectedMetricType, selectedQueryType = this.state.selectedQueryType) {
|
async getLabels(selectedMetricType, selectedQueryType = this.state.selectedQueryType) {
|
||||||
let result = { labels: this.state.labels, labelKey: this.state.labelKey };
|
let result = { labels: this.state.labels, labelKey: this.state.labelKey };
|
||||||
if (selectedMetricType && selectedQueryType === MetricFindQueryTypes.LabelValues) {
|
if (selectedMetricType && selectedQueryType === MetricFindQueryTypes.LabelValues) {
|
||||||
const refId = 'StackdriverVariableQueryEditor';
|
const labels = await getLabelKeys(this.props.datasource, selectedMetricType);
|
||||||
const response = await this.props.datasource.getLabels(selectedMetricType, refId);
|
const labelKey = labels.some(l => l === this.props.templateSrv.replace(this.state.labelKey))
|
||||||
const labels = [...Object.keys(response.meta.resourceLabels), ...Object.keys(response.meta.metricLabels)];
|
? this.state.labelKey
|
||||||
const labelKey = labels.some(l => l === this.state.labelKey) ? this.state.labelKey : labels[0];
|
: labels[0];
|
||||||
result = { labels, labelKey };
|
result = { labels, labelKey };
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
insertTemplateVariables(options) {
|
||||||
|
const templateVariables = this.props.templateSrv.variables.map(v => ({ name: `$${v.name}`, value: `$${v.name}` }));
|
||||||
|
return [...templateVariables, ...options];
|
||||||
|
}
|
||||||
|
|
||||||
renderQueryTypeSwitch(queryType) {
|
renderQueryTypeSwitch(queryType) {
|
||||||
switch (queryType) {
|
switch (queryType) {
|
||||||
case MetricFindQueryTypes.MetricTypes:
|
case MetricFindQueryTypes.MetricTypes:
|
||||||
|
|
@ -136,14 +143,14 @@ export class StackdriverVariableQueryEditor extends PureComponent<VariableQueryP
|
||||||
/>
|
/>
|
||||||
<SimpleSelect
|
<SimpleSelect
|
||||||
value={this.state.selectedMetricType}
|
value={this.state.selectedMetricType}
|
||||||
options={this.state.metricTypes}
|
options={this.insertTemplateVariables(this.state.metricTypes)}
|
||||||
onValueChange={e => this.onMetricTypeChange(e)}
|
onValueChange={e => this.onMetricTypeChange(e)}
|
||||||
label="Metric Types"
|
label="Metric Types"
|
||||||
/>
|
/>
|
||||||
{queryType === MetricFindQueryTypes.LabelValues && (
|
{queryType === MetricFindQueryTypes.LabelValues && (
|
||||||
<SimpleSelect
|
<SimpleSelect
|
||||||
value={this.state.labelKey}
|
value={this.state.labelKey}
|
||||||
options={this.state.labels.map(l => ({ value: l, name: l }))}
|
options={this.insertTemplateVariables(this.state.labels.map(l => ({ value: l, name: l })))}
|
||||||
onValueChange={e => this.onLabelKeyChange(e)}
|
onValueChange={e => this.onLabelKeyChange(e)}
|
||||||
label="Label Keys"
|
label="Label Keys"
|
||||||
/>
|
/>
|
||||||
|
|
@ -162,7 +169,7 @@ export class StackdriverVariableQueryEditor extends PureComponent<VariableQueryP
|
||||||
/>
|
/>
|
||||||
<SimpleSelect
|
<SimpleSelect
|
||||||
value={this.state.selectedMetricType}
|
value={this.state.selectedMetricType}
|
||||||
options={this.state.metricTypes}
|
options={this.insertTemplateVariables(this.state.metricTypes)}
|
||||||
onValueChange={e => this.onMetricTypeChange(e)}
|
onValueChange={e => this.onMetricTypeChange(e)}
|
||||||
label="Metric Types"
|
label="Metric Types"
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,12 @@ import { alignOptions, aggOptions } from './constants';
|
||||||
export const getMetricTypesByService = (metricDescriptors, service) =>
|
export const getMetricTypesByService = (metricDescriptors, service) =>
|
||||||
metricDescriptors.filter(m => m.service === service);
|
metricDescriptors.filter(m => m.service === service);
|
||||||
|
|
||||||
export const getMetricTypes = (metricDescriptors, metricType, selectedService) => {
|
export const getMetricTypes = (metricDescriptors, metricType, interpolatedMetricType, selectedService) => {
|
||||||
const metricTypes = getMetricTypesByService(metricDescriptors, selectedService).map(m => ({
|
const metricTypes = getMetricTypesByService(metricDescriptors, selectedService).map(m => ({
|
||||||
value: m.type,
|
value: m.type,
|
||||||
name: m.displayName,
|
name: m.displayName,
|
||||||
}));
|
}));
|
||||||
const metricTypeExistInArray = metricTypes.some(m => m.value === metricType);
|
const metricTypeExistInArray = metricTypes.some(m => m.value === interpolatedMetricType);
|
||||||
const selectedMetricType = metricTypeExistInArray ? metricType : metricTypes[0].value;
|
const selectedMetricType = metricTypeExistInArray ? metricType : metricTypes[0].value;
|
||||||
return {
|
return {
|
||||||
metricTypes,
|
metricTypes,
|
||||||
|
|
@ -31,3 +31,15 @@ export const getAggregationOptionsByMetric = (valueType, metricKind) => {
|
||||||
return i.valueTypes.indexOf(valueType) !== -1 && i.metricKinds.indexOf(metricKind) !== -1;
|
return i.valueTypes.indexOf(valueType) !== -1 && i.metricKinds.indexOf(metricKind) !== -1;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getLabelKeys = async (datasource, selectedMetricType) => {
|
||||||
|
const refId = 'handleLabelKeysQuery';
|
||||||
|
const response = await datasource.getLabels(selectedMetricType, refId);
|
||||||
|
const labelKeys = response.meta
|
||||||
|
? [
|
||||||
|
...Object.keys(response.meta.resourceLabels).map(l => `resource.label.${l}`),
|
||||||
|
...Object.keys(response.meta.metricLabels).map(l => `metric.label.${l}`),
|
||||||
|
]
|
||||||
|
: [];
|
||||||
|
return labelKeys;
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,9 @@ export class StackdriverAggregationCtrl {
|
||||||
const selectedAlignment = this.alignOptions.find(
|
const selectedAlignment = this.alignOptions.find(
|
||||||
ap => ap.value === this.templateSrv.replace(this.target.aggregation.perSeriesAligner)
|
ap => ap.value === this.templateSrv.replace(this.target.aggregation.perSeriesAligner)
|
||||||
);
|
);
|
||||||
return `${kbn.secondsToHms(this.$scope.alignmentPeriod)} interval (${selectedAlignment.text})`;
|
return `${kbn.secondsToHms(this.$scope.alignmentPeriod)} interval (${
|
||||||
|
selectedAlignment ? selectedAlignment.text : ''
|
||||||
|
})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
deselectAggregationOption(notValidOptionValue: string) {
|
deselectAggregationOption(notValidOptionValue: string) {
|
||||||
|
|
|
||||||
|
|
@ -104,4 +104,5 @@ export interface VariableQueryProps {
|
||||||
query: any;
|
query: any;
|
||||||
onChange: (query: any, definition: string) => void;
|
onChange: (query: any, definition: string) => void;
|
||||||
datasource: any;
|
datasource: any;
|
||||||
|
templateSrv: any;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue