From 80d7d17a180a3ab6db0708b57e6ba36c2f7b2c9e Mon Sep 17 00:00:00 2001 From: Abby Hu Date: Fri, 10 Sep 2021 21:38:04 +0000 Subject: [PATCH] Darkmode configurations for header logo, welcome logo and loading logo Add dark mode configs in the yml file that allows user to configure a dark mode version of the logo. When user toggles dark mode under the Advanced Setting, the logo will be rendered accordingly. Signed-off-by: Abby Hu --- config/opensearch_dashboards.yml | 2 +- .../header/__snapshots__/header.test.tsx.snap | 4 + ...earch_dashboards_custom_logo.test.tsx.snap | 738 +++++++++++++++- ...opensearch_dashboards_custom_logo.test.tsx | 114 ++- .../opensearch_dashboards_custom_logo.tsx | 57 +- .../public/chrome/ui/header/header.test.tsx | 1 + src/core/public/chrome/ui/header/header.tsx | 1 + src/core/public/index.ts | 1 + .../injected_metadata_service.ts | 2 + .../rendering_service.test.ts.snap | 65 +- .../server/rendering/rendering_service.tsx | 213 ++++- src/core/server/rendering/types.ts | 32 + .../__snapshots__/template.test.tsx.snap | 801 +++++++++++++++++- .../server/rendering/views/template.test.tsx | 136 ++- src/core/server/rendering/views/template.tsx | 85 +- .../__snapshots__/welcome.test.tsx.snap | 369 ++++++-- .../application/components/welcome.test.tsx | 167 ++-- .../public/application/components/welcome.tsx | 70 +- test/common/config.js | 2 + .../apps/visualize/_custom_branding.js | 39 +- 20 files changed, 2522 insertions(+), 377 deletions(-) diff --git a/config/opensearch_dashboards.yml b/config/opensearch_dashboards.yml index f3b70890465a..bfc2b05c6db3 100644 --- a/config/opensearch_dashboards.yml +++ b/config/opensearch_dashboards.yml @@ -162,4 +162,4 @@ # defaultUrl: "" # darkModeUrl: "" # favicon: "" - # applicationTitle: "" \ No newline at end of file + # applicationTitle: "" 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 640a43d3481c..f51531d6145f 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,7 @@ exports[`Header renders 1`] = ` branding={ Object { "applicationTitle": "OpenSearch Dashboards", + "darkMode": false, "logo": Object { "defaultUrl": "/", }, @@ -1679,6 +1680,7 @@ exports[`Header renders 1`] = ` branding={ Object { "applicationTitle": "OpenSearch Dashboards", + "darkMode": false, "logo": Object { "defaultUrl": "/", }, @@ -2796,6 +2798,7 @@ exports[`Header renders 1`] = ` branding={ Object { "applicationTitle": "OpenSearch Dashboards", + "darkMode": false, "logo": Object { "defaultUrl": "/", }, @@ -2958,6 +2961,7 @@ exports[`Header renders 1`] = ` > +
+ custom title logo +
+
+`; + +exports[`Header logo in dark mode rendered using logo default mode URL 1`] = ` + +
+ custom title logo +
+
+`; + +exports[`Header logo in dark mode rendered using mark dark mode URL 1`] = ` + +
+ custom title logo +
+
+`; + +exports[`Header logo in dark mode rendered using mark default mode URL 1`] = ` + +
+ custom title logo +
+
+`; + +exports[`Header logo in dark mode rendered using original opensearch logo 1`] = ` + + + + + + + + + + + + + + + + + + + +`; + +exports[`Header logo in default mode rendered using logo default mode URL 1`] = ` + title logo `; -exports[`Custom Logo Take in an invalid full logo URL string and a valid logo URL string 1`] = ` +exports[`Header logo in default mode rendered using mark default mode URL 1`] = ` @@ -243,20 +952,21 @@ exports[`Custom Logo Take in an invalid full logo URL string and a valid logo UR className="logoContainer" > title logo `; -exports[`Custom Logo Take in invalid full logo URL and logo URL 1`] = ` +exports[`Header logo in default mode rendered using the original opensearch logo 1`] = ` { - it('Take in a normal full logo URL string', () => { - const branding = { - logo: { defaultUrl: '/' }, - mark: {}, - applicationTitle: 'title', - }; - const component = mountWithIntl(); - expect(component).toMatchSnapshot(); - }); +describe('Header logo ', () => { + describe('in default mode ', () => { + it('rendered using logo default mode URL', () => { + const branding = { + darkMode: false, + logo: { defaultUrl: '/defaultModeLogo' }, + mark: {}, + applicationTitle: 'custom title', + }; + const component = mountWithIntl(); + expect(component).toMatchSnapshot(); + }); + + it('rendered using mark default mode URL', () => { + const branding = { + darkMode: false, + logo: {}, + mark: { defaultUrl: '/defaultModeMark' }, + applicationTitle: 'custom title', + }; + const component = mountWithIntl(); + expect(component).toMatchSnapshot(); + }); - it('Take in an invalid full logo URL string and a valid logo URL string', () => { - const branding = { - logo: {}, - mark: { defaultUrl: '/' }, - applicationTitle: 'title', - }; - const component = mountWithIntl(); - expect(component).toMatchSnapshot(); + it('rendered using the original opensearch logo', () => { + const branding = { + darkMode: false, + logo: {}, + mark: {}, + applicationTitle: 'custom title', + }; + const component = mountWithIntl(); + expect(component).toMatchSnapshot(); + }); }); - it('Take in invalid full logo URL and logo URL', () => { - const branding = { - logo: {}, - mark: {}, - applicationTitle: 'title', - }; - const component = mountWithIntl(); - expect(component).toMatchSnapshot(); + describe('in dark mode ', () => { + it('rendered using logo dark mode URL', () => { + const branding = { + darkMode: true, + logo: { defaultUrl: '/defaultModeLogo', darkModeUrl: '/darkModeLogo' }, + mark: { defaultUrl: '/defaultModeMark', darkModeUrl: '/darkModeMark' }, + applicationTitle: 'custom title', + }; + const component = mountWithIntl(); + expect(component).toMatchSnapshot(); + }); + + it('rendered using logo default mode URL', () => { + const branding = { + darkMode: true, + logo: { defaultUrl: '/defaultModeLogo' }, + mark: { defaultUrl: '/defaultModeMark', darkModeUrl: '/darkModeMark' }, + applicationTitle: 'custom title', + }; + const component = mountWithIntl(); + expect(component).toMatchSnapshot(); + }); + + it('rendered using mark dark mode URL', () => { + const branding = { + darkMode: true, + logo: {}, + mark: { defaultUrl: '/defaultModeMark', darkModeUrl: '/darkModeMark' }, + applicationTitle: 'custom title', + }; + const component = mountWithIntl(); + expect(component).toMatchSnapshot(); + }); + + it('rendered using mark default mode URL', () => { + const branding = { + darkMode: true, + logo: {}, + mark: { defaultUrl: '/defaultModeMark' }, + applicationTitle: 'custom title', + }; + const component = mountWithIntl(); + expect(component).toMatchSnapshot(); + }); + + it('rendered using original opensearch logo', () => { + const branding = { + darkMode: true, + logo: {}, + mark: {}, + applicationTitle: 'custom title', + }; + 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 6b90c02f338e..5ef77548f86b 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 @@ -40,6 +40,7 @@ import { OpenSearchDashboardsLogoDarkMode } from './opensearch_dashboards_logo_d * @param {string} applicationTitle - custom title for the application */ export interface CustomLogoType { + darkMode: boolean; logo: { defaultUrl?: string; darkModeUrl?: string; @@ -50,7 +51,9 @@ export interface CustomLogoType { }; applicationTitle?: string; } + /** + * Use branding configurations to render the header logo on the nab bar. * * @param {CustomLogoType} - branding object consist of logo, mark and title * @returns A image component which is going to be rendered on the main page header bar. @@ -59,21 +62,57 @@ export interface CustomLogoType { * the default opensearch logo will be rendered. */ export const CustomLogo = ({ ...branding }: CustomLogoType) => { - const headerLogoUrl = !branding.logo.defaultUrl - ? branding.mark.defaultUrl - : branding.logo.defaultUrl; - return !branding.logo.defaultUrl && !branding.mark.defaultUrl ? ( - OpenSearchDashboardsLogoDarkMode() - ) : ( + const darkMode = branding.darkMode; + const logoDefault = branding.logo.defaultUrl; + const logoDarkMode = branding.logo.darkModeUrl; + const markDefault = branding.mark.defaultUrl; + const markDarkMode = branding.mark.darkModeUrl; + const applicationTitle = branding.applicationTitle; + + /** + * Use branding configurations to check which URL to use for rendering + * header logo in nav bar in default mode + * + * @returns a valid custom URL or undefined if no valid URL is provided + */ + const customHeaderLogoDefaultMode = () => { + return logoDefault ?? markDefault ?? undefined; + }; + + /** + * Use branding configurations to check which URL to use for rendering + * header logo in nav bar in dark mode + * + * @returns a valid custom URL or undefined if no valid URL is provided + */ + const customHeaderLogoDarkMode = () => { + return logoDarkMode ?? logoDefault ?? markDarkMode ?? markDefault ?? undefined; + }; + + /** + * Render custom header logo for both default mode and dark mode + * + * @returns a valid custom header logo URL, or undefined + */ + const customHeaderLogo = () => { + if (darkMode) { + return customHeaderLogoDarkMode(); + } + return customHeaderLogoDefaultMode(); + }; + + return customHeaderLogo() ? (
{branding.applicationTitle
+ ) : ( + OpenSearchDashboardsLogoDarkMode() ); }; diff --git a/src/core/public/chrome/ui/header/header.test.tsx b/src/core/public/chrome/ui/header/header.test.tsx index 1566ca67dbf4..740e9d9145dc 100644 --- a/src/core/public/chrome/ui/header/header.test.tsx +++ b/src/core/public/chrome/ui/header/header.test.tsx @@ -70,6 +70,7 @@ function mockProps() { loadingCount$: new BehaviorSubject(0), onIsLockedUpdate: () => {}, branding: { + darkMode: false, logo: { defaultUrl: '/' }, mark: { defaultUrl: '/' }, applicationTitle: 'OpenSearch Dashboards', diff --git a/src/core/public/chrome/ui/header/header.tsx b/src/core/public/chrome/ui/header/header.tsx index 5dd4415ccafa..50e0a3a1e6b6 100644 --- a/src/core/public/chrome/ui/header/header.tsx +++ b/src/core/public/chrome/ui/header/header.tsx @@ -88,6 +88,7 @@ export interface HeaderProps { loadingCount$: ReturnType; onIsLockedUpdate: OnIsLockedUpdate; branding: { + darkMode: boolean; logo: { defaultUrl?: string; darkModeUrl?: string; diff --git a/src/core/public/index.ts b/src/core/public/index.ts index 4fecc2e64405..db61347a2181 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -299,6 +299,7 @@ export interface CoreStart { injectedMetadata: { getInjectedVar: (name: string, defaultValue?: any) => unknown; getBranding: () => { + darkMode: boolean; mark: { defaultUrl?: string; darkModeUrl?: string; diff --git a/src/core/public/injected_metadata/injected_metadata_service.ts b/src/core/public/injected_metadata/injected_metadata_service.ts index 47d5d73f67b3..681d7e8d496c 100644 --- a/src/core/public/injected_metadata/injected_metadata_service.ts +++ b/src/core/public/injected_metadata/injected_metadata_service.ts @@ -77,6 +77,7 @@ export interface InjectedMetadataParams { }; }; branding: { + darkMode: boolean; logo: { defaultUrl?: string; darkModeUrl?: string; @@ -197,6 +198,7 @@ export interface InjectedMetadataSetup { [key: string]: unknown; }; getBranding: () => { + darkMode: boolean; logo: { defaultUrl?: string; darkModeUrl?: string; 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 73d1d75e3f9b..715e6e846989 100644 --- a/src/core/server/rendering/__snapshots__/rendering_service.test.ts.snap +++ b/src/core/server/rendering/__snapshots__/rendering_service.test.ts.snap @@ -7,16 +7,11 @@ Object { "branch": Any, "branding": Object { "applicationTitle": "OpenSearch Dashboards", + "darkMode": false, "favicon": "", - "loadingLogo": Object { - "darkModeUrl": "", - }, - "logo": Object { - "darkModeUrl": "", - }, - "mark": Object { - "darkModeUrl": "", - }, + "loadingLogo": Object {}, + "logo": Object {}, + "mark": Object {}, }, "buildNumber": Any, "csp": Object { @@ -63,16 +58,11 @@ Object { "branch": Any, "branding": Object { "applicationTitle": "OpenSearch Dashboards", + "darkMode": false, "favicon": "", - "loadingLogo": Object { - "darkModeUrl": "", - }, - "logo": Object { - "darkModeUrl": "", - }, - "mark": Object { - "darkModeUrl": "", - }, + "loadingLogo": Object {}, + "logo": Object {}, + "mark": Object {}, }, "buildNumber": Any, "csp": Object { @@ -119,16 +109,11 @@ Object { "branch": Any, "branding": Object { "applicationTitle": "OpenSearch Dashboards", + "darkMode": true, "favicon": "", - "loadingLogo": Object { - "darkModeUrl": "", - }, - "logo": Object { - "darkModeUrl": "", - }, - "mark": Object { - "darkModeUrl": "", - }, + "loadingLogo": Object {}, + "logo": Object {}, + "mark": Object {}, }, "buildNumber": Any, "csp": Object { @@ -179,16 +164,11 @@ Object { "branch": Any, "branding": Object { "applicationTitle": "OpenSearch Dashboards", + "darkMode": false, "favicon": "", - "loadingLogo": Object { - "darkModeUrl": "", - }, - "logo": Object { - "darkModeUrl": "", - }, - "mark": Object { - "darkModeUrl": "", - }, + "loadingLogo": Object {}, + "logo": Object {}, + "mark": Object {}, }, "buildNumber": Any, "csp": Object { @@ -235,16 +215,11 @@ Object { "branch": Any, "branding": Object { "applicationTitle": "OpenSearch Dashboards", + "darkMode": false, "favicon": "", - "loadingLogo": Object { - "darkModeUrl": "", - }, - "logo": Object { - "darkModeUrl": "", - }, - "mark": Object { - "darkModeUrl": "", - }, + "loadingLogo": Object {}, + "logo": Object {}, + "mark": Object {}, }, "buildNumber": Any, "csp": Object { diff --git a/src/core/server/rendering/rendering_service.tsx b/src/core/server/rendering/rendering_service.tsx index dc34d8ed63da..c9aea75e1c9f 100644 --- a/src/core/server/rendering/rendering_service.tsx +++ b/src/core/server/rendering/rendering_service.tsx @@ -46,6 +46,8 @@ import { RenderingSetupDeps, InternalRenderingServiceSetup, RenderingMetadata, + BrandingValidation, + BrandingAssignment, } from './types'; import { OpenSearchDashboardsConfigType } from '../opensearch_dashboards_config'; @@ -65,23 +67,6 @@ export class RenderingService { .pipe(first()) .toPromise(); - const isLogoDefaultValid = await this.checkUrlValid( - opensearchDashboardsConfig.branding.logo.defaultUrl, - 'logo default' - ); - const isMarkDefaultValid = await this.checkUrlValid( - opensearchDashboardsConfig.branding.mark.defaultUrl, - 'mark default' - ); - const isLoadingLogoDefaultValid = await this.checkUrlValid( - opensearchDashboardsConfig.branding.loadingLogo.defaultUrl, - 'loadingLogo default' - ); - const isTitleValid = this.checkTitleValid( - opensearchDashboardsConfig.branding.applicationTitle, - 'applicationTitle' - ); - return { render: async ( request, @@ -98,15 +83,21 @@ export class RenderingService { defaults: uiSettings.getRegistered(), user: includeUserSettings ? await uiSettings.getUserProvided() : {}, }; + const darkMode = settings.user?.['theme:darkMode']?.userValue + ? Boolean(settings.user['theme:darkMode'].userValue) + : false; + const brandingAssignment = await this.assignBrandingConfig( + darkMode, + opensearchDashboardsConfig + ); + const metadata: RenderingMetadata = { strictCsp: http.csp.strict, uiPublicUrl: `${basePath}/ui`, bootstrapScriptUrl: `${basePath}/bootstrap.js`, i18n: i18n.translate, locale: i18n.getLocale(), - darkMode: settings.user?.['theme:darkMode']?.userValue - ? Boolean(settings.user['theme:darkMode'].userValue) - : false, + darkMode, injectedMetadata: { version: env.packageInfo.version, buildNumber: env.packageInfo.buildNum, @@ -131,28 +122,21 @@ export class RenderingService { uiSettings: settings, }, branding: { + darkMode, logo: { - defaultUrl: isLogoDefaultValid - ? opensearchDashboardsConfig.branding.logo.defaultUrl - : undefined, - darkModeUrl: '', + defaultUrl: brandingAssignment.logoDefault, + darkModeUrl: brandingAssignment.logoDarkmode, }, mark: { - defaultUrl: isMarkDefaultValid - ? opensearchDashboardsConfig.branding.mark.defaultUrl - : undefined, - darkModeUrl: '', + defaultUrl: brandingAssignment.markDefault, + darkModeUrl: brandingAssignment.markDarkmode, }, loadingLogo: { - defaultUrl: isLoadingLogoDefaultValid - ? opensearchDashboardsConfig.branding.loadingLogo.defaultUrl - : undefined, - darkModeUrl: '', + defaultUrl: brandingAssignment.loadingLogoDefault, + darkModeUrl: brandingAssignment.loadingLogoDarkmode, }, favicon: '', - applicationTitle: isTitleValid - ? opensearchDashboardsConfig.branding.applicationTitle - : DEFAULT_TITLE, + applicationTitle: brandingAssignment.applicationTitle, }, }, }; @@ -164,12 +148,163 @@ export class RenderingService { public async stop() {} + /** + * Assign values for branding related configurations based on branding validation + * by calling checkBrandingValid(). For dark mode URLs, add additonal validation + * to see if there is a valid default mode URL exist first. If URL is valid, pass in + * the actual URL; if not, pass in undefined. + * + * @param {boolean} darkMode + * @param {Readonly} opensearchDashboardsConfig + * @returns {BrandingAssignment} valid URLs or undefined assigned for each branding configs + */ + private assignBrandingConfig = async ( + darkMode: boolean, + opensearchDashboardsConfig: Readonly + ): Promise => { + const brandingValidation: BrandingValidation = await this.checkBrandingValid( + darkMode, + opensearchDashboardsConfig + ); + const branding = opensearchDashboardsConfig.branding; + + // assign default mode URL based on the brandingValidation function result + const logoDefault = brandingValidation.isLogoDefaultValid + ? branding.logo.defaultUrl + : undefined; + + const markDefault = brandingValidation.isMarkDefaultValid + ? branding.mark.defaultUrl + : undefined; + + const loadingLogoDefault = brandingValidation.isLoadingLogoDefaultValid + ? branding.loadingLogo.defaultUrl + : undefined; + + // assign dark mode URLs based on brandingValidation function result + let logoDarkmode = brandingValidation.isLogoDarkmodeValid + ? branding.logo.darkModeUrl + : undefined; + + let markDarkmode = brandingValidation.isMarkDarkmodeValid + ? branding.mark.darkModeUrl + : undefined; + + let loadingLogoDarkmode = brandingValidation.isLoadingLogoDarkmodeValid + ? branding.loadingLogo.darkModeUrl + : undefined; + + /** + * For dark mode URLs, we added another validation: + * user can only provide a dark mode URL after providing a valid default mode URL, + * If user provides a valid dark mode URL but fails to provide a valid default mode URL, + * return undefined for the dark mode URL + */ + if (logoDarkmode && !logoDefault) { + this.logger + .get('branding') + .error('Must provide a valid logo default mode URL before providing a logo dark mode URL'); + logoDarkmode = undefined; + } + + if (markDarkmode && !markDefault) { + this.logger + .get('branding') + .error('Must provide a valid mark default mode URL before providing a mark dark mode URL'); + markDarkmode = undefined; + } + + if (loadingLogoDarkmode && !loadingLogoDefault) { + this.logger + .get('branding') + .error( + 'Must provide a valid loading logo default mode URL before providing a loading logo dark mode URL' + ); + loadingLogoDarkmode = undefined; + } + + // assign applition title based on brandingValidation function result + const applicationTitle = brandingValidation.isTitleValid + ? branding.applicationTitle + : DEFAULT_TITLE; + + const brandingAssignment: BrandingAssignment = { + logoDefault, + logoDarkmode, + markDefault, + markDarkmode, + loadingLogoDefault, + loadingLogoDarkmode, + applicationTitle, + }; + + return brandingAssignment; + }; + + /** + * Assign boolean values for branding related configurations to indicate if + * user inputs valid or invalid URLs by calling checkUrlValid() function. Also + * check if title is valid by calling checkTitleValid() function. + * + * @param {boolean} darkMode + * @param {Readonly} opensearchDashboardsConfig + * @returns {BrandingValidation} indicate valid/invalid URL for each branding config + */ + private checkBrandingValid = async ( + darkMode: boolean, + opensearchDashboardsConfig: Readonly + ): Promise => { + const branding = opensearchDashboardsConfig.branding; + const isLogoDefaultValid = await this.checkUrlValid(branding.logo.defaultUrl, 'logo default'); + + const isLogoDarkmodeValid = darkMode + ? await this.checkUrlValid(branding.logo.darkModeUrl, 'logo darkMode') + : false; + + const isMarkDefaultValid = await this.checkUrlValid(branding.mark.defaultUrl, 'mark default'); + + const isMarkDarkmodeValid = darkMode + ? await this.checkUrlValid(branding.mark.darkModeUrl, 'mark darkMode') + : false; + + const isLoadingLogoDefaultValid = await this.checkUrlValid( + branding.loadingLogo.defaultUrl, + 'loadingLogo default' + ); + + const isLoadingLogoDarkmodeValid = darkMode + ? await this.checkUrlValid(branding.loadingLogo.darkModeUrl, 'loadingLogo darkMode') + : false; + + const isTitleValid = this.checkTitleValid(branding.applicationTitle, 'applicationTitle'); + + const brandingValidation: BrandingValidation = { + isLogoDefaultValid, + isLogoDarkmodeValid, + isMarkDefaultValid, + isMarkDarkmodeValid, + isLoadingLogoDefaultValid, + isLoadingLogoDarkmodeValid, + isTitleValid, + }; + + return brandingValidation; + }; + private async getUiConfig(uiPlugins: UiPlugins, pluginId: string) { const browserConfig = uiPlugins.browserConfigs.get(pluginId); return ((await browserConfig?.pipe(take(1)).toPromise()) ?? {}) as Record; } + /** + * Validation function for URLs. Use Axios to call URL and check validity. + * Also needs to be ended with png, svg, gif, PNG, SVG and GIF. + * + * @param {string} url + * @param {string} configName + * @returns {boolean} indicate if the URL is valid/invalid + */ public checkUrlValid = async (url: string, configName?: string): Promise => { if (url.match(/\.(png|svg|gif|PNG|SVG|GIF)$/) === null) { this.logger.get('branding').warn(configName + ' config is not found or invalid.'); @@ -185,6 +320,14 @@ export class RenderingService { }); }; + /** + * Validation function for applicationTitle config. + * Title length needs to be between 1 to 36 letters. + * + * @param {string} title + * @param {string} configName + * @returns {boolean} indicate if user input title is valid/invalid + */ public checkTitleValid = (title: string, configName?: string): boolean => { if (!title || title.length > 36) { this.logger diff --git a/src/core/server/rendering/types.ts b/src/core/server/rendering/types.ts index 45fc49705c4c..be3d0c737c6d 100644 --- a/src/core/server/rendering/types.ts +++ b/src/core/server/rendering/types.ts @@ -75,6 +75,7 @@ export interface RenderingMetadata { }; }; branding: { + darkMode: boolean; logo: { defaultUrl?: string; darkModeUrl?: string; @@ -133,3 +134,34 @@ export interface InternalRenderingServiceSetup { options?: IRenderOptions ): Promise; } + +export interface BrandingValidation { + /** + * For each branding config, check if user provides a valid URL. + * True -- if user provides a valid URL + * False -- if user provides an invalid URL or user does not provide any URL. + */ + + isLogoDefaultValid: boolean; + isLogoDarkmodeValid: boolean; + isMarkDefaultValid: boolean; + isMarkDarkmodeValid: boolean; + isLoadingLogoDefaultValid: boolean; + isLoadingLogoDarkmodeValid: boolean; + isTitleValid: boolean; +} + +export interface BrandingAssignment { + /** + * For each branding config, if user provides a valid URL, the URL will be assigned; + * if not, undefined will be assigned. + */ + + logoDefault?: string; + logoDarkmode?: string; + markDefault?: string; + markDarkmode?: string; + loadingLogoDefault?: string; + loadingLogoDarkmode?: string; + applicationTitle?: string; +} diff --git a/src/core/server/rendering/views/__snapshots__/template.test.tsx.snap b/src/core/server/rendering/views/__snapshots__/template.test.tsx.snap index bfc4c27d407f..df44408819c3 100644 --- a/src/core/server/rendering/views/__snapshots__/template.test.tsx.snap +++ b/src/core/server/rendering/views/__snapshots__/template.test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Template renders with customized loading logo 1`] = ` +exports[`Loading logo in dark mode rendered using loading logo dark mode URL 1`] = ` Array [ , ,
, ,
- - - - - - - +
+
+
, +