[ML] Apply theme based on the User Profile settings (#158258)

## 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
https://github.com/elastic/kibana/issues/158304)
- Charts-related theme settings, e.g. the Single Metric Viewer
This commit is contained in:
Dima Arnautov 2023-05-25 11:57:48 +02:00 committed by GitHub
parent d14ed5fbbe
commit c5eee26671
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 252 additions and 155 deletions

1
.github/CODEOWNERS vendored
View file

@ -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

View file

@ -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",

View file

@ -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"],

View file

@ -0,0 +1,3 @@
# @kbn/ml-kibana-theme
Provides hooks to retrieve currently applied theme and EUI theme variables.

View file

@ -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';

View file

@ -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'],
};

View file

@ -0,0 +1,5 @@
{
"type": "shared-common",
"id": "@kbn/ml-kibana-theme",
"owner": "@elastic/ml-ui"
}

View file

@ -0,0 +1,6 @@
{
"name": "@kbn/ml-kibana-theme",
"private": true,
"version": "1.0.0",
"license": "Elastic License 2.0"
}

View file

@ -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]);
}

View file

@ -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",
]
}

View file

@ -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>
);

View file

@ -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;
}

View file

@ -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/**/*",

View file

@ -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';
/**
@ -194,5 +191,3 @@ export const useColorRange = (
return scaleTypes[colorRangeScale];
};
export type EuiThemeType = typeof euiThemeLight | typeof euiThemeDark;

View file

@ -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;
}

View file

@ -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/**/*",

View file

@ -13,5 +13,4 @@ export {
useColorRange,
COLOR_RANGE,
COLOR_RANGE_SCALE,
useCurrentEuiTheme,
} from './use_color_range';

View file

@ -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
@ -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]: [
@ -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]
);
}

View file

@ -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 {
@ -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) => {

View file

@ -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,
@ -45,11 +48,7 @@ jest.mock('../../contexts/kibana', () => ({
},
},
}),
}));
const mockEuiTheme = euiThemeLight;
jest.mock('../color_range_legend', () => ({
useCurrentEuiTheme: () => ({
useCurrentThemeVars: () => ({
euiTheme: mockEuiTheme,
}),
}));

View file

@ -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 {
@ -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';
@ -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(

View file

@ -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';

View file

@ -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);
}

View file

@ -7,7 +7,7 @@
import './_classification_exploration.scss';
import React, { FC, useState, useEffect } from 'react';
import React, { FC, useEffect, useState } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import {
@ -20,15 +20,14 @@ import {
EuiText,
EuiTitle,
} from '@elastic/eui';
import { useMlKibana } from '../../../../../contexts/kibana';
import { useCurrentThemeVars, useMlKibana } from '../../../../../contexts/kibana';
// Separate imports for lazy loadable VegaChart and related code
import { VegaChart } from '../../../../../components/vega_chart';
import { VegaChartLoading } from '../../../../../components/vega_chart/vega_chart_loading';
import { useCurrentEuiTheme } from '../../../../../components/color_range_legend';
import { ErrorCallout } from '../error_callout';
import { getDependentVar, DataFrameAnalyticsConfig } from '../../../../common';
import { DataFrameAnalyticsConfig, getDependentVar } from '../../../../common';
import { DataFrameTaskStateType } from '../../../analytics_management/components/analytics_list/common';
import { ResultsSearchQuery } from '../../../../common/analytics';
@ -40,11 +39,11 @@ import { EvaluationQualityMetricsTable } from './evaluation_quality_metrics_tabl
import { getRocCurveChartVegaLiteSpec } from './get_roc_curve_chart_vega_lite_spec';
import {
getColumnData,
getTrailingControlColumns,
ACTUAL_CLASS_ID,
ConfusionMatrixColumn,
ConfusionMatrixColumnData,
ACTUAL_CLASS_ID,
getColumnData,
getTrailingControlColumns,
MAX_COLUMNS,
} from './column_data';
@ -108,7 +107,7 @@ export const EvaluatePanel: FC<EvaluatePanelProps> = ({ jobConfig, jobStatus, se
const {
services: { docLinks },
} = useMlKibana();
const { euiTheme } = useCurrentEuiTheme();
const { euiTheme } = useCurrentThemeVars();
const [columns, setColumns] = useState<ConfusionMatrixColumn[]>([]);
const [columnsData, setColumnsData] = useState<ConfusionMatrixColumnData[]>([]);

View file

@ -13,8 +13,10 @@ import React, {
ReactNode,
createContext,
useCallback,
useMemo,
} from 'react';
import cytoscape from 'cytoscape';
import { css } from '@emotion/react';
import cytoscape, { type Stylesheet } from 'cytoscape';
// @ts-ignore no declaration file
import dagre from 'cytoscape-dagre';
import { EuiThemeType } from '../../../../components/color_range_legend';
@ -42,17 +44,23 @@ function useCytoscape(options: cytoscape.CytoscapeOptions) {
useEffect(() => {
if (!cy) {
setCy(cytoscape({ ...options, container: ref.current }));
} else {
// update styles for existing instance
cy.style(options.style as unknown as Stylesheet);
}
}, [options, cy]);
// Destroy the cytoscape instance on unmount
useEffect(() => {
return () => {
if (cy) {
cy.destroy();
}
};
}, [cy]);
useEffect(
function destroyOnUnmount() {
return () => {
if (cy) {
cy.destroy();
}
};
},
[cy]
);
return [ref, cy] as [React.MutableRefObject<any>, cytoscape.Core | undefined];
}
@ -78,14 +86,20 @@ export function Cytoscape({
style,
width,
}: CytoscapeProps) {
const [ref, cy] = useCytoscape({
...getCytoscapeOptions(theme),
elements,
});
const cytoscapeOptions = useMemo(() => {
return {
...getCytoscapeOptions(theme),
elements,
};
}, [theme, elements]);
const [ref, cy] = useCytoscape(cytoscapeOptions);
// Add the height to the div style. The height is a separate prop because it
// is required and can trigger rendering when changed.
const divStyle = { ...style, height };
const divStyle = useMemo(() => {
return { ...style, height };
}, [style, height]);
const dataHandler = useCallback<cytoscape.EventHandler>(
(event) => {
@ -135,7 +149,13 @@ export function Cytoscape({
return (
<CytoscapeContext.Provider value={cy}>
<div ref={ref} style={divStyle} data-test-subj="mlPageDataFrameAnalyticsMapCytoscape">
<div
ref={ref}
css={css`
${divStyle}
`}
data-test-subj="mlPageDataFrameAnalyticsMapCytoscape"
>
{children}
</div>
</CytoscapeContext.Provider>

View file

@ -9,11 +9,11 @@ import React, { FC, useEffect, useState } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui';
import { Cytoscape, Controls, JobMapLegend } from './components';
import { useMlKibana, useMlLocator } from '../../../contexts/kibana';
import { Controls, Cytoscape, JobMapLegend } from './components';
import { useCurrentThemeVars, useMlKibana, useMlLocator } from '../../../contexts/kibana';
import { JOB_MAP_NODE_TYPES } from '../../../../../common/constants/data_frame_analytics';
import { ML_PAGES } from '../../../../../common/constants/locator';
import { useCurrentEuiTheme, EuiThemeType } from '../../../components/color_range_legend';
import { EuiThemeType } from '../../../components/color_range_legend';
import { useRefresh } from '../../../routing/use_refresh';
import { useRefDimensions } from './components/use_ref_dimensions';
import { useFetchAnalyticsMapData } from './use_fetch_analytics_map_data';
@ -65,7 +65,7 @@ export const JobMap: FC<Props> = ({ analyticsId, modelId, forceRefresh }) => {
},
} = useMlKibana();
const locator = useMlLocator()!;
const { euiTheme } = useCurrentEuiTheme();
const { euiTheme } = useCurrentThemeVars();
const refresh = useRefresh();
const redirectToAnalyticsManagementPage = async () => {

View file

@ -10,9 +10,9 @@ import d3 from 'd3';
import { scaleTime } from 'd3-scale';
import { i18n } from '@kbn/i18n';
import moment from 'moment';
import { useCurrentThemeVars } from '../contexts/kibana';
import type { Annotation, AnnotationsTable } from '../../../common/types/annotations';
import { ChartTooltipService } from '../components/chart_tooltip';
import { useCurrentEuiTheme } from '../components/color_range_legend';
export const Y_AXIS_LABEL_WIDTH = 170;
export const Y_AXIS_LABEL_PADDING = 8;
@ -36,8 +36,7 @@ export const SwimlaneAnnotationContainer: FC<SwimlaneAnnotationContainerProps> =
tooltipService,
}) => {
const canvasRef = React.useRef<HTMLDivElement | null>(null);
const { euiTheme } = useCurrentEuiTheme();
const { euiTheme } = useCurrentThemeVars();
useEffect(() => {
if (canvasRef.current !== null && Array.isArray(annotationsData)) {

View file

@ -7,32 +7,30 @@
import React, { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import {
EuiText,
EuiLoadingChart,
EuiResizeObserver,
EuiFlexGroup,
EuiFlexItem,
EuiLoadingChart,
EuiResizeObserver,
EuiText,
} from '@elastic/eui';
import { throttle } from 'lodash';
import {
Chart,
BrushEndListener,
Settings,
Heatmap,
HeatmapElementEvent,
Chart,
ElementClickListener,
TooltipValue,
HeatmapSpec,
TooltipSettings,
Heatmap,
HeatmapBrushEvent,
HeatmapElementEvent,
HeatmapSpec,
HeatmapStyle,
PartialTheme,
Position,
ScaleType,
PartialTheme,
HeatmapStyle,
Settings,
TooltipSettings,
TooltipValue,
} from '@elastic/charts';
import moment from 'moment';
import { i18n } from '@kbn/i18n';
import { ChartsPluginStart, useActiveCursor } from '@kbn/charts-plugin/public';
import { css } from '@emotion/react';
@ -41,6 +39,7 @@ import {
ML_ANOMALY_THRESHOLD,
ML_SEVERITY_COLORS,
} from '@kbn/ml-anomaly-utils';
import { useIsDarkTheme } from '@kbn/ml-kibana-theme';
import { SwimLanePagination } from './swimlane_pagination';
import { AppStateSelectedCells, OverallSwimlaneData, ViewBySwimLaneData } from './explorer_utils';
import { TimeBuckets as TimeBucketsClass } from '../util/time_buckets';
@ -48,12 +47,10 @@ import { SWIMLANE_TYPE, SwimlaneType } from './explorer_constants';
import { mlEscape } from '../util/string_utils';
import { FormattedTooltip } from '../components/chart_tooltip/chart_tooltip';
import { formatHumanReadableDateTime } from '../../../common/util/date_utils';
import './_explorer.scss';
import { EMPTY_FIELD_VALUE_LABEL } from '../timeseriesexplorer/components/entity_control/entity_control';
import { useUiSettings } from '../contexts/kibana';
import { Y_AXIS_LABEL_WIDTH, Y_AXIS_LABEL_PADDING } from './swimlane_annotation_container';
import { useCurrentEuiTheme } from '../components/color_range_legend';
import { Y_AXIS_LABEL_PADDING, Y_AXIS_LABEL_WIDTH } from './swimlane_annotation_container';
import { useCurrentThemeVars, useMlKibana } from '../contexts/kibana';
declare global {
interface Window {
@ -191,8 +188,12 @@ export const SwimlaneContainer: FC<SwimlaneProps> = ({
}) => {
const [chartWidth, setChartWidth] = useState<number>(0);
const isDarkTheme = !!useUiSettings().get('theme:darkMode');
const { euiTheme } = useCurrentEuiTheme();
const {
services: { theme: themeService },
} = useMlKibana();
const isDarkTheme = useIsDarkTheme(themeService);
const { euiTheme } = useCurrentThemeVars();
// Holds the container height for previously fetched data
const containerHeightRef = useRef<number>();
@ -515,7 +516,7 @@ export const SwimlaneContainer: FC<SwimlaneProps> = ({
{isLoading && (
<EuiText
textAlign={'center'}
style={{
css={{
position: 'absolute',
top: '50%',
left: '50%',

View file

@ -34,38 +34,36 @@ import {
CurveType,
CustomAnnotationTooltip,
LineAnnotation,
LineSeries,
LineAnnotationDatum,
LineAnnotationEvent,
LineSeries,
Position,
RectAnnotation,
RectAnnotationDatum,
RectAnnotationEvent,
ScaleType,
Settings,
timeFormatter,
RectAnnotationEvent,
LineAnnotationEvent,
Tooltip,
TooltipType,
} from '@elastic/charts';
import { DATAFEED_STATE } from '../../../../../../common/constants/states';
import {
CombinedJobWithStats,
ModelSnapshot,
MlSummaryJob,
ModelSnapshot,
} from '../../../../../../common/types/anomaly_detection_jobs';
import { JobMessage } from '../../../../../../common/types/audit_message';
import { LineAnnotationDatumWithModelSnapshot } from '../../../../../../common/types/results';
import { useToastNotificationService } from '../../../../services/toast_notification_service';
import { useMlApiContext } from '../../../../contexts/kibana';
import { useCurrentEuiTheme } from '../../../../components/color_range_legend';
import { useCurrentThemeVars, useMlApiContext } from '../../../../contexts/kibana';
import { RevertModelSnapshotFlyout } from '../../../../components/model_snapshots/revert_model_snapshot_flyout';
import { JobMessagesPane } from '../job_details/job_messages_pane';
import { EditQueryDelay } from './edit_query_delay';
import { CHART_DIRECTION, ChartDirectionType, CHART_SIZE } from './constants';
import { CHART_DIRECTION, CHART_SIZE, ChartDirectionType } from './constants';
import { loadFullJob } from '../utils';
import { checkPermission } from '../../../../capabilities/check_capabilities';
import { fillMissingChartData, type ChartDataWithNullValues } from './fill_missing_chart_data';
import { type ChartDataWithNullValues, fillMissingChartData } from './fill_missing_chart_data';
const dateFormatter = timeFormatter('MM-DD HH:mm:ss');
const MAX_CHART_POINTS = 480;
@ -142,10 +140,8 @@ export const DatafeedChartFlyout: FC<DatafeedChartFlyoutProps> = ({
results: { getDatafeedResultChartData },
} = useMlApiContext();
const { displayErrorToast } = useToastNotificationService();
const { euiTheme } = useCurrentEuiTheme();
const { euiTheme } = useCurrentThemeVars();
const handleChange = (date: moment.Moment) => setEndDate(date);
const handleEndDateChange = (direction: ChartDirectionType) => {
if (data.bucketSpan === undefined) return;

View file

@ -5,23 +5,21 @@
* 2.0.
*/
import { euiLightVars as lightTheme, euiDarkVars as darkTheme } from '@kbn/ui-theme';
import { useCurrentThemeVars } from '../../../../../../contexts/kibana';
import {
JobCreatorType,
isMultiMetricJobCreator,
isPopulationJobCreator,
JobCreatorType,
} from '../../../../common/job_creator';
import { getTimeBucketsFromCache, TimeBuckets } from '../../../../../../util/time_buckets';
import { useUiSettings } from '../../../../../../contexts/kibana/use_ui_settings_context';
export function useChartColors() {
const IS_DARK_THEME = useUiSettings().get('theme:darkMode');
const themeName = IS_DARK_THEME ? darkTheme : lightTheme;
const { euiTheme } = useCurrentThemeVars();
return {
LINE_COLOR: themeName.euiColorPrimary,
MODEL_COLOR: themeName.euiColorPrimary,
EVENT_RATE_COLOR: themeName.euiColorPrimary,
EVENT_RATE_COLOR_WITH_ANOMALIES: themeName.euiColorLightShade,
LINE_COLOR: euiTheme.euiColorPrimary,
MODEL_COLOR: euiTheme.euiColorPrimary,
EVENT_RATE_COLOR: euiTheme.euiColorPrimary,
EVENT_RATE_COLOR_WITH_ANOMALIES: euiTheme.euiColorLightShade,
};
}

View file

@ -7,9 +7,9 @@
import React, { FC } from 'react';
import { EuiIcon } from '@elastic/eui';
import { RectAnnotation, LineAnnotation, AnnotationDomainType, Position } from '@elastic/charts';
import { AnnotationDomainType, LineAnnotation, Position, RectAnnotation } from '@elastic/charts';
import { useCurrentThemeVars } from '../../../../../../contexts/kibana';
import { timeFormatter } from '../../../../../../../../common/util/date_utils';
import { useCurrentEuiTheme } from '../../../../../../components/color_range_legend';
interface Props {
overlayKey: number;
@ -20,7 +20,7 @@ interface Props {
}
export const OverlayRange: FC<Props> = ({ overlayKey, start, end, color, showMarker = true }) => {
const { euiTheme } = useCurrentEuiTheme();
const { euiTheme } = useCurrentThemeVars();
return (
<>

View file

@ -19,11 +19,12 @@ import { FIELD_FORMAT_IDS } from '@kbn/field-formats-plugin/common';
import { EuiComboBox, EuiComboBoxOptionOption, EuiEmptyPrompt, EuiSpacer } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { useIsDarkTheme } from '@kbn/ml-kibana-theme';
import { MemoryUsageInfo } from '../../../../common/types/trained_models';
import { JobType, MlSavedObjectType } from '../../../../common/types/saved_objects';
import { useTrainedModelsApiService } from '../../services/ml_api_service/trained_models';
import { LoadingWrapper } from '../../jobs/new_job/pages/components/charts/loading_wrapper';
import { useFieldFormatter, useUiSettings } from '../../contexts/kibana';
import { useFieldFormatter, useMlKibana } from '../../contexts/kibana';
import { useRefresh } from '../../routing/use_refresh';
import { getMemoryItemColor } from '../memory_item_colors';
@ -65,7 +66,11 @@ const TYPE_OPTIONS: EuiComboBoxOptionOption[] = Object.entries(TYPE_LABELS).map(
);
export const JobMemoryTreeMap: FC<Props> = ({ node, type, height }) => {
const isDarkTheme = useUiSettings().get('theme:darkMode');
const {
services: { theme: themeService },
} = useMlKibana();
const isDarkTheme = useIsDarkTheme(themeService);
const { theme, baseTheme } = useMemo(
() =>
isDarkTheme

View file

@ -10,18 +10,15 @@ import React, { FC, ReactNode } from 'react';
import useObservable from 'react-use/lib/useObservable';
import { FormattedMessage } from '@kbn/i18n-react';
import {
EuiHorizontalRule,
EuiBadge,
EuiToolTip,
EuiFlexGroup,
EuiFlexItem,
EuiHorizontalRule,
EuiIcon,
EuiToolTip,
} from '@elastic/eui';
import {
useCurrentEuiTheme,
EuiThemeType,
} from '../../../../components/color_range_legend/use_color_range';
import { useCurrentThemeVars } from '../../../../contexts/kibana';
import { EuiThemeType } from '../../../../components/color_range_legend/use_color_range';
import type { NerInference, NerResponse } from './ner_inference';
import { INPUT_TYPE } from '../inference_base';
@ -88,7 +85,7 @@ const NerOutput: FC<{ inferrer: NerInference }> = ({ inferrer }) => {
};
const Lines: FC<{ result: NerResponse }> = ({ result }) => {
const { euiTheme } = useCurrentEuiTheme();
const { euiTheme } = useCurrentThemeVars();
const lineSplit: JSX.Element[] = [];
result.response.forEach(({ value, entity }) => {
if (entity === null) {
@ -146,7 +143,7 @@ const EntityBadge = ({
entity: estypes.MlTrainedModelEntities;
children: ReactNode;
}) => {
const { euiTheme } = useCurrentEuiTheme();
const { euiTheme } = useCurrentThemeVars();
return (
<EuiBadge
// @ts-expect-error colors are correct in ENTITY_TYPES

View file

@ -7,14 +7,11 @@
import React, { FC, ReactNode } from 'react';
import useObservable from 'react-use/lib/useObservable';
import { EuiBadge, EuiHorizontalRule } from '@elastic/eui';
import { useCurrentEuiTheme } from '../../../../components/color_range_legend/use_color_range';
import { useCurrentThemeVars } from '../../../../contexts/kibana';
import type {
QuestionAnsweringInference,
FormattedQuestionAnsweringResult,
QuestionAnsweringInference,
} from './question_answering_inference';
const ICON_PADDING = '2px';
@ -61,7 +58,7 @@ function insertHighlighting(result: FormattedQuestionAnsweringResult, inputText:
}
const ResultBadge = ({ children }: { children: ReactNode }) => {
const { euiTheme } = useCurrentEuiTheme();
const { euiTheme } = useCurrentThemeVars();
return (
<EuiBadge
color={euiTheme.euiColorVis5_behindText}

View file

@ -91,5 +91,6 @@
"@kbn/utility-types",
"@kbn/ml-error-utils",
"@kbn/ml-anomaly-utils",
"@kbn/ml-kibana-theme",
],
}

View file

@ -4586,6 +4586,10 @@
version "0.0.0"
uid ""
"@kbn/ml-kibana-theme@link:x-pack/packages/ml/kibana_theme":
version "0.0.0"
uid ""
"@kbn/ml-local-storage@link:x-pack/packages/ml/local_storage":
version "0.0.0"
uid ""