Explore: Add correlation variables for interpolation (#61008)

* Add correlation variables for interpolation

* Change to only look at relevant field

* Add links ignoring correlation check, add tests

* Add variables for all fields in dataframe, add tests for it, simplify URL expect
This commit is contained in:
Kristina 2023-01-17 11:12:37 -06:00 committed by GitHub
parent 70f2b01525
commit 6ed7c77516
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 131 additions and 8 deletions

View File

@ -133,7 +133,7 @@ describe('getFieldLinksForExplore', () => {
expect(links).toHaveLength(0);
});
it('returns internal links when target contains defined template variables', () => {
it('returns internal links when target contains __data template variables', () => {
const { field, range, dataFrame } = setup({
title: '',
url: '',
@ -145,6 +145,100 @@ describe('getFieldLinksForExplore', () => {
});
const links = getFieldLinksForExplore({ field, rowIndex: ROW_WITH_TEXT_VALUE.index, range, dataFrame });
expect(links).toHaveLength(1);
expect(links[0].href).toBe(
`/explore?left=${encodeURIComponent(
'{"range":{"from":"now-1h","to":"now"},"datasource":"uid_1","queries":[{"query":"query_1-foo"}],"panelsState":{}}'
)}`
);
});
it('returns internal links when target contains targetField template variable', () => {
const { field, range, dataFrame } = setup({
title: '',
url: '',
internal: {
query: { query: 'query_1-${__targetField}' },
datasourceUid: 'uid_1',
datasourceName: 'test_ds',
},
});
const links = getFieldLinksForExplore({ field, rowIndex: ROW_WITH_TEXT_VALUE.index, range, dataFrame });
expect(links).toHaveLength(1);
expect(links[0].href).toBe(
`/explore?left=${encodeURIComponent(
'{"range":{"from":"now-1h","to":"now"},"datasource":"uid_1","queries":[{"query":"query_1-foo"}],"panelsState":{}}'
)}`
);
});
it('returns internal links when target contains field name template variable', () => {
// field cannot be hyphenated, change field name to non-hyphenated
const noHyphenLink = {
title: '',
url: '',
internal: {
query: { query: 'query_1-${fluxDimensions}' },
datasourceUid: 'uid_1',
datasourceName: 'test_ds',
},
};
const { field, range, dataFrame } = setup(noHyphenLink, true, {
name: 'fluxDimensions',
type: FieldType.string,
values: new ArrayVector([ROW_WITH_TEXT_VALUE.value, ROW_WITH_NULL_VALUE.value]),
config: {
links: [noHyphenLink],
},
});
const links = getFieldLinksForExplore({ field, rowIndex: ROW_WITH_TEXT_VALUE.index, range, dataFrame });
expect(links).toHaveLength(1);
expect(links[0].href).toBe(
`/explore?left=${encodeURIComponent(
'{"range":{"from":"now-1h","to":"now"},"datasource":"uid_1","queries":[{"query":"query_1-foo"}],"panelsState":{}}'
)}`
);
});
it('returns internal links when target contains other field name template variables', () => {
// field cannot be hyphenated, change field name to non-hyphenated
const noHyphenLink = {
title: '',
url: '',
internal: {
query: { query: 'query_1-${fluxDimensions}-${fluxDimension2}' },
datasourceUid: 'uid_1',
datasourceName: 'test_ds',
},
};
const { field, range, dataFrame } = setup(
noHyphenLink,
true,
{
name: 'fluxDimensions',
type: FieldType.string,
values: new ArrayVector([ROW_WITH_TEXT_VALUE.value, ROW_WITH_NULL_VALUE.value]),
config: {
links: [noHyphenLink],
},
},
[
{
name: 'fluxDimension2',
type: FieldType.string,
values: new ArrayVector(['foo2', ROW_WITH_NULL_VALUE.value]),
config: {
links: [noHyphenLink],
},
},
]
);
const links = getFieldLinksForExplore({ field, rowIndex: ROW_WITH_TEXT_VALUE.index, range, dataFrame });
expect(links).toHaveLength(1);
expect(links[0].href).toBe(
`/explore?left=${encodeURIComponent(
'{"range":{"from":"now-1h","to":"now"},"datasource":"uid_1","queries":[{"query":"query_1-foo-foo2"}],"panelsState":{}}'
)}`
);
});
it('returns no internal links when target contains empty template variables', () => {
@ -165,7 +259,12 @@ describe('getFieldLinksForExplore', () => {
const ROW_WITH_TEXT_VALUE = { value: 'foo', index: 0 };
const ROW_WITH_NULL_VALUE = { value: null, index: 1 };
function setup(link: DataLink, hasAccess = true) {
function setup(
link: DataLink,
hasAccess = true,
fieldOverride?: Field<string | null>,
dataFrameOtherFieldOverride?: Field[]
) {
setLinkSrv({
getDataLinkUIModel(link: DataLink, replaceVariables: InterpolateFunction | undefined, origin: any): LinkModel<any> {
return {
@ -196,8 +295,14 @@ function setup(link: DataLink, hasAccess = true) {
},
};
let fieldsArr = [fieldOverride || field];
if (dataFrameOtherFieldOverride) {
fieldsArr = [...fieldsArr, ...dataFrameOtherFieldOverride];
}
const dataFrame: DataFrame = toDataFrame({
fields: [field],
fields: fieldsArr,
});
const range: TimeRange = {
@ -209,5 +314,5 @@ function setup(link: DataLink, hasAccess = true) {
},
};
return { range, field, dataFrame };
return { range, field: fieldOverride || field, dataFrame };
}

View File

@ -11,6 +11,7 @@ import {
getFieldDisplayValuesProxy,
SplitOpen,
DataLink,
DisplayValue,
} from '@grafana/data';
import { getTemplateSrv } from '@grafana/runtime';
import { contextSrv } from 'app/core/services/context_srv';
@ -72,19 +73,36 @@ export const getFieldLinksForExplore = (options: {
text: 'Raw value',
};
let fieldDisplayValuesProxy: Record<string, DisplayValue> | undefined = undefined;
// If we have a dataFrame we can allow referencing other columns and their values in the interpolation.
if (dataFrame) {
fieldDisplayValuesProxy = getFieldDisplayValuesProxy({
frame: dataFrame,
rowIndex,
});
scopedVars['__data'] = {
value: {
name: dataFrame.name,
refId: dataFrame.refId,
fields: getFieldDisplayValuesProxy({
frame: dataFrame,
rowIndex,
}),
fields: fieldDisplayValuesProxy,
},
text: 'Data',
};
dataFrame.fields.forEach((f) => {
if (fieldDisplayValuesProxy && fieldDisplayValuesProxy[f.name]) {
scopedVars[f.name] = {
value: fieldDisplayValuesProxy[f.name],
};
}
});
// add this for convenience
scopedVars['__targetField'] = {
value: fieldDisplayValuesProxy[field.name],
};
}
if (field.config.links) {