Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Borealis the default theme in non-serverless #203840

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
4ce8481
Update uiSettings `theme:name` default value to 'borealis' in non-ser…
tkajtoch Dec 11, 2024
46f458c
update default value of `__kbnThemeTag__` to 'borealis' in non-server…
tkajtoch Dec 11, 2024
3029b62
update logic of `theme:name` readonly state to default to `true` in s…
tkajtoch Dec 11, 2024
3bfb2ab
update core-ui-settings-server-internal tests and fix a typo in `isTh…
tkajtoch Dec 11, 2024
a453893
fix `isThemeSwitcherEnabled` condition
tkajtoch Dec 11, 2024
2daee71
update theme tags returned by `parseThemeTags` to include borealis wh…
tkajtoch Dec 11, 2024
5e53377
update limits
tkajtoch Dec 11, 2024
2068665
update theme uiSettings to set default theme to borealis for non-serv…
tkajtoch Dec 12, 2024
22d2278
fix tests
tkajtoch Dec 12, 2024
d12cbe3
update hardcoded theme colors in FTR tests
tkajtoch Dec 18, 2024
a43718e
update limits
tkajtoch Dec 19, 2024
59bd030
fix more FTRs
tkajtoch Dec 19, 2024
1d6af69
update hardcoded colors in lens group 5 FTRs
tkajtoch Jan 7, 2025
8147e95
update hardcoded colors in lens group 6 FTRs
tkajtoch Jan 7, 2025
4aeb2f9
update baseline screenshots in maps group 3 FTRs
tkajtoch Jan 7, 2025
1cae9e6
update hardcoded colors in transform creation FTRs
tkajtoch Jan 7, 2025
e163a74
update hardcoded colors in infra home page FTRs
tkajtoch Jan 7, 2025
4558f92
update hardcoded colors in lens group 6 FTRs
tkajtoch Jan 7, 2025
23d2063
update hardcoded colors in maps group 4 FTRs
tkajtoch Jan 7, 2025
177831c
update theme tag names in functional cloud FTRs
tkajtoch Jan 8, 2025
630c79f
update hardcoded colors in maps group 4 FTRs
tkajtoch Jan 8, 2025
088bb12
update hardcoded colors in lens group 4 FTRs
tkajtoch Jan 8, 2025
1f638bb
update hardcoded colors in visualize group 5 FTRs
tkajtoch Jan 8, 2025
c0b02f7
update hardcoded colors in lens group 2 FTRs
tkajtoch Jan 9, 2025
bdbb321
update hardcoded colors in dashboard group 3 FTRs
tkajtoch Jan 9, 2025
8582a46
update limits after rebase
tkajtoch Jan 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: why not v9light...?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JasonStoltz We didn't use Amsterdam for v8, perhaps we should use v9 here...?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the past, themes were pretty much directly related to Kibana major versions. Moving forward, we want themes to be more dynamic than that, meaning a theme may change over the lifespan of a single major, and there might be more than one theme available.

"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';
}
Comment on lines +67 to +69
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it is worth having this conditional also depend on some configuration setting... That way when the time comes we can rollout borealis incrementally to serverless. Not a blocker for this PR, but would be nice to hear your thoughts!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally would want this to depend solely on a configuration setting.


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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason this was switched to required?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has only one usage, and I don't see why it would be optional if it stores important data like isDist. This change ensures nobody forgets to define it if this ever gets refactored.

): 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');
});
});
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';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels brittle, depending on whether or not we're in serverless to default the theme. I feel like this shouldn't be determined here.

}

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
Loading