Skip to content

Commit

Permalink
Make Borealis the default theme in non-serverless (#203840)
Browse files Browse the repository at this point in the history
  • Loading branch information
tkajtoch authored Jan 11, 2025
1 parent 873b5c9 commit 9393561
Show file tree
Hide file tree
Showing 27 changed files with 315 additions and 202 deletions.
8 changes: 4 additions & 4 deletions packages/kbn-optimizer/limits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ pageLoadAssetSize:
actions: 20000
advancedSettings: 27596
aiAssistantManagementSelection: 19146
aiops: 18000
aiops: 32733
alerting: 106936
apm: 64385
banners: 17946
Expand All @@ -15,8 +15,8 @@ pageLoadAssetSize:
cloudExperiments: 109746
cloudFullStory: 18493
cloudLinks: 55984
cloudSecurityPosture: 19270
console: 46091
cloudSecurityPosture: 34398
console: 61298
contentManagement: 16254
controls: 60000
core: 564663
Expand Down Expand Up @@ -63,7 +63,7 @@ pageLoadAssetSize:
expressionTagcloud: 27505
expressionXY: 45000
features: 21723
fieldFormats: 65209
fieldFormats: 80485
fieldsMetadata: 21885
files: 22673
filesManagement: 18683
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ describe('getOptimizerCacheKey()', () => {
"themeTags": Array [
"v8light",
"v8dark",
"borealislight",
"borealisdark",
],
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,31 @@ describe('bootstrapRenderer', () => {
uiSettingsClient,
});

expect(getThemeTagMock).toHaveBeenCalledTimes(1);
expect(getThemeTagMock).toHaveBeenCalledWith({
name: 'borealis',
darkMode: false,
});
});

it('calls getThemeTag with `v8` theme name when buildFlavor is `serverless`', async () => {
renderer = bootstrapRendererFactory({
auth,
packageInfo: {
...packageInfo,
buildFlavor: 'serverless',
},
uiPlugins,
baseHref: `/base-path/${packageInfo.buildShaShort}`, // the base href as provided by static assets module
});

const request = httpServerMock.createKibanaRequest();

await renderer({
request,
uiSettingsClient,
});

expect(getThemeTagMock).toHaveBeenCalledTimes(1);
expect(getThemeTagMock).toHaveBeenCalledWith({
name: 'v8',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
import { createHash } from 'crypto';
import { PackageInfo } from '@kbn/config';
import type { KibanaRequest, HttpAuth } from '@kbn/core-http-server';
import { type DarkModeValue, parseDarkModeValue } from '@kbn/core-ui-settings-common';
import {
type DarkModeValue,
DEFAULT_THEME_NAME,
parseDarkModeValue,
} from '@kbn/core-ui-settings-common';
import type { IUiSettingsClient } from '@kbn/core-ui-settings-server';
import type { UiPlugins } from '@kbn/core-plugins-base-server-internal';
import { InternalUserSettingsServiceSetup } from '@kbn/core-user-settings-server-internal';
Expand Down Expand Up @@ -58,7 +62,11 @@ export const bootstrapRendererFactory: BootstrapRendererFactory = ({

return async function bootstrapRenderer({ uiSettingsClient, request, isAnonymousPage = false }) {
let darkMode: DarkModeValue = false;
let themeName: string = 'amsterdam';
let themeName: string = DEFAULT_THEME_NAME;

if (packageInfo.buildFlavor !== 'serverless') {
themeName = 'borealis';
}

try {
const authenticated = isAuthenticated(request);
Expand Down
12 changes: 4 additions & 8 deletions src/core/packages/ui-settings/common/src/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,26 +35,22 @@ export type ThemeTags = readonly ThemeTag[];
* An array of theme tags available in Kibana by default when not customized
* using KBN_OPTIMIZER_THEMES environment variable.
*/
export const DEFAULT_THEME_TAGS: ThemeTags = ThemeAmsterdamTags;
export const DEFAULT_THEME_TAGS: ThemeTags = SUPPORTED_THEME_TAGS;

export const FALLBACK_THEME_TAG: ThemeTag = 'v8light';

const isValidTag = (tag: unknown) =>
SUPPORTED_THEME_TAGS.includes(tag as (typeof SUPPORTED_THEME_TAGS)[number]);

export function parseThemeTags(input?: unknown): ThemeTags {
if (!input) {
return DEFAULT_THEME_TAGS;
}

if (input === '*') {
// TODO: Replace with SUPPORTED_THEME_TAGS when Borealis is in public beta
if (!input || input === '*') {
return DEFAULT_THEME_TAGS;
}

// TODO: remove when Borealis is in public beta
// This is left here for backwards compatibility during Borealis testing.
if (input === 'experimental') {
return SUPPORTED_THEME_TAGS;
return DEFAULT_THEME_TAGS;
}

let rawTags: string[];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,26 @@ import { getDateFormatSettings } from './date_formats';
import { getMiscUiSettings } from './misc';
import { getNotificationsSettings } from './notifications';
import { getThemeSettings } from './theme';
import { getCoreSettings } from '.';
import { getCoreSettings, type GetCoreSettingsOptions } from '.';
import { getStateSettings } from './state';
import { getAnnouncementsSettings } from './announcements';

const defaultOptions: GetCoreSettingsOptions = {
isServerless: false,
isDist: true,
isThemeSwitcherEnabled: undefined,
};

describe('getCoreSettings', () => {
it('should not have setting overlaps', () => {
const coreSettingsLength = Object.keys(getCoreSettings()).length;
const coreSettingsLength = Object.keys(getCoreSettings(defaultOptions)).length;
const summedLength = [
getAccessibilitySettings(),
getAnnouncementsSettings(),
getDateFormatSettings(),
getMiscUiSettings(),
getNotificationsSettings(),
getThemeSettings(),
getThemeSettings(defaultOptions),
getStateSettings(),
].reduce((sum, settings) => sum + Object.keys(settings).length, 0);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ import { getThemeSettings } from './theme';
import { getStateSettings } from './state';
import { getAnnouncementsSettings } from './announcements';

interface GetCoreSettingsOptions {
isDist?: boolean;
isThemeSwitcherEnabled?: boolean;
export interface GetCoreSettingsOptions {
isServerless: boolean;
isDist: boolean;
isThemeSwitcherEnabled: boolean | undefined;
}

export const getCoreSettings = (
options?: GetCoreSettingsOptions
options: GetCoreSettingsOptions
): Record<string, UiSettingsParams> => {
return {
...getAccessibilitySettings(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,16 @@
*/

import type { UiSettingsParams } from '@kbn/core-ui-settings-common';
import { getThemeSettings } from './theme';
import { getThemeSettings, type GetThemeSettingsOptions } from './theme';

const defaultOptions: GetThemeSettingsOptions = {
isServerless: false,
isDist: true,
isThemeSwitcherEnabled: undefined,
};

describe('theme settings', () => {
const themeSettings = getThemeSettings();
const themeSettings = getThemeSettings(defaultOptions);

const getValidationFn = (setting: UiSettingsParams) => (value: any) =>
setting.schema.validate(value);
Expand All @@ -31,28 +37,74 @@ describe('theme settings', () => {
expect(() => validate(12)).toThrowError();
});
});

describe('theme:name', () => {
const validate = getValidationFn(themeSettings['theme:name']);

it('should only accept expected values', () => {
expect(() => validate('amsterdam')).not.toThrow();
expect(() => validate('borealis')).not.toThrow();

expect(() => validate(true)).toThrow();
expect(() => validate(12)).toThrow();
});

describe('readonly', () => {
it('should be readonly when `isServerless = true`', () => {
expect(
getThemeSettings({ ...defaultOptions, isServerless: true })['theme:name'].readonly
).toBe(true);
expect(
getThemeSettings({ ...defaultOptions, isServerless: false })['theme:name'].readonly
).toBe(false);
});

it('should be editable when `isThemeSwitcherEnabled = true`', () => {
expect(
getThemeSettings({ ...defaultOptions, isServerless: true, isThemeSwitcherEnabled: true })[
'theme:name'
].readonly
).toBe(false);
expect(
getThemeSettings({
...defaultOptions,
isServerless: false,
isThemeSwitcherEnabled: true,
})['theme:name'].readonly
).toBe(false);
});
});

describe('value', () => {
it('should default to `amsterdam` when `isServerless = true`', () => {
expect(
getThemeSettings({ ...defaultOptions, isServerless: true })['theme:name'].value
).toBe('amsterdam');
});

it('should default to `borealis` when `isServerless = false`', () => {
expect(
getThemeSettings({ ...defaultOptions, isServerless: false })['theme:name'].value
).toBe('borealis');
});
});
});
});

describe('process.env.KBN_OPTIMIZER_THEMES handling', () => {
it('defaults to properties of first tag', () => {
process.env.KBN_OPTIMIZER_THEMES = 'v8dark,v8light';
let settings = getThemeSettings({ isDist: false });
let settings = getThemeSettings({ ...defaultOptions, isDist: false });
expect(settings['theme:darkMode'].value).toBe('enabled');

process.env.KBN_OPTIMIZER_THEMES = 'v8light,v8dark';
settings = getThemeSettings({ isDist: false });
expect(settings['theme:darkMode'].value).toBe('disabled');
});

it('ignores the value when isDist is undefined', () => {
process.env.KBN_OPTIMIZER_THEMES = 'v8dark';
const settings = getThemeSettings({ isDist: undefined });
settings = getThemeSettings({ ...defaultOptions, isDist: false });
expect(settings['theme:darkMode'].value).toBe('disabled');
});

it('ignores the value when isDist is true', () => {
process.env.KBN_OPTIMIZER_THEMES = 'v8dark';
const settings = getThemeSettings({ isDist: true });
const settings = getThemeSettings({ ...defaultOptions, isDist: true });
expect(settings['theme:darkMode'].value).toBe('disabled');
});
});
56 changes: 38 additions & 18 deletions src/core/packages/ui-settings/server-internal/src/settings/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,54 @@ import { i18n } from '@kbn/i18n';
import type { ThemeVersion } from '@kbn/ui-shared-deps-npm';
import {
type UiSettingsParams,
type ThemeName,
parseThemeTags,
SUPPORTED_THEME_NAMES,
DEFAULT_THEME_NAME,
} from '@kbn/core-ui-settings-common';

function getThemeInfo(options: GetThemeSettingsOptions) {
if (options?.isDist ?? true) {
return {
defaultDarkMode: false,
};
}
interface ThemeInfo {
defaultDarkMode: boolean;
defaultThemeName: ThemeName;
}

const getThemeInfo = ({ isDist, isServerless }: GetThemeSettingsOptions): ThemeInfo => {
const themeTags = parseThemeTags(process.env.KBN_OPTIMIZER_THEMES);
return {
defaultDarkMode: themeTags[0].endsWith('dark'),

const themeInfo: ThemeInfo = {
defaultDarkMode: false,
defaultThemeName: DEFAULT_THEME_NAME,
};
}

interface GetThemeSettingsOptions {
isDist?: boolean;
isThemeSwitcherEnabled?: boolean;
if (!isDist) {
// Allow environment-specific config when not building for distribution
themeInfo.defaultDarkMode = themeTags[0]?.endsWith('dark') || false;
}

if (!isServerless) {
// Default to Borealis theme in non-serverless
themeInfo.defaultThemeName = 'borealis';
}

return themeInfo;
};

export interface GetThemeSettingsOptions {
isServerless: boolean;
isDist: boolean;
isThemeSwitcherEnabled: boolean | undefined;
}

export const getThemeSettings = (
options: GetThemeSettingsOptions = {}
options: GetThemeSettingsOptions
): Record<string, UiSettingsParams> => {
const { defaultDarkMode } = getThemeInfo(options);
const { defaultDarkMode, defaultThemeName } = getThemeInfo(options);

// Make `theme:name` readonly in serverless unless the theme switcher is enabled
let isThemeNameReadonly = options.isServerless;
if (options.isThemeSwitcherEnabled !== undefined) {
isThemeNameReadonly = !options.isThemeSwitcherEnabled;
}

return {
'theme:darkMode': {
Expand Down Expand Up @@ -109,10 +131,8 @@ export const getThemeSettings = (
defaultMessage: 'Borealis',
}),
},
value: 'amsterdam',
readonly: Object.hasOwn(options, 'isThemeSwitcherEnabled')
? !options.isThemeSwitcherEnabled
: true,
value: defaultThemeName,
readonly: isThemeNameReadonly,
requiresPageReload: true,
schema: schema.oneOf([
schema.literal('amsterdam'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export class UiSettingsService
private readonly config$: Observable<UiSettingsConfigType>;
private readonly isDist: boolean;
private readonly isDev: boolean;
private readonly isServerless: boolean;
private readonly uiSettingsDefaults = new Map<string, UiSettingsParams>();
private readonly uiSettingsGlobalDefaults = new Map<string, UiSettingsParams>();
private overrides: Record<string, any> = {};
Expand All @@ -63,6 +64,7 @@ export class UiSettingsService
this.isDist = coreContext.env.packageInfo.dist;
this.config$ = coreContext.configService.atPath<UiSettingsConfigType>(uiConfigDefinition.path);
this.isDev = coreContext.env.mode.dev;
this.isServerless = coreContext.env.packageInfo.buildFlavor === 'serverless';
}

public async preboot(): Promise<InternalUiSettingsServicePreboot> {
Expand All @@ -74,6 +76,7 @@ export class UiSettingsService
this.register(
getCoreSettings({
isDist: this.isDist,
isServerless: this.isServerless,
isThemeSwitcherEnabled: experimental?.themeSwitcherEnabled,
})
);
Expand Down
2 changes: 1 addition & 1 deletion test/functional/apps/dashboard/group3/dashboard_state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await queryBar.clickQuerySubmitButton();

await visChart.openLegendOptionColorsForXY('Count', `[data-title="${visName}"]`);
const overwriteColor = '#d36086';
const overwriteColor = '#64d8d5';
await visChart.selectNewLegendColorChoice(overwriteColor);

await dashboard.saveDashboard(dashboardName, { saveAsNew: false });
Expand Down
Loading

0 comments on commit 9393561

Please sign in to comment.