diff --git a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap index 86cacfe98f767..1bff6cd9301ed 100644 --- a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap +++ b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap @@ -279,6 +279,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` } } navigateToApp={[Function]} + navigateToUrl={[Function]} onIsLockedUpdate={[Function]} recentlyAccessed$={ BehaviorSubject { @@ -2156,6 +2157,7 @@ exports[`CollapsibleNav renders the default nav 1`] = ` } } navigateToApp={[Function]} + navigateToUrl={[Function]} onIsLockedUpdate={[Function]} recentlyAccessed$={ BehaviorSubject { @@ -2391,6 +2393,7 @@ exports[`CollapsibleNav renders the default nav 2`] = ` } } navigateToApp={[Function]} + navigateToUrl={[Function]} onIsLockedUpdate={[Function]} recentlyAccessed$={ BehaviorSubject { @@ -2626,6 +2629,7 @@ exports[`CollapsibleNav renders the default nav 3`] = ` } } navigateToApp={[Function]} + navigateToUrl={[Function]} onIsLockedUpdate={[Function]} recentlyAccessed$={ BehaviorSubject { diff --git a/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap index 505f242794212..d90d0824a1237 100644 --- a/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap +++ b/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap @@ -5380,6 +5380,7 @@ exports[`Header renders 1`] = ` } } navigateToApp={[MockFunction]} + navigateToUrl={[MockFunction]} onIsLockedUpdate={[Function]} recentlyAccessed$={ BehaviorSubject { diff --git a/src/core/public/chrome/ui/header/collapsible_nav.test.tsx b/src/core/public/chrome/ui/header/collapsible_nav.test.tsx index e33e76a45580e..267e17dc0a9d0 100644 --- a/src/core/public/chrome/ui/header/collapsible_nav.test.tsx +++ b/src/core/public/chrome/ui/header/collapsible_nav.test.tsx @@ -67,6 +67,7 @@ function mockProps() { onIsLockedUpdate: () => {}, closeNav: () => {}, navigateToApp: () => Promise.resolve(), + navigateToUrl: () => Promise.resolve(), customNavLink$: new BehaviorSubject(undefined), }; } diff --git a/src/core/public/chrome/ui/header/collapsible_nav.tsx b/src/core/public/chrome/ui/header/collapsible_nav.tsx index 01cdb9c38881a..b00e82b660e9f 100644 --- a/src/core/public/chrome/ui/header/collapsible_nav.tsx +++ b/src/core/public/chrome/ui/header/collapsible_nav.tsx @@ -87,6 +87,7 @@ interface Props { onIsLockedUpdate: OnIsLockedUpdate; closeNav: () => void; navigateToApp: InternalApplicationStart['navigateToApp']; + navigateToUrl: InternalApplicationStart['navigateToUrl']; customNavLink$: Rx.Observable; } @@ -100,6 +101,7 @@ export function CollapsibleNav({ onIsLockedUpdate, closeNav, navigateToApp, + navigateToUrl, ...observables }: Props) { const navLinks = useObservable(observables.navLinks$, []).filter((link) => !link.hidden); @@ -217,17 +219,21 @@ export function CollapsibleNav({ listItems={recentlyAccessed.map((link) => { // TODO #64541 // Can remove icon from recent links completely - const { iconType, ...hydratedLink } = createRecentNavLink(link, navLinks, basePath); + const { iconType, onClick, ...hydratedLink } = createRecentNavLink( + link, + navLinks, + basePath, + navigateToUrl + ); return { ...hydratedLink, 'data-test-subj': 'collapsibleNavAppLink--recent', onClick: (event) => { - if (isModifiedOrPrevented(event)) { - return; + if (!isModifiedOrPrevented(event)) { + closeNav(); + onClick(event); } - - closeNav(); }, }; })} diff --git a/src/core/public/chrome/ui/header/header.tsx b/src/core/public/chrome/ui/header/header.tsx index 7ec03ea4c6da6..e01a62a54c34d 100644 --- a/src/core/public/chrome/ui/header/header.tsx +++ b/src/core/public/chrome/ui/header/header.tsx @@ -184,6 +184,7 @@ export function Header({ homeHref={homeHref} basePath={basePath} navigateToApp={application.navigateToApp} + navigateToUrl={application.navigateToUrl} onIsLockedUpdate={onIsLockedUpdate} closeNav={() => { setIsNavOpen(false); diff --git a/src/core/public/chrome/ui/header/nav_link.tsx b/src/core/public/chrome/ui/header/nav_link.tsx index 04d9c5bf7a10a..a3c73fc454362 100644 --- a/src/core/public/chrome/ui/header/nav_link.tsx +++ b/src/core/public/chrome/ui/header/nav_link.tsx @@ -22,6 +22,7 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; import { ChromeNavLink, ChromeRecentlyAccessedHistoryItem, CoreStart } from '../../..'; import { HttpStart } from '../../../http'; +import { InternalApplicationStart } from '../../../application/types'; import { relativeToAbsolute } from '../../nav_links/to_nav_link'; export const isModifiedOrPrevented = (event: React.MouseEvent) => @@ -87,6 +88,7 @@ export interface RecentNavLink { title: string; 'aria-label': string; iconType?: string; + onClick: React.MouseEventHandler; } /** @@ -102,8 +104,9 @@ export interface RecentNavLink { export function createRecentNavLink( recentLink: ChromeRecentlyAccessedHistoryItem, navLinks: ChromeNavLink[], - basePath: HttpStart['basePath'] -) { + basePath: HttpStart['basePath'], + navigateToUrl: InternalApplicationStart['navigateToUrl'] +): RecentNavLink { const { link, label } = recentLink; const href = relativeToAbsolute(basePath.prepend(link)); const navLink = navLinks.find((nl) => href.startsWith(nl.baseUrl)); @@ -125,5 +128,12 @@ export function createRecentNavLink( title: titleAndAriaLabel, 'aria-label': titleAndAriaLabel, iconType: navLink?.euiIconType, + /* Use href and onClick to support "open in new tab" and SPA navigation in the same link */ + onClick(event: React.MouseEvent) { + if (event.button === 0 && !isModifiedOrPrevented(event)) { + event.preventDefault(); + navigateToUrl(href); + } + }, }; }