diff --git a/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx b/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx
index cf0fb81f7407e7..3cc1c30877a893 100644
--- a/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx
+++ b/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx
@@ -398,6 +398,7 @@ export class ChromeService {
globalHelpExtensionMenuLinks$={globalHelpExtensionMenuLinks$}
actionMenu$={application.currentActionMenu$}
breadcrumbs$={currentProjectBreadcrumbs$}
+ customBranding$={customBranding$}
helpExtension$={helpExtension$.pipe(takeUntil(this.stop$))}
helpSupportUrl$={helpSupportUrl$.pipe(takeUntil(this.stop$))}
helpMenuLinks$={helpMenuLinks$}
diff --git a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts
index f07ac64de38564..03e40d7678f026 100644
--- a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts
+++ b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/project_navigation_service.ts
@@ -114,9 +114,7 @@ export class ProjectNavigationService {
);
return {
- setProjectHome: (homeHref: string) => {
- this.projectHome$.next(homeHref);
- },
+ setProjectHome: this.setProjectHome.bind(this),
getProjectHome$: () => {
return this.projectHome$.asObservable();
},
@@ -408,14 +406,25 @@ export class ProjectNavigationService {
return;
}
- const { sideNavComponent } = definition;
+ const { sideNavComponent, homePage = '' } = definition;
+ const homePageLink = this.navLinksService?.get(homePage);
+
if (sideNavComponent) {
this.setSideNavComponent(sideNavComponent);
}
+
+ if (homePageLink) {
+ this.setProjectHome(homePageLink.href);
+ }
+
this.initNavigation(nextId, definition.navigationTree$);
});
}
+ private setProjectHome(homeHref: string) {
+ this.projectHome$.next(homeHref);
+ }
+
private goToSolutionHome(id: string) {
const definitions = this.solutionNavDefinitions$.getValue();
const definition = definitions[id];
diff --git a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.test.tsx b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.test.tsx
index 04e5773e176bdd..10a6c75d709beb 100644
--- a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.test.tsx
+++ b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.test.tsx
@@ -33,6 +33,7 @@ describe('Header', () => {
navControlsLeft$: Rx.of([]),
navControlsCenter$: Rx.of([]),
navControlsRight$: Rx.of([]),
+ customBranding$: Rx.of({}),
prependBasePath: (str) => `hello/world/${str}`,
toggleSideNav: jest.fn(),
};
@@ -46,5 +47,16 @@ describe('Header', () => {
expect(await screen.findByTestId('euiCollapsibleNavButton')).toBeVisible();
expect(await screen.findByText('Hello, world!')).toBeVisible();
+ expect(screen.queryByTestId(/customLogo/)).toBeNull();
+ });
+
+ it('renders custom branding logo', async () => {
+ const { queryByTestId } = render(
+
+ Hello, world!
+
+ );
+
+ expect(queryByTestId(/customLogo/)).not.toBeNull();
});
});
diff --git a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx
index 77aef1053a8a24..637e87773cf7a8 100644
--- a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx
+++ b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx
@@ -14,6 +14,7 @@ import {
EuiLoadingSpinner,
useEuiTheme,
EuiThemeComputed,
+ EuiImage,
} from '@elastic/eui';
import { css } from '@emotion/react';
import type { InternalApplicationStart } from '@kbn/core-application-browser-internal';
@@ -33,7 +34,9 @@ import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app';
import { Router } from '@kbn/shared-ux-router';
import React, { useCallback } from 'react';
import useObservable from 'react-use/lib/useObservable';
-import { debounceTime, Observable, of } from 'rxjs';
+import { debounceTime, Observable } from 'rxjs';
+import type { CustomBranding } from '@kbn/core-custom-branding-common';
+
import { useHeaderActionMenuMounter } from '../header/header_action_menu';
import { Breadcrumbs } from './breadcrumbs';
import { HeaderHelpMenu } from '../header/header_help_menu';
@@ -46,11 +49,11 @@ import { ProjectNavigation } from './navigation';
const getHeaderCss = ({ size, colors }: EuiThemeComputed) => ({
logo: {
container: css`
- display: inline-block;
+ display: flex;
+ align-items: center;
+ justify-content: center;
min-width: 56px; /* 56 = 40 + 8 + 8 */
- padding: 0 ${size.s};
cursor: pointer;
- margin-left: -${size.s}; // to get equal spacing between .euiCollapsibleNavButtonWrapper, logo and breadcrumbs
`,
logo: css`
min-width: 0; /* overrides min-width: 40px */
@@ -113,6 +116,7 @@ export interface Props {
actionMenu$: Observable;
docLinks: DocLinksStart;
children: React.ReactNode;
+ customBranding$: Observable;
globalHelpExtensionMenuLinks$: Observable;
helpExtension$: Observable;
helpSupportUrl$: Observable;
@@ -130,46 +134,77 @@ export interface Props {
const LOADING_DEBOUNCE_TIME = 80;
-type LogoProps = Pick & {
+type LogoProps = Pick<
+ Props,
+ 'application' | 'homeHref$' | 'loadingCount$' | 'prependBasePath' | 'customBranding$'
+> & {
logoCss: HeaderCss['logo'];
};
-const Logo = (props: LogoProps) => {
- const loadingCount = useObservable(
- props.loadingCount$.pipe(debounceTime(LOADING_DEBOUNCE_TIME)),
- 0
- );
-
- const homeHref = useObservable(props.homeHref$, '/app/home');
+const Logo = ({
+ loadingCount$,
+ homeHref$,
+ prependBasePath,
+ application,
+ logoCss,
+ customBranding$,
+}: LogoProps) => {
+ const loadingCount = useObservable(loadingCount$.pipe(debounceTime(LOADING_DEBOUNCE_TIME)), 0);
+ const homeHref = useObservable(homeHref$, '/app/home');
+ const customBranding = useObservable(customBranding$, {});
+ const { logo } = customBranding;
let fullHref: string | undefined;
if (homeHref) {
- fullHref = props.prependBasePath(homeHref);
+ fullHref = prependBasePath(homeHref);
}
const navigateHome = useCallback(
(event: React.MouseEvent) => {
if (fullHref) {
- props.application.navigateToUrl(fullHref);
+ application.navigateToUrl(fullHref);
}
event.preventDefault();
},
- [fullHref, props.application]
+ [fullHref, application]
);
+ const renderLogo = () => {
+ if (logo) {
+ return (
+
+
+
+ );
+ }
+
+ return (
+
+ );
+ };
+
return (
-
+
{loadingCount === 0 ? (
-
+ renderLogo()
) : (
-
+
{
const headerActionMenuMounter = useHeaderActionMenuMounter(observables.actionMenu$);
@@ -200,7 +236,7 @@ export const ProjectHeader = ({
<>
@@ -220,6 +256,7 @@ export const ProjectHeader = ({
application={application}
homeHref$={observables.homeHref$}
loadingCount$={observables.loadingCount$}
+ customBranding$={customBranding$}
logoCss={logoCss}
/>