diff --git a/public/app/features/templating/DefaultTemplateQueryComponent.tsx b/public/app/features/templating/DefaultTemplateQueryComponent.tsx index 88e2b82c7e7..cd4c5adf157 100644 --- a/public/app/features/templating/DefaultTemplateQueryComponent.tsx +++ b/public/app/features/templating/DefaultTemplateQueryComponent.tsx @@ -1,11 +1,7 @@ import React, { PureComponent } from 'react'; +import { TemplateQueryProps } from 'app/types/plugins'; -interface Props { - query: string; - onChange: (c: string) => void; -} - -export default class DefaultTemplateQueryComponent extends PureComponent { +export default class DefaultTemplateQueryComponent extends PureComponent { constructor(props) { super(props); this.state = { value: props.query }; diff --git a/public/app/features/templating/editor_ctrl.ts b/public/app/features/templating/editor_ctrl.ts index 6bdd71620b3..aef5f5ee502 100644 --- a/public/app/features/templating/editor_ctrl.ts +++ b/public/app/features/templating/editor_ctrl.ts @@ -72,6 +72,7 @@ export class VariableEditorCtrl { if ( $scope.current.type === 'query' && + _.isString($scope.current.query) && $scope.current.query.match(new RegExp('\\$' + $scope.current.name + '(/| |$)')) ) { appEvents.emit('alert-warning', [ diff --git a/public/app/plugins/datasource/stackdriver/StackdriverMetricFindQuery.ts b/public/app/plugins/datasource/stackdriver/StackdriverMetricFindQuery.ts new file mode 100644 index 00000000000..abe88131cc7 --- /dev/null +++ b/public/app/plugins/datasource/stackdriver/StackdriverMetricFindQuery.ts @@ -0,0 +1,36 @@ +import { extractServicesFromMetricDescriptors, getMetricTypesByService } from './functions'; + +export default class StackdriverMetricFindQuery { + constructor(private datasource) {} + + async query(query: any) { + switch (query.type) { + case 'services': + return this.handleServiceQueryType(); + case 'metricTypes': + return this.handleMetricTypesQueryType(query); + default: + return []; + } + } + + async handleServiceQueryType() { + const metricDescriptors = await this.datasource.getMetricTypes(this.datasource.projectName); + const services = extractServicesFromMetricDescriptors(metricDescriptors); + return services.map(s => ({ + text: s.name, + expandable: true, + })); + } + + async handleMetricTypesQueryType({ service }) { + if (!service) { + return []; + } + const metricDescriptors = await this.datasource.getMetricTypes(this.datasource.projectName); + return getMetricTypesByService(metricDescriptors, service).map(s => ({ + text: s.name, + expandable: true, + })); + } +} diff --git a/public/app/plugins/datasource/stackdriver/components/MetricTypeSelector.tsx b/public/app/plugins/datasource/stackdriver/components/MetricTypeSelector.tsx index cf25a100747..9aa3f9de6cb 100644 --- a/public/app/plugins/datasource/stackdriver/components/MetricTypeSelector.tsx +++ b/public/app/plugins/datasource/stackdriver/components/MetricTypeSelector.tsx @@ -1,4 +1,5 @@ import React, { SFC } from 'react'; +import { getMetricTypesByService } from '../functions'; interface Props { onMetricTypeChange: any; @@ -12,7 +13,7 @@ const MetricTypeSelector: SFC = props => { return []; } - return props.metricDescriptors.filter(m => m.service === props.selectedService).map(m => ({ + return getMetricTypesByService(props.metricDescriptors, props.selectedService).map(m => ({ value: m.service, name: m.displayName, })); diff --git a/public/app/plugins/datasource/stackdriver/components/ServiceSelector.tsx b/public/app/plugins/datasource/stackdriver/components/ServiceSelector.tsx index 44cf6122ebf..6bb29a46a6a 100644 --- a/public/app/plugins/datasource/stackdriver/components/ServiceSelector.tsx +++ b/public/app/plugins/datasource/stackdriver/components/ServiceSelector.tsx @@ -1,5 +1,5 @@ import React, { SFC } from 'react'; -import uniqBy from 'lodash/uniqBy'; +import { extractServicesFromMetricDescriptors } from '../functions'; interface Props { onServiceChange: any; @@ -7,11 +7,12 @@ interface Props { } const ServiceSelector: SFC = props => { - const extractServices = () => - uniqBy(props.metricDescriptors, 'service').map(m => ({ + const extractServices = () => { + return extractServicesFromMetricDescriptors(props.metricDescriptors).map(m => ({ value: m.service, name: m.serviceShortName, })); + }; return (
diff --git a/public/app/plugins/datasource/stackdriver/components/TemplateQueryComponent.tsx b/public/app/plugins/datasource/stackdriver/components/TemplateQueryComponent.tsx index a0ca1ad422e..95cd9cd6c64 100644 --- a/public/app/plugins/datasource/stackdriver/components/TemplateQueryComponent.tsx +++ b/public/app/plugins/datasource/stackdriver/components/TemplateQueryComponent.tsx @@ -1,27 +1,24 @@ import React, { PureComponent } from 'react'; -import StackdriverDatasource from '../datasource'; +// import StackdriverDatasource from '../datasource'; import ServiceSelector from './ServiceSelector'; import MetricTypeSelector from './MetricTypeSelector'; +import { TemplateQueryProps } from 'app/types/plugins'; +import defaultsDeep from 'lodash/defaultsDeep'; -interface Props { - datasource: StackdriverDatasource; - query: any; - onChange: (c: string) => void; -} - -export class StackdriverTemplateQueryComponent extends PureComponent { +export class StackdriverTemplateQueryComponent extends PureComponent { queryTypes: Array<{ value: string; name: string }> = [ { value: 'services', name: 'Services' }, { value: 'metricTypes', name: 'Metric Types' }, { value: 'metricLabels', name: 'Metric labels For Metric Type' }, ]; + defaults = { type: undefined, metricDescriptors: [], service: undefined, metricType: undefined }; - constructor(props) { + constructor(props: TemplateQueryProps) { super(props); this.handleQueryTypeChange = this.handleQueryTypeChange.bind(this); this.onServiceChange = this.onServiceChange.bind(this); this.onMetricTypeChange = this.onMetricTypeChange.bind(this); - this.state = { queryType: undefined, metricDescriptors: [], service: undefined, metricType: undefined }; + this.state = defaultsDeep(this.props.query, this.defaults); } async componentDidMount() { @@ -30,7 +27,7 @@ export class StackdriverTemplateQueryComponent extends PureComponent } handleQueryTypeChange(event) { - this.setState({ queryType: event.target.value }); + this.setState({ type: event.target.value }); } onServiceChange(event) { @@ -41,6 +38,11 @@ export class StackdriverTemplateQueryComponent extends PureComponent this.setState({ metricType: event.target.value }); } + componentDidUpdate() { + const { metricDescriptors, ...queryModel } = this.state; + this.props.onChange(queryModel); + } + renderSwitch(queryType) { switch (queryType) { case 'metricTypes': @@ -78,7 +80,7 @@ export class StackdriverTemplateQueryComponent extends PureComponent
- {this.renderSwitch(this.state.queryType)} + {this.renderSwitch(this.state.type)} ); } diff --git a/public/app/plugins/datasource/stackdriver/datasource.ts b/public/app/plugins/datasource/stackdriver/datasource.ts index 034333cbb86..d04e571b616 100644 --- a/public/app/plugins/datasource/stackdriver/datasource.ts +++ b/public/app/plugins/datasource/stackdriver/datasource.ts @@ -1,6 +1,7 @@ import { stackdriverUnitMappings } from './constants'; import appEvents from 'app/core/app_events'; import _ from 'lodash'; +import StackdriverMetricFindQuery from './StackdriverMetricFindQuery'; export default class StackdriverDatasource { id: number; @@ -9,6 +10,7 @@ export default class StackdriverDatasource { projectName: string; authenticationType: string; queryPromise: Promise; + metricTypes: any[]; /** @ngInject */ constructor(instanceSettings, private backendSrv, private templateSrv, private timeSrv) { @@ -18,6 +20,7 @@ export default class StackdriverDatasource { this.id = instanceSettings.id; this.projectName = instanceSettings.jsonData.defaultProject || ''; this.authenticationType = instanceSettings.jsonData.authenticationType || 'jwt'; + this.metricTypes = []; } async getTimeSeries(options) { @@ -177,8 +180,10 @@ export default class StackdriverDatasource { return results; } - metricFindQuery(query) { - throw new Error('Template variables support is not yet imlemented'); + async metricFindQuery(query) { + const stackdriverMetricFindQuery = new StackdriverMetricFindQuery(this); + return stackdriverMetricFindQuery.query(query); + // throw new Error('Template variables support is not yet imlemented'); } async testDatasource() { @@ -258,19 +263,21 @@ export default class StackdriverDatasource { async getMetricTypes(projectName: string) { try { - const metricsApiPath = `v3/projects/${projectName}/metricDescriptors`; - const { data } = await this.doRequest(`${this.baseUrl}${metricsApiPath}`); + if (this.metricTypes.length === 0) { + const metricsApiPath = `v3/projects/${projectName}/metricDescriptors`; + const { data } = await this.doRequest(`${this.baseUrl}${metricsApiPath}`); - const metrics = data.metricDescriptors.map(m => { - const [service] = m.type.split('/'); - const [serviceShortName] = service.split('.'); - m.service = service; - m.serviceShortName = serviceShortName; - m.displayName = m.displayName || m.type; - return m; - }); + this.metricTypes = data.metricDescriptors.map(m => { + const [service] = m.type.split('/'); + const [serviceShortName] = service.split('.'); + m.service = service; + m.serviceShortName = serviceShortName; + m.displayName = m.displayName || m.type; + return m; + }); + } - return metrics; + return this.metricTypes; } catch (error) { appEvents.emit('ds-request-error', this.formatStackdriverError(error)); return []; diff --git a/public/app/plugins/datasource/stackdriver/functions.ts b/public/app/plugins/datasource/stackdriver/functions.ts new file mode 100644 index 00000000000..15e84f050e8 --- /dev/null +++ b/public/app/plugins/datasource/stackdriver/functions.ts @@ -0,0 +1,6 @@ +import uniqBy from 'lodash/uniqBy'; + +export const extractServicesFromMetricDescriptors = metricDescriptors => uniqBy(metricDescriptors, 'service'); + +export const getMetricTypesByService = (metricDescriptors, service) => + metricDescriptors.filter(m => m.service === service); diff --git a/public/app/types/plugins.ts b/public/app/types/plugins.ts index 4d6ad6584c6..eb8ff5dcaf2 100644 --- a/public/app/types/plugins.ts +++ b/public/app/types/plugins.ts @@ -99,3 +99,10 @@ export interface PluginsState { hasFetched: boolean; dashboards: PluginDashboard[]; } + +export interface TemplateQueryProps { + query: any; + onChange: (c: any) => void; + datasource: any; + // datasource: StackdriverDatasource; +}