diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 541e3f64b516e3..495f907c561b78 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -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 diff --git a/package.json b/package.json index 13eb7b8374c806..f5b1b479035496 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/tsconfig.base.json b/tsconfig.base.json index f34569e56f0e6d..221b712c83d776 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -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"], diff --git a/x-pack/packages/ml/kibana_theme/README.md b/x-pack/packages/ml/kibana_theme/README.md new file mode 100644 index 00000000000000..a61492e4e7b8d8 --- /dev/null +++ b/x-pack/packages/ml/kibana_theme/README.md @@ -0,0 +1,3 @@ +# @kbn/ml-kibana-theme + +Provides hooks to retrieve currently applied theme and EUI theme variables. diff --git a/x-pack/packages/ml/kibana_theme/index.ts b/x-pack/packages/ml/kibana_theme/index.ts new file mode 100644 index 00000000000000..0bd52263c70fbe --- /dev/null +++ b/x-pack/packages/ml/kibana_theme/index.ts @@ -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'; diff --git a/x-pack/packages/ml/kibana_theme/jest.config.js b/x-pack/packages/ml/kibana_theme/jest.config.js new file mode 100644 index 00000000000000..267dfc52f2b123 --- /dev/null +++ b/x-pack/packages/ml/kibana_theme/jest.config.js @@ -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: ['/x-pack/packages/ml/kibana_theme'], +}; diff --git a/x-pack/packages/ml/kibana_theme/kibana.jsonc b/x-pack/packages/ml/kibana_theme/kibana.jsonc new file mode 100644 index 00000000000000..e9f16a15377946 --- /dev/null +++ b/x-pack/packages/ml/kibana_theme/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-common", + "id": "@kbn/ml-kibana-theme", + "owner": "@elastic/ml-ui" +} diff --git a/x-pack/packages/ml/kibana_theme/package.json b/x-pack/packages/ml/kibana_theme/package.json new file mode 100644 index 00000000000000..02eb5de15712fd --- /dev/null +++ b/x-pack/packages/ml/kibana_theme/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/ml-kibana-theme", + "private": true, + "version": "1.0.0", + "license": "Elastic License 2.0" +} \ No newline at end of file diff --git a/x-pack/packages/ml/kibana_theme/src/hooks.ts b/x-pack/packages/ml/kibana_theme/src/hooks.ts new file mode 100644 index 00000000000000..0c30edeea2683e --- /dev/null +++ b/x-pack/packages/ml/kibana_theme/src/hooks.ts @@ -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]); +} diff --git a/x-pack/packages/ml/kibana_theme/tsconfig.json b/x-pack/packages/ml/kibana_theme/tsconfig.json new file mode 100644 index 00000000000000..9783a201c7e75e --- /dev/null +++ b/x-pack/packages/ml/kibana_theme/tsconfig.json @@ -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", + ] +} diff --git a/x-pack/plugins/aiops/public/components/field_stats_popover/field_stats_popover.tsx b/x-pack/plugins/aiops/public/components/field_stats_popover/field_stats_popover.tsx index ba0d1c29e89653..89d4611788f5b2 100644 --- a/x-pack/plugins/aiops/public/components/field_stats_popover/field_stats_popover.tsx +++ b/x-pack/plugins/aiops/public/components/field_stats_popover/field_stats_popover.tsx @@ -60,7 +60,7 @@ export function FieldStatsPopover({ defaultMessage: 'Show top field values', })} data-test-subj={'aiopsContextPopoverButton'} - style={{ marginLeft: euiTheme.euiSizeXS }} + css={{ marginLeft: euiTheme.euiSizeXS }} /> ); diff --git a/x-pack/plugins/aiops/public/hooks/use_eui_theme.ts b/x-pack/plugins/aiops/public/hooks/use_eui_theme.ts index 662a83b908e986..fa1374a22800b7 100644 --- a/x-pack/plugins/aiops/public/hooks/use_eui_theme.ts +++ b/x-pack/plugins/aiops/public/hooks/use_eui_theme.ts @@ -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; } diff --git a/x-pack/plugins/aiops/tsconfig.json b/x-pack/plugins/aiops/tsconfig.json index 3e152f89314099..f53bf4255bf112 100644 --- a/x-pack/plugins/aiops/tsconfig.json +++ b/x-pack/plugins/aiops/tsconfig.json @@ -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/**/*", diff --git a/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/hooks/use_color_range.ts b/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/hooks/use_color_range.ts index e7e8e9c7cb0e49..d230da125c13e5 100644 --- a/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/hooks/use_color_range.ts +++ b/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/hooks/use_color_range.ts @@ -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; diff --git a/x-pack/plugins/data_visualizer/public/application/common/hooks/use_current_eui_theme.ts b/x-pack/plugins/data_visualizer/public/application/common/hooks/use_current_eui_theme.ts index 06ad27ccb21b99..bd2500b1b77e61 100644 --- a/x-pack/plugins/data_visualizer/public/application/common/hooks/use_current_eui_theme.ts +++ b/x-pack/plugins/data_visualizer/public/application/common/hooks/use_current_eui_theme.ts @@ -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; } diff --git a/x-pack/plugins/data_visualizer/tsconfig.json b/x-pack/plugins/data_visualizer/tsconfig.json index 4609d1e9497d26..39e316646415d0 100644 --- a/x-pack/plugins/data_visualizer/tsconfig.json +++ b/x-pack/plugins/data_visualizer/tsconfig.json @@ -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/**/*", diff --git a/x-pack/plugins/ml/public/application/components/color_range_legend/index.ts b/x-pack/plugins/ml/public/application/components/color_range_legend/index.ts index e72a835cb1f63a..8e0549fb522fbf 100644 --- a/x-pack/plugins/ml/public/application/components/color_range_legend/index.ts +++ b/x-pack/plugins/ml/public/application/components/color_range_legend/index.ts @@ -13,5 +13,4 @@ export { useColorRange, COLOR_RANGE, COLOR_RANGE_SCALE, - useCurrentEuiTheme, } from './use_color_range'; diff --git a/x-pack/plugins/ml/public/application/components/color_range_legend/use_color_range.ts b/x-pack/plugins/ml/public/application/components/color_range_legend/use_color_range.ts index c1ed6bff306f91..66b2be1cf48310 100644 --- a/x-pack/plugins/ml/public/application/components/color_range_legend/use_color_range.ts +++ b/x-pack/plugins/ml/public/application/components/color_range_legend/use_color_range.ts @@ -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.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] - ); -} diff --git a/x-pack/plugins/ml/public/application/components/model_snapshots/revert_model_snapshot_flyout/create_calendar.tsx b/x-pack/plugins/ml/public/application/components/model_snapshots/revert_model_snapshot_flyout/create_calendar.tsx index 5bb0eb7ad2db75..7a85d4c877fc60 100644 --- a/x-pack/plugins/ml/public/application/components/model_snapshots/revert_model_snapshot_flyout/create_calendar.tsx +++ b/x-pack/plugins/ml/public/application/components/model_snapshots/revert_model_snapshot_flyout/create_calendar.tsx @@ -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 = ({ const maxSelectableTimeMoment = moment(maxSelectableTimeStamp); const minSelectableTimeMoment = moment(minSelectableTimeStamp); - const { euiTheme } = useCurrentEuiTheme(); + const { euiTheme } = useCurrentThemeVars(); const onBrushEnd = useCallback( ({ x }: XYBrushEvent) => { diff --git a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.test.tsx b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.test.tsx index 28cf8e7c6ffd23..247623d1dcacb0 100644 --- a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.test.tsx +++ b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.test.tsx @@ -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, }), })); diff --git a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.tsx b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.tsx index 404c8978221254..58361c9bca1ea3 100644 --- a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.tsx +++ b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.tsx @@ -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 = ({ { 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( diff --git a/x-pack/plugins/ml/public/application/contexts/kibana/index.ts b/x-pack/plugins/ml/public/application/contexts/kibana/index.ts index d72119dac3cde1..9ae430baa44fc0 100644 --- a/x-pack/plugins/ml/public/application/contexts/kibana/index.ts +++ b/x-pack/plugins/ml/public/application/contexts/kibana/index.ts @@ -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'; diff --git a/x-pack/plugins/ml/public/application/contexts/kibana/use_current_theme.ts b/x-pack/plugins/ml/public/application/contexts/kibana/use_current_theme.ts new file mode 100644 index 00000000000000..906fd599af75ad --- /dev/null +++ b/x-pack/plugins/ml/public/application/contexts/kibana/use_current_theme.ts @@ -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); +} diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_panel.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_panel.tsx index 752b933373e155..fc811aca893de2 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_panel.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_panel.tsx @@ -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 = ({ jobConfig, jobStatus, se const { services: { docLinks }, } = useMlKibana(); - const { euiTheme } = useCurrentEuiTheme(); + const { euiTheme } = useCurrentThemeVars(); const [columns, setColumns] = useState([]); const [columnsData, setColumnsData] = useState([]); diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/cytoscape.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/cytoscape.tsx index 24f7b9035d62e8..c3d25f44a33940 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/cytoscape.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/cytoscape.tsx @@ -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, 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( (event) => { @@ -135,7 +149,13 @@ export function Cytoscape({ return ( -
+
{children}
diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/job_map.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/job_map.tsx index f7bd29129f2a1d..49954c9ecac25d 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/job_map.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/job_map.tsx @@ -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 = ({ analyticsId, modelId, forceRefresh }) => { }, } = useMlKibana(); const locator = useMlLocator()!; - const { euiTheme } = useCurrentEuiTheme(); + const { euiTheme } = useCurrentThemeVars(); const refresh = useRefresh(); const redirectToAnalyticsManagementPage = async () => { diff --git a/x-pack/plugins/ml/public/application/explorer/swimlane_annotation_container.tsx b/x-pack/plugins/ml/public/application/explorer/swimlane_annotation_container.tsx index 6d98cc8cc21728..45ffefc557a6d4 100644 --- a/x-pack/plugins/ml/public/application/explorer/swimlane_annotation_container.tsx +++ b/x-pack/plugins/ml/public/application/explorer/swimlane_annotation_container.tsx @@ -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 = tooltipService, }) => { const canvasRef = React.useRef(null); - - const { euiTheme } = useCurrentEuiTheme(); + const { euiTheme } = useCurrentThemeVars(); useEffect(() => { if (canvasRef.current !== null && Array.isArray(annotationsData)) { diff --git a/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx b/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx index cbff2587ccf4c7..987e47efdcf1ab 100644 --- a/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx +++ b/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx @@ -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, + Chart, + ElementClickListener, Heatmap, + HeatmapBrushEvent, HeatmapElementEvent, - ElementClickListener, - TooltipValue, HeatmapSpec, - TooltipSettings, - HeatmapBrushEvent, + 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 = ({ }) => { const [chartWidth, setChartWidth] = useState(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(); @@ -515,7 +516,7 @@ export const SwimlaneContainer: FC = ({ {isLoading && ( = ({ 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; diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/charts/common/settings.ts b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/charts/common/settings.ts index e51fb68ce70967..d12989f35f310f 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/charts/common/settings.ts +++ b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/charts/common/settings.ts @@ -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, }; } diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/charts/event_rate_chart/overlay_range.tsx b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/charts/event_rate_chart/overlay_range.tsx index 58e4265ba4f972..0e1b29f8485c30 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/charts/event_rate_chart/overlay_range.tsx +++ b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/charts/event_rate_chart/overlay_range.tsx @@ -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 = ({ overlayKey, start, end, color, showMarker = true }) => { - const { euiTheme } = useCurrentEuiTheme(); + const { euiTheme } = useCurrentThemeVars(); return ( <> diff --git a/x-pack/plugins/ml/public/application/memory_usage/memory_tree_map/tree_map.tsx b/x-pack/plugins/ml/public/application/memory_usage/memory_tree_map/tree_map.tsx index e0bd62103dae5d..a90c088b40e26c 100644 --- a/x-pack/plugins/ml/public/application/memory_usage/memory_tree_map/tree_map.tsx +++ b/x-pack/plugins/ml/public/application/memory_usage/memory_tree_map/tree_map.tsx @@ -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 = ({ node, type, height }) => { - const isDarkTheme = useUiSettings().get('theme:darkMode'); + const { + services: { theme: themeService }, + } = useMlKibana(); + const isDarkTheme = useIsDarkTheme(themeService); + const { theme, baseTheme } = useMemo( () => isDarkTheme diff --git a/x-pack/plugins/ml/public/application/model_management/test_models/models/ner/ner_output.tsx b/x-pack/plugins/ml/public/application/model_management/test_models/models/ner/ner_output.tsx index 90b416b817b87f..c97d503da60aef 100644 --- a/x-pack/plugins/ml/public/application/model_management/test_models/models/ner/ner_output.tsx +++ b/x-pack/plugins/ml/public/application/model_management/test_models/models/ner/ner_output.tsx @@ -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 ( { - const { euiTheme } = useCurrentEuiTheme(); + const { euiTheme } = useCurrentThemeVars(); return (