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` ); }); });