From 115038a35bf727ea0215ea700b47648c1ece5d5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 22 Sep 2023 07:38:34 +0200 Subject: [PATCH] Breadcrumbs: Enable plugins to override breadcrumbs that are generated by pages defined in plugin.json (#75218) * Breadcrumbs: Make it more flexible for plugins to override items defined in plugin.json * only check when we have a url * better fix --- .../core/components/Breadcrumbs/utils.test.ts | 22 +++++++++++++ .../app/core/components/Breadcrumbs/utils.ts | 33 ++++++++++++++----- 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/public/app/core/components/Breadcrumbs/utils.test.ts b/public/app/core/components/Breadcrumbs/utils.test.ts index c696d65a4d3..8302d42c0ca 100644 --- a/public/app/core/components/Breadcrumbs/utils.test.ts +++ b/public/app/core/components/Breadcrumbs/utils.test.ts @@ -144,5 +144,27 @@ describe('breadcrumb utils', () => { { text: 'My page', href: '/my-page' }, ]); }); + + it('does ignore duplicates', () => { + const pageNav: NavModelItem = { + text: 'My page', + url: '/my-page', + parentItem: { + text: 'My section', + // same url as section nav, but this one should win/overwrite it + url: '/my-section?from=1h&to=now', + }, + }; + + const sectionNav: NavModelItem = { + text: 'My section', + url: '/my-section', + }; + + expect(buildBreadcrumbs(sectionNav, pageNav, mockHomeNav)).toEqual([ + { text: 'My section', href: '/my-section?from=1h&to=now' }, + { text: 'My page', href: '/my-page' }, + ]); + }); }); }); diff --git a/public/app/core/components/Breadcrumbs/utils.ts b/public/app/core/components/Breadcrumbs/utils.ts index bb4b686ed40..fa88667efc5 100644 --- a/public/app/core/components/Breadcrumbs/utils.ts +++ b/public/app/core/components/Breadcrumbs/utils.ts @@ -5,23 +5,38 @@ import { Breadcrumb } from './types'; export function buildBreadcrumbs(sectionNav: NavModelItem, pageNav?: NavModelItem, homeNav?: NavModelItem) { const crumbs: Breadcrumb[] = []; let foundHome = false; + let lastPath: string | undefined = undefined; function addCrumbs(node: NavModelItem) { + if (foundHome) { + return; + } + // construct the URL to match // we want to ignore query params except for the editview query param - const urlSearchParams = new URLSearchParams(node.url?.split('?')[1]); - let urlToMatch = `${node.url?.split('?')[0]}`; + const urlParts = node.url?.split('?') ?? ['', '']; + let urlToMatch = urlParts[0]; + + const urlSearchParams = new URLSearchParams(urlParts[1]); + if (urlSearchParams.has('editview')) { urlToMatch += `?editview=${urlSearchParams.get('editview')}`; } - if (!foundHome && !node.hideFromBreadcrumbs) { - if (homeNav && urlToMatch === homeNav.url) { - crumbs.unshift({ text: homeNav.text, href: node.url ?? '' }); - foundHome = true; - } else { - crumbs.unshift({ text: node.text, href: node.url ?? '' }); - } + // This enabled app plugins to control breadcrumbs of their root pages + const isSamePathAsLastBreadcrumb = urlToMatch.length > 0 && lastPath === urlToMatch; + // Remember this path for the next breadcrumb + lastPath = urlToMatch; + + // Check if we found home/root if if so return early + if (homeNav && urlToMatch === homeNav.url) { + crumbs.unshift({ text: homeNav.text, href: node.url ?? '' }); + foundHome = true; + return; + } + + if (!node.hideFromBreadcrumbs && !isSamePathAsLastBreadcrumb) { + crumbs.unshift({ text: node.text, href: node.url ?? '' }); } if (node.parentItem) {