diff --git a/.betterer.results b/.betterer.results index 5f5c8d7acf4..b8fea9a9d92 100644 --- a/.betterer.results +++ b/.betterer.results @@ -312,8 +312,7 @@ exports[`better eslint`] = { ], "packages/grafana-data/src/types/ScopedVars.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], - [0, 0, 0, "Unexpected any. Specify a different type.", "1"], - [0, 0, 0, "Unexpected any. Specify a different type.", "2"] + [0, 0, 0, "Unexpected any. Specify a different type.", "1"] ], "packages/grafana-data/src/types/annotations.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], diff --git a/packages/grafana-data/src/field/fieldOverrides.ts b/packages/grafana-data/src/field/fieldOverrides.ts index 95faaac51fc..9408547b269 100644 --- a/packages/grafana-data/src/field/fieldOverrides.ts +++ b/packages/grafana-data/src/field/fieldOverrides.ts @@ -413,7 +413,7 @@ export const getLinksSupplier = } } - const variables = { + const variables: ScopedVars = { ...fieldScopedVars, __value: { text: 'Value', @@ -423,10 +423,12 @@ export const getLinksSupplier = [DataLinkBuiltInVars.keepTime]: { text: timeRangeUrl, value: timeRangeUrl, + skipFormat: true, }, [DataLinkBuiltInVars.includeVars]: { text: variablesQuery, value: variablesQuery, + skipFormat: true, }, }; diff --git a/packages/grafana-data/src/types/ScopedVars.ts b/packages/grafana-data/src/types/ScopedVars.ts index 2d953c4a840..685e6e0ca62 100644 --- a/packages/grafana-data/src/types/ScopedVars.ts +++ b/packages/grafana-data/src/types/ScopedVars.ts @@ -1,7 +1,8 @@ export interface ScopedVar { text?: any; value: T; - [key: string]: any; + skipUrlSync?: boolean; + skipFormat?: boolean; } export interface ScopedVars extends Record {} diff --git a/public/app/features/dashboard/state/PanelModel.ts b/public/app/features/dashboard/state/PanelModel.ts index b01795f5126..579b003fa61 100644 --- a/public/app/features/dashboard/state/PanelModel.ts +++ b/public/app/features/dashboard/state/PanelModel.ts @@ -647,11 +647,13 @@ export class PanelModel implements DataConfigSource, IPanelModel { vars[DataLinkBuiltInVars.keepTime] = { text: timeRangeUrl, value: timeRangeUrl, + skipFormat: true, }; vars[DataLinkBuiltInVars.includeVars] = { text: variablesQuery, value: variablesQuery, + skipFormat: true, }; return getTemplateSrv().replace(value, vars, format); diff --git a/public/app/features/plugins/tests/datasource_srv.test.ts b/public/app/features/plugins/tests/datasource_srv.test.ts index 489d579dc32..6b6342a06f5 100644 --- a/public/app/features/plugins/tests/datasource_srv.test.ts +++ b/public/app/features/plugins/tests/datasource_srv.test.ts @@ -3,7 +3,7 @@ import { DataSourceInstanceSettings, DataSourcePlugin, DataSourcePluginMeta, - ScopedVar, + ScopedVars, } from '@grafana/data'; import { ExpressionDatasourceRef } from '@grafana/runtime/src/utils/DataSourceWithBackend'; import { DatasourceSrv } from 'app/features/plugins/datasource_srv'; @@ -26,7 +26,7 @@ const templateSrv: any = { }, }, ], - replace: (v: string, scopedVars: ScopedVar) => { + replace: (v: string, scopedVars: ScopedVars) => { if (scopedVars && scopedVars.datasource) { return v.replace('${datasource}', scopedVars.datasource.value); } diff --git a/public/app/features/templating/template_srv.test.ts b/public/app/features/templating/template_srv.test.ts index 26b13bcac4a..1d9459c35f3 100644 --- a/public/app/features/templating/template_srv.test.ts +++ b/public/app/features/templating/template_srv.test.ts @@ -821,6 +821,15 @@ describe('templateSrv', () => { const target = _templateSrv.replace('${adhoc}', { adhoc: { value: 'value2', text: 'value2' } }, 'queryparam'); expect(target).toBe('var-adhoc=value2'); }); + + it('Variable named ${__all_variables} is already formatted so skip any formatting', () => { + const target = _templateSrv.replace( + '${__all_variables}', + { __all_variables: { value: 'var-server=server+name+with+plus%2B', skipFormat: true } }, + 'percentencode' + ); + expect(target).toBe('var-server=server+name+with+plus%2B'); + }); }); describe('scenes compatibility', () => { diff --git a/public/app/features/templating/template_srv.ts b/public/app/features/templating/template_srv.ts index 2c6bdc79e64..59b44542dfb 100644 --- a/public/app/features/templating/template_srv.ts +++ b/public/app/features/templating/template_srv.ts @@ -295,13 +295,17 @@ export class TemplateSrv implements BaseTemplateSrv { return target.replace(this.regex, (match, var1, var2, fmt2, var3, fieldPath, fmt3) => { const variableName = var1 || var2 || var3; const variable = this.getVariableAtIndex(variableName); - const fmt = fmt2 || fmt3 || format; + let fmt = fmt2 || fmt3 || format; if (scopedVars) { const value = this.getVariableValue(variableName, fieldPath, scopedVars); const text = this.getVariableText(variableName, value, scopedVars); if (value !== null && value !== undefined) { + if (scopedVars[variableName].skipFormat) { + fmt = undefined; + } + return this.formatValue(value, fmt, variable, text); } } diff --git a/public/app/features/variables/getAllVariableValuesForUrl.test.ts b/public/app/features/variables/getAllVariableValuesForUrl.test.ts index 159ec8405d2..8ffbef97da1 100644 --- a/public/app/features/variables/getAllVariableValuesForUrl.test.ts +++ b/public/app/features/variables/getAllVariableValuesForUrl.test.ts @@ -107,7 +107,7 @@ describe('getAllVariableValuesForUrl', () => { it('should not set scoped value as url params', () => { const params = getVariablesUrlParams({ - test: { name: 'test', value: 'val1', text: 'val1text', skipUrlSync: true }, + test: { value: 'val1', text: 'val1text', skipUrlSync: true }, }); expect(params['var-test']).toBe(undefined); }); diff --git a/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchMetricsQueryRunner.test.ts b/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchMetricsQueryRunner.test.ts index 722ac0a4120..addab806a4d 100644 --- a/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchMetricsQueryRunner.test.ts +++ b/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchMetricsQueryRunner.test.ts @@ -513,8 +513,8 @@ describe('CloudWatchMetricsQueryRunner', () => { runner.handleMetricQueries(queries, { ...request, scopedVars: { - var1: { selected: true, value: 'var1-foo', text: '' }, - var2: { selected: true, value: 'var2-foo', text: '' }, + var1: { value: 'var1-foo', text: '' }, + var2: { value: 'var2-foo', text: '' }, }, }) ).toEmitValuesWith(() => { @@ -579,7 +579,7 @@ describe('CloudWatchMetricsQueryRunner', () => { runner.handleMetricQueries(queries, { ...request, scopedVars: { - var1: { selected: true, value: 'var1-foo', text: '' }, + var1: { value: 'var1-foo', text: '' }, }, }) ).toEmitValuesWith(() => {