DataLinks: Allow providing a dynamic data link builder (#60452)

This commit is contained in:
Dominik Prokop 2022-12-21 05:09:31 -08:00 committed by GitHub
parent 0adb00b692
commit 70dd5b42ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 107 additions and 16 deletions

View File

@ -247,13 +247,7 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "24"], [0, 0, 0, "Unexpected any. Specify a different type.", "24"],
[0, 0, 0, "Unexpected any. Specify a different type.", "25"], [0, 0, 0, "Unexpected any. Specify a different type.", "25"],
[0, 0, 0, "Unexpected any. Specify a different type.", "26"], [0, 0, 0, "Unexpected any. Specify a different type.", "26"],
[0, 0, 0, "Unexpected any. Specify a different type.", "27"], [0, 0, 0, "Unexpected any. Specify a different type.", "27"]
[0, 0, 0, "Unexpected any. Specify a different type.", "28"],
[0, 0, 0, "Unexpected any. Specify a different type.", "29"],
[0, 0, 0, "Unexpected any. Specify a different type.", "30"],
[0, 0, 0, "Unexpected any. Specify a different type.", "31"],
[0, 0, 0, "Unexpected any. Specify a different type.", "32"],
[0, 0, 0, "Unexpected any. Specify a different type.", "33"]
], ],
"packages/grafana-data/src/field/fieldOverrides.ts:5381": [ "packages/grafana-data/src/field/fieldOverrides.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "0"],

View File

@ -9,6 +9,7 @@ import {
FieldConfigPropertyItem, FieldConfigPropertyItem,
FieldConfigSource, FieldConfigSource,
FieldType, FieldType,
GrafanaConfig,
InterpolateFunction, InterpolateFunction,
ScopedVars, ScopedVars,
ThresholdsMode, ThresholdsMode,
@ -566,9 +567,9 @@ describe('setDynamicConfigValue', () => {
describe('getLinksSupplier', () => { describe('getLinksSupplier', () => {
it('will replace variables in url and title of the data link', () => { it('will replace variables in url and title of the data link', () => {
locationUtil.initialize({ locationUtil.initialize({
config: {} as any, config: {} as GrafanaConfig,
getVariablesUrlParams: (() => {}) as any, getVariablesUrlParams: () => ({}),
getTimeRangeForUrl: (() => {}) as any, getTimeRangeForUrl: () => ({ from: 'now-7d', to: 'now' }),
}); });
const f0 = new MutableDataFrame({ const f0 = new MutableDataFrame({
@ -601,9 +602,9 @@ describe('getLinksSupplier', () => {
it('handles internal links', () => { it('handles internal links', () => {
locationUtil.initialize({ locationUtil.initialize({
config: { appSubUrl: '' } as any, config: { appSubUrl: '' } as GrafanaConfig,
getVariablesUrlParams: (() => {}) as any, getVariablesUrlParams: () => ({}),
getTimeRangeForUrl: (() => {}) as any, getTimeRangeForUrl: () => ({ from: 'now-7d', to: 'now' }),
}); });
const datasourceUid = '1234'; const datasourceUid = '1234';
@ -651,6 +652,93 @@ describe('getLinksSupplier', () => {
}) })
); );
}); });
describe('dynamic links', () => {
beforeEach(() => {
locationUtil.initialize({
config: {} as GrafanaConfig,
getVariablesUrlParams: () => ({}),
getTimeRangeForUrl: () => ({ from: 'now-7d', to: 'now' }),
});
});
it('handles link click handlers', () => {
const onClickSpy = jest.fn();
const replaceSpy = jest.fn();
const f0 = new MutableDataFrame({
name: 'A',
fields: [
{
name: 'message',
type: FieldType.string,
values: [10, 20],
config: {
links: [
{
url: 'should not be ignored',
onClick: onClickSpy,
title: 'title to be interpolated',
},
{
url: 'should not be ignored',
title: 'title to be interpolated',
},
],
},
},
],
});
const supplier = getLinksSupplier(f0, f0.fields[0], {}, replaceSpy);
const links = supplier({});
expect(links.length).toBe(2);
expect(links[0].href).toEqual('should not be ignored');
expect(links[0].onClick).toBeDefined();
links[0].onClick!({});
expect(onClickSpy).toBeCalledTimes(1);
});
it('handles links built dynamically', () => {
const replaceSpy = jest.fn().mockReturnValue('url interpolated 10');
const onBuildUrlSpy = jest.fn();
const f0 = new MutableDataFrame({
name: 'A',
fields: [
{
name: 'message',
type: FieldType.string,
values: [10, 20],
config: {
links: [
{
url: 'should be ignored',
onBuildUrl: () => {
onBuildUrlSpy();
return 'url to be interpolated';
},
title: 'title to be interpolated',
},
{
url: 'should not be ignored',
title: 'title to be interpolated',
},
],
},
},
],
});
const supplier = getLinksSupplier(f0, f0.fields[0], {}, replaceSpy);
const links = supplier({});
expect(onBuildUrlSpy).toBeCalledTimes(1);
expect(links.length).toBe(2);
expect(links[0].href).toEqual('url interpolated 10');
});
});
}); });
describe('applyRawFieldOverrides', () => { describe('applyRawFieldOverrides', () => {

View File

@ -450,9 +450,18 @@ export const getLinksSupplier =
}); });
} }
let href = locationUtil.assureBaseUrl(link.url.replace(/\n/g, '')); let href = link.onBuildUrl
? link.onBuildUrl({
origin: field,
replaceVariables,
})
: link.url;
if (href) {
locationUtil.assureBaseUrl(href.replace(/\n/g, ''));
href = replaceVariables(href, variables); href = replaceVariables(href, variables);
href = locationUtil.processUrl(href); href = locationUtil.processUrl(href);
}
const info: LinkModel<Field> = { const info: LinkModel<Field> = {
href, href,