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 */ | ||||
| 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', () => { | ||||
|  |  | |||
|  | @ -1,7 +1,12 @@ | |||
| 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; | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue