From dd37d003efd3fa594f26b8afb8dded131b7719d4 Mon Sep 17 00:00:00 2001 From: Dominik Prokop Date: Mon, 10 Feb 2020 12:45:15 +0100 Subject: [PATCH] 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 --- .../testdata-datalinks.json | 8 ++--- public/app/core/specs/location_util.test.ts | 2 +- public/app/core/utils/location_util.ts | 13 +++++-- .../PanelHeader/PanelHeaderCorner.tsx | 2 +- .../app/features/panel/panellinks/link_srv.ts | 8 +++-- .../panel/panellinks/specs/link_srv.test.ts | 35 +++++++++++++++++++ public/app/plugins/panel/singlestat/module.ts | 3 +- 7 files changed, 58 insertions(+), 13 deletions(-) diff --git a/devenv/dev-dashboards/feature-templating/testdata-datalinks.json b/devenv/dev-dashboards/feature-templating/testdata-datalinks.json index 0f425bab088..b255d116c7e 100644 --- a/devenv/dev-dashboards/feature-templating/testdata-datalinks.json +++ b/devenv/dev-dashboards/feature-templating/testdata-datalinks.json @@ -66,7 +66,7 @@ { "targetBlank": false, "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 @@ { "targetBlank": false, "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 @@ { "targetBlank": true, "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": [ @@ -307,7 +307,7 @@ "links": [ { "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": [], diff --git a/public/app/core/specs/location_util.test.ts b/public/app/core/specs/location_util.test.ts index c109ab7315a..8aee29d9a87 100644 --- a/public/app/core/specs/location_util.test.ts +++ b/public/app/core/specs/location_util.test.ts @@ -2,7 +2,7 @@ import locationUtil from 'app/core/utils/location_util'; jest.mock('app/core/config', () => { return { - appSubUrl: '/subUrl', + getConfig: () => ({ appSubUrl: '/subUrl' }), }; }); diff --git a/public/app/core/utils/location_util.ts b/public/app/core/utils/location_util.ts index 15e1c275550..a329577dd8e 100644 --- a/public/app/core/utils/location_util.ts +++ b/public/app/core/utils/location_util.ts @@ -1,7 +1,7 @@ -import config from 'app/core/config'; +import { getConfig } from 'app/core/config'; export const stripBaseFromUrl = (url: string): string => { - const appSubUrl = config.appSubUrl; + const appSubUrl = getConfig().appSubUrl; const stripExtraChars = appSubUrl.endsWith('/') ? 1 : 0; const urlWithoutBase = url.length > 0 && url.indexOf(appSubUrl) === 0 ? url.slice(appSubUrl.length - stripExtraChars) : url; @@ -9,4 +9,11 @@ export const stripBaseFromUrl = (url: string): string => { return urlWithoutBase; }; -export default { stripBaseFromUrl }; +export const assureBaseUrl = (url: string) => { + if (url.startsWith('/')) { + return `${getConfig().appSubUrl}${stripBaseFromUrl(url)}`; + } + return url; +}; + +export default { stripBaseFromUrl, assureBaseUrl }; diff --git a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderCorner.tsx b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderCorner.tsx index 5d6192a9d5f..acecfc29ccc 100644 --- a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderCorner.tsx +++ b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderCorner.tsx @@ -2,11 +2,11 @@ import React, { Component } from 'react'; import { renderMarkdown, LinkModelSupplier, ScopedVars } from '@grafana/data'; import { Tooltip, PopoverContent } from '@grafana/ui'; +import { getLocationSrv } from '@grafana/runtime'; import { PanelModel } from 'app/features/dashboard/state/PanelModel'; import templateSrv from 'app/features/templating/template_srv'; import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv'; -import { getLocationSrv } from '@grafana/runtime'; import { InspectTab } from '../../components/Inspector/PanelInspector'; enum InfoMode { diff --git a/public/app/features/panel/panellinks/link_srv.ts b/public/app/features/panel/panellinks/link_srv.ts index 4b33d48c724..7807c20b9f4 100644 --- a/public/app/features/panel/panellinks/link_srv.ts +++ b/public/app/features/panel/panellinks/link_srv.ts @@ -5,6 +5,7 @@ import coreModule from 'app/core/core_module'; import { appendQueryToUrl, toUrlParams } from 'app/core/utils/url'; import { sanitizeUrl } from 'app/core/utils/text'; import { getConfig } from 'app/core/config'; +import locationUtil from 'app/core/utils/location_util'; import { VariableSuggestion, VariableOrigin, DataLinkBuiltInVars } from '@grafana/ui'; import { DataLink, @@ -216,7 +217,7 @@ export class LinkSrv implements LinkService { constructor(private templateSrv: TemplateSrv, private timeSrv: TimeSrv) {} getLinkUrl(link: any) { - const url = this.templateSrv.replace(link.url || ''); + let url = locationUtil.assureBaseUrl(this.templateSrv.replace(link.url || '')); const params: { [key: string]: any } = {}; if (link.keepTime) { @@ -229,7 +230,8 @@ export class LinkSrv implements LinkService { this.templateSrv.fillVariableValuesForUrl(params); } - return appendQueryToUrl(url, toUrlParams(params)); + url = appendQueryToUrl(url, toUrlParams(params)); + return getConfig().disableSanitizeHtml ? url : sanitizeUrl(url); } getAnchorInfo(link: any) { @@ -266,7 +268,7 @@ export class LinkSrv implements LinkService { } const info: LinkModel = { - href: href.replace(/\s|\n/g, ''), + href: locationUtil.assureBaseUrl(href.replace(/\s|\n/g, '')), title: this.templateSrv.replace(link.title || '', scopedVars), target: link.targetBlank ? '_blank' : '_self', origin, diff --git a/public/app/features/panel/panellinks/specs/link_srv.test.ts b/public/app/features/panel/panellinks/specs/link_srv.test.ts index 5405f1bf47c..a5f65c264fc 100644 --- a/public/app/features/panel/panellinks/specs/link_srv.test.ts +++ b/public/app/features/panel/panellinks/specs/link_srv.test.ts @@ -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); + } + ); + }); }); diff --git a/public/app/plugins/panel/singlestat/module.ts b/public/app/plugins/panel/singlestat/module.ts index d60d4771d31..35f6ffca051 100644 --- a/public/app/plugins/panel/singlestat/module.ts +++ b/public/app/plugins/panel/singlestat/module.ts @@ -4,6 +4,7 @@ import $ from 'jquery'; import 'vendor/flot/jquery.flot'; import 'vendor/flot/jquery.flot.gauge'; import 'app/features/panel/panellinks/link_srv'; +import locationUtil from 'app/core/utils/location_util'; import { DataFrame, @@ -656,7 +657,7 @@ class SingleStatCtrl extends MetricsPanelCtrl { window.location.href = linkInfo.href; } else { $timeout(() => { - $location.url(linkInfo.href); + $location.url(locationUtil.stripBaseFromUrl(linkInfo.href)); }); }