diff --git a/public/app/core/reducers/navModel.ts b/public/app/core/reducers/navModel.ts index b341176e2ad..e0b9a2658f7 100644 --- a/public/app/core/reducers/navModel.ts +++ b/public/app/core/reducers/navModel.ts @@ -13,10 +13,12 @@ export function buildInitialState(): NavIndex { // set home as parent for the rootNodes buildNavIndex(navIndex, rootNodes, homeNav); + // remove circular parent reference on the home node if (navIndex[HOME_NAV_ID]) { delete navIndex[HOME_NAV_ID].parentItem; } + return navIndex; } diff --git a/public/app/core/selectors/navModel.ts b/public/app/core/selectors/navModel.ts index 67a345946ba..95bdca3aadc 100644 --- a/public/app/core/selectors/navModel.ts +++ b/public/app/core/selectors/navModel.ts @@ -20,7 +20,7 @@ const getNotFoundModel = (): NavModel => { export const getNavModel = (navIndex: NavIndex, id: string, fallback?: NavModel, onlyChild = false): NavModel => { if (navIndex[id]) { const node = navIndex[id]; - const main = onlyChild ? node : getSectionRoot(node); + const main = onlyChild ? node : getRootSectionForNode(node); const mainWithActive = enrichNodeWithActiveState(main, id); return { @@ -36,8 +36,8 @@ export const getNavModel = (navIndex: NavIndex, id: string, fallback?: NavModel, return getNotFoundModel(); }; -function getSectionRoot(node: NavModelItem): NavModelItem { - return node.parentItem && node.parentItem.id !== HOME_NAV_ID ? getSectionRoot(node.parentItem) : node; +export function getRootSectionForNode(node: NavModelItem): NavModelItem { + return node.parentItem && node.parentItem.id !== HOME_NAV_ID ? getRootSectionForNode(node.parentItem) : node; } function enrichNodeWithActiveState(node: NavModelItem, activeId: string): NavModelItem { diff --git a/public/app/features/plugins/utils.test.ts b/public/app/features/plugins/utils.test.ts index 6133741d3dc..60a22f3dd3e 100644 --- a/public/app/features/plugins/utils.test.ts +++ b/public/app/features/plugins/utils.test.ts @@ -2,6 +2,7 @@ import { Location as HistoryLocation } from 'history'; import { NavIndex, NavModelItem } from '@grafana/data'; import { config } from '@grafana/runtime'; +import { HOME_NAV_ID } from 'app/core/reducers/navModel'; import { buildPluginSectionNav } from './utils'; @@ -33,6 +34,10 @@ describe('buildPluginSectionNav', () => { text: 'Admin', id: 'admin', children: [], + parentItem: { + id: HOME_NAV_ID, + text: 'Home', + }, }; const standalonePluginPage = { diff --git a/public/app/features/plugins/utils.ts b/public/app/features/plugins/utils.ts index 1bc6d90e292..45a10a2a1ed 100644 --- a/public/app/features/plugins/utils.ts +++ b/public/app/features/plugins/utils.ts @@ -2,6 +2,7 @@ import { Location as HistoryLocation } from 'history'; import { GrafanaPlugin, NavIndex, NavModel, NavModelItem, PanelPluginMeta, PluginType } from '@grafana/data'; import { config } from '@grafana/runtime'; +import { getRootSectionForNode } from 'app/core/selectors/navModel'; import { importPanelPluginFromMeta } from './importPanelPlugin'; import { getPluginSettings } from './pluginSettings'; @@ -92,9 +93,7 @@ export function getPluginSection(location: HistoryLocation, navIndex: NavIndex, // First check if this page exist in navIndex using path, some plugin pages are not under their own section const byPath = navIndex[`standalone-plugin-page-${location.pathname}`]; if (byPath) { - const parent = byPath.parentItem!; - // in case the standalone page is in nested section - return parent.parentItem ?? parent; + return getRootSectionForNode(byPath); } // Some plugins like cloud home don't have any precense in the navtree so we need to allow those