Skip to content

Commit

Permalink
[ML] Apply theme based on the User Profile settings (#158258)
Browse files Browse the repository at this point in the history
## Summary

With the release of Per User Dark Mode, code should no longer rely on
calling `uiSettings` to determine which theme Kibana is displayed with.

With theme settings now configurable from User Profiles and Adv.
Settings, the code that was calling uiSettings to determine the Kibana
theme will not take into account which theme is currently being
displayed.


Applies an appropriate EUI theme based on the profile settings. In
particular for the following components:
- Anomaly swim lane (Fixes #158155 )
- Job tree map view (Fixes
#158304)
- Charts-related theme settings, e.g. the Single Metric Viewer
  • Loading branch information
darnautov authored May 25, 2023
1 parent d14ed5f commit c5eee26
Show file tree
Hide file tree
Showing 36 changed files with 251 additions and 154 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@ x-pack/packages/ml/date_picker @elastic/ml-ui
x-pack/packages/ml/error_utils @elastic/ml-ui
x-pack/packages/ml/is_defined @elastic/ml-ui
x-pack/packages/ml/is_populated_object @elastic/ml-ui
x-pack/packages/ml/kibana_theme @elastic/ml-ui
x-pack/packages/ml/local_storage @elastic/ml-ui
x-pack/packages/ml/nested_property @elastic/ml-ui
x-pack/packages/ml/number_utils @elastic/ml-ui
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@
"@kbn/ml-error-utils": "link:x-pack/packages/ml/error_utils",
"@kbn/ml-is-defined": "link:x-pack/packages/ml/is_defined",
"@kbn/ml-is-populated-object": "link:x-pack/packages/ml/is_populated_object",
"@kbn/ml-kibana-theme": "link:x-pack/packages/ml/kibana_theme",
"@kbn/ml-local-storage": "link:x-pack/packages/ml/local_storage",
"@kbn/ml-nested-property": "link:x-pack/packages/ml/nested_property",
"@kbn/ml-number-utils": "link:x-pack/packages/ml/number_utils",
Expand Down
2 changes: 2 additions & 0 deletions tsconfig.base.json
Original file line number Diff line number Diff line change
Expand Up @@ -924,6 +924,8 @@
"@kbn/ml-is-defined/*": ["x-pack/packages/ml/is_defined/*"],
"@kbn/ml-is-populated-object": ["x-pack/packages/ml/is_populated_object"],
"@kbn/ml-is-populated-object/*": ["x-pack/packages/ml/is_populated_object/*"],
"@kbn/ml-kibana-theme": ["x-pack/packages/ml/kibana_theme"],
"@kbn/ml-kibana-theme/*": ["x-pack/packages/ml/kibana_theme/*"],
"@kbn/ml-local-storage": ["x-pack/packages/ml/local_storage"],
"@kbn/ml-local-storage/*": ["x-pack/packages/ml/local_storage/*"],
"@kbn/ml-nested-property": ["x-pack/packages/ml/nested_property"],
Expand Down
3 changes: 3 additions & 0 deletions x-pack/packages/ml/kibana_theme/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# @kbn/ml-kibana-theme

Provides hooks to retrieve currently applied theme and EUI theme variables.
8 changes: 8 additions & 0 deletions x-pack/packages/ml/kibana_theme/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

export { useIsDarkTheme, useCurrentEuiThemeVars, type EuiThemeType } from './src/hooks';
12 changes: 12 additions & 0 deletions x-pack/packages/ml/kibana_theme/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

module.exports = {
preset: '@kbn/test/jest_node',
rootDir: '../../../..',
roots: ['<rootDir>/x-pack/packages/ml/kibana_theme'],
};
5 changes: 5 additions & 0 deletions x-pack/packages/ml/kibana_theme/kibana.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"type": "shared-common",
"id": "@kbn/ml-kibana-theme",
"owner": "@elastic/ml-ui"
}
6 changes: 6 additions & 0 deletions x-pack/packages/ml/kibana_theme/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "@kbn/ml-kibana-theme",
"private": true,
"version": "1.0.0",
"license": "Elastic License 2.0"
}
38 changes: 38 additions & 0 deletions x-pack/packages/ml/kibana_theme/src/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { useMemo } from 'react';
import { of } from 'rxjs';
import useObservable from 'react-use/lib/useObservable';
import { euiDarkVars as euiThemeDark, euiLightVars as euiThemeLight } from '@kbn/ui-theme';
import { ThemeServiceStart } from '@kbn/core-theme-browser';

export type EuiThemeType = typeof euiThemeLight | typeof euiThemeDark;

const themeDefault = { darkMode: false };

/**
* Indicates if the currently applied theme is either dark or light.
* @return {boolean} - Returns true if the currently applied theme is dark.
*/
export function useIsDarkTheme(theme: ThemeServiceStart): boolean {
const themeObservable$ = useMemo(() => {
return theme?.theme$ ?? of(themeDefault);
}, [theme]);

const { darkMode } = useObservable(themeObservable$, themeDefault);

return darkMode;
}

/**
* Returns an EUI theme definition based on the currently applied theme.
*/
export function useCurrentEuiThemeVars(theme: ThemeServiceStart): { euiTheme: EuiThemeType } {
const isDarkMode = useIsDarkTheme(theme);
return useMemo(() => ({ euiTheme: isDarkMode ? euiThemeDark : euiThemeLight }), [isDarkMode]);
}
20 changes: 20 additions & 0 deletions x-pack/packages/ml/kibana_theme/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"extends": "../../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "target/types",
"types": [
"jest",
"node"
]
},
"include": [
"**/*.ts",
],
"exclude": [
"target/**/*"
],
"kbn_references": [
"@kbn/ui-theme",
"@kbn/core-theme-browser",
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export function FieldStatsPopover({
defaultMessage: 'Show top field values',
})}
data-test-subj={'aiopsContextPopoverButton'}
style={{ marginLeft: euiTheme.euiSizeXS }}
css={{ marginLeft: euiTheme.euiSizeXS }}
/>
</EuiToolTip>
);
Expand Down
15 changes: 3 additions & 12 deletions x-pack/plugins/aiops/public/hooks/use_eui_theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,10 @@
* 2.0.
*/

import { useMemo } from 'react';

import { euiLightVars as euiThemeLight, euiDarkVars as euiThemeDark } from '@kbn/ui-theme';

import { useCurrentEuiThemeVars } from '@kbn/ml-kibana-theme';
import { useAiopsAppContext } from './use_aiops_app_context';

export type EuiThemeType = typeof euiThemeLight | typeof euiThemeDark;

export function useEuiTheme() {
const { uiSettings } = useAiopsAppContext();

return useMemo(
() => (uiSettings.get('theme:darkMode') ? euiThemeDark : euiThemeLight),
[uiSettings]
);
const { theme } = useAiopsAppContext();
return useCurrentEuiThemeVars(theme).euiTheme;
}
2 changes: 1 addition & 1 deletion x-pack/plugins/aiops/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@
"@kbn/saved-search-plugin",
"@kbn/share-plugin",
"@kbn/ui-actions-plugin",
"@kbn/ui-theme",
"@kbn/unified-field-list-plugin",
"@kbn/unified-search-plugin",
"@kbn/utility-types",
"@kbn/ml-kibana-theme",
],
"exclude": [
"target/**/*",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@
*/

import d3 from 'd3';
import { euiLightVars as euiThemeLight, euiDarkVars as euiThemeDark } from '@kbn/ui-theme';

import { i18n } from '@kbn/i18n';

import { useCurrentEuiTheme } from '../../../hooks/use_current_eui_theme';

/**
Expand Down Expand Up @@ -194,5 +191,3 @@ export const useColorRange = (

return scaleTypes[colorRangeScale];
};

export type EuiThemeType = typeof euiThemeLight | typeof euiThemeDark;
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,13 @@
* 2.0.
*/

import { useMemo } from 'react';
import { euiDarkVars as euiThemeDark, euiLightVars as euiThemeLight } from '@kbn/ui-theme';
import { useCurrentEuiThemeVars } from '@kbn/ml-kibana-theme';
import { useDataVisualizerKibana } from '../../kibana_context';

export function useCurrentEuiTheme() {
const { services } = useDataVisualizerKibana();
const uiSettings = services.uiSettings;
return useMemo(
() => (uiSettings.get('theme:darkMode') ? euiThemeDark : euiThemeLight),
[uiSettings]
);
const {
services: { theme },
} = useDataVisualizerKibana();

return useCurrentEuiThemeVars(theme).euiTheme;
}
2 changes: 1 addition & 1 deletion x-pack/plugins/data_visualizer/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@
"@kbn/share-plugin",
"@kbn/test-jest-helpers",
"@kbn/ui-actions-plugin",
"@kbn/ui-theme",
"@kbn/unified-field-list-plugin",
"@kbn/unified-search-plugin",
"@kbn/usage-collection-plugin",
"@kbn/utility-types",
"@kbn/ml-error-utils",
"@kbn/ml-kibana-theme",
],
"exclude": [
"target/**/*",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,4 @@ export {
useColorRange,
COLOR_RANGE,
COLOR_RANGE_SCALE,
useCurrentEuiTheme,
} from './use_color_range';
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@
*/

import d3 from 'd3';
import { useMemo } from 'react';
import { euiLightVars as euiThemeLight, euiDarkVars as euiThemeDark } from '@kbn/ui-theme';
import { euiDarkVars as euiThemeDark, euiLightVars as euiThemeLight } from '@kbn/ui-theme';

import { i18n } from '@kbn/i18n';

import { useUiSettings } from '../../contexts/kibana/use_ui_settings_context';
import { useCurrentThemeVars } from '../../contexts/kibana';

/**
* Custom color scale factory that takes the amount of feature influencers
Expand Down Expand Up @@ -150,7 +148,7 @@ export const useColorRange = (
colorRangeScale = COLOR_RANGE_SCALE.LINEAR,
featureCount = 1
) => {
const { euiTheme } = useCurrentEuiTheme();
const { euiTheme } = useCurrentThemeVars();

const colorRanges: Record<COLOR_RANGE, string[]> = {
[COLOR_RANGE.BLUE]: [
Expand Down Expand Up @@ -188,11 +186,3 @@ export const useColorRange = (
};

export type EuiThemeType = typeof euiThemeLight | typeof euiThemeDark;

export function useCurrentEuiTheme() {
const uiSettings = useUiSettings();
return useMemo(
() => ({ euiTheme: uiSettings.get('theme:darkMode') ? euiThemeDark : euiThemeLight }),
[uiSettings]
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,24 @@
* 2.0.
*/

import React, { FC, Fragment, useCallback, memo } from 'react';
import React, { FC, Fragment, memo, useCallback } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import moment from 'moment';
import { XYBrushEvent, BrushEndListener } from '@elastic/charts';
import { BrushEndListener, XYBrushEvent } from '@elastic/charts';
import {
EuiButtonIcon,
EuiDatePicker,
EuiFieldText,
EuiFlexGroup,
EuiFlexItem,
EuiSpacer,
EuiFormRow,
EuiFieldText,
EuiDatePicker,
EuiButtonIcon,
EuiPanel,
EuiSpacer,
} from '@elastic/eui';

import { useCurrentThemeVars } from '../../../contexts/kibana';
import { EventRateChart } from '../../../jobs/new_job/pages/components/charts/event_rate_chart/event_rate_chart';
import { Anomaly } from '../../../jobs/new_job/common/results_loader/results_loader';
import { useCurrentEuiTheme } from '../../color_range_legend';
import { LineChartPoint } from '../../../jobs/new_job/common/chart_loader/chart_loader';

export interface CalendarEvent {
Expand Down Expand Up @@ -54,7 +53,7 @@ export const CreateCalendar: FC<Props> = ({
const maxSelectableTimeMoment = moment(maxSelectableTimeStamp);
const minSelectableTimeMoment = moment(minSelectableTimeStamp);

const { euiTheme } = useCurrentEuiTheme();
const { euiTheme } = useCurrentThemeVars();

const onBrushEnd = useCallback(
({ x }: XYBrushEvent) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ const mockFilterManager = createFilterManagerMock();
const mockEsSearch = jest.fn((body) => ({
hits: { hits: [{ fields: { x: [1], y: [2] } }, { fields: { x: [2], y: [3] } }] },
}));

const mockEuiTheme = euiThemeLight;

jest.mock('../../contexts/kibana', () => ({
useMlApiContext: () => ({
esSearch: mockEsSearch,
Expand All @@ -45,11 +48,7 @@ jest.mock('../../contexts/kibana', () => ({
},
},
}),
}));

const mockEuiTheme = euiThemeLight;
jest.mock('../color_range_legend', () => ({
useCurrentEuiTheme: () => ({
useCurrentThemeVars: () => ({
euiTheme: mockEuiTheme,
}),
}));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import React, { useMemo, useEffect, useState, FC, useCallback } from 'react';
import React, { FC, useCallback, useEffect, useMemo, useState } from 'react';

import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import {
Expand All @@ -28,15 +28,11 @@ import { Query } from '@kbn/data-plugin/common/query';
import { DataView } from '@kbn/data-views-plugin/public';
import { stringHash } from '@kbn/ml-string-hash';
import { extractErrorMessage } from '@kbn/ml-error-utils';

import { isRuntimeMappings } from '../../../../common/util/runtime_field_utils';
import { RuntimeMappings } from '../../../../common/types/fields';

import { getCombinedRuntimeMappings } from '../data_grid';
import { useMlApiContext, useMlKibana } from '../../contexts/kibana';

import { getProcessedFields } from '../data_grid';
import { useCurrentEuiTheme } from '../color_range_legend';
import { getCombinedRuntimeMappings, getProcessedFields } from '../data_grid';
import { useCurrentThemeVars, useMlApiContext, useMlKibana } from '../../contexts/kibana';

// Separate imports for lazy loadable VegaChart and related code
import { VegaChart } from '../vega_chart';
Expand Down Expand Up @@ -149,7 +145,7 @@ export const ScatterplotMatrix: FC<ScatterplotMatrixProps> = ({
{ items: any[]; backgroundItems: any[]; columns: string[]; messages: string[] } | undefined
>();

const { euiTheme } = useCurrentEuiTheme();
const { euiTheme } = useCurrentThemeVars();

// formats the array of field names for EuiComboBox
const fieldOptions = useMemo(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ export { useNotifications } from './use_notifications_context';
export { useMlLocator, useMlLink } from './use_create_url';
export { useMlApiContext } from './use_ml_api_context';
export { useFieldFormatter } from './use_field_formatter';
export { useCurrentThemeVars } from './use_current_theme';
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { useCurrentEuiThemeVars } from '@kbn/ml-kibana-theme';
import { useMlKibana } from './kibana_context';

export function useCurrentThemeVars() {
const {
services: { theme },
} = useMlKibana();
return useCurrentEuiThemeVars(theme);
}
Loading

0 comments on commit c5eee26

Please sign in to comment.