Commit dd37d003 by Dominik Prokop Committed by GitHub

Links: Assure base url when single stat, panel and data links are built (#21956)

* Assure base url when single stat, panel and data links are built

* Update public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderCorner.tsx

* Update public/app/features/panel/panellinks/link_srv.ts

* Update public/app/features/panel/panellinks/link_srv.ts

* Update public/app/features/panel/panellinks/link_srv.ts

* Update public/app/features/panel/panellinks/link_srv.ts

* Review updates

* Remove unnecessary code
parent cd680968
...@@ -66,7 +66,7 @@ ...@@ -66,7 +66,7 @@
{ {
"targetBlank": false, "targetBlank": false,
"title": "Drill it down", "title": "Drill it down",
"url": "http://localhost:3000/d/wfTJJL5Wz/datalinks-source?var-seriesName=${__series.name}&var-labelDatacenter=${__series.labels.datacenter}&var-labelDatacenterRegion=${__series.labels[\"datacenter.region\"]}&var-valueTime=${__value.time}&var-valueNumeric=${__value.numeric}&var-valueText=${__value.text}" "url": "/d/wfTJJL5Wz/datalinks-source?var-seriesName=${__series.name}&var-labelDatacenter=${__series.labels.datacenter}&var-labelDatacenterRegion=${__series.labels[\"datacenter.region\"]}&var-valueTime=${__value.time}&var-valueNumeric=${__value.numeric}&var-valueText=${__value.text}"
} }
] ]
}, },
...@@ -164,7 +164,7 @@ ...@@ -164,7 +164,7 @@
{ {
"targetBlank": false, "targetBlank": false,
"title": "Drill it down", "title": "Drill it down",
"url": "http://localhost:3000/d/wfTJJL5Wz/datalinks-source?var-seriesName=${__series.name}&var-valueTime=${__value.time}&var-valueNumeric=${__value.numeric}&var-valueText=${__value.text}&var-fieldName=${__field.name}" "url": "/d/wfTJJL5Wz/datalinks-source?var-seriesName=${__series.name}&var-valueTime=${__value.time}&var-valueNumeric=${__value.numeric}&var-valueText=${__value.text}&var-fieldName=${__field.name}"
} }
] ]
}, },
...@@ -246,7 +246,7 @@ ...@@ -246,7 +246,7 @@
{ {
"targetBlank": true, "targetBlank": true,
"title": "Drill it down!", "title": "Drill it down!",
"url": "http://localhost:3000/d/wfTJJL5Wz/datalinks-source\n?var-fieldName=${__field.name}\n&var-labelDatacenter=${__series.labels.datacenter}\n&var-labelDatacenterRegion=${__series.labels[\"datacenter.region\"]}\n&var-valueNumeric=${__value.numeric}\n&var-valueText=${__value.text}\n&var-valueCalc=${__value.calc}" "url": "/d/wfTJJL5Wz/datalinks-source\n?var-fieldName=${__field.name}\n&var-labelDatacenter=${__series.labels.datacenter}\n&var-labelDatacenterRegion=${__series.labels[\"datacenter.region\"]}\n&var-valueNumeric=${__value.numeric}\n&var-valueText=${__value.text}\n&var-valueCalc=${__value.calc}"
} }
], ],
"mappings": [ "mappings": [
...@@ -307,7 +307,7 @@ ...@@ -307,7 +307,7 @@
"links": [ "links": [
{ {
"title": "Drill it down", "title": "Drill it down",
"url": "http://localhost:3000/d/wfTJJL5Wz/datalinks-source?var-fieldName=${__field.name}&var-labelDatacenter=${__series.labels.datacenter}&var-labelDatacenterRegion=${__series.labels[\"datacenter.region\"]}&var-valueNumeric=${__value.numeric}&var-valueText=${__value.text}&var-valueCalc=${__value.calc}" "url": "/d/wfTJJL5Wz/datalinks-source?var-fieldName=${__field.name}&var-labelDatacenter=${__series.labels.datacenter}&var-labelDatacenterRegion=${__series.labels[\"datacenter.region\"]}&var-valueNumeric=${__value.numeric}&var-valueText=${__value.text}&var-valueCalc=${__value.calc}"
} }
], ],
"mappings": [], "mappings": [],
......
...@@ -2,7 +2,7 @@ import locationUtil from 'app/core/utils/location_util'; ...@@ -2,7 +2,7 @@ import locationUtil from 'app/core/utils/location_util';
jest.mock('app/core/config', () => { jest.mock('app/core/config', () => {
return { return {
appSubUrl: '/subUrl', getConfig: () => ({ appSubUrl: '/subUrl' }),
}; };
}); });
......
import config from 'app/core/config'; import { getConfig } from 'app/core/config';
export const stripBaseFromUrl = (url: string): string => { export const stripBaseFromUrl = (url: string): string => {
const appSubUrl = config.appSubUrl; const appSubUrl = getConfig().appSubUrl;
const stripExtraChars = appSubUrl.endsWith('/') ? 1 : 0; const stripExtraChars = appSubUrl.endsWith('/') ? 1 : 0;
const urlWithoutBase = const urlWithoutBase =
url.length > 0 && url.indexOf(appSubUrl) === 0 ? url.slice(appSubUrl.length - stripExtraChars) : url; url.length > 0 && url.indexOf(appSubUrl) === 0 ? url.slice(appSubUrl.length - stripExtraChars) : url;
...@@ -9,4 +9,11 @@ export const stripBaseFromUrl = (url: string): string => { ...@@ -9,4 +9,11 @@ export const stripBaseFromUrl = (url: string): string => {
return urlWithoutBase; return urlWithoutBase;
}; };
export default { stripBaseFromUrl }; export const assureBaseUrl = (url: string) => {
if (url.startsWith('/')) {
return `${getConfig().appSubUrl}${stripBaseFromUrl(url)}`;
}
return url;
};
export default { stripBaseFromUrl, assureBaseUrl };
...@@ -2,11 +2,11 @@ import React, { Component } from 'react'; ...@@ -2,11 +2,11 @@ import React, { Component } from 'react';
import { renderMarkdown, LinkModelSupplier, ScopedVars } from '@grafana/data'; import { renderMarkdown, LinkModelSupplier, ScopedVars } from '@grafana/data';
import { Tooltip, PopoverContent } from '@grafana/ui'; import { Tooltip, PopoverContent } from '@grafana/ui';
import { getLocationSrv } from '@grafana/runtime';
import { PanelModel } from 'app/features/dashboard/state/PanelModel'; import { PanelModel } from 'app/features/dashboard/state/PanelModel';
import templateSrv from 'app/features/templating/template_srv'; import templateSrv from 'app/features/templating/template_srv';
import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv'; import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv';
import { getLocationSrv } from '@grafana/runtime';
import { InspectTab } from '../../components/Inspector/PanelInspector'; import { InspectTab } from '../../components/Inspector/PanelInspector';
enum InfoMode { enum InfoMode {
......
...@@ -5,6 +5,7 @@ import coreModule from 'app/core/core_module'; ...@@ -5,6 +5,7 @@ import coreModule from 'app/core/core_module';
import { appendQueryToUrl, toUrlParams } from 'app/core/utils/url'; import { appendQueryToUrl, toUrlParams } from 'app/core/utils/url';
import { sanitizeUrl } from 'app/core/utils/text'; import { sanitizeUrl } from 'app/core/utils/text';
import { getConfig } from 'app/core/config'; import { getConfig } from 'app/core/config';
import locationUtil from 'app/core/utils/location_util';
import { VariableSuggestion, VariableOrigin, DataLinkBuiltInVars } from '@grafana/ui'; import { VariableSuggestion, VariableOrigin, DataLinkBuiltInVars } from '@grafana/ui';
import { import {
DataLink, DataLink,
...@@ -216,7 +217,7 @@ export class LinkSrv implements LinkService { ...@@ -216,7 +217,7 @@ export class LinkSrv implements LinkService {
constructor(private templateSrv: TemplateSrv, private timeSrv: TimeSrv) {} constructor(private templateSrv: TemplateSrv, private timeSrv: TimeSrv) {}
getLinkUrl(link: any) { getLinkUrl(link: any) {
const url = this.templateSrv.replace(link.url || ''); let url = locationUtil.assureBaseUrl(this.templateSrv.replace(link.url || ''));
const params: { [key: string]: any } = {}; const params: { [key: string]: any } = {};
if (link.keepTime) { if (link.keepTime) {
...@@ -229,7 +230,8 @@ export class LinkSrv implements LinkService { ...@@ -229,7 +230,8 @@ export class LinkSrv implements LinkService {
this.templateSrv.fillVariableValuesForUrl(params); this.templateSrv.fillVariableValuesForUrl(params);
} }
return appendQueryToUrl(url, toUrlParams(params)); url = appendQueryToUrl(url, toUrlParams(params));
return getConfig().disableSanitizeHtml ? url : sanitizeUrl(url);
} }
getAnchorInfo(link: any) { getAnchorInfo(link: any) {
...@@ -266,7 +268,7 @@ export class LinkSrv implements LinkService { ...@@ -266,7 +268,7 @@ export class LinkSrv implements LinkService {
} }
const info: LinkModel<T> = { const info: LinkModel<T> = {
href: href.replace(/\s|\n/g, ''), href: locationUtil.assureBaseUrl(href.replace(/\s|\n/g, '')),
title: this.templateSrv.replace(link.title || '', scopedVars), title: this.templateSrv.replace(link.title || '', scopedVars),
target: link.targetBlank ? '_blank' : '_self', target: link.targetBlank ? '_blank' : '_self',
origin, origin,
......
...@@ -175,4 +175,39 @@ describe('linkSrv', () => { ...@@ -175,4 +175,39 @@ describe('linkSrv', () => {
} }
); );
}); });
describe('Building links with root_url set', () => {
it.each`
url | appSubUrl | expected
${'/d/XXX'} | ${'/grafana'} | ${'/grafana/d/XXX'}
${'/grafana/d/XXX'} | ${'/grafana'} | ${'/grafana/d/XXX'}
${'d/whatever'} | ${'/grafana'} | ${'d/whatever'}
${'/d/XXX'} | ${''} | ${'/d/XXX'}
${'/grafana/d/XXX'} | ${''} | ${'/grafana/d/XXX'}
${'d/whatever'} | ${''} | ${'d/whatever'}
`(
"when link '$url' and config.appSubUrl set to '$appSubUrl' then result should be '$expected'",
({ url, appSubUrl, expected }) => {
updateConfig({
appSubUrl,
});
const link = linkSrv.getDataLinkUIModel(
{
title: 'Any title',
url,
},
{
__value: {
value: { time: dataPointMock.datapoint[0] },
text: 'Value',
},
},
{}
).href;
expect(link).toBe(expected);
}
);
});
}); });
...@@ -4,6 +4,7 @@ import $ from 'jquery'; ...@@ -4,6 +4,7 @@ import $ from 'jquery';
import 'vendor/flot/jquery.flot'; import 'vendor/flot/jquery.flot';
import 'vendor/flot/jquery.flot.gauge'; import 'vendor/flot/jquery.flot.gauge';
import 'app/features/panel/panellinks/link_srv'; import 'app/features/panel/panellinks/link_srv';
import locationUtil from 'app/core/utils/location_util';
import { import {
DataFrame, DataFrame,
...@@ -656,7 +657,7 @@ class SingleStatCtrl extends MetricsPanelCtrl { ...@@ -656,7 +657,7 @@ class SingleStatCtrl extends MetricsPanelCtrl {
window.location.href = linkInfo.href; window.location.href = linkInfo.href;
} else { } else {
$timeout(() => { $timeout(() => {
$location.url(linkInfo.href); $location.url(locationUtil.stripBaseFromUrl(linkInfo.href));
}); });
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment