From c9cbf31d2313b510b995024689f9c5fdff6cc4c3 Mon Sep 17 00:00:00 2001 From: Miki Date: Fri, 7 Jul 2023 10:55:45 -0700 Subject: [PATCH] Update header logo selection logic and assets (#4383) Signed-off-by: Miki --- CHANGELOG.md | 1 + .../header/__snapshots__/header.test.tsx.snap | 20 + .../__snapshots__/header_logo.test.tsx.snap | 398 ++++++++++++++++-- src/core/public/chrome/ui/header/header.tsx | 8 +- .../chrome/ui/header/header_logo.test.tsx | 62 ++- .../public/chrome/ui/header/header_logo.tsx | 37 +- .../opensearch_logo_dark_mode.svg | 95 ----- .../opensearch_logo_default_mode.svg | 95 ----- .../assets/logos/opensearch_dashboards.svg | 13 + .../logos/opensearch_dashboards_darkmode.svg | 13 + 10 files changed, 472 insertions(+), 270 deletions(-) delete mode 100644 src/core/server/core_app/assets/default_branding/opensearch_logo_dark_mode.svg delete mode 100644 src/core/server/core_app/assets/default_branding/opensearch_logo_default_mode.svg create mode 100644 src/core/server/core_app/assets/logos/opensearch_dashboards.svg create mode 100644 src/core/server/core_app/assets/logos/opensearch_dashboards_darkmode.svg diff --git a/CHANGELOG.md b/CHANGELOG.md index d54edc04772e..fd7f9dcdf4b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - [@osd/pm] Fix `file:`-linked dependencies' resolution to improve ability to test with local packages ([#4342](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4342)) - [Multiple DataSource] Backend support for adding sample data ([#4268](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4268)) - Add configurable defaults and overrides to uiSettings ([#4344](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4344)) +- Update header logo selection logic to match the header's theme ([#4383](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4383)) - Introduce new fonts for the Next theme ([#4381](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4381)) - Bump OUI to `1.1.2` to make `anomalyDetection` icon available ([#4408](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4408)) - Add `color-scheme` to the root styling ([#4477](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4477)) 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 4c2beb329a98..f1ed5f38f073 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 @@ -1888,6 +1888,15 @@ exports[`Header handles visibility and lock changes 1`] = ` "borders": "none", "items": Array [ , ], }, @@ -2325,6 +2335,15 @@ exports[`Header handles visibility and lock changes 1`] = ` className="euiHeaderSectionItem" > `; -exports[`Header logo in dark mode uses custom logo default mode URL if no dark mode logo provided 1`] = ` +exports[`Header logo when dark-themed uses dashboards' dark logo if branding containing a mark but not a logo is provided 1`] = ` `; -exports[`Header logo in dark mode uses opensearch logo if custom mark provided without logo 1`] = ` +exports[`Header logo when dark-themed uses dashboards' dark logo if branding containing no logo is provided 1`] = ` + + +`; + +exports[`Header logo when dark-themed uses dashboards' dark logo if no branding is provided 1`] = ` + + + opensearch dashboards logo `; -exports[`Header logo in dark mode uses opensearch logo if no logo provided 1`] = ` +exports[`Header logo when dark-themed uses default-themed custom logo if branding without dark-mode logo is provided 1`] = ` `; -exports[`Header logo in default mode uses custom logo default mode URL 1`] = ` +exports[`Header logo when default-themed uses custom default-mode logo if branding logo is provided 1`] = ` `; -exports[`Header logo in default mode uses opensearch logo if custom mark provided without logo 1`] = ` +exports[`Header logo when default-themed uses dashboards logo if branding containing a mark but not a logo is provided 1`] = ` `; -exports[`Header logo in default mode uses opensearch logo if no branding provided 1`] = ` +exports[`Header logo when default-themed uses dashboards logo if branding containing no logo is provided 1`] = ` opensearch dashboards logo `; -exports[`Header logo in default mode uses opensearch logo if no logo provided 1`] = ` +exports[`Header logo when default-themed uses dashboards logo if no branding is provided 1`] = ` custom title logo diff --git a/src/core/public/chrome/ui/header/header.tsx b/src/core/public/chrome/ui/header/header.tsx index a78371f4f264..0e595001480d 100644 --- a/src/core/public/chrome/ui/header/header.tsx +++ b/src/core/public/chrome/ui/header/header.tsx @@ -30,6 +30,7 @@ import { EuiHeader, + EuiHeaderProps, EuiHeaderSection, EuiHeaderSectionItem, EuiHeaderSectionItemButton, @@ -116,6 +117,8 @@ export function Header({ const className = classnames('hide-for-sharing', 'headerGlobalNav'); const { useExpandedHeader = true, darkMode } = branding; + const headerTheme: EuiHeaderProps['theme'] = 'dark'; + return ( <>
@@ -123,7 +126,7 @@ export function Header({ {useExpandedHeader && ( , ], borders: 'none', diff --git a/src/core/public/chrome/ui/header/header_logo.test.tsx b/src/core/public/chrome/ui/header/header_logo.test.tsx index 0ac5a03b3589..6d31e71c1f0a 100644 --- a/src/core/public/chrome/ui/header/header_logo.test.tsx +++ b/src/core/public/chrome/ui/header/header_logo.test.tsx @@ -3,22 +3,27 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { EuiHeaderProps } from '@elastic/eui'; import React from 'react'; import { BehaviorSubject } from 'rxjs'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { HeaderLogo, DEFAULT_DARK_LOGO, DEFAULT_LOGO } from './header_logo'; +import { BasePath } from '../../../http/base_path'; +const basePath = new BasePath('/base'); const mockProps = () => ({ href: '/', + basePath, navLinks$: new BehaviorSubject([]), forceNavigation$: new BehaviorSubject(false), navigateToApp: jest.fn(), branding: {}, + theme: 'default' as EuiHeaderProps['theme'], }); -describe('Header logo ', () => { - describe('in default mode ', () => { - it('uses opensearch logo if no branding provided', () => { +describe('Header logo', () => { + describe('when default-themed ', () => { + it('uses dashboards logo if no branding is provided', () => { const branding = {}; const props = { ...mockProps(), @@ -26,14 +31,13 @@ describe('Header logo ', () => { }; const component = mountWithIntl(); const img = component.find('.logoContainer img'); - expect(img.prop('src')).toEqual(`/${DEFAULT_LOGO}`); + expect(img.prop('src')).toEqual(`${basePath.serverBasePath}/${DEFAULT_LOGO}`); expect(img.prop('alt')).toEqual(`opensearch dashboards logo`); expect(component).toMatchSnapshot(); }); - it('uses opensearch logo if no logo provided', () => { + it('uses dashboards logo if branding containing no logo is provided', () => { const branding = { - darkMode: false, logo: {}, mark: {}, applicationTitle: 'custom title', @@ -45,14 +49,13 @@ describe('Header logo ', () => { }; const component = mountWithIntl(); const img = component.find('.logoContainer img'); - expect(img.prop('src')).toEqual(`${branding.assetFolderUrl}/${DEFAULT_LOGO}`); + expect(img.prop('src')).toEqual(`${basePath.serverBasePath}/${DEFAULT_LOGO}`); expect(img.prop('alt')).toEqual(`${branding.applicationTitle} logo`); expect(component).toMatchSnapshot(); }); - it('uses opensearch logo if custom mark provided without logo', () => { + it('uses dashboards logo if branding containing a mark but not a logo is provided', () => { const branding = { - darkMode: false, logo: {}, mark: { defaultUrl: '/defaultModeMark' }, applicationTitle: 'custom title', @@ -64,14 +67,13 @@ describe('Header logo ', () => { }; const component = mountWithIntl(); const img = component.find('.logoContainer img'); - expect(img.prop('src')).toEqual(`${branding.assetFolderUrl}/${DEFAULT_LOGO}`); + expect(img.prop('src')).toEqual(`${basePath.serverBasePath}/${DEFAULT_LOGO}`); expect(img.prop('alt')).toEqual(`${branding.applicationTitle} logo`); expect(component).toMatchSnapshot(); }); - it('uses custom logo default mode URL', () => { + it('uses custom default-mode logo if branding logo is provided', () => { const branding = { - darkMode: false, logo: { defaultUrl: '/defaultModeLogo' }, mark: {}, applicationTitle: 'custom title', @@ -89,10 +91,23 @@ describe('Header logo ', () => { }); }); - describe('in dark mode ', () => { - it('uses opensearch logo if no logo provided', () => { + describe('when dark-themed', () => { + it("uses dashboards' dark logo if no branding is provided", () => { + const branding = {}; + const props = { + ...mockProps(), + branding, + theme: 'dark' as EuiHeaderProps['theme'], + }; + const component = mountWithIntl(); + const img = component.find('.logoContainer img'); + expect(img.prop('src')).toEqual(`${basePath.serverBasePath}/${DEFAULT_DARK_LOGO}`); + expect(img.prop('alt')).toEqual(`opensearch dashboards logo`); + expect(component).toMatchSnapshot(); + }); + + it("uses dashboards' dark logo if branding containing no logo is provided", () => { const branding = { - darkMode: true, logo: {}, mark: {}, applicationTitle: 'custom title', @@ -101,17 +116,17 @@ describe('Header logo ', () => { const props = { ...mockProps(), branding, + theme: 'dark' as EuiHeaderProps['theme'], }; const component = mountWithIntl(); const img = component.find('.logoContainer img'); - expect(img.prop('src')).toEqual(`${branding.assetFolderUrl}/${DEFAULT_DARK_LOGO}`); + expect(img.prop('src')).toEqual(`${basePath.serverBasePath}/${DEFAULT_DARK_LOGO}`); expect(img.prop('alt')).toEqual(`${branding.applicationTitle} logo`); expect(component).toMatchSnapshot(); }); - it('uses opensearch logo if custom mark provided without logo', () => { + it("uses dashboards' dark logo if branding containing a mark but not a logo is provided", () => { const branding = { - darkMode: true, logo: {}, mark: { defaultUrl: '/defaultModeMark' }, applicationTitle: 'custom title', @@ -120,17 +135,17 @@ describe('Header logo ', () => { const props = { ...mockProps(), branding, + theme: 'dark' as EuiHeaderProps['theme'], }; const component = mountWithIntl(); const img = component.find('.logoContainer img'); - expect(img.prop('src')).toEqual(`${branding.assetFolderUrl}/${DEFAULT_DARK_LOGO}`); + expect(img.prop('src')).toEqual(`${basePath.serverBasePath}/${DEFAULT_DARK_LOGO}`); expect(img.prop('alt')).toEqual(`${branding.applicationTitle} logo`); expect(component).toMatchSnapshot(); }); - it('uses custom logo default mode URL if no dark mode logo provided', () => { + it('uses default-themed custom logo if branding without dark-mode logo is provided', () => { const branding = { - darkMode: true, logo: { defaultUrl: '/defaultModeLogo' }, mark: {}, applicationTitle: 'custom title', @@ -139,6 +154,7 @@ describe('Header logo ', () => { const props = { ...mockProps(), branding, + theme: 'dark' as EuiHeaderProps['theme'], }; const component = mountWithIntl(); const img = component.find('.logoContainer img'); @@ -147,9 +163,8 @@ describe('Header logo ', () => { expect(component).toMatchSnapshot(); }); - it('uses custom logo dark mode URL', () => { + it('uses custom dark-mode logo if branding dark-mode logo is provided', () => { const branding = { - darkMode: true, logo: { defaultUrl: '/defaultModeLogo', darkModeUrl: '/darkModeLogo' }, mark: {}, applicationTitle: 'custom title', @@ -158,6 +173,7 @@ describe('Header logo ', () => { const props = { ...mockProps(), branding, + theme: 'dark' as EuiHeaderProps['theme'], }; const component = mountWithIntl(); const img = component.find('.logoContainer img'); diff --git a/src/core/public/chrome/ui/header/header_logo.tsx b/src/core/public/chrome/ui/header/header_logo.tsx index 26b1783e132b..00de679f5184 100644 --- a/src/core/public/chrome/ui/header/header_logo.tsx +++ b/src/core/public/chrome/ui/header/header_logo.tsx @@ -29,12 +29,14 @@ */ import './header_logo.scss'; +import { EuiHeaderProps } from '@elastic/eui'; import { i18n } from '@osd/i18n'; import React from 'react'; import useObservable from 'react-use/lib/useObservable'; import { Observable } from 'rxjs'; import { ChromeNavLink } from '../..'; import { ChromeBranding } from '../../chrome_service'; +import { HttpStart } from '../../../http'; function findClosestAnchor(element: HTMLElement): HTMLAnchorElement | void { let current = element; @@ -96,32 +98,45 @@ function onClick( } } -export const DEFAULT_DARK_LOGO = 'opensearch_logo_dark_mode.svg'; -export const DEFAULT_LOGO = 'opensearch_logo_default_mode.svg'; +export const DEFAULT_LOGO = 'ui/logos/opensearch_dashboards.svg'; +export const DEFAULT_DARK_LOGO = 'ui/logos/opensearch_dashboards_darkmode.svg'; + interface Props { href: string; navLinks$: Observable; forceNavigation$: Observable; navigateToApp: (appId: string) => void; branding: ChromeBranding; + basePath: HttpStart['basePath']; + // What background is the logo appearing on; this is independent of theme:darkMode + theme?: EuiHeaderProps['theme']; } -export function HeaderLogo({ href, navigateToApp, branding, ...observables }: Props) { +export function HeaderLogo({ + href, + navigateToApp, + branding, + basePath, + theme = 'default', + ...observables +}: Props) { const forceNavigation = useObservable(observables.forceNavigation$, false); const navLinks = useObservable(observables.navLinks$, []); const { - darkMode, - assetFolderUrl = '', - logo = {}, + logo: { defaultUrl: customLogoUrl, darkModeUrl: customDarkLogoUrl } = {}, applicationTitle = 'opensearch dashboards', } = branding; - const { defaultUrl: logoUrl, darkModeUrl: darkLogoUrl } = logo; - const customLogo = darkMode ? darkLogoUrl ?? logoUrl : logoUrl; - const defaultLogo = darkMode ? DEFAULT_DARK_LOGO : DEFAULT_LOGO; + // Attempt to find a suitable custom branded logo before falling back on OSD's + let logoSrc = theme === 'dark' && customDarkLogoUrl ? customDarkLogoUrl : customLogoUrl; + let testSubj = 'customLogo'; + + // If no custom branded logo was set, use OSD's + if (!logoSrc) { + logoSrc = `${basePath.serverBasePath}/${theme === 'dark' ? DEFAULT_DARK_LOGO : DEFAULT_LOGO}`; + testSubj = 'defaultLogo'; + } - const logoSrc = customLogo ? customLogo : `${assetFolderUrl}/${defaultLogo}`; - const testSubj = customLogo ? 'customLogo' : 'defaultLogo'; const alt = `${applicationTitle} logo`; return ( diff --git a/src/core/server/core_app/assets/default_branding/opensearch_logo_dark_mode.svg b/src/core/server/core_app/assets/default_branding/opensearch_logo_dark_mode.svg deleted file mode 100644 index 5fc96631974a..000000000000 --- a/src/core/server/core_app/assets/default_branding/opensearch_logo_dark_mode.svg +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/core/server/core_app/assets/default_branding/opensearch_logo_default_mode.svg b/src/core/server/core_app/assets/default_branding/opensearch_logo_default_mode.svg deleted file mode 100644 index 9ee816341523..000000000000 --- a/src/core/server/core_app/assets/default_branding/opensearch_logo_default_mode.svg +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/src/core/server/core_app/assets/logos/opensearch_dashboards.svg b/src/core/server/core_app/assets/logos/opensearch_dashboards.svg new file mode 100644 index 000000000000..bb85dcdd10ed --- /dev/null +++ b/src/core/server/core_app/assets/logos/opensearch_dashboards.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/core/server/core_app/assets/logos/opensearch_dashboards_darkmode.svg b/src/core/server/core_app/assets/logos/opensearch_dashboards_darkmode.svg new file mode 100644 index 000000000000..ba023b5b9a37 --- /dev/null +++ b/src/core/server/core_app/assets/logos/opensearch_dashboards_darkmode.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + +