Commit 0aeaec1a by Erik Sundell

stackdriver: add support for template variables

parent 26b1cc5d
......@@ -14,7 +14,7 @@ async function loadComponent(module) {
}
/** @ngInject */
function variableQueryEditorLoader() {
function variableQueryEditorLoader(templateSrv) {
return {
restrict: 'E',
link: async (scope, elem) => {
......@@ -23,6 +23,7 @@ function variableQueryEditorLoader() {
datasource: scope.currentDatasource,
query: scope.current.query,
onChange: scope.onQueryChange,
templateSrv,
};
ReactDOM.render(<Component {...props} />, elem[0]);
scope.$on('$destroy', () => {
......
import isString from 'lodash/isString';
import { alignmentPeriods } from './constants';
import { MetricFindQueryTypes } from './types';
import { getMetricTypesByService, getAlignmentOptionsByMetric, getAggregationOptionsByMetric } from './functions';
import {
getMetricTypesByService,
getAlignmentOptionsByMetric,
getAggregationOptionsByMetric,
getLabelKeys,
} from './functions';
export default class StackdriverMetricFindQuery {
constructor(private datasource) {}
......@@ -37,37 +42,34 @@ export default class StackdriverMetricFindQuery {
return [];
}
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,
value: s.type,
expandable: true,
}));
}
async handleLabelKeysQuery({ selectedQueryType, selectedMetricType, labelKey }) {
async handleLabelKeysQuery({ selectedMetricType }) {
if (!selectedMetricType) {
return [];
}
const refId = 'handleLabelKeysQuery';
const response = await this.datasource.getLabels(selectedMetricType, refId);
const labelKeys = response.meta
? [...Object.keys(response.meta.resourceLabels), ...Object.keys(response.meta.metricLabels)]
: [];
const labelKeys = await getLabelKeys(this.datasource, selectedMetricType);
return labelKeys.map(this.toFindQueryResult);
}
async handleLabelValuesQuery({ selectedQueryType, selectedMetricType, labelKey }) {
async handleLabelValuesQuery({ selectedMetricType, labelKey }) {
if (!selectedMetricType) {
return [];
}
const refId = 'handleLabelValuesQuery';
const response = await this.datasource.getLabels(selectedMetricType, refId);
const interpolatedKey = this.datasource.templateSrv.replace(labelKey);
const [name] = interpolatedKey.split('.').reverse();
let values = [];
if (response.meta && response.meta.metricLabels && response.meta.metricLabels.hasOwnProperty(labelKey)) {
values = response.meta.metricLabels[labelKey];
} else if (response.meta && response.meta.resourceLabels && response.meta.resourceLabels.hasOwnProperty(labelKey)) {
values = response.meta.resourceLabels[labelKey];
if (response.meta && response.meta.metricLabels && response.meta.metricLabels.hasOwnProperty(name)) {
values = response.meta.metricLabels[name];
} else if (response.meta && response.meta.resourceLabels && response.meta.resourceLabels.hasOwnProperty(name)) {
values = response.meta.resourceLabels[name];
}
return values.map(this.toFindQueryResult);
......@@ -87,7 +89,9 @@ export default class StackdriverMetricFindQuery {
return [];
}
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);
}
......@@ -96,7 +100,9 @@ export default class StackdriverMetricFindQuery {
return [];
}
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);
}
......
......@@ -14,6 +14,7 @@ const props: VariableQueryProps = {
datasource: {
getMetricTypes: async p => [],
},
templateSrv: { replace: s => s },
};
describe('VariableQueryEditor', () => {
......
......@@ -2,7 +2,7 @@ import React, { PureComponent } from 'react';
import uniqBy from 'lodash/uniqBy';
import { VariableQueryProps } from 'app/types/plugins';
import SimpleSelect from './SimpleSelect';
import { getMetricTypes } from '../functions';
import { getMetricTypes, getLabelKeys } from '../functions';
import { MetricFindQueryTypes, VariableQueryData } from '../types';
export class StackdriverVariableQueryEditor extends PureComponent<VariableQueryProps, VariableQueryData> {
......@@ -40,7 +40,7 @@ export class StackdriverVariableQueryEditor extends PureComponent<VariableQueryP
}));
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;
} else if (services && services.length > 0) {
selectedService = services[0].value;
......@@ -49,6 +49,7 @@ export class StackdriverVariableQueryEditor extends PureComponent<VariableQueryP
const { metricTypes, selectedMetricType } = getMetricTypes(
metricDescriptors,
this.state.selectedMetricType,
this.props.templateSrv.replace(this.state.selectedMetricType),
selectedService
);
const state: any = {
......@@ -57,7 +58,7 @@ export class StackdriverVariableQueryEditor extends PureComponent<VariableQueryP
metricTypes,
selectedMetricType,
metricDescriptors,
...await this.getLabelValues(selectedMetricType),
...await this.getLabels(selectedMetricType),
};
this.setState(state);
}
......@@ -65,7 +66,7 @@ export class StackdriverVariableQueryEditor extends PureComponent<VariableQueryP
async handleQueryTypeChange(event) {
const state: any = {
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);
}
......@@ -74,19 +75,20 @@ export class StackdriverVariableQueryEditor extends PureComponent<VariableQueryP
const { metricTypes, selectedMetricType } = getMetricTypes(
this.state.metricDescriptors,
this.state.selectedMetricType,
this.props.templateSrv.replace(this.state.selectedMetricType),
event.target.value
);
const state: any = {
selectedService: event.target.value,
metricTypes,
selectedMetricType,
...await this.getLabelValues(selectedMetricType),
...await this.getLabels(selectedMetricType),
};
this.setState(state);
}
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);
}
......@@ -100,18 +102,23 @@ export class StackdriverVariableQueryEditor extends PureComponent<VariableQueryP
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 };
if (selectedMetricType && selectedQueryType === MetricFindQueryTypes.LabelValues) {
const refId = 'StackdriverVariableQueryEditor';
const response = await this.props.datasource.getLabels(selectedMetricType, refId);
const labels = [...Object.keys(response.meta.resourceLabels), ...Object.keys(response.meta.metricLabels)];
const labelKey = labels.some(l => l === this.state.labelKey) ? this.state.labelKey : labels[0];
const labels = await getLabelKeys(this.props.datasource, selectedMetricType);
const labelKey = labels.some(l => l === this.props.templateSrv.replace(this.state.labelKey))
? this.state.labelKey
: labels[0];
result = { labels, labelKey };
}
return result;
}
insertTemplateVariables(options) {
const templateVariables = this.props.templateSrv.variables.map(v => ({ name: `$${v.name}`, value: `$${v.name}` }));
return [...templateVariables, ...options];
}
renderQueryTypeSwitch(queryType) {
switch (queryType) {
case MetricFindQueryTypes.MetricTypes:
......@@ -136,14 +143,14 @@ export class StackdriverVariableQueryEditor extends PureComponent<VariableQueryP
/>
<SimpleSelect
value={this.state.selectedMetricType}
options={this.state.metricTypes}
options={this.insertTemplateVariables(this.state.metricTypes)}
onValueChange={e => this.onMetricTypeChange(e)}
label="Metric Types"
/>
{queryType === MetricFindQueryTypes.LabelValues && (
<SimpleSelect
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)}
label="Label Keys"
/>
......@@ -162,7 +169,7 @@ export class StackdriverVariableQueryEditor extends PureComponent<VariableQueryP
/>
<SimpleSelect
value={this.state.selectedMetricType}
options={this.state.metricTypes}
options={this.insertTemplateVariables(this.state.metricTypes)}
onValueChange={e => this.onMetricTypeChange(e)}
label="Metric Types"
/>
......
......@@ -3,12 +3,12 @@ import { alignOptions, aggOptions } from './constants';
export const getMetricTypesByService = (metricDescriptors, 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 => ({
value: m.type,
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;
return {
metricTypes,
......@@ -31,3 +31,15 @@ export const getAggregationOptionsByMetric = (valueType, metricKind) => {
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(
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) {
......
......@@ -104,4 +104,5 @@ export interface VariableQueryProps {
query: any;
onChange: (query: any, definition: string) => void;
datasource: any;
templateSrv: any;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment