diff --git a/packages/grafana-ui/src/components/Link/TextLink.test.tsx b/packages/grafana-ui/src/components/Link/TextLink.test.tsx
new file mode 100644
index 00000000000..442bbcf1025
--- /dev/null
+++ b/packages/grafana-ui/src/components/Link/TextLink.test.tsx
@@ -0,0 +1,52 @@
+import { render, screen } from '@testing-library/react';
+import React from 'react';
+import { MemoryRouter } from 'react-router-dom';
+
+import { GrafanaConfig, locationUtil } from '@grafana/data';
+
+import { TextLink } from './TextLink';
+
+describe('TextLink', () => {
+ let windowSpy: jest.SpyInstance;
+
+ beforeAll(() => {
+ windowSpy = jest.spyOn(window, 'location', 'get');
+ windowSpy.mockImplementation(() => ({
+ origin: 'http://www.grafana.com',
+ }));
+ });
+
+ afterAll(() => {
+ windowSpy.mockRestore();
+ });
+
+ const link = 'http://www.grafana.com/grafana/after-sub-url';
+ it('should keep the whole url, including app sub url, if external', () => {
+ locationUtil.initialize({
+ config: { appSubUrl: '/grafana' } as GrafanaConfig,
+ getVariablesUrlParams: jest.fn(),
+ getTimeRangeForUrl: jest.fn(),
+ });
+
+ render(
+
+ Link to Grafana
+
+ );
+ expect(screen.getByRole('link')).toHaveAttribute('href', link);
+ });
+ it('should turn it into a relative url, if not external', () => {
+ locationUtil.initialize({
+ config: { appSubUrl: '/grafana' } as GrafanaConfig,
+ getVariablesUrlParams: jest.fn(),
+ getTimeRangeForUrl: jest.fn(),
+ });
+
+ render(
+
+ Link to Grafana
+
+ );
+ expect(screen.getByRole('link')).toHaveAttribute('href', '/after-sub-url');
+ });
+});
diff --git a/packages/grafana-ui/src/components/Link/TextLink.tsx b/packages/grafana-ui/src/components/Link/TextLink.tsx
index b925308738a..2a50bc9e2db 100644
--- a/packages/grafana-ui/src/components/Link/TextLink.tsx
+++ b/packages/grafana-ui/src/components/Link/TextLink.tsx
@@ -46,19 +46,25 @@ export const TextLink = forwardRef(
{ href, color = 'link', external = false, inline = true, variant = 'body', weight, icon, children, ...rest },
ref
) => {
- const validUrl = locationUtil.stripBaseFromUrl(textUtil.sanitizeUrl(href ?? ''));
+ const validUrl = textUtil.sanitizeUrl(href ?? '');
const theme = useTheme2();
const styles = getLinkStyles(theme, inline, variant, weight, color);
const externalIcon = icon || 'external-link-alt';
- return external ? (
-
- {children}
-
-
- ) : (
-
+ if (external) {
+ return (
+
+ {children}
+
+
+ );
+ }
+
+ const strippedUrl = locationUtil.stripBaseFromUrl(validUrl);
+
+ return (
+
{children}
{icon && }
diff --git a/public/app/features/dashboard/components/ShareModal/ShareLink.test.tsx b/public/app/features/dashboard/components/ShareModal/ShareLink.test.tsx
index 87d8072f153..4306467358b 100644
--- a/public/app/features/dashboard/components/ShareModal/ShareLink.test.tsx
+++ b/public/app/features/dashboard/components/ShareModal/ShareLink.test.tsx
@@ -104,7 +104,7 @@ describe('ShareModal', () => {
mockLocationHref('http://dashboards.grafana.com/d/abcdefghi/my-dash');
render();
- const base = '/render/d-solo/abcdefghi/my-dash';
+ const base = 'http://dashboards.grafana.com/render/d-solo/abcdefghi/my-dash';
const params = '?from=1000&to=2000&orgId=1&panelId=22&width=1000&height=500&tz=UTC';
expect(
await screen.findByRole('link', { name: selectors.pages.SharePanelModal.linkToRenderedImage })
@@ -115,7 +115,7 @@ describe('ShareModal', () => {
mockLocationHref('http://dashboards.grafana.com/dashboard/script/my-dash.js');
render();
- const base = '/render/dashboard-solo/script/my-dash.js';
+ const base = 'http://dashboards.grafana.com/render/dashboard-solo/script/my-dash.js';
const params = '?from=1000&to=2000&orgId=1&panelId=22&width=1000&height=500&tz=UTC';
expect(
await screen.findByRole('link', { name: selectors.pages.SharePanelModal.linkToRenderedImage })
@@ -151,7 +151,7 @@ describe('ShareModal', () => {
);
expect(
await screen.findByRole('link', { name: selectors.pages.SharePanelModal.linkToRenderedImage })
- ).toHaveAttribute('href', path + '?from=1000&to=2000&orgId=1&panelId=1&width=1000&height=500&tz=UTC');
+ ).toHaveAttribute('href', base + path + '?from=1000&to=2000&orgId=1&panelId=1&width=1000&height=500&tz=UTC');
});
it('should shorten url', async () => {
@@ -198,7 +198,7 @@ describe('when appUrl is set in the grafana config', () => {
await screen.findByRole('link', { name: selectors.pages.SharePanelModal.linkToRenderedImage })
).toHaveAttribute(
'href',
- `/render/d-solo/${mockDashboard.uid}?orgId=1&from=1000&to=2000&panelId=${mockPanel.id}&width=1000&height=500&tz=UTC`
+ `http://dashboards.grafana.com/render/d-solo/${mockDashboard.uid}?orgId=1&from=1000&to=2000&panelId=${mockPanel.id}&width=1000&height=500&tz=UTC`
);
});
});