Scopes: Fix icon lookup for scope navigation (#113313)

Fix icon lookup for scope navigation
This commit is contained in:
Tobias Skarhed
2025-11-03 13:09:58 +01:00
committed by GitHub
parent 3c0409fe05
commit 3b99370aac
2 changed files with 47 additions and 14 deletions
@@ -105,4 +105,32 @@ describe('ScopesNavigationTreeLink', () => {
expect(matchingLink).toHaveAttribute('aria-current', 'page');
expect(otherLink).not.toHaveAttribute('aria-current');
});
it('shows correct icon for grafana-metricsdrilldown-app with query parameters', () => {
renderWithRouter(
<ScopesNavigationTreeLink
to="/a/grafana-metricsdrilldown-app?from=now-1h&to=now"
title="Metrics Drilldown"
id="metrics-drilldown"
/>
);
const link = screen.getByTestId('scopes-dashboards-metrics-drilldown');
// Icon should be rendered (check for SVG element which is how Icon renders)
const icon = link.querySelector('svg');
expect(icon).toBeInTheDocument();
// The link should contain the title text
expect(link).toHaveTextContent('Metrics Drilldown');
});
it('shows correct icon for grafana-metricsdrilldown-app without trailing slash', () => {
renderWithRouter(
<ScopesNavigationTreeLink to="/a/grafana-metricsdrilldown-app" title="Metrics Drilldown" id="metrics-drilldown" />
);
const link = screen.getByTestId('scopes-dashboards-metrics-drilldown');
const icon = link.querySelector('svg');
expect(icon).toBeInTheDocument();
expect(link).toHaveTextContent('Metrics Drilldown');
});
});
@@ -5,7 +5,7 @@ import { Link, useLocation } from 'react-router-dom-v5-compat';
import { GrafanaTheme2, IconName, locationUtil } from '@grafana/data';
import { Icon, useStyles2 } from '@grafana/ui';
import { isCurrentPath } from './scopeNavgiationUtils';
import { isCurrentPath, normalizePath } from './scopeNavgiationUtils';
export interface ScopesNavigationTreeLinkProps {
to: string;
@@ -36,25 +36,30 @@ export function ScopesNavigationTreeLink({ to, title, id }: ScopesNavigationTree
}
function getLinkIcon(to: string) {
// Strip base URL and normalize path
const normalizedPath = locationUtil.stripBaseFromUrl(to);
for (const [key, value] of linkMap.entries()) {
if (normalizedPath.startsWith(key)) {
return value;
}
// Check for external links before stripping base (stripBaseFromUrl removes http:// for same-origin URLs)
if (to.startsWith('http')) {
return 'external-link-alt';
}
return 'link';
// Strip base URL and normalize path (remove query params and hash)
const baseStripped = locationUtil.stripBaseFromUrl(to);
const normalizedPath = normalizePath(baseStripped);
// Check for dashboard paths with startsWith (e.g., /d/dashboard-id)
if (normalizedPath.startsWith('/d')) {
return 'apps';
}
// Use direct Map lookup for exact path matches
return linkMap.get(normalizedPath) ?? 'link';
}
const linkMap = new Map<string, IconName>([
['http', 'external-link-alt'],
['/d', 'apps'],
['/explore/metrics', 'drilldown'],
['/a/grafana-metricsdrilldown-app/', 'drilldown'],
['/a/grafana-lokiexplore-app/', 'drilldown'],
['/a/grafana-exploretraces-app/', 'drilldown'],
['/a/grafana-pyroscope-app/', 'drilldown'],
['/a/grafana-metricsdrilldown-app', 'drilldown'],
['/a/grafana-lokiexplore-app', 'drilldown'],
['/a/grafana-exploretraces-app', 'drilldown'],
['/a/grafana-pyroscope-app', 'drilldown'],
]);
const getStyles = (theme: GrafanaTheme2) => {