diff --git a/pkg/tsdb/stackdriver/stackdriver.go b/pkg/tsdb/stackdriver/stackdriver.go
index 123ab49c61e..788627598d2 100644
--- a/pkg/tsdb/stackdriver/stackdriver.go
+++ b/pkg/tsdb/stackdriver/stackdriver.go
@@ -30,9 +30,15 @@ import (
)
var (
- slog log.Logger
- legendKeyFormat *regexp.Regexp
- metricNameFormat *regexp.Regexp
+ slog log.Logger
+)
+
+var (
+ matchAllCap = regexp.MustCompile("(.)([A-Z][a-z]*)")
+ legendKeyFormat = regexp.MustCompile(`\{\{\s*(.+?)\s*\}\}`)
+ metricNameFormat = regexp.MustCompile(`([\w\d_]+)\.(googleapis\.com|io)/(.+)`)
+ wildcardRegexRe = regexp.MustCompile(`[-\/^$+?.()|[\]{}]`)
+ alignmentPeriodRe = regexp.MustCompile("[0-9]+")
)
const (
@@ -62,8 +68,6 @@ func NewStackdriverExecutor(dsInfo *models.DataSource) (tsdb.TsdbQueryEndpoint,
func init() {
slog = log.New("tsdb.stackdriver")
tsdb.RegisterTsdbQueryEndpoint("stackdriver", NewStackdriverExecutor)
- legendKeyFormat = regexp.MustCompile(`\{\{\s*(.+?)\s*\}\}`)
- metricNameFormat = regexp.MustCompile(`([\w\d_]+)\.googleapis\.com/(.+)`)
}
// Query takes in the frontend queries, parses them into the Stackdriver query format
@@ -197,8 +201,7 @@ func interpolateFilterWildcards(value string) string {
value = reverse(strings.Replace(reverse(value), "*", "", 1))
value = fmt.Sprintf(`starts_with("%s")`, value)
} else if matches != 0 {
- re := regexp.MustCompile(`[-\/^$+?.()|[\]{}]`)
- value = string(re.ReplaceAllFunc([]byte(value), func(in []byte) []byte {
+ value = string(wildcardRegexRe.ReplaceAllFunc([]byte(value), func(in []byte) []byte {
return []byte(strings.Replace(string(in), string(in), `\\`+string(in), 1))
}))
value = strings.Replace(value, "*", ".*", -1)
@@ -287,8 +290,7 @@ func (e *StackdriverExecutor) executeQuery(ctx context.Context, query *Stackdriv
alignmentPeriod, ok := req.URL.Query()["aggregation.alignmentPeriod"]
if ok {
- re := regexp.MustCompile("[0-9]+")
- seconds, err := strconv.ParseInt(re.FindString(alignmentPeriod[0]), 10, 64)
+ seconds, err := strconv.ParseInt(alignmentPeriodRe.FindString(alignmentPeriod[0]), 10, 64)
if err == nil {
queryResult.Meta.Set("alignmentPeriod", seconds)
}
@@ -333,8 +335,6 @@ func (e *StackdriverExecutor) unmarshalResponse(res *http.Response) (Stackdriver
return StackdriverResponse{}, err
}
- // slog.Info("stackdriver", "response", string(body))
-
if res.StatusCode/100 != 2 {
slog.Error("Request failed", "status", res.Status, "body", string(body))
return StackdriverResponse{}, fmt.Errorf(string(body))
@@ -351,42 +351,66 @@ func (e *StackdriverExecutor) unmarshalResponse(res *http.Response) (Stackdriver
}
func (e *StackdriverExecutor) parseResponse(queryRes *tsdb.QueryResult, data StackdriverResponse, query *StackdriverQuery) error {
- metricLabels := make(map[string][]string)
- resourceLabels := make(map[string][]string)
- var resourceTypes []string
-
- for _, series := range data.TimeSeries {
- if !containsLabel(resourceTypes, series.Resource.Type) {
- resourceTypes = append(resourceTypes, series.Resource.Type)
- }
- }
+ labels := make(map[string]map[string]bool)
for _, series := range data.TimeSeries {
points := make([]tsdb.TimePoint, 0)
-
+ seriesLabels := make(map[string]string)
defaultMetricName := series.Metric.Type
- if len(resourceTypes) > 1 {
- defaultMetricName += " " + series.Resource.Type
- }
+ labels["resource.type"] = map[string]bool{series.Resource.Type: true}
for key, value := range series.Metric.Labels {
- if !containsLabel(metricLabels[key], value) {
- metricLabels[key] = append(metricLabels[key], value)
+ if _, ok := labels["metric.label."+key]; !ok {
+ labels["metric.label."+key] = map[string]bool{}
}
+ labels["metric.label."+key][value] = true
+ seriesLabels["metric.label."+key] = value
+
if len(query.GroupBys) == 0 || containsLabel(query.GroupBys, "metric.label."+key) {
defaultMetricName += " " + value
}
}
for key, value := range series.Resource.Labels {
- if !containsLabel(resourceLabels[key], value) {
- resourceLabels[key] = append(resourceLabels[key], value)
+ if _, ok := labels["resource.label."+key]; !ok {
+ labels["resource.label."+key] = map[string]bool{}
}
+ labels["resource.label."+key][value] = true
+ seriesLabels["resource.label."+key] = value
+
if containsLabel(query.GroupBys, "resource.label."+key) {
defaultMetricName += " " + value
}
}
+ for labelType, labelTypeValues := range series.MetaData {
+ for labelKey, labelValue := range labelTypeValues {
+ key := toSnakeCase(fmt.Sprintf("metadata.%s.%s", labelType, labelKey))
+ if _, ok := labels[key]; !ok {
+ labels[key] = map[string]bool{}
+ }
+
+ switch v := labelValue.(type) {
+ case string:
+ labels[key][v] = true
+ seriesLabels[key] = v
+ case bool:
+ strVal := strconv.FormatBool(v)
+ labels[key][strVal] = true
+ seriesLabels[key] = strVal
+ case []interface{}:
+ for _, v := range v {
+ strVal := v.(string)
+ labels[key][strVal] = true
+ if len(seriesLabels[key]) > 0 {
+ strVal = fmt.Sprintf("%s, %s", seriesLabels[key], strVal)
+ }
+ seriesLabels[key] = strVal
+ }
+ }
+ }
+ }
+
// reverse the order to be ascending
if series.ValueType != "DISTRIBUTION" {
for i := len(series.Points) - 1; i >= 0; i-- {
@@ -411,7 +435,7 @@ func (e *StackdriverExecutor) parseResponse(queryRes *tsdb.QueryResult, data Sta
points = append(points, tsdb.NewTimePoint(null.FloatFrom(value), float64((point.Interval.EndTime).Unix())*1000))
}
- metricName := formatLegendKeys(series.Metric.Type, defaultMetricName, series.Resource.Type, series.Metric.Labels, series.Resource.Labels, make(map[string]string), query)
+ metricName := formatLegendKeys(series.Metric.Type, defaultMetricName, seriesLabels, nil, query)
queryRes.Series = append(queryRes.Series, &tsdb.TimeSeries{
Name: metricName,
@@ -437,7 +461,7 @@ func (e *StackdriverExecutor) parseResponse(queryRes *tsdb.QueryResult, data Sta
bucketBound := calcBucketBound(point.Value.DistributionValue.BucketOptions, i)
additionalLabels := map[string]string{"bucket": bucketBound}
buckets[i] = &tsdb.TimeSeries{
- Name: formatLegendKeys(series.Metric.Type, defaultMetricName, series.Resource.Type, series.Metric.Labels, series.Resource.Labels, additionalLabels, query),
+ Name: formatLegendKeys(series.Metric.Type, defaultMetricName, nil, additionalLabels, query),
Points: make([]tsdb.TimePoint, 0),
}
if maxKey < i {
@@ -453,7 +477,7 @@ func (e *StackdriverExecutor) parseResponse(queryRes *tsdb.QueryResult, data Sta
bucketBound := calcBucketBound(point.Value.DistributionValue.BucketOptions, i)
additionalLabels := map[string]string{"bucket": bucketBound}
buckets[i] = &tsdb.TimeSeries{
- Name: formatLegendKeys(series.Metric.Type, defaultMetricName, series.Resource.Type, series.Metric.Labels, series.Resource.Labels, additionalLabels, query),
+ Name: formatLegendKeys(series.Metric.Type, defaultMetricName, seriesLabels, additionalLabels, query),
Points: make([]tsdb.TimePoint, 0),
}
}
@@ -465,14 +489,23 @@ func (e *StackdriverExecutor) parseResponse(queryRes *tsdb.QueryResult, data Sta
}
}
- queryRes.Meta.Set("resourceLabels", resourceLabels)
- queryRes.Meta.Set("metricLabels", metricLabels)
+ labelsByKey := make(map[string][]string)
+ for key, values := range labels {
+ for value := range values {
+ labelsByKey[key] = append(labelsByKey[key], value)
+ }
+ }
+
+ queryRes.Meta.Set("labels", labelsByKey)
queryRes.Meta.Set("groupBys", query.GroupBys)
- queryRes.Meta.Set("resourceTypes", resourceTypes)
return nil
}
+func toSnakeCase(str string) string {
+ return strings.ToLower(matchAllCap.ReplaceAllString(str, "${1}_${2}"))
+}
+
func containsLabel(labels []string, newLabel string) bool {
for _, val := range labels {
if val == newLabel {
@@ -482,7 +515,7 @@ func containsLabel(labels []string, newLabel string) bool {
return false
}
-func formatLegendKeys(metricType string, defaultMetricName string, resourceType string, metricLabels map[string]string, resourceLabels map[string]string, additionalLabels map[string]string, query *StackdriverQuery) string {
+func formatLegendKeys(metricType string, defaultMetricName string, labels map[string]string, additionalLabels map[string]string, query *StackdriverQuery) string {
if query.AliasBy == "" {
return defaultMetricName
}
@@ -496,25 +529,13 @@ func formatLegendKeys(metricType string, defaultMetricName string, resourceType
return []byte(metricType)
}
- if metaPartName == "resource.type" && resourceType != "" {
- return []byte(resourceType)
- }
-
metricPart := replaceWithMetricPart(metaPartName, metricType)
if metricPart != nil {
return metricPart
}
- metaPartName = strings.Replace(metaPartName, "metric.label.", "", 1)
-
- if val, exists := metricLabels[metaPartName]; exists {
- return []byte(val)
- }
-
- metaPartName = strings.Replace(metaPartName, "resource.label.", "", 1)
-
- if val, exists := resourceLabels[metaPartName]; exists {
+ if val, exists := labels[metaPartName]; exists {
return []byte(val)
}
@@ -533,8 +554,8 @@ func replaceWithMetricPart(metaPartName string, metricType string) []byte {
shortMatches := metricNameFormat.FindStringSubmatch(metricType)
if metaPartName == "metric.name" {
- if len(shortMatches) > 0 {
- return []byte(shortMatches[2])
+ if len(shortMatches) > 2 {
+ return []byte(shortMatches[3])
}
}
diff --git a/pkg/tsdb/stackdriver/stackdriver_test.go b/pkg/tsdb/stackdriver/stackdriver_test.go
index 9d72162cf86..7ee52db2de9 100644
--- a/pkg/tsdb/stackdriver/stackdriver_test.go
+++ b/pkg/tsdb/stackdriver/stackdriver_test.go
@@ -260,22 +260,20 @@ func TestStackdriver(t *testing.T) {
})
Convey("Should add meta for labels to the response", func() {
- metricLabels := res.Meta.Get("metricLabels").Interface().(map[string][]string)
- So(metricLabels, ShouldNotBeNil)
- So(len(metricLabels["instance_name"]), ShouldEqual, 3)
- So(metricLabels["instance_name"][0], ShouldEqual, "collector-asia-east-1")
- So(metricLabels["instance_name"][1], ShouldEqual, "collector-europe-west-1")
- So(metricLabels["instance_name"][2], ShouldEqual, "collector-us-east-1")
+ labels := res.Meta.Get("labels").Interface().(map[string][]string)
+ So(labels, ShouldNotBeNil)
+ So(len(labels["metric.label.instance_name"]), ShouldEqual, 3)
+ So(labels["metric.label.instance_name"], ShouldContain, "collector-asia-east-1")
+ So(labels["metric.label.instance_name"], ShouldContain, "collector-europe-west-1")
+ So(labels["metric.label.instance_name"], ShouldContain, "collector-us-east-1")
- resourceLabels := res.Meta.Get("resourceLabels").Interface().(map[string][]string)
- So(resourceLabels, ShouldNotBeNil)
- So(len(resourceLabels["zone"]), ShouldEqual, 3)
- So(resourceLabels["zone"][0], ShouldEqual, "asia-east1-a")
- So(resourceLabels["zone"][1], ShouldEqual, "europe-west1-b")
- So(resourceLabels["zone"][2], ShouldEqual, "us-east1-b")
+ So(len(labels["resource.label.zone"]), ShouldEqual, 3)
+ So(labels["resource.label.zone"], ShouldContain, "asia-east1-a")
+ So(labels["resource.label.zone"], ShouldContain, "europe-west1-b")
+ So(labels["resource.label.zone"], ShouldContain, "us-east1-b")
- So(len(resourceLabels["project_id"]), ShouldEqual, 1)
- So(resourceLabels["project_id"][0], ShouldEqual, "grafana-prod")
+ So(len(labels["resource.label.project_id"]), ShouldEqual, 1)
+ So(labels["resource.label.project_id"][0], ShouldEqual, "grafana-prod")
})
})
@@ -419,6 +417,72 @@ func TestStackdriver(t *testing.T) {
So(res.Series[10].Points[1][0].Float64, ShouldEqual, 56)
})
})
+
+ Convey("when data from query returns metadata system labels", func() {
+ data, err := loadTestFile("./test-data/5-series-response-meta-data.json")
+ So(err, ShouldBeNil)
+ So(len(data.TimeSeries), ShouldEqual, 3)
+
+ res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"}
+ query := &StackdriverQuery{AliasBy: "{{bucket}}"}
+ err = executor.parseResponse(res, data, query)
+ labels := res.Meta.Get("labels").Interface().(map[string][]string)
+ So(err, ShouldBeNil)
+
+ So(len(res.Series), ShouldEqual, 3)
+
+ Convey("and systemlabel contains key with array of string", func() {
+ So(len(labels["metadata.system_labels.test"]), ShouldEqual, 5)
+ So(labels["metadata.system_labels.test"], ShouldContain, "value1")
+ So(labels["metadata.system_labels.test"], ShouldContain, "value2")
+ So(labels["metadata.system_labels.test"], ShouldContain, "value3")
+ So(labels["metadata.system_labels.test"], ShouldContain, "value4")
+ So(labels["metadata.system_labels.test"], ShouldContain, "value5")
+ })
+
+ Convey("and systemlabel contains key with primitive strings", func() {
+ So(len(labels["metadata.system_labels.region"]), ShouldEqual, 2)
+ So(labels["metadata.system_labels.region"], ShouldContain, "us-central1")
+ So(labels["metadata.system_labels.region"], ShouldContain, "us-west1")
+ })
+
+ Convey("and userLabel contains key with primitive strings", func() {
+ So(len(labels["metadata.user_labels.region"]), ShouldEqual, 2)
+ So(labels["metadata.user_labels.region"], ShouldContain, "region1")
+ So(labels["metadata.user_labels.region"], ShouldContain, "region3")
+
+ So(len(labels["metadata.user_labels.name"]), ShouldEqual, 2)
+ So(labels["metadata.user_labels.name"], ShouldContain, "name1")
+ So(labels["metadata.user_labels.name"], ShouldContain, "name3")
+ })
+ })
+ Convey("when data from query returns metadata system labels and alias by is defined", func() {
+ data, err := loadTestFile("./test-data/5-series-response-meta-data.json")
+ So(err, ShouldBeNil)
+ So(len(data.TimeSeries), ShouldEqual, 3)
+
+ Convey("and systemlabel contains key with array of string", func() {
+ res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"}
+ query := &StackdriverQuery{AliasBy: "{{metadata.system_labels.test}}"}
+ err = executor.parseResponse(res, data, query)
+ So(err, ShouldBeNil)
+ So(len(res.Series), ShouldEqual, 3)
+ fmt.Println(res.Series[0].Name)
+ So(res.Series[0].Name, ShouldEqual, "value1, value2")
+ So(res.Series[1].Name, ShouldEqual, "value1, value2, value3")
+ So(res.Series[2].Name, ShouldEqual, "value1, value2, value4, value5")
+ })
+
+ Convey("and systemlabel contains key with array of string2", func() {
+ res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "A"}
+ query := &StackdriverQuery{AliasBy: "{{metadata.system_labels.test2}}"}
+ err = executor.parseResponse(res, data, query)
+ So(err, ShouldBeNil)
+ So(len(res.Series), ShouldEqual, 3)
+ fmt.Println(res.Series[0].Name)
+ So(res.Series[2].Name, ShouldEqual, "testvalue")
+ })
+ })
})
Convey("when interpolating filter wildcards", func() {
diff --git a/pkg/tsdb/stackdriver/test-data/5-series-response-meta-data.json b/pkg/tsdb/stackdriver/test-data/5-series-response-meta-data.json
new file mode 100644
index 00000000000..8066d4589f2
--- /dev/null
+++ b/pkg/tsdb/stackdriver/test-data/5-series-response-meta-data.json
@@ -0,0 +1,78 @@
+{
+ "timeSeries": [{
+ "metric": {
+ "type": "compute.googleapis.com/firewall/dropped_bytes_count"
+ },
+ "resource": {
+ "type": "gce_instance",
+ "labels": {
+ "instance_id": "114250375703598695",
+ "project_id": "raintank-dev"
+ }
+ },
+ "metricKind": "DELTA",
+ "valueType": "INT64",
+ "metadata": {
+ "systemLabels": {
+ "region": "us-west1",
+ "name": "diana-debian9",
+ "test": ["value1", "value2"],
+ "spot_instance": false
+ },
+ "userLabels": {
+ "name": "name1",
+ "region": "region1"
+ }
+ }
+ },
+ {
+ "metric": {
+ "type": "compute.googleapis.com/firewall/dropped_bytes_count"
+ },
+ "resource": {
+ "type": "gce_instance",
+ "labels": {
+ "instance_id": "2268399396335228490",
+ "project_id": "raintank-dev"
+ }
+ },
+ "metricKind": "DELTA",
+ "valueType": "INT64",
+ "metadata": {
+ "systemLabels": {
+ "region": "us-west1",
+ "name": "diana-ubuntu1910",
+ "test": ["value1", "value2","value3"],
+ "spot_instance": false
+ }
+ }
+ },
+ {
+ "metric": {
+ "type": "compute.googleapis.com/firewall/dropped_bytes_count"
+ },
+ "resource": {
+ "type": "gce_instance",
+ "labels": {
+ "instance_id": "2390486324245305300",
+ "project_id": "raintank-dev"
+ }
+ },
+ "metricKind": "DELTA",
+ "valueType": "INT64",
+ "metadata": {
+ "systemLabels": {
+ "name": "premium-plugin-staging",
+ "region": "us-central1",
+ "test": ["value1", "value2","value4", "value5"],
+ "test2": ["testvalue"],
+ "spot_instance": true
+ },
+ "userLabels": {
+ "name": "name3",
+ "region": "region3"
+ }
+ }
+ }
+ ]
+}
diff --git a/pkg/tsdb/stackdriver/types.go b/pkg/tsdb/stackdriver/types.go
index e4ede41d269..a8a4661b597 100644
--- a/pkg/tsdb/stackdriver/types.go
+++ b/pkg/tsdb/stackdriver/types.go
@@ -41,8 +41,9 @@ type StackdriverResponse struct {
Type string `json:"type"`
Labels map[string]string `json:"labels"`
} `json:"resource"`
- MetricKind string `json:"metricKind"`
- ValueType string `json:"valueType"`
+ MetaData map[string]map[string]interface{} `json:"metadata"`
+ MetricKind string `json:"metricKind"`
+ ValueType string `json:"valueType"`
Points []struct {
Interval struct {
StartTime time.Time `json:"startTime"`
diff --git a/public/app/core/angular_wrappers.ts b/public/app/core/angular_wrappers.ts
index 92657fd80e7..36bf0cd9aeb 100644
--- a/public/app/core/angular_wrappers.ts
+++ b/public/app/core/angular_wrappers.ts
@@ -90,7 +90,6 @@ export function registerAngularDirectives() {
react2AngularDirective('stackdriverAnnotationQueryEditor', StackdriverAnnotationQueryEditor, [
'target',
'onQueryChange',
- 'onExecuteQuery',
['datasource', { watchDepth: 'reference' }],
['templateSrv', { watchDepth: 'reference' }],
]);
diff --git a/public/app/plugins/datasource/stackdriver/StackdriverMetricFindQuery.ts b/public/app/plugins/datasource/stackdriver/StackdriverMetricFindQuery.ts
index 3d37a952068..311be8634c9 100644
--- a/public/app/plugins/datasource/stackdriver/StackdriverMetricFindQuery.ts
+++ b/public/app/plugins/datasource/stackdriver/StackdriverMetricFindQuery.ts
@@ -77,16 +77,9 @@ export default class StackdriverMetricFindQuery {
return [];
}
const refId = 'handleLabelValuesQuery';
- const response = await this.datasource.getLabels(selectedMetricType, refId);
+ const labels = await this.datasource.getLabels(selectedMetricType, refId, [labelKey]);
const interpolatedKey = this.datasource.templateSrv.replace(labelKey);
- const [name] = interpolatedKey.split('.').reverse();
- let values = [];
- 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];
- }
-
+ const values = labels.hasOwnProperty(interpolatedKey) ? labels[interpolatedKey] : [];
return values.map(this.toFindQueryResult);
}
@@ -95,8 +88,8 @@ export default class StackdriverMetricFindQuery {
return [];
}
const refId = 'handleResourceTypeQueryQueryType';
- const response = await this.datasource.getLabels(selectedMetricType, refId);
- return response.meta.resourceTypes ? response.meta.resourceTypes.map(this.toFindQueryResult) : [];
+ const labels = await this.datasource.getLabels(selectedMetricType, refId);
+ return labels['resource.type'].map(this.toFindQueryResult);
}
async handleAlignersQuery({ selectedMetricType }: any) {
diff --git a/public/app/plugins/datasource/stackdriver/annotations_query_ctrl.ts b/public/app/plugins/datasource/stackdriver/annotations_query_ctrl.ts
index 1b37dfefe98..3968e1b1ec5 100644
--- a/public/app/plugins/datasource/stackdriver/annotations_query_ctrl.ts
+++ b/public/app/plugins/datasource/stackdriver/annotations_query_ctrl.ts
@@ -6,8 +6,7 @@ export class StackdriverAnnotationsQueryCtrl {
templateSrv: TemplateSrv;
/** @ngInject */
- constructor(templateSrv: TemplateSrv) {
- this.templateSrv = templateSrv;
+ constructor() {
this.annotation.target = this.annotation.target || {};
this.onQueryChange = this.onQueryChange.bind(this);
}
diff --git a/public/app/plugins/datasource/stackdriver/components/Aggregations.test.tsx b/public/app/plugins/datasource/stackdriver/components/Aggregations.test.tsx
index 4c81e54ab4a..ad1880e9806 100644
--- a/public/app/plugins/datasource/stackdriver/components/Aggregations.test.tsx
+++ b/public/app/plugins/datasource/stackdriver/components/Aggregations.test.tsx
@@ -16,6 +16,7 @@ const props: Props = {
crossSeriesReducer: '',
groupBys: [],
children: renderProps =>
,
+ templateVariableOptions: [],
};
describe('Aggregations', () => {
@@ -32,7 +33,7 @@ describe('Aggregations', () => {
wrapper = shallow();
});
it('', () => {
- const options = wrapper.state().aggOptions[0].options;
+ const options = wrapper.state().aggOptions;
expect(options.length).toEqual(11);
expect(options.map((o: any) => o.value)).toEqual(
expect.not.arrayContaining(['REDUCE_COUNT_TRUE', 'REDUCE_COUNT_FALSE'])
@@ -49,8 +50,7 @@ describe('Aggregations', () => {
wrapper = shallow();
});
it('', () => {
- const options = wrapper.state().aggOptions[0].options;
-
+ const options = wrapper.state().aggOptions;
expect(options.length).toEqual(10);
expect(options.map((o: any) => o.value)).toEqual(expect.arrayContaining(['REDUCE_NONE']));
});
diff --git a/public/app/plugins/datasource/stackdriver/components/Aggregations.tsx b/public/app/plugins/datasource/stackdriver/components/Aggregations.tsx
index 0ab20eb22ce..f3299bc9959 100644
--- a/public/app/plugins/datasource/stackdriver/components/Aggregations.tsx
+++ b/public/app/plugins/datasource/stackdriver/components/Aggregations.tsx
@@ -1,14 +1,13 @@
import React from 'react';
import _ from 'lodash';
-import { MetricSelect } from 'app/core/components/Select/MetricSelect';
+import { SelectableValue } from '@grafana/data';
+import { Segment } from '@grafana/ui';
import { getAggregationOptionsByMetric } from '../functions';
-import { TemplateSrv } from 'app/features/templating/template_srv';
import { ValueTypes, MetricKind } from '../constants';
export interface Props {
onChange: (metricDescriptor: any) => void;
- templateSrv: TemplateSrv;
metricDescriptor: {
valueType: string;
metricKind: string;
@@ -16,6 +15,7 @@ export interface Props {
crossSeriesReducer: string;
groupBys: string[];
children?: (renderProps: any) => JSX.Element;
+ templateVariableOptions: Array>;
}
export interface State {
@@ -40,19 +40,13 @@ export class Aggregations extends React.Component {
setAggOptions({ metricDescriptor }: Props) {
let aggOptions: any[] = [];
if (metricDescriptor) {
- aggOptions = [
- {
- label: 'Aggregations',
- expanded: true,
- options: getAggregationOptionsByMetric(
- metricDescriptor.valueType as ValueTypes,
- metricDescriptor.metricKind as MetricKind
- ).map(a => ({
- ...a,
- label: a.text,
- })),
- },
- ];
+ aggOptions = getAggregationOptionsByMetric(
+ metricDescriptor.valueType as ValueTypes,
+ metricDescriptor.metricKind as MetricKind
+ ).map(a => ({
+ ...a,
+ label: a.text,
+ }));
}
this.setState({ aggOptions });
}
@@ -65,22 +59,28 @@ export class Aggregations extends React.Component {
render() {
const { displayAdvancedOptions, aggOptions } = this.state;
- const { templateSrv, onChange, crossSeriesReducer } = this.props;
+ const { templateVariableOptions, onChange, crossSeriesReducer } = this.props;
return (
<>
-
-
-
-
+
+
onChange(value)}
+ value={[...aggOptions, ...templateVariableOptions].find(s => s.value === crossSeriesReducer)}
+ options={[
+ {
+ label: 'Template Variables',
+ options: templateVariableOptions,
+ },
+ {
+ label: 'Aggregations',
+ expanded: true,
+ options: aggOptions,
+ },
+ ]}
+ placeholder="Select Reducer"
+ >