DataLinks: Fix bug where links which use built in variables could be hidden (#71372)

This commit is contained in:
Andrej Ocenas 2023-07-13 14:38:07 +02:00 committed by GitHub
parent ceb702b96a
commit 7ccd73c9ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 42 additions and 58 deletions

View File

@ -644,86 +644,47 @@ describe('explore links utils', () => {
});
describe('getVariableUsageInfo', () => {
it('returns true when query contains variables and all variables are used', () => {
const dataLink = {
function makeDataLinkWithQuery(query: string): DataLink {
return {
url: '',
title: '',
internal: {
datasourceUid: 'uid',
datasourceName: 'dsName',
query: { query: 'test ${testVal}' },
query: { query },
},
};
}
function allVariablesDefinedInQuery(query: string) {
const scopedVars = {
testVal: { text: '', value: 'val1' },
};
const dataLinkRtnVal = getVariableUsageInfo(dataLink, scopedVars).allVariablesDefined;
return getVariableUsageInfo(makeDataLinkWithQuery(query), scopedVars).allVariablesDefined;
}
expect(dataLinkRtnVal).toBe(true);
it('returns true when query contains variables and all variables are used', () => {
expect(allVariablesDefinedInQuery('test ${testVal}')).toBe(true);
});
it('ignores global variables', () => {
expect(allVariablesDefinedInQuery('test ${__rate_interval} $__from $__to')).toBe(true);
});
it('returns false when query contains variables and no variables are used', () => {
const dataLink = {
url: '',
title: '',
internal: {
datasourceUid: 'uid',
datasourceName: 'dsName',
query: { query: 'test ${diffVar}' },
},
};
const scopedVars = {
testVal: { text: '', value: 'val1' },
};
const dataLinkRtnVal = getVariableUsageInfo(dataLink, scopedVars).allVariablesDefined;
expect(dataLinkRtnVal).toBe(false);
expect(allVariablesDefinedInQuery('test ${diffVar}')).toBe(false);
});
it('returns false when query contains variables and some variables are used', () => {
const dataLink = {
url: '',
title: '',
internal: {
datasourceUid: 'uid',
datasourceName: 'dsName',
query: { query: 'test ${testVal} ${diffVar}' },
},
};
const scopedVars = {
testVal: { text: '', value: 'val1' },
};
const dataLinkRtnVal = getVariableUsageInfo(dataLink, scopedVars).allVariablesDefined;
expect(dataLinkRtnVal).toBe(false);
expect(allVariablesDefinedInQuery('test ${testVal} ${diffVar}')).toBe(false);
});
it('returns true when query contains no variables', () => {
const dataLink = {
url: '',
title: '',
internal: {
datasourceUid: 'uid',
datasourceName: 'dsName',
query: { query: 'test' },
},
};
const scopedVars = {
testVal: { text: '', value: 'val1' },
};
const dataLinkRtnVal = getVariableUsageInfo(dataLink, scopedVars).allVariablesDefined;
expect(dataLinkRtnVal).toBe(true);
expect(allVariablesDefinedInQuery('test')).toBe(true);
});
it('returns deduplicated list of variables', () => {
const dataLink = {
url: '',
title: '',
internal: {
datasourceUid: 'uid',
datasourceName: 'dsName',
query: { query: 'test ${test} ${foo} ${test:raw} $test' },
},
};
const dataLink = makeDataLinkWithQuery('test ${test} ${foo} ${test:raw} $test');
const scopedVars = {
testVal: { text: '', value: 'val1' },
};

View File

@ -233,6 +233,23 @@ export function useLinks(range: TimeRange, splitOpenFn?: SplitOpen) {
);
}
// See https://grafana.com/docs/grafana/latest/dashboards/variables/add-template-variables/#global-variables
const builtInVariables = [
'__from',
'__to',
'__interval',
'__interval_ms',
'__org',
'__user',
'__range',
'__rate_interval',
'__timeFilter',
'timeFilter',
// These are only applicable in dashboards so should not affect this for Explore
// '__dashboard',
//'__name',
];
/**
* Use variable map from templateSrv to determine if all variables have values
* @param query
@ -244,14 +261,20 @@ export function getVariableUsageInfo<T extends DataLink>(
): { variables: VariableInterpolation[]; allVariablesDefined: boolean } {
let variables: VariableInterpolation[] = [];
const replaceFn = getTemplateSrv().replace.bind(getTemplateSrv());
// This adds info to the variables array while interpolating
replaceFn(getStringsFromObject(query), scopedVars, undefined, variables);
variables = uniqBy(variables, 'variableName');
return {
variables: variables,
allVariablesDefined: variables.every((variable) => variable.found),
allVariablesDefined: variables
// We filter out builtin variables as they should be always defined but sometimes only later, like
// __range_interval which is defined in prometheus at query time.
.filter((v) => !builtInVariables.includes(v.variableName))
.every((variable) => variable.found),
};
}
// Recursively get all strings from an object into a simple list with space as separator.
function getStringsFromObject(obj: Object): string {
let acc = '';
let k: keyof typeof obj;