diff --git a/config/opensearch_dashboards.yml b/config/opensearch_dashboards.yml index 6d8f26da7c02..2ed7d8fa2b0b 100644 --- a/config/opensearch_dashboards.yml +++ b/config/opensearch_dashboards.yml @@ -151,6 +151,13 @@ # ] #vis_type_timeline.graphiteBlockedIPs: [] -# user input URL for customized logo +# full version customized logo URL # opensearchDashboards.branding.logoUrl: "" +# smaller version customized logo URL +# opensearchDashboards.branding.smallLogoUrl: "" + +# custom application title +# opensearchDashboards.branding.title: "" + + 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 139c4510de33..23021f21c535 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 @@ -250,6 +250,8 @@ exports[`Header renders 1`] = ` branding={ Object { "logoUrl": "/", + "smallLogoUrl": "/", + "title": "OpenSearch Dashboards", } } breadcrumbs$={ @@ -2936,6 +2938,8 @@ exports[`Header renders 1`] = ` logo diff --git a/src/core/public/chrome/ui/header/branding/__snapshots__/opensearch_dashboards_custom_logo.test.tsx.snap b/src/core/public/chrome/ui/header/branding/__snapshots__/opensearch_dashboards_custom_logo.test.tsx.snap index 11c1aa814449..86e03ca908e1 100644 --- a/src/core/public/chrome/ui/header/branding/__snapshots__/opensearch_dashboards_custom_logo.test.tsx.snap +++ b/src/core/public/chrome/ui/header/branding/__snapshots__/opensearch_dashboards_custom_logo.test.tsx.snap @@ -1,8 +1,124 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`Custom Logo Take in a invalid URL string 1`] = ` + + logo + +`; + exports[`Custom Logo Take in a normal URL string 1`] = ` logo `; diff --git a/src/core/public/chrome/ui/header/branding/opensearch_dashboards_custom_logo.test.tsx b/src/core/public/chrome/ui/header/branding/opensearch_dashboards_custom_logo.test.tsx index 3a8d057a7e04..83b6064d2aa1 100644 --- a/src/core/public/chrome/ui/header/branding/opensearch_dashboards_custom_logo.test.tsx +++ b/src/core/public/chrome/ui/header/branding/opensearch_dashboards_custom_logo.test.tsx @@ -12,7 +12,12 @@ import { CustomLogo } from './opensearch_dashboards_custom_logo'; describe('Custom Logo', () => { it('Take in a normal URL string', () => { - const branding = { logoUrl: '/', className: '' }; + const branding = { logoUrl: '/custom' }; + const component = mountWithIntl(); + expect(component).toMatchSnapshot(); + }); + it('Take in a invalid URL string', () => { + const branding = { logoUrl: '' }; const component = mountWithIntl(); expect(component).toMatchSnapshot(); }); diff --git a/src/core/public/chrome/ui/header/branding/opensearch_dashboards_custom_logo.tsx b/src/core/public/chrome/ui/header/branding/opensearch_dashboards_custom_logo.tsx index 00f5a70d915a..4d267424455b 100644 --- a/src/core/public/chrome/ui/header/branding/opensearch_dashboards_custom_logo.tsx +++ b/src/core/public/chrome/ui/header/branding/opensearch_dashboards_custom_logo.tsx @@ -38,11 +38,13 @@ export interface CustomLogoType { } export const CustomLogo = ({ ...branding }: CustomLogoType) => { + const defaultUrl = + 'https://opensearch.org/assets/brand/SVG/Logo/opensearch_dashboards_logo_darkmode.svg'; return ( logo {}, - branding: { logoUrl: '/' }, + branding: { logoUrl: '/', smallLogoUrl: '/', title: 'OpenSearch Dashboards' }, }; } diff --git a/src/core/public/core_system.ts b/src/core/public/core_system.ts index 9a071bfdf2fa..bb873ddd3f45 100644 --- a/src/core/public/core_system.ts +++ b/src/core/public/core_system.ts @@ -239,7 +239,7 @@ export class CoreSystem { docLinks, http, i18n, - injectedMetadata: pick(injectedMetadata, ['getInjectedVar']), + injectedMetadata: pick(injectedMetadata, ['getInjectedVar', 'getBranding']), notifications, overlays, savedObjects, diff --git a/src/core/public/index.ts b/src/core/public/index.ts index f4ecc3848b96..b000f72df337 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -236,6 +236,11 @@ export interface CoreSetup unknown; + getBranding: () => { + logoUrl: string; + smallLogoUrl: string; + title: string; + }; }; /** {@link StartServicesAccessor} */ getStartServices: StartServicesAccessor; @@ -291,6 +296,11 @@ export interface CoreStart { * */ injectedMetadata: { getInjectedVar: (name: string, defaultValue?: any) => unknown; + getBranding: () => { + logoUrl: string; + smallLogoUrl: string; + title: string; + }; }; } diff --git a/src/core/public/injected_metadata/injected_metadata_service.test.ts b/src/core/public/injected_metadata/injected_metadata_service.test.ts index 185cb23b6c58..140fa96f72f3 100644 --- a/src/core/public/injected_metadata/injected_metadata_service.test.ts +++ b/src/core/public/injected_metadata/injected_metadata_service.test.ts @@ -234,11 +234,11 @@ describe('setup.getBranding()', () => { it('returns injectedMetadata.branding', () => { const injectedMetadata = new InjectedMetadataService({ injectedMetadata: { - branding: { logoUrl: '/' }, + branding: { logoUrl: '/', smallLogoUrl: '/', title: 'title' }, }, } as any); - const logoURL = injectedMetadata.setup().getBranding(); - expect(logoURL).toEqual({ logoUrl: '/' }); + const branding = injectedMetadata.setup().getBranding(); + expect(branding).toEqual({ logoUrl: '/', smallLogoUrl: '/', title: 'title' }); }); }); diff --git a/src/core/public/injected_metadata/injected_metadata_service.ts b/src/core/public/injected_metadata/injected_metadata_service.ts index 9e57f09191c1..2b1b9f1d493e 100644 --- a/src/core/public/injected_metadata/injected_metadata_service.ts +++ b/src/core/public/injected_metadata/injected_metadata_service.ts @@ -78,6 +78,8 @@ export interface InjectedMetadataParams { }; branding: { logoUrl: string; + smallLogoUrl: string; + title: string; }; }; } @@ -185,6 +187,8 @@ export interface InjectedMetadataSetup { }; getBranding: () => { logoUrl: string; + smallLogoUrl: string; + title: string; }; } diff --git a/src/core/public/mocks.ts b/src/core/public/mocks.ts index 166a335a3556..ac96b745dc90 100644 --- a/src/core/public/mocks.ts +++ b/src/core/public/mocks.ts @@ -103,6 +103,7 @@ function createCoreStartMock({ basePath = '' } = {}) { savedObjects: savedObjectsServiceMock.createStartContract(), injectedMetadata: { getInjectedVar: injectedMetadataServiceMock.createStartContract().getInjectedVar, + getBranding: injectedMetadataServiceMock.createStartContract().getBranding, }, fatalErrors: fatalErrorsServiceMock.createStartContract(), }; diff --git a/src/core/public/plugins/plugin_context.ts b/src/core/public/plugins/plugin_context.ts index 69779b3162c1..d6c98e7126b2 100644 --- a/src/core/public/plugins/plugin_context.ts +++ b/src/core/public/plugins/plugin_context.ts @@ -120,6 +120,7 @@ export function createPluginSetupContext< uiSettings: deps.uiSettings, injectedMetadata: { getInjectedVar: deps.injectedMetadata.getInjectedVar, + getBranding: deps.injectedMetadata.getBranding, }, getStartServices: () => plugin.startDependencies, }; @@ -166,6 +167,7 @@ export function createPluginStartContext< savedObjects: deps.savedObjects, injectedMetadata: { getInjectedVar: deps.injectedMetadata.getInjectedVar, + getBranding: deps.injectedMetadata.getBranding, }, fatalErrors: deps.fatalErrors, }; diff --git a/src/core/public/plugins/plugins_service.test.ts b/src/core/public/plugins/plugins_service.test.ts index c95cb42869ad..eedcd5290ca4 100644 --- a/src/core/public/plugins/plugins_service.test.ts +++ b/src/core/public/plugins/plugins_service.test.ts @@ -113,7 +113,7 @@ describe('PluginsService', () => { ...mockSetupDeps, application: expect.any(Object), getStartServices: expect.any(Function), - injectedMetadata: pick(mockSetupDeps.injectedMetadata, 'getInjectedVar'), + injectedMetadata: pick(mockSetupDeps.injectedMetadata, 'getInjectedVar', 'getBranding'), }; mockStartDeps = { application: applicationServiceMock.createInternalStartContract(), @@ -132,7 +132,7 @@ describe('PluginsService', () => { ...mockStartDeps, application: expect.any(Object), chrome: omit(mockStartDeps.chrome, 'getComponent'), - injectedMetadata: pick(mockStartDeps.injectedMetadata, 'getInjectedVar'), + injectedMetadata: pick(mockStartDeps.injectedMetadata, 'getInjectedVar', 'getBranding'), }; // Reset these for each test. diff --git a/src/core/server/opensearch_dashboards_config.ts b/src/core/server/opensearch_dashboards_config.ts index 7e3b64a7b219..a4628e19fb3e 100644 --- a/src/core/server/opensearch_dashboards_config.ts +++ b/src/core/server/opensearch_dashboards_config.ts @@ -54,9 +54,12 @@ export const config = { autocompleteTimeout: schema.duration({ defaultValue: 1000 }), branding: schema.object({ logoUrl: schema.string({ - defaultValue: - 'https://opensearch.org/assets/brand/SVG/Logo/opensearch_dashboards_logo_darkmode.svg', + defaultValue: '/', }), + smallLogoUrl: schema.string({ + defaultValue: '/', + }), + title: schema.string({ defaultValue: 'OpenSearch Dashboards' }), }), }), deprecations, diff --git a/src/core/server/rendering/__snapshots__/rendering_service.test.ts.snap b/src/core/server/rendering/__snapshots__/rendering_service.test.ts.snap index e934b3f9af6f..c2e21d635e22 100644 --- a/src/core/server/rendering/__snapshots__/rendering_service.test.ts.snap +++ b/src/core/server/rendering/__snapshots__/rendering_service.test.ts.snap @@ -6,7 +6,9 @@ Object { "basePath": "/mock-server-basepath", "branch": Any, "branding": Object { - "logoUrl": "https://opensearch.org/assets/brand/SVG/Logo/opensearch_dashboards_logo_darkmode.svg", + "logoUrl": "", + "smallLogoUrl": "", + "title": "OpenSearch Dashboards", }, "buildNumber": Any, "csp": Object { @@ -52,7 +54,9 @@ Object { "basePath": "/mock-server-basepath", "branch": Any, "branding": Object { - "logoUrl": "https://opensearch.org/assets/brand/SVG/Logo/opensearch_dashboards_logo_darkmode.svg", + "logoUrl": "", + "smallLogoUrl": "", + "title": "OpenSearch Dashboards", }, "buildNumber": Any, "csp": Object { @@ -98,7 +102,9 @@ Object { "basePath": "/mock-server-basepath", "branch": Any, "branding": Object { - "logoUrl": "https://opensearch.org/assets/brand/SVG/Logo/opensearch_dashboards_logo_darkmode.svg", + "logoUrl": "", + "smallLogoUrl": "", + "title": "OpenSearch Dashboards", }, "buildNumber": Any, "csp": Object { @@ -148,7 +154,9 @@ Object { "basePath": "", "branch": Any, "branding": Object { - "logoUrl": "https://opensearch.org/assets/brand/SVG/Logo/opensearch_dashboards_logo_darkmode.svg", + "logoUrl": "", + "smallLogoUrl": "", + "title": "OpenSearch Dashboards", }, "buildNumber": Any, "csp": Object { @@ -194,7 +202,9 @@ Object { "basePath": "/mock-server-basepath", "branch": Any, "branding": Object { - "logoUrl": "https://opensearch.org/assets/brand/SVG/Logo/opensearch_dashboards_logo_darkmode.svg", + "logoUrl": "", + "smallLogoUrl": "", + "title": "OpenSearch Dashboards", }, "buildNumber": Any, "csp": Object { diff --git a/src/core/server/rendering/rendering_service.test.ts b/src/core/server/rendering/rendering_service.test.ts index 5c5c091de7c4..79331ef6f97a 100644 --- a/src/core/server/rendering/rendering_service.test.ts +++ b/src/core/server/rendering/rendering_service.test.ts @@ -137,41 +137,31 @@ describe('RenderingService', () => { }); }); describe('checkUrlvalid()', () => { - it('URL is valid', async () => { - jest.mock('axios', () => ({ - async get() { - return { - status: 200, - }; - }, - })); + it('SVG URL is valid', async () => { const result = await service.checkUrlValid( - 'https://opensearch.org/assets/brand/SVG/Logo/opensearch_dashboards_logo_darkmode.svg' + 'https://opensearch.org/assets/brand/SVG/Mark/opensearch_mark_default.svg', + 'error' ); expect(result).toEqual( - 'https://opensearch.org/assets/brand/SVG/Logo/opensearch_dashboards_logo_darkmode.svg' + 'https://opensearch.org/assets/brand/SVG/Mark/opensearch_mark_default.svg' ); }); - it('URL does not contain jpeg, jpg, gif, or png', async () => { + it('PNG URL is valid', async () => { const result = await service.checkUrlValid( - 'https://opensearch.org/assets/brand/SVG/Logo/opensearch_dashboards_logo_darkmode' + 'https://opensearch.org/assets/brand/PNG/Mark/opensearch_mark_default.png', + 'error' ); expect(result).toEqual( - 'https://opensearch.org/assets/brand/SVG/Logo/opensearch_dashboards_logo_darkmode.svg' + 'https://opensearch.org/assets/brand/PNG/Mark/opensearch_mark_default.png' ); }); + it('URL does not contain svg, or png', async () => { + const result = await service.checkUrlValid('https://validUrl', 'error'); + expect(result).toEqual(''); + }); it('URL is invalid', async () => { - jest.mock('axios', () => ({ - async get() { - return { - status: 404, - }; - }, - })); - const result = await service.checkUrlValid('http://notfound'); - expect(result).toEqual( - 'https://opensearch.org/assets/brand/SVG/Logo/opensearch_dashboards_logo_darkmode.svg' - ); + const result = await service.checkUrlValid('http://notfound.svg', 'error'); + expect(result).toEqual(''); }); }); }); diff --git a/src/core/server/rendering/rendering_service.tsx b/src/core/server/rendering/rendering_service.tsx index 13be829d0b7c..b7bb9c384085 100644 --- a/src/core/server/rendering/rendering_service.tsx +++ b/src/core/server/rendering/rendering_service.tsx @@ -63,7 +63,14 @@ export class RenderingService { .pipe(first()) .toPromise(); - const validLogoUrl = await this.checkUrlValid(opensearchDashboardsConfig.branding.logoUrl); + const validLogoUrl = await this.checkUrlValid( + opensearchDashboardsConfig.branding.logoUrl, + 'Config logoUrl is not found or invalid, default OpenSearch logo will be rendered on the main page' + ); + const validSmallLogoUrl = await this.checkUrlValid( + opensearchDashboardsConfig.branding.smallLogoUrl, + 'Config smallLogoUrl is not found or invalid, default OpenSearch logo will be rendered on the welcome page' + ); return { render: async ( @@ -115,6 +122,8 @@ export class RenderingService { }, branding: { logoUrl: validLogoUrl, + smallLogoUrl: validSmallLogoUrl, + title: opensearchDashboardsConfig.branding.title, }, }, }; @@ -132,22 +141,18 @@ export class RenderingService { return ((await browserConfig?.pipe(take(1)).toPromise()) ?? {}) as Record; } - public checkUrlValid = async (url: string): Promise => { + public checkUrlValid = async (url: string, errorMessage: string): Promise => { if (url.match(/\.(png|svg)$/) === null) { - this.logger - .get('branding') - .error('Invalid URL for logo. Rendering default OpenSearch Dashboard Logo.'); - return 'https://opensearch.org/assets/brand/SVG/Logo/opensearch_dashboards_logo_darkmode.svg'; + this.logger.get('branding').error(errorMessage); + return ''; } return await Axios.get(url, { adapter: AxiosHttpAdapter }) .then(() => { return url; }) .catch(() => { - this.logger - .get('branding') - .error('Invalid URL for logo. Rendering default OpenSearch Dashboard Logo.'); - return 'https://opensearch.org/assets/brand/SVG/Logo/opensearch_dashboards_logo_darkmode.svg'; + this.logger.get('branding').error(errorMessage); + return ''; }); }; } diff --git a/src/core/server/rendering/types.ts b/src/core/server/rendering/types.ts index 72a45661ed4a..9e9c08a37c26 100644 --- a/src/core/server/rendering/types.ts +++ b/src/core/server/rendering/types.ts @@ -76,6 +76,8 @@ export interface RenderingMetadata { }; branding: { logoUrl: string; + smallLogoUrl: string; + title: string; }; }; } diff --git a/src/legacy/server/config/schema.js b/src/legacy/server/config/schema.js index 3f21233ad9c9..9d6352587cbe 100644 --- a/src/legacy/server/config/schema.js +++ b/src/legacy/server/config/schema.js @@ -237,6 +237,10 @@ export default () => logoUrl: Joi.string().default( 'https://opensearch.org/assets/brand/SVG/Logo/opensearch_dashboards_logo_darkmode.svg' ), + smallLogoUrl: Joi.string().default( + 'https://opensearch.org/assets/brand/SVG/Logo/opensearch_dashboards_logo_darkmode.svg' + ), + title: Joi.string().default('OpenSearch Dashboards'), }), }).default(), diff --git a/src/plugins/home/public/application/components/__snapshots__/home.test.js.snap b/src/plugins/home/public/application/components/__snapshots__/home.test.js.snap index 6b59eca2f25a..2b522815e339 100644 --- a/src/plugins/home/public/application/components/__snapshots__/home.test.js.snap +++ b/src/plugins/home/public/application/components/__snapshots__/home.test.js.snap @@ -790,6 +790,7 @@ exports[`home welcome should show the normal home page if welcome screen is disa exports[`home welcome should show the welcome screen if enabled, and there are no index patterns defined 1`] = ` diff --git a/src/plugins/home/public/application/components/__snapshots__/welcome.test.tsx.snap b/src/plugins/home/public/application/components/__snapshots__/welcome.test.tsx.snap index b52becae745a..bb331c752bad 100644 --- a/src/plugins/home/public/application/components/__snapshots__/welcome.test.tsx.snap +++ b/src/plugins/home/public/application/components/__snapshots__/welcome.test.tsx.snap @@ -1,6 +1,138 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`should render a Welcome screen with customized branding 1`] = ` + +
+
+
+ +
+ logo +
+ +

+ +

+
+ +
+
+
+ + + + + + +
+
+
+`; + exports[`should render a Welcome screen with no telemetry disclaimer 1`] = ` + +
+
+
+ +
+ logo +
+ +

+ +

+
+ +
+
+
+ + + + + + +
+
+
+`; + +exports[`should render a Welcome screen with the default OpenSearch Dashboards branding 1`] = `

@@ -75,21 +209,26 @@ exports[`should render a Welcome screen with the telemetry disclaimer when optIn - - - +

@@ -173,21 +312,26 @@ exports[`should render a Welcome screen with the telemetry disclaimer when optIn - - - +

diff --git a/src/plugins/home/public/application/components/_welcome.scss b/src/plugins/home/public/application/components/_welcome.scss index 8cb2539247b2..e429c578a40b 100644 --- a/src/plugins/home/public/application/components/_welcome.scss +++ b/src/plugins/home/public/application/components/_welcome.scss @@ -14,6 +14,16 @@ @include euiBottomShadowMedium; } +.homWelcome__customLogoContainer { + height: 80px; + padding: 10px 10px 10px 10px; +} + +.homWelcome__customLogo{ + height: 100%; + max-width: 100%; +} + .homWelcome__footerAction { margin-right: $euiSizeS; } diff --git a/src/plugins/home/public/application/components/home.js b/src/plugins/home/public/application/components/home.js index 52259cd6a6f0..ff670edbb3c6 100644 --- a/src/plugins/home/public/application/components/home.js +++ b/src/plugins/home/public/application/components/home.js @@ -201,13 +201,13 @@ export class Home extends Component { onSkip={this.skipWelcome} urlBasePath={this.props.urlBasePath} telemetry={this.props.telemetry} + branding={getServices().injectedMetadata.getBranding()} /> ); } render() { const { isLoading, isWelcomeEnabled, isNewOpenSearchDashboardsInstance } = this.state; - if (isWelcomeEnabled) { if (isLoading) { return this.renderLoading(); diff --git a/src/plugins/home/public/application/components/home.test.js b/src/plugins/home/public/application/components/home.test.js index 5c0de0365d6c..072e21eff9bd 100644 --- a/src/plugins/home/public/application/components/home.test.js +++ b/src/plugins/home/public/application/components/home.test.js @@ -45,6 +45,9 @@ jest.mock('../opensearch_dashboards_services', () => ({ chrome: { setBreadcrumbs: () => {}, }, + injectedMetadata: { + getBranding: () => ({}), + }, }), })); diff --git a/src/plugins/home/public/application/components/welcome.test.tsx b/src/plugins/home/public/application/components/welcome.test.tsx index d047746ca9cf..cc83a2ca6deb 100644 --- a/src/plugins/home/public/application/components/welcome.test.tsx +++ b/src/plugins/home/public/application/components/welcome.test.tsx @@ -49,10 +49,19 @@ test('should render a Welcome screen with the telemetry disclaimer', () => { expect(component).toMatchSnapshot(); }); */ + +const branding = { + logoUrl: '/', + smallLogoUrl: '/', + title: 'OpenSearch Dashboards', +}; + test('should render a Welcome screen with the telemetry disclaimer when optIn is true', () => { const telemetry = telemetryPluginMock.createStartContract(); telemetry.telemetryService.getIsOptedIn = jest.fn().mockReturnValue(true); - const component = shallow( {}} telemetry={telemetry} />); + const component = shallow( + {}} telemetry={telemetry} branding={branding} /> + ); expect(component).toMatchSnapshot(); }); @@ -60,13 +69,15 @@ test('should render a Welcome screen with the telemetry disclaimer when optIn is test('should render a Welcome screen with the telemetry disclaimer when optIn is false', () => { const telemetry = telemetryPluginMock.createStartContract(); telemetry.telemetryService.getIsOptedIn = jest.fn().mockReturnValue(false); - const component = shallow( {}} telemetry={telemetry} />); + const component = shallow( + {}} telemetry={telemetry} branding={branding} /> + ); expect(component).toMatchSnapshot(); }); test('should render a Welcome screen with no telemetry disclaimer', () => { - const component = shallow( {}} />); + const component = shallow( {}} branding={branding} />); expect(component).toMatchSnapshot(); }); @@ -75,7 +86,31 @@ test('fires opt-in seen when mounted', () => { const telemetry = telemetryPluginMock.createStartContract(); const mockSetOptedInNoticeSeen = jest.fn(); telemetry.telemetryNotifications.setOptedInNoticeSeen = mockSetOptedInNoticeSeen; - shallow( {}} telemetry={telemetry} />); + shallow( {}} telemetry={telemetry} branding={branding} />); expect(mockSetOptedInNoticeSeen).toHaveBeenCalled(); }); + +test('should render a Welcome screen with the default OpenSearch Dashboards branding', () => { + const defaultBranding = { + logoUrl: '/', + smallLogoUrl: '', + title: 'OpenSearch Dashboards', + }; + const component = shallow( + {}} branding={defaultBranding} /> + ); + expect(component).toMatchSnapshot(); +}); + +test('should render a Welcome screen with customized branding', () => { + const customBranding = { + logoUrl: '/', + smallLogoUrl: '/custom', + title: 'custom title', + }; + const component = shallow( + {}} branding={customBranding} /> + ); + expect(component).toMatchSnapshot(); +}); diff --git a/src/plugins/home/public/application/components/welcome.tsx b/src/plugins/home/public/application/components/welcome.tsx index 336414be130f..3747c89b1ca6 100644 --- a/src/plugins/home/public/application/components/welcome.tsx +++ b/src/plugins/home/public/application/components/welcome.tsx @@ -58,6 +58,11 @@ interface Props { urlBasePath: string; onSkip: () => void; telemetry?: TelemetryPluginStart; + branding: { + logoUrl: string; + smallLogoUrl: string; + title: string; + }; } /** @@ -141,19 +146,39 @@ export class Welcome extends React.Component { }; render() { - const { urlBasePath, telemetry } = this.props; + const { urlBasePath, telemetry, branding } = this.props; return (
- - - - + {branding.smallLogoUrl === '' ? ( + + + + ) : ( +
+ logo +
+ )} +

- +

diff --git a/src/plugins/home/public/application/opensearch_dashboards_services.ts b/src/plugins/home/public/application/opensearch_dashboards_services.ts index a5b9fe616a24..b6bb4728726d 100644 --- a/src/plugins/home/public/application/opensearch_dashboards_services.ts +++ b/src/plugins/home/public/application/opensearch_dashboards_services.ts @@ -68,6 +68,14 @@ export interface HomeOpenSearchDashboardsServices { environmentService: EnvironmentService; telemetry?: TelemetryPluginStart; tutorialService: TutorialService; + injectedMetadata: { + getInjectedVar: (name: string, defaultValue?: any) => unknown; + getBranding: () => { + logoUrl: string; + smallLogoUrl: string; + title: string; + }; + }; } let services: HomeOpenSearchDashboardsServices | null = null; diff --git a/src/plugins/home/public/plugin.ts b/src/plugins/home/public/plugin.ts index eef92ea8ec99..c0ef1c2b56ff 100644 --- a/src/plugins/home/public/plugin.ts +++ b/src/plugins/home/public/plugin.ts @@ -119,6 +119,7 @@ export class HomePublicPlugin homeConfig: this.initializerContext.config.get(), tutorialService: this.tutorialService, featureCatalogue: this.featuresCatalogueRegistry, + injectedMetadata: coreStart.injectedMetadata, }); coreStart.chrome.docTitle.change( i18n.translate('home.pageTitle', { defaultMessage: 'Home' }) diff --git a/test/common/config.js b/test/common/config.js index be5baaa5d055..05432914a95b 100644 --- a/test/common/config.js +++ b/test/common/config.js @@ -60,7 +60,7 @@ export default function () { `--opensearch.hosts=${formatUrl(servers.opensearch)}`, `--opensearch.username=${opensearchDashboardsServerTestUser.username}`, `--opensearch.password=${opensearchDashboardsServerTestUser.password}`, - `--home.disableWelcomeScreen=true`, + `--home.disableWelcomeScreen=false`, // Needed for async search functional tests to introduce a delay `--data.search.aggs.shardDelay.enabled=true`, //`--security.showInsecureClusterWarning=false`, @@ -76,6 +76,8 @@ export default function () { // `--newsfeed.service.pathTemplate=/api/_newsfeed-FTS-external-service-simulators/opensearch-dashboards/v{VERSION}.json`, // Custom branding config `--opensearchDashboards.branding.logoUrl=https://opensearch.org/assets/brand/SVG/Logo/opensearch_logo_darkmode.svg`, + `--opensearchDashboards.branding.smallLogoUrl=https://opensearch.org/assets/brand/SVG/Logo/opensearch_logo_darkmode.svg`, + `--opensearchDashboards.branding.title=OpenSearch`, ], }, services, diff --git a/test/functional/apps/visualize/_custom_branding.js b/test/functional/apps/visualize/_custom_branding.js index b783a3e5acab..7b9d8894edcf 100644 --- a/test/functional/apps/visualize/_custom_branding.js +++ b/test/functional/apps/visualize/_custom_branding.js @@ -30,29 +30,75 @@ * GitHub history for details. */ import expect from '@osd/expect'; +import { UI_SETTINGS } from '../../../../src/plugins/data/common'; export default function ({ getService, getPageObjects }) { const browser = getService('browser'); const globalNav = getService('globalNav'); + const opensearchArchiver = getService('opensearchArchiver'); + const opensearchDashboardsServer = getService('opensearchDashboardsServer'); const PageObjects = getPageObjects(['common', 'home', 'header']); + const testSubjects = getService('testSubjects'); - describe('OpenSearch Dashboards branding configuration', function customLogo() { - this.tags('includeFirefox'); - const expectedUrl = 'https://opensearch.org/assets/brand/SVG/Logo/opensearch_logo_darkmode.svg'; - before(async function () { - await PageObjects.common.navigateToApp('home'); + describe('OpenSearch Dashboards branding configuration', function customHomeBranding() { + describe('should render welcome page', async () => { + this.tags('includeFirefox'); + const expectedWelcomeLogo = + 'https://opensearch.org/assets/brand/SVG/Logo/opensearch_logo_darkmode.svg'; + const expectedWelcomeMessage = 'Welcome to OpenSearch'; + before(async function () { + await opensearchArchiver.unload('logstash_functional'); + await opensearchArchiver.unload('long_window_logstash'); + await opensearchArchiver.unload('visualize'); + await PageObjects.common.navigateToApp('home'); + }); + after(async function () { + await browser.setWindowSize(1280, 800); + await opensearchArchiver.loadIfNeeded('logstash_functional'); + await opensearchArchiver.loadIfNeeded('long_window_logstash'); + await opensearchArchiver.load('visualize'); + await opensearchDashboardsServer.uiSettings.replace({ + defaultIndex: 'logstash-*', + [UI_SETTINGS.FORMAT_BYTES_DEFAULT_PATTERN]: '0,0.[000]b', + }); + }); + it('with customized logo', async () => { + await testSubjects.existOrFail('welcomeCustomLogo'); + const actualLabel = await testSubjects.getAttribute( + 'welcomeCustomLogo', + 'data-test-image-url' + ); + expect(actualLabel.toUpperCase()).to.equal(expectedWelcomeLogo.toUpperCase()); + }); + it('with customized title', async () => { + await testSubjects.existOrFail('welcomeCustomTitle'); + const actualLabel = await testSubjects.getAttribute( + 'welcomeCustomTitle', + 'data-test-title-message' + ); + expect(actualLabel.toUpperCase()).to.equal(expectedWelcomeMessage.toUpperCase()); + }); }); - it('should show customized logo in Navbar on the main page', async () => { - await globalNav.logoExistsOrFail(expectedUrl); - }); + describe('should render home page', async () => { + this.tags('includeFirefox'); + const expectedUrl = + 'https://opensearch.org/assets/brand/SVG/Logo/opensearch_logo_darkmode.svg'; + before(async function () { + await PageObjects.common.navigateToApp('home'); + }); + + it('should show customized logo in Navbar for home page', async () => { + await globalNav.logoExistsOrFail(expectedUrl); + }); - it('should show a customized logo that can take to home page', async () => { - await PageObjects.common.navigateToApp('settings'); - await globalNav.clickLogo(); - await PageObjects.header.waitUntilLoadingHasFinished(); - const url = await browser.getCurrentUrl(); - expect(url.includes('/app/home')).to.be(true); + it('should show a customized logo that can take back to home page', async () => { + await PageObjects.common.navigateToApp('settings'); + await globalNav.clickLogo(); + await PageObjects.header.waitUntilLoadingHasFinished(); + const url = await browser.getCurrentUrl(); + expect(url.includes('/app/home')).to.be(true); + }); }); }); } diff --git a/test/functional/page_objects/common_page.ts b/test/functional/page_objects/common_page.ts index d6a018c96b50..84adae2509e7 100644 --- a/test/functional/page_objects/common_page.ts +++ b/test/functional/page_objects/common_page.ts @@ -68,8 +68,7 @@ export function CommonPageProvider({ getService, getPageObjects }: FtrProviderCo // Disable the welcome screen. This is relevant for environments // which don't allow to use the yml setting, e.g. cloud production. // It is done here so it applies to logins but also to a login re-use. - await browser.setLocalStorageItem('home:welcome:show', 'false'); - + await browser.setLocalStorageItem('home:welcome:show', 'true'); let currentUrl = await browser.getCurrentUrl(); log.debug(`currentUrl = ${currentUrl}\n appUrl = ${appUrl}`); await testSubjects.find('opensearchDashboardsChrome', 6 * defaultFindTimeout); // 60 sec waiting