fix template variable handling

This commit is contained in:
Isabella Siu
2022-04-22 17:29:18 -04:00
parent 3dceca881a
commit 8597728ecb
3 changed files with 74 additions and 15 deletions
@@ -9,7 +9,11 @@ import { CustomVariableModel } from 'app/features/variables/types';
import { TemplateSrvMock } from '../../../../features/templating/template_srv.mock';
import { CloudWatchDatasource } from '../datasource';
export function setupMockedDataSource({ data = [], variables }: { data?: any; variables?: any } = {}) {
export function setupMockedDataSource({
data = [],
variables,
mockGetVariableName = true,
}: { data?: any; variables?: any; mockGetVariableName?: boolean } = {}) {
let templateService = new TemplateSrvMock({
region: 'templatedRegion',
fields: 'templatedField',
@@ -19,7 +23,9 @@ export function setupMockedDataSource({ data = [], variables }: { data?: any; va
templateService = new TemplateSrv();
templateService.init(variables);
templateService.getVariables = jest.fn().mockReturnValue(variables);
templateService.getVariableName = (name: string) => name;
if (mockGetVariableName) {
templateService.getVariableName = (name: string) => name;
}
}
const datasource = new CloudWatchDatasource(
@@ -125,3 +131,19 @@ export const aggregationvariable: CustomVariableModel = {
],
multi: false,
};
export const dimensionVariable: CustomVariableModel = {
...initialCustomVariableModelState,
id: 'dimension',
name: 'dimension',
current: {
value: 'env',
text: 'env',
selected: true,
},
options: [
{ value: 'env', text: 'env', selected: false },
{ value: 'tag', text: 'tag', selected: false },
],
multi: false,
};
@@ -5,6 +5,7 @@ import { ArrayVector, DataFrame, dataFrameToJSON, dateTime, Field, MutableDataFr
import { setDataSourceSrv } from '@grafana/runtime';
import {
dimensionVariable,
labelsVariable,
limitVariable,
metricVariable,
@@ -398,6 +399,19 @@ describe('datasource', () => {
});
});
describe('convertMultiFiltersFormat', () => {
const ds = setupMockedDataSource({ variables: [labelsVariable, dimensionVariable], mockGetVariableName: false });
it('converts keys and values correctly', () => {
// the json in this line doesn't matter, but it makes sure that old queries will be parsed
const filters = { $dimension: ['b'], a: ['${labels:json}', 'bar'] };
const result = ds.datasource.convertMultiFilterFormat(filters);
expect(result).toStrictEqual({
env: ['b'],
a: ['InstanceId', 'InstanceType', 'bar'],
});
});
});
describe('getLogGroupFields', () => {
it('passes region correctly', async () => {
const { datasource, fetchMock } = setupMockedDataSource();
@@ -54,6 +54,7 @@ import {
MetricQuery,
MetricQueryType,
MetricRequest,
MultiFilters,
StartQueryRequest,
TSDBResponse,
} from './types';
@@ -720,7 +721,7 @@ export class CloudWatchDatasource
return this.doMetricResourceRequest('ec2-instance-attribute', {
region: this.templateSrv.replace(this.getActualRegion(region)),
attributeName: this.templateSrv.replace(attributeName),
filters: JSON.stringify(filters),
filters: JSON.stringify(this.convertMultiFilterFormat(filters, 'filter key')),
});
}
@@ -728,7 +729,7 @@ export class CloudWatchDatasource
return this.doMetricResourceRequest('resource-arns', {
region: this.templateSrv.replace(this.getActualRegion(region)),
resourceType: this.templateSrv.replace(resourceType),
tags: JSON.stringify(tags),
tags: JSON.stringify(this.convertMultiFilterFormat(tags, 'tag name')),
});
}
@@ -836,18 +837,40 @@ export class CloudWatchDatasource
return { ...result, [key]: null };
}
const valueVar = this.templateSrv
.getVariables()
.find(({ name }) => name === this.templateSrv.getVariableName(value));
if (valueVar) {
if ((valueVar as unknown as VariableWithMultiSupport).multi) {
const values = this.templateSrv.replace(value, scopedVars, 'pipe').split('|');
return { ...result, [key]: values };
}
return { ...result, [key]: [this.templateSrv.replace(value, scopedVars)] };
}
const newValues = this.getVariableValue(value, scopedVars);
return { ...result, [key]: newValues };
}, {});
}
return { ...result, [key]: [value] };
// get the value for a given template variable
getVariableValue(value: string, scopedVars: ScopedVars): string[] {
const variableName = this.templateSrv.getVariableName(value);
const valueVar = this.templateSrv.getVariables().find(({ name }) => {
return name === variableName;
});
if (variableName && valueVar) {
if ((valueVar as unknown as VariableWithMultiSupport).multi) {
// rebuild the variable name to handle old migrated queries
const values = this.templateSrv.replace('$' + variableName, scopedVars, 'pipe').split('|');
return values;
}
return [this.templateSrv.replace(value, scopedVars)];
}
return [value];
}
convertMultiFilterFormat(multiFilters: MultiFilters, fieldName?: string) {
return Object.entries(multiFilters).reduce((result, [key, values]) => {
key = this.replace(key, {}, true, fieldName);
if (!values) {
return { ...result, [key]: null };
}
const initialVal: string[] = [];
const newValues = values.reduce((result, value) => {
const vals = this.getVariableValue(value, {});
return [...result, ...vals];
}, initialVal);
return { ...result, [key]: newValues };
}, {});
}