[Theme] fix theme$ usage when used with useObservable (#220141)

## Summary

When using `theme$` with
[`useObservable`](ad33f76dff/src/useObservable.ts (L10-L21))
passing custom default `theme`, the resulting `theme` can be wrong.

Take for example this code...

```ts
import useObservable from 'react-use/lib/useObservable';

const theme = useObservable<CoreTheme>(kibanaTheme.theme$, {
  darkMode: false,
  name: 'amsterdam',
});
```

In such case `kibanaTheme.theme$` has the correct value but the
`useObservable` returns the default/initial value immediately, so the
default is always applied then updated, requiring 2 renderings just to
update to the correct theme.

The simplest approach to fix this is just to pass the
`kibanaTheme.getTheme()` as the default when using with `useObservable`.

```ts
const theme = useObservable<CoreTheme>(kibanaTheme.theme$, kibanaTheme.getTheme());
```

---

Ideally, in the future we have a commonly shared way to access the theme
in react via a `useKibanaTheme` hook or a better/more consistent API for
`useEuiTheme`.

### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Edgar Santos <edgar.santos@elastic.co>
This commit is contained in:
Nick Partridge 2025-05-22 11:54:15 -07:00 committed by GitHub
parent fdf3ef7ffc
commit 12b7429afe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
81 changed files with 212 additions and 376 deletions

View file

@ -25,7 +25,6 @@ const buildTableContext = (dataView: DataView, rows: DataTableRecord[]): DataTab
getRowByIndex: jest.fn((index) => rows[index]),
onFilter: jest.fn(),
dataView,
isDarkMode: false,
selectedDocsState: buildSelectedDocsState([]),
pageIndex: 0,
pageSize: 10,

View file

@ -10,8 +10,6 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import classnames from 'classnames';
import { FormattedMessage } from '@kbn/i18n-react';
import { of } from 'rxjs';
import useObservable from 'react-use/lib/useObservable';
import './data_table.scss';
import type { Storage } from '@kbn/kibana-utils-plugin/public';
import {
@ -99,7 +97,6 @@ import {
import { useSorting } from '../hooks/use_sorting';
const CONTROL_COLUMN_IDS_DEFAULT = [SELECT_ROW, OPEN_DETAILS];
const THEME_DEFAULT = { darkMode: false };
const VIRTUALIZATION_OPTIONS: EuiDataGridProps['virtualizationOptions'] = {
// Allowing some additional rows to be rendered outside
// the view minimizes pop-in when scrolling quickly
@ -520,7 +517,6 @@ export const UnifiedDataTable = ({
}: UnifiedDataTableProps) => {
const { fieldFormats, toastNotifications, dataViewFieldEditor, uiSettings, storage, data } =
services;
const { darkMode } = useObservable(services.theme?.theme$ ?? of(THEME_DEFAULT), THEME_DEFAULT);
const dataGridRef = useRef<EuiDataGridRefProps>(null);
const [isFilterActive, setIsFilterActive] = useState(false);
const [isCompareActive, setIsCompareActive] = useState(false);
@ -686,7 +682,6 @@ export const UnifiedDataTable = ({
getRowByIndex: (index: number) => displayedRows[index],
onFilter,
dataView,
isDarkMode: darkMode,
selectedDocsState,
valueToStringConverter,
componentsTourSteps,
@ -696,7 +691,6 @@ export const UnifiedDataTable = ({
}),
[
componentsTourSteps,
darkMode,
dataView,
isPlainRecord,
isPaginationEnabled,

View file

@ -20,7 +20,6 @@ export interface DataTableContext {
getRowByIndex: (index: number) => DataTableRecord | undefined;
onFilter?: DocViewFilterFn;
dataView: DataView;
isDarkMode: boolean;
selectedDocsState: UseSelectedDocsState;
valueToStringConverter: ValueToStringConverter;
componentsTourSteps?: Record<string, string>;

View file

@ -8,7 +8,6 @@
*/
import React from 'react';
import { of } from 'rxjs';
import { shallow } from 'enzyme';
import { findTestSubject } from '@elastic/eui/lib/test';
import { mountWithIntl } from '@kbn/test-jest-helpers';
@ -51,9 +50,6 @@ const mockServices = {
fieldFormats: {
getDefaultInstance: jest.fn(() => ({ convert: (value: unknown) => (value ? value : '-') })),
},
theme: {
theme$: of({ darkMode: false }),
},
};
const rowsSource: EsHitRecord[] = [

View file

@ -7,4 +7,4 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/
export { useDarkMode } from './use_dark_mode';
export { useKibanaIsDarkMode } from './use_kibana_is_dark_mode';

View file

@ -0,0 +1,22 @@
/*
* 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", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { useEuiTheme, COLOR_MODES_STANDARD } from '@elastic/eui';
/**
* A **temporary** hook to simplify getting `isDarkMode` from eui context
*
* TODO: Replace with hook directly from eui
* See https://github.com/elastic/eui/issues/8693
*/
export const useKibanaIsDarkMode = (): boolean => {
const { colorMode } = useEuiTheme();
return colorMode === COLOR_MODES_STANDARD.dark;
};

View file

@ -9,6 +9,7 @@
export { KibanaThemeProvider, type KibanaThemeProviderProps } from './theme_provider';
export { wrapWithTheme } from './with_theme';
export { useKibanaIsDarkMode } from './hooks';
// Re-exporting from @kbn/react-kibana-context-common for convenience to consumers.
export { defaultTheme, type KibanaTheme } from '@kbn/react-kibana-context-common';

View file

@ -10,7 +10,6 @@
import { snakeCase } from 'lodash';
import React, { FC, useState, useEffect, useMemo } from 'react';
import { css } from '@emotion/react';
import useObservable from 'react-use/lib/useObservable';
import {
EuiCard,
EuiFlexGroup,
@ -36,6 +35,7 @@ import {
RedirectAppLinksContainer as RedirectAppLinks,
RedirectAppLinksKibanaProvider,
} from '@kbn/shared-ux-link-redirect-app';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import { FetchResult } from '@kbn/newsfeed-plugin/public';
import {
FeatureCatalogueEntry,
@ -66,20 +66,11 @@ export const Overview: FC<Props> = ({ newsFetchResult, solutions, features }) =>
const [hasDataView, setHasDataView] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const { services } = useKibana<CoreStart & AppPluginStartDependencies>();
const {
http,
docLinks,
dataViews,
share,
application,
chrome,
dataViewEditor,
customBranding,
theme,
} = services;
const { http, docLinks, dataViews, share, application, chrome, dataViewEditor, customBranding } =
services;
const addBasePath = http.basePath.prepend;
const currentTheme = useObservable(theme.theme$, { darkMode: false, name: 'amsterdam' });
const { euiTheme } = useEuiTheme();
const isDarkMode = useKibanaIsDarkMode();
const minBreakpointM = useEuiMinBreakpoint('m');
// Home does not have a locator implemented, so hard-code it here.
@ -152,9 +143,7 @@ export const Overview: FC<Props> = ({ newsFetchResult, solutions, features }) =>
trackUiMetric(METRIC_TYPE.CLICK, `app_card_${appId}`);
}}
image={addBasePath(
`/plugins/${PLUGIN_ID}/assets/kibana_${appId}_${
currentTheme.darkMode ? 'dark' : 'light'
}.svg`
`/plugins/${PLUGIN_ID}/assets/kibana_${appId}_${isDarkMode ? 'dark' : 'light'}.svg`
)}
title={app.title}
titleElement="h3"

View file

@ -31,6 +31,7 @@
"@kbn/react-kibana-context-render",
"@kbn/core-application-browser-mocks",
"@kbn/core-http-browser-mocks",
"@kbn/react-kibana-context-theme",
],
"exclude": [
"target/**/*"

View file

@ -43,6 +43,7 @@ import { i18n } from '@kbn/i18n';
import { DatatableColumn } from '@kbn/expressions-plugin/public';
import { IconChartHeatmap } from '@kbn/chart-icons';
import { getOverridesFor } from '@kbn/chart-expressions-common';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import type { HeatmapRenderProps, FilterEvent, BrushEvent } from '../../common';
import {
applyPaletteParams,
@ -156,7 +157,7 @@ export const HeatmapComponent: FC<HeatmapRenderProps> = memo(
overrides,
}) => {
const chartRef = useRef<Chart>(null);
const isDarkTheme = chartsThemeService.useDarkMode();
const isDarkTheme = useKibanaIsDarkMode();
// legacy heatmap legend is handled by the uiState
const [showLegend, setShowLegend] = useState<boolean>(() => {
const bwcLegendStateDefault = args.legend.isVisible ?? true;

View file

@ -31,6 +31,7 @@
"@kbn/react-kibana-context-render",
"@kbn/transpose-utils",
"@kbn/ebt-tools",
"@kbn/react-kibana-context-theme",
],
"exclude": [
"target/**/*",

View file

@ -43,6 +43,7 @@ import type { FieldFormat } from '@kbn/field-formats-plugin/common';
import { getOverridesFor } from '@kbn/chart-expressions-common';
import { useKbnPalettes } from '@kbn/palettes';
import { useAppFixedViewport } from '@kbn/core-rendering-browser';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import { consolidateMetricColumns } from '../../common/utils';
import { DEFAULT_PERCENT_DECIMALS } from '../../common/constants';
import {
@ -303,7 +304,7 @@ const PartitionVisComponent = (props: PartitionVisComponentProps) => {
},
});
const isDarkMode = props.chartsThemeService.useDarkMode();
const isDarkMode = useKibanaIsDarkMode();
const layers = useMemo(
() =>
getLayers(

View file

@ -33,6 +33,7 @@
"@kbn/core-rendering-browser",
"@kbn/palettes",
"@kbn/ebt-tools",
"@kbn/react-kibana-context-theme",
],
"exclude": [
"target/**/*",

View file

@ -27,6 +27,7 @@ import {
extractVisualizationType,
} from '@kbn/chart-expressions-common';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import { ExpressionTagcloudRendererDependencies } from '../plugin';
import { TagcloudRendererConfig } from '../../common/types';
import { EXPRESSION_NAME } from '../../common';
@ -98,12 +99,6 @@ export const tagcloudRenderer: (
handlers.event(chartSizeEvent);
const palettesRegistry = await plugins.charts.palettes.getPalettes();
let isDarkMode = false;
plugins.charts.theme.darkModeEnabled$
.subscribe((val) => {
isDarkMode = val.darkMode;
})
.unsubscribe();
performanceTracker.mark(PERFORMANCE_TRACKER_MARKS.RENDER_START);
@ -125,7 +120,7 @@ export const tagcloudRenderer: (
fireEvent={handlers.event}
syncColors={config.syncColors}
overrides={config.overrides}
isDarkMode={isDarkMode}
isDarkMode={useKibanaIsDarkMode()}
/>
</VisualizationContainer>
)}

View file

@ -31,6 +31,7 @@
"@kbn/palettes",
"@kbn/charts-theme",
"@kbn/ebt-tools",
"@kbn/react-kibana-context-theme",
],
"exclude": [
"target/**/*",

View file

@ -58,6 +58,7 @@ import {
import { PersistedState } from '@kbn/visualizations-plugin/public';
import { getOverridesFor, ChartSizeSpec } from '@kbn/chart-expressions-common';
import { useAppFixedViewport } from '@kbn/core-rendering-browser';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import { AlertRuleFromVisUIActionData } from '@kbn/alerts-ui-shared';
import type {
FilterEvent,
@ -237,7 +238,7 @@ export function XYChart({
const chartRef = useRef<Chart>(null);
const chartBaseTheme = chartsThemeService.useChartsBaseTheme();
const darkMode = chartsThemeService.useDarkMode();
const darkMode = useKibanaIsDarkMode();
const palettes = useKbnPalettes();
const appFixedViewport = useAppFixedViewport();
const filteredLayers = getFilteredLayers(layers);

View file

@ -41,6 +41,7 @@
"@kbn/alerts-ui-shared",
"@kbn/ui-actions-browser",
"@kbn/ebt-tools",
"@kbn/react-kibana-context-theme",
],
"exclude": [
"target/**/*",

View file

@ -23,7 +23,11 @@ export class ThemeService {
/** An observable of the current charts base theme */
public chartsBaseTheme$ = this._chartsBaseTheme$.asObservable();
/** An observable boolean for dark mode of kibana */
/**
* An observable boolean for dark mode of kibana
*
* @deprecated use `useKibanaIsDarkMode`
*/
public get darkModeEnabled$(): Observable<CoreTheme> {
if (!this.theme$) {
throw new Error('ThemeService not initialized');
@ -32,7 +36,11 @@ export class ThemeService {
return this.theme$;
}
/** A React hook for consuming the dark mode value */
/**
* A React hook for consuming the dark mode value
*
* @deprecated use `useKibanaIsDarkMode`
*/
public useDarkMode = (): boolean => {
const [value, update] = useState(false);

View file

@ -8,7 +8,6 @@
*/
import React, { useMemo, useState } from 'react';
import useObservable from 'react-use/lib/useObservable';
import { i18n } from '@kbn/i18n';
import {
EuiButton,
@ -20,6 +19,7 @@ import {
EuiText,
} from '@elastic/eui';
import { useStateFromPublishingSubject } from '@kbn/presentation-publishing';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import useMountedState from 'react-use/lib/useMountedState';
import { useDashboardApi } from '../../../dashboard_api/use_dashboard_api';
@ -36,7 +36,7 @@ export function DashboardEmptyScreen() {
const isMounted = useMountedState();
const dashboardApi = useDashboardApi();
const [isLoading, setIsLoading] = useState(false);
const isDarkTheme = useObservable(coreServices.theme.theme$)?.darkMode;
const isDarkTheme = useKibanaIsDarkMode();
const viewMode = useStateFromPublishingSubject(dashboardApi.viewMode$);
const isEditMode = useMemo(() => {
return viewMode === 'edit';

View file

@ -84,6 +84,7 @@
"@kbn/ui-actions-browser",
"@kbn/esql-types",
"@kbn/saved-objects-tagging-plugin",
"@kbn/react-kibana-context-theme",
"@kbn/std"
],
"exclude": ["target/**/*"]

View file

@ -8,17 +8,16 @@
*/
import React, { useState, useEffect, useCallback } from 'react';
import useObservable from 'react-use/lib/useObservable';
import type { Observable } from 'rxjs';
import { useEuiTheme } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { ApplicationStart, CoreTheme, NotificationsStart } from '@kbn/core/public';
import { ApplicationStart, NotificationsStart } from '@kbn/core/public';
import type { GuideState, GuideStep as GuideStepStatus } from '@kbn/guided-onboarding';
import type { GuideId, GuideConfig, StepConfig } from '@kbn/guided-onboarding';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import type { GuidedOnboardingApi } from '../types';
import type { PluginState } from '../../common';
@ -33,7 +32,6 @@ interface GuidePanelProps {
api: GuidedOnboardingApi;
application: ApplicationStart;
notifications: NotificationsStart;
theme$: Observable<CoreTheme>;
}
const getProgress = (state?: GuideState): number => {
@ -48,15 +46,16 @@ const getProgress = (state?: GuideState): number => {
return 0;
};
export const GuidePanel = ({ api, application, notifications, theme$ }: GuidePanelProps) => {
export const GuidePanel = ({ api, application, notifications }: GuidePanelProps) => {
const euiThemeContext = useEuiTheme();
const euiTheme = euiThemeContext.euiTheme;
const isDarkTheme = useKibanaIsDarkMode();
const [isGuideOpen, setIsGuideOpen] = useState(false);
const [isQuitGuideModalOpen, setIsQuitGuideModalOpen] = useState(false);
const [pluginState, setPluginState] = useState<PluginState | undefined>(undefined);
const [guideConfig, setGuideConfig] = useState<GuideConfig | undefined>(undefined);
const [isLoading, setIsLoading] = useState<boolean>(false);
const { darkMode: isDarkTheme } = useObservable(theme$, { darkMode: false, name: 'amsterdam' });
const styles = getGuidePanelStyles({ euiThemeContext, isDarkTheme });

View file

@ -86,15 +86,9 @@ export class GuidedOnboardingPlugin
application: ApplicationStart;
notifications: NotificationsStart;
}) {
const { theme } = startServices;
ReactDOM.render(
<KibanaRenderContextProvider {...startServices}>
<GuidePanel
api={api}
application={application}
notifications={notifications}
theme$={theme.theme$}
/>
<GuidePanel api={api} application={application} notifications={notifications} />
</KibanaRenderContextProvider>,
targetDomElement
);

View file

@ -17,6 +17,7 @@
"@kbn/config-schema",
"@kbn/features-plugin",
"@kbn/react-kibana-context-render",
"@kbn/react-kibana-context-theme",
],
"exclude": [
"target/**/*",

View file

@ -17,7 +17,7 @@ import React from 'react';
import { EuiCard, EuiButton, EuiButtonEmpty, UseEuiTheme } from '@elastic/eui';
import { css } from '@emotion/react';
import { FormattedMessage } from '@kbn/i18n-react';
import { getServices } from '../../kibana_services';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
interface Props {
urlBasePath: string;
@ -26,8 +26,9 @@ interface Props {
}
export function SampleDataCard({ urlBasePath, onDecline, onConfirm }: Props) {
const IS_DARK_THEME = getServices().theme.getTheme().darkMode;
const cardGraphicFile = !IS_DARK_THEME
const isDarkMode = useKibanaIsDarkMode();
const cardGraphicFile = !isDarkMode
? 'illustration_integrations_lightmode.png'
: 'illustration_integrations_darkmode.png';
const cardGraphicURL = `${urlBasePath}/plugins/home/assets/common/${cardGraphicFile}`;

View file

@ -36,6 +36,7 @@
"@kbn/react-kibana-context-render",
"@kbn/core-http-browser",
"@kbn/deeplinks-observability",
"@kbn/react-kibana-context-theme",
],
"exclude": [
"target/**/*",

View file

@ -1,82 +0,0 @@
/*
* 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", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { act } from 'react-dom/test-utils';
import { useDarkMode } from './use_dark_mode';
import { createKibanaReactContext } from '../context';
import { KibanaServices } from '../context/types';
import { BehaviorSubject } from 'rxjs';
import { CoreTheme } from '@kbn/core/public';
import { coreMock } from '@kbn/core/public/mocks';
describe('useDarkMode', () => {
let container: HTMLDivElement | null;
beforeEach(() => {
container = document.createElement('div');
document.body.appendChild(container);
});
afterEach(() => {
document.body.removeChild(container!);
container = null;
});
const TestConsumer: React.FC = () => {
const darkMode = useDarkMode();
return <div>{String(darkMode)}</div>;
};
const mock = (): [KibanaServices, BehaviorSubject<CoreTheme>] => {
const core = coreMock.createStart();
const subject = new BehaviorSubject<CoreTheme>({ darkMode: false, name: 'amsterdam' });
core.theme.theme$ = subject.asObservable();
return [core, subject];
};
test('returns the value from the theme', () => {
const [core] = mock();
const { Provider } = createKibanaReactContext(core);
ReactDOM.render(
<Provider>
<TestConsumer />
</Provider>,
container
);
const div = container!.querySelector('div');
expect(div!.textContent).toBe('false');
});
test('value changes if the theme changes', () => {
const [core, subject] = mock();
const { Provider } = createKibanaReactContext(core);
ReactDOM.render(
<Provider>
<TestConsumer />
</Provider>,
container
);
let div = container!.querySelector('div');
expect(div!.textContent).toBe('false');
act(() => {
subject.next({ darkMode: true, name: 'amsterdam' });
});
div = container!.querySelector('div');
expect(div!.textContent).toBe('true');
});
});

View file

@ -1,27 +0,0 @@
/*
* 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", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import useObservable from 'react-use/lib/useObservable';
import { useKibana } from '../context';
export const useDarkMode = (defaultValue?: boolean): boolean => {
const {
services: { theme },
} = useKibana();
if (!theme) {
if (defaultValue !== undefined) {
return defaultValue;
}
throw new TypeError('theme service not available in kibana-react context.');
}
const currentTheme = useObservable(theme.theme$, theme.getTheme());
return currentTheme.darkMode;
};

View file

@ -31,8 +31,6 @@ export {
useGlobalUiSetting$,
} from './ui_settings';
export { useDarkMode } from './dark_mode';
export { useExecutionContext } from './use_execution_context';
export { reactRouterNavigate, reactRouterOnClickHandler } from './react_router_navigate';

View file

@ -8,7 +8,7 @@
*/
import React from 'react';
import { Observable } from 'rxjs';
import { of, type Observable } from 'rxjs';
import { I18nProvider } from '@kbn/i18n-react';
import type { MountPoint } from '@kbn/core/public';
@ -24,7 +24,7 @@ import { toMountPoint as _toMountPoint } from '@kbn/react-kibana-mount';
// dark mode is applied correctly. This code is for compatibility purposes,
// and will be removed when the deprecated usages are removed.
const themeStart: ThemeServiceStart = {
theme$: new Observable((subscriber) => subscriber.next(defaultTheme)),
theme$: of(defaultTheme),
getTheme: () => defaultTheme,
};

View file

@ -14,7 +14,6 @@ import { Router, Routes, Route } from '@kbn/shared-ux-router';
import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render';
import { FormattedMessage } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';
import useObservable from 'react-use/lib/useObservable';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { css } from '@emotion/css';
@ -23,11 +22,15 @@ import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app';
import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import type { FleetConfigType, FleetStartServices } from '../../plugin';
import { PackageInstallProvider } from '../integrations/hooks';
import { SpaceSettingsContextProvider } from '../../hooks/use_space_settings_context';
import { ErrorLayout, PermissionsError } from '../../layouts/error';
import { type FleetStatusProviderProps, useAuthz, useFleetStatus, useFlyoutContext } from './hooks';
import {
@ -60,7 +63,6 @@ import { EnrollmentTokenListPage } from './sections/agents/enrollment_token_list
import { UninstallTokenListPage } from './sections/agents/uninstall_token_list_page';
import { SettingsApp } from './sections/settings';
import { DebugPage } from './sections/debug';
import { ErrorLayout, PermissionsError } from '../../layouts/error';
const FEEDBACK_URL = 'https://ela.st/fleet-feedback';
@ -199,8 +201,7 @@ export const FleetAppContext: React.FC<{
fleetStatus,
}) => {
const XXL_BREAKPOINT = 1600;
const darkModeObservable = useObservable(startServices.theme.theme$);
const isDarkMode = darkModeObservable && darkModeObservable.darkMode;
const isDarkMode = useKibanaIsDarkMode();
return (
<KibanaRenderContextProvider

View file

@ -28,7 +28,7 @@ import type { Pagination } from '../../../../hooks';
import { useAgentVersion } from '../../../../hooks';
import { useLink, useAuthz } from '../../../../hooks';
import { AgentPolicySummaryLine } from '../../../../components';
import { AgentPolicySummaryLine } from '../../../../../../components';
import { Tags } from '../../components/tags';
import type { AgentMetrics } from '../../../../../../../common/types';
import { formatAgentCPU, formatAgentMemory } from '../../services/agent_metrics';

View file

@ -17,7 +17,7 @@ import { sendGetAgents, sendGetAgentStatus } from '../../../hooks';
import { AgentListPage } from '.';
jest.mock('../../../../integrations/hooks/use_confirm_force_install', () => ({
useConfirmForceInstall: () => <>confirmForceInstall</>,
useConfirmForceInstall: jest.fn(),
}));
jest.mock('./hooks/use_missing_encryption_key_callout', () => ({
@ -195,6 +195,8 @@ describe('agent_list_page', () => {
totalInactive: 0,
},
});
jest.useFakeTimers({ legacyFakeTimers: true });
({ utils } = renderAgentList());
await waitFor(() => {
@ -212,6 +214,10 @@ describe('agent_list_page', () => {
utils.getByText('All agents selected');
});
afterEach(() => {
jest.useRealTimers();
});
it('should not set selection mode when agent selection changed automatically', async () => {
act(() => {
jest.runOnlyPendingTimers();

View file

@ -13,12 +13,13 @@ import { Redirect, useRouteMatch } from 'react-router-dom';
import { Router, Routes, Route } from '@kbn/shared-ux-router';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import useObservable from 'react-use/lib/useObservable';
import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render';
import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import type { FleetConfigType, FleetStartServices } from '../../plugin';
import {
@ -33,6 +34,8 @@ import { SpaceSettingsContextProvider } from '../../hooks/use_space_settings_con
import { FleetServerFlyout } from '../fleet/components';
import { ErrorLayout, PermissionsError } from '../../layouts/error';
import { AgentPolicyContextProvider, useFlyoutContext } from './hooks';
import { FLEET_ROUTING_PATHS, INTEGRATIONS_ROUTING_PATHS, pagePathGetters } from './constants';
@ -40,12 +43,11 @@ import type { UIExtensionsStorage } from './types';
import { EPMApp } from './sections/epm';
import { ErrorLayout, PermissionsError } from '../../layouts/error';
import { PackageInstallProvider, UIExtensionsContext, FlyoutContextProvider } from './hooks';
import { IntegrationsHeader } from './components/header';
import { AgentEnrollmentFlyout } from './components';
import { ReadOnlyContextProvider } from './hooks/use_read_only_context';
const queryClient = new QueryClient();
const EmptyContext = () => <></>;
@ -78,8 +80,7 @@ export const IntegrationsAppContext: React.FC<{
fleetStatus,
}) => {
const XXL_BREAKPOINT = 1600;
const darkModeObservable = useObservable(startServices.theme.theme$);
const isDarkMode = darkModeObservable && darkModeObservable.darkMode;
const isDarkMode = useKibanaIsDarkMode();
const CloudContext = startServices.cloud?.CloudContextProvider || EmptyContext;

View file

@ -7,10 +7,12 @@
import React from 'react';
import { COLOR_MODES_STANDARD, EuiCallOut, EuiSpacer, EuiToolTip, useEuiTheme } from '@elastic/eui';
import { EuiCallOut, EuiSpacer, EuiToolTip, useEuiTheme } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { css } from '@emotion/css';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import { installationStatuses } from '../../../../../../common/constants';
import type { EpmPackageInstallStatus } from '../../../../../../common/types';
@ -90,8 +92,8 @@ const getCalloutText = ({
const useInstallationStatusStyles = (): InstallationStatusStylesProps &
CompressedInstallationStylesProps => {
const { euiTheme, colorMode } = useEuiTheme();
const isDarkMode = colorMode === COLOR_MODES_STANDARD.dark;
const { euiTheme } = useEuiTheme();
const isDarkMode = useKibanaIsDarkMode();
return React.useMemo(
() => ({

View file

@ -107,6 +107,7 @@
"@kbn/zod-helpers",
"@kbn/react-kibana-mount",
"@kbn/react-kibana-context-render",
"@kbn/react-kibana-context-theme",
"@kbn/fields-metadata-plugin",
"@kbn/test-jest-helpers",
"@kbn/core-saved-objects-utils-server",

View file

@ -6,10 +6,10 @@
*/
import React, { useState, useEffect, useMemo, useCallback, useRef } from 'react';
import useObservable from 'react-use/lib/useObservable';
import classNames from 'classnames';
import { FormattedMessage } from '@kbn/i18n-react';
import { toExpression } from '@kbn/interpreter';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import type { KibanaExecutionContext } from '@kbn/core-execution-context-common';
import { i18n } from '@kbn/i18n';
import {
@ -497,10 +497,7 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({
}
}, [suggestionForDraggedField, dispatchLens]);
const IS_DARK_THEME: boolean = useObservable(core.theme.theme$, {
darkMode: false,
name: 'amsterdam',
}).darkMode;
const isDarkMode = useKibanaIsDarkMode();
const renderDragDropPrompt = () => {
if (chartSizeSpec) {
@ -580,7 +577,7 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({
<img
aria-hidden={true}
css={promptIllustrationStyle}
src={IS_DARK_THEME ? applyChangesIllustrationDark : applyChangesIllustrationLight}
src={isDarkMode ? applyChangesIllustrationDark : applyChangesIllustrationLight}
alt={applyChangesString}
/>
<h2>

View file

@ -690,7 +690,7 @@ describe('DatatableComponent', () => {
renderDatatableComponent();
expect(getCellColorFn).toBeCalledTimes(3); // 3 initial renders of table
expect(getCellColorFn).toBeCalledTimes(2); // 2 initial renders of table
});
test('caches getCellColorFn by columnId with transpose columns', () => {
@ -717,7 +717,7 @@ describe('DatatableComponent', () => {
},
});
expect(getCellColorFn).toBeCalledTimes(3); // 3 initial renders of table
expect(getCellColorFn).toBeCalledTimes(2); // 2 initial renders of table
});
});

View file

@ -29,13 +29,12 @@ import {
import { CustomPaletteState, EmptyPlaceholder } from '@kbn/charts-plugin/public';
import { ClickTriggerEvent } from '@kbn/charts-plugin/public';
import { IconChartDatatable } from '@kbn/chart-icons';
import useObservable from 'react-use/lib/useObservable';
import { getOriginalId } from '@kbn/transpose-utils';
import { CoreTheme } from '@kbn/core/public';
import { getKbnPalettes } from '@kbn/palettes';
import { useKbnPalettes } from '@kbn/palettes';
import type { IFieldFormat } from '@kbn/field-formats-plugin/common';
import { getColorCategories, getLegacyColorCategories } from '@kbn/chart-expressions-common';
import { css } from '@emotion/react';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme/hooks';
import type { LensTableRowContextMenuEvent } from '../../../types';
import { RowHeightMode } from '../../../../common/types';
import { LensGridDirection } from '../../../../common/expressions';
@ -82,11 +81,8 @@ export const DatatableComponent = (props: DatatableRenderProps) => {
const dataGridRef = useRef<EuiDataGridRefProps>(null);
const isInteractive = props.interactive;
const theme = useObservable<CoreTheme>(props.theme.theme$, {
darkMode: false,
name: 'amsterdam',
});
const palettes = getKbnPalettes(theme);
const isDarkMode = useKibanaIsDarkMode();
const palettes = useKbnPalettes();
const [columnConfig, setColumnConfig] = useState({
columns: props.args.columns,
@ -423,7 +419,7 @@ export const DatatableComponent = (props: DatatableRenderProps) => {
palettes,
data,
colorByTerms,
theme.darkMode,
isDarkMode,
syncColors,
palette,
colorMapping
@ -437,14 +433,14 @@ export const DatatableComponent = (props: DatatableRenderProps) => {
formatters,
columnConfig,
DataContext,
theme.darkMode,
isDarkMode,
getCellColor,
props.args.fitRowToContent
);
}, [
formatters,
columnConfig,
theme.darkMode,
isDarkMode,
props.args.fitRowToContent,
props.paletteService,
palettes,

View file

@ -9,7 +9,7 @@ import React from 'react';
import { Ast } from '@kbn/interpreter';
import { i18n } from '@kbn/i18n';
import { CoreTheme, ThemeServiceStart } from '@kbn/core/public';
import { ThemeServiceStart } from '@kbn/core/public';
import {
PaletteRegistry,
CUSTOM_PALETTE,
@ -23,9 +23,9 @@ import { IconChartDatatable } from '@kbn/chart-icons';
import { getOriginalId } from '@kbn/transpose-utils';
import { LayerTypes } from '@kbn/expression-xy-plugin/public';
import { buildExpression, buildExpressionFunction } from '@kbn/expressions-plugin/common';
import useObservable from 'react-use/lib/useObservable';
import { getSortingCriteria } from '@kbn/sort-predicates';
import { getKbnPalettes } from '@kbn/palettes';
import { getKbnPalettes, useKbnPalettes } from '@kbn/palettes';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import type { FormBasedPersistedState } from '../../datasources/form_based/types';
import type {
SuggestionRequest,
@ -493,16 +493,13 @@ export const getDatatableVisualization = ({
};
},
DimensionEditorComponent(props) {
const theme = useObservable<CoreTheme>(kibanaTheme.theme$, {
darkMode: false,
name: 'amsterdam',
});
const palettes = getKbnPalettes(theme);
const isDarkMode = useKibanaIsDarkMode();
const palettes = useKbnPalettes();
return (
<TableDimensionEditor
{...props}
isDarkMode={theme.darkMode}
isDarkMode={isDarkMode}
palettes={palettes}
paletteService={paletteService}
formatFactory={formatFactory}

View file

@ -505,10 +505,7 @@ export const getPieVisualization = ({
};
},
DimensionEditorComponent(props) {
const theme = useObservable<CoreTheme>(kibanaTheme.theme$, {
darkMode: false,
name: 'amsterdam',
});
const theme = useObservable<CoreTheme>(kibanaTheme.theme$, kibanaTheme.getTheme());
const palettes = getKbnPalettes(theme);
return (
<DimensionEditor

View file

@ -305,10 +305,7 @@ export const getTagcloudVisualization = ({
},
DimensionEditorComponent(props) {
const theme = useObservable<CoreTheme>(kibanaTheme.theme$, {
darkMode: false,
name: 'amsterdam',
});
const theme = useObservable<CoreTheme>(kibanaTheme.theme$, kibanaTheme.getTheme());
const palettes = getKbnPalettes(theme);
if (props.groupId === TAG_GROUP_ID) {

View file

@ -754,10 +754,7 @@ export const getXyVisualization = ({
paletteService,
};
const theme = useObservable<CoreTheme>(kibanaTheme.theme$, {
darkMode: false,
name: 'amsterdam',
});
const theme = useObservable<CoreTheme>(kibanaTheme.theme$, kibanaTheme.getTheme());
const palettes = getKbnPalettes(theme);
const layer = props.state.layers.find((l) => l.layerId === props.layerId)!;
const dimensionEditor = isReferenceLayer(layer) ? (

View file

@ -120,6 +120,7 @@
"@kbn/core-capabilities-common",
"@kbn/presentation-panel-plugin",
"@kbn/esql-types",
"@kbn/react-kibana-context-theme",
"@kbn/fields-metadata-plugin",
"@kbn/response-ops-rule-form",
"@kbn/alerts-ui-shared",

View file

@ -41,7 +41,8 @@ import type { KibanaFeature } from '@kbn/features-plugin/common';
import type { FeaturesPluginStart } from '@kbn/features-plugin/public';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { reactRouterNavigate, useDarkMode } from '@kbn/kibana-react-plugin/public';
import { reactRouterNavigate } from '@kbn/kibana-react-plugin/public';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import { toMountPoint } from '@kbn/react-kibana-mount';
import type { Cluster } from '@kbn/remote-clusters-plugin/public';
import { REMOTE_CLUSTERS_PATH } from '@kbn/remote-clusters-plugin/public';
@ -339,7 +340,7 @@ export const EditRolePage: FunctionComponent<Props> = ({
cloudOrgUrl,
...startServices
}) => {
const isDarkMode = useDarkMode();
const isDarkMode = useKibanaIsDarkMode();
if (!dataViews) {
// The dataViews plugin is technically marked as an optional dependency because we don't need to pull it in for Anonymous pages (such

View file

@ -92,6 +92,7 @@
"@kbn/core-elasticsearch-server",
"@kbn/core-http-server-utils",
"@kbn/core-user-profile-browser-mocks",
"@kbn/react-kibana-context-theme",
],
"exclude": [
"target/**/*",

View file

@ -5,16 +5,17 @@
* 2.0.
*/
import React from 'react';
import { EuiEmptyPrompt, EuiImage, useEuiTheme } from '@elastic/eui';
import { EuiEmptyPrompt, EuiImage } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { dashboardsDark, dashboardsLight } from '@kbn/shared-svg';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
interface Props {
actions: React.ReactNode;
}
export function EmptyDashboards({ actions }: Props) {
const { colorMode } = useEuiTheme();
const isDarkMode = useKibanaIsDarkMode();
return (
<>
@ -22,11 +23,7 @@ export function EmptyDashboards({ actions }: Props) {
hasShadow={false}
hasBorder={false}
icon={
<EuiImage
size="fullWidth"
src={colorMode === 'DARK' ? dashboardsDark : dashboardsLight}
alt=""
/>
<EuiImage size="fullWidth" src={isDarkMode ? dashboardsDark : dashboardsLight} alt="" />
}
title={
<h2>

View file

@ -5,13 +5,14 @@
* 2.0.
*/
import { EuiFlexGroup, EuiFlexItem, EuiSkeletonText, useEuiTheme } from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, EuiSkeletonText } from '@elastic/eui';
import type { CloudProvider } from '@kbn/custom-icons';
import { getAgentIcon, getCloudProviderIcon } from '@kbn/custom-icons';
import { i18n } from '@kbn/i18n';
import { get } from 'lodash';
import React from 'react';
import { useHistory } from 'react-router-dom';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import {
CLOUD_AVAILABILITY_ZONE,
CLOUD_INSTANCE_ID,
@ -89,7 +90,7 @@ const cloudDetailsKeys = [
];
export function InstanceDetails({ serviceName, serviceNodeName, kuery }: Props) {
const { colorMode } = useEuiTheme();
const isDarkMode = useKibanaIsDarkMode();
const history = useHistory();
const { data, status } = useInstanceDetailsFetcher({
@ -133,7 +134,6 @@ export function InstanceDetails({ serviceName, serviceNodeName, kuery }: Props)
const containerType = data.kubernetes?.pod?.name ? 'Kubernetes' : 'Docker';
const isDarkMode = colorMode === 'DARK';
return (
<EuiFlexGroup direction="column" responsive={false}>
<EuiFlexItem>

View file

@ -31,6 +31,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiSpacer, useEuiTheme } from '@ela
import { i18n } from '@kbn/i18n';
import type { ReactElement } from 'react';
import React from 'react';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import { useHistory } from 'react-router-dom';
import { useChartThemes } from '@kbn/observability-shared-plugin/public';
import { isExpectedBoundsComparison } from '../time_comparison/get_comparison_options';
@ -77,7 +78,8 @@ export function TimeseriesChart({
}: TimeseriesChartProps) {
const history = useHistory();
const { chartRef, updatePointerEvent } = useChartPointerEventContext();
const { euiTheme, colorMode } = useEuiTheme();
const { euiTheme } = useEuiTheme();
const isDarkMode = useKibanaIsDarkMode();
const chartThemes = useChartThemes();
const anomalyChartTimeseries = getChartAnomalyTimeseries({
anomalyTimeseries,
@ -117,7 +119,6 @@ export function TimeseriesChart({
}
: undefined;
const isDarkMode = colorMode === 'DARK';
const endZoneColor = isDarkMode ? euiTheme.colors.lightShade : euiTheme.colors.darkShade;
const endZoneRectAnnotationStyle: Partial<RectAnnotationStyle> = {
stroke: endZoneColor,
@ -152,7 +153,7 @@ export function TimeseriesChart({
alignItems="center"
responsive={false}
gutterSize="xs"
style={{ fontWeight: 'normal' }}
css={{ fontWeight: 'normal' }}
>
<EuiFlexItem grow={false}>
<EuiIcon type="iInCircle" />

View file

@ -5,8 +5,9 @@
* 2.0.
*/
import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, useEuiTheme } from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import type { CloudProvider } from '@kbn/custom-icons';
import { getAgentIcon, getCloudProviderIcon, getServerlessIcon } from '@kbn/custom-icons';
import type { ReactChild } from 'react';
@ -75,11 +76,9 @@ export interface PopoverItem {
}
export function ServiceIcons({ start, end, serviceName, environment }: Props) {
const isDarkMode = useKibanaIsDarkMode();
const [selectedIconPopover, setSelectedIconPopover] = useState<Icons | null>();
const { colorMode } = useEuiTheme();
const isDarkMode = colorMode === 'DARK';
const { data: icons, status: iconsFetchStatus } = useFetcher(
(callApmApi) => {
if (serviceName && start && end) {

View file

@ -15,6 +15,7 @@ import type { Storage } from '@kbn/kibana-utils-plugin/public';
import { NavigationWarningPromptProvider } from '@kbn/observability-shared-plugin/public';
import type { TriggersAndActionsUIPublicPluginStart } from '@kbn/triggers-actions-ui-plugin/public';
import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme/hooks';
import {
type KibanaEnvContext,
useKibanaContextForPluginProvider,
@ -23,7 +24,6 @@ import {
import type { InfraClientStartDeps, InfraClientStartExports } from '../types';
import { HeaderActionMenuProvider } from '../containers/header_action_menu_provider';
import { TriggersActionsProvider } from '../containers/triggers_actions_context';
import { useIsDarkMode } from '../hooks/use_is_dark_mode';
export const CommonInfraProviders: FC<
PropsWithChildren<{
@ -34,7 +34,7 @@ export const CommonInfraProviders: FC<
theme$: AppMountParameters['theme$'];
}>
> = ({ children, triggersActionsUI, setHeaderActionMenu, appName, storage, theme$ }) => {
const darkMode = useIsDarkMode();
const darkMode = useKibanaIsDarkMode();
return (
<TriggersActionsProvider triggersActionsUI={triggersActionsUI}>

View file

@ -6,7 +6,7 @@
*/
import type { FC, PropsWithChildren } from 'react';
import React, { useEffect, useMemo, useState } from 'react';
import React, { useMemo } from 'react';
import { merge } from 'rxjs';
import { i18n } from '@kbn/i18n';
import { EuiCallOut, EuiLink, useEuiTheme } from '@elastic/eui';
@ -21,6 +21,7 @@ import {
import { initializeUnsavedChanges } from '@kbn/presentation-containers';
import { LogStream } from '@kbn/logs-shared-plugin/public';
import type { AppMountParameters, CoreStart } from '@kbn/core/public';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common';
import type { Query } from '@kbn/es-query';
import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render';
@ -73,6 +74,7 @@ export function getLogStreamEmbeddableFactory(services: Services) {
return {
api,
Component: () => {
const darkMode = useKibanaIsDarkMode();
const { filters, query, timeRange } = useFetchContext(api);
const { startTimestamp, endTimestamp } = useMemo(() => {
return {
@ -81,14 +83,6 @@ export function getLogStreamEmbeddableFactory(services: Services) {
};
}, [timeRange]);
const [darkMode, setDarkMode] = useState(false);
useEffect(() => {
const subscription = services.coreStart.theme.theme$.subscribe((theme) => {
setDarkMode(theme.darkMode);
});
return () => subscription.unsubscribe();
}, []);
return !startTimestamp || !endTimestamp ? null : (
<LogStreamEmbeddableProviders
core={services.coreStart}

View file

@ -1,20 +0,0 @@
/*
* 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 type { CoreTheme } from '@kbn/core/public';
import useObservable from 'react-use/lib/useObservable';
import { of } from 'rxjs';
import { useKibanaContextForPlugin } from './use_kibana';
const themeDefault: CoreTheme = { darkMode: false, name: 'amsterdam' };
export const useIsDarkMode = () => {
const { services } = useKibanaContextForPlugin();
const { darkMode } = useObservable(services.theme?.theme$ ?? of(themeDefault), themeDefault);
return darkMode;
};

View file

@ -17,7 +17,7 @@ import {
import styled from 'styled-components';
import { FormattedMessage } from '@kbn/i18n-react';
import { euiLightVars, euiDarkVars } from '@kbn/ui-theme';
import { useDarkMode } from '@kbn/kibana-react-plugin/public';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import { getCoreVitalTooltipMessage, Thresholds } from './core_vital_item';
import {
LEGEND_NEEDS_IMPROVEMENT_LABEL,
@ -50,7 +50,7 @@ interface Props {
}
export function PaletteLegends({ ranks, title, onItemHover, thresholds, isCls }: Props) {
const darkMode = useDarkMode(false);
const darkMode = useKibanaIsDarkMode();
const palette = euiPaletteForStatus(3);
const labels = [LEGEND_GOOD_LABEL, LEGEND_NEEDS_IMPROVEMENT_LABEL, LEGEND_POOR_LABEL];

View file

@ -17,13 +17,14 @@ import type { AppMountParameters } from '@kbn/core/public';
import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common';
import { CellActionsProvider } from '@kbn/cell-actions';
import { NavigationProvider } from '@kbn/security-solution-navigation';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import { UpsellingProvider } from '../common/components/upselling_provider';
import { ManageUserInfo } from '../detections/components/user_info';
import { APP_NAME } from '../../common/constants';
import { ErrorToastDispatcher } from '../common/components/error_toast_dispatcher';
import { MlCapabilitiesProvider } from '../common/components/ml/permissions/ml_capabilities_provider';
import { GlobalToaster, ManageGlobalToaster } from '../common/components/toasters';
import { KibanaContextProvider, useKibana, useDarkMode } from '../common/lib/kibana';
import { KibanaContextProvider, useKibana } from '../common/lib/kibana';
import type { State } from '../common/store';
import type { StartServices } from '../types';
import { PageRouter } from './routes';
@ -47,7 +48,7 @@ const StartAppComponent: FC<StartAppComponent> = ({ children, history, store, th
upselling,
} = services;
const darkMode = useDarkMode();
const darkMode = useKibanaIsDarkMode();
return (
<KibanaRenderContextProvider {...services}>

View file

@ -19,7 +19,7 @@ import type { GenerationInterval } from '@kbn/elastic-assistant-common';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import moment from 'moment';
import { useKibana } from '../../../../common/lib/kibana';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import { InfoPopoverBody } from '../info_popover_body';
import { getTimerPrefix } from './last_times_popover/helpers';
import * as i18n from '../translations';
@ -42,8 +42,7 @@ const CountdownComponent: React.FC<Props> = ({
}) => {
// theming:
const { euiTheme } = useEuiTheme();
const { theme } = useKibana().services;
const isDarkMode = useMemo(() => theme.getTheme().darkMode === true, [theme]);
const isDarkMode = useKibanaIsDarkMode();
// popover state:
const [isPopoverOpen, setIsPopoverOpen] = useState(false);

View file

@ -9,10 +9,10 @@ import { EuiFlexGroup, EuiFlexItem, EuiBadge, EuiText, useEuiTheme } from '@elas
import { css } from '@emotion/react';
import type { GenerationInterval } from '@kbn/elastic-assistant-common';
import moment from 'moment';
import React, { useMemo } from 'react';
import React from 'react';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import { PreferenceFormattedDate } from '../../../../../../common/components/formatted_date';
import { useKibana } from '../../../../../../common/lib/kibana';
import { MAX_SECONDS_BADGE_WIDTH } from '../helpers';
import * as i18n from '../translations';
@ -22,8 +22,7 @@ interface Props {
const GenerationTimingComponent: React.FC<Props> = ({ interval }) => {
const { euiTheme } = useEuiTheme();
const { theme } = useKibana().services;
const isDarkMode = useMemo(() => theme.getTheme().darkMode === true, [theme]);
const isDarkMode = useKibanaIsDarkMode();
return (
<EuiFlexGroup alignItems="center" data-test-subj="generationTiming" gutterSize="none">

View file

@ -7,10 +7,10 @@
import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText, useEuiTheme } from '@elastic/eui';
import { css } from '@emotion/react';
import React, { useMemo } from 'react';
import React from 'react';
import type { GenerationInterval } from '@kbn/elastic-assistant-common';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import { useKibana } from '../../../../../common/lib/kibana';
import { GenerationTiming } from './generation_timing';
import { useKibanaFeatureFlags } from '../../../use_kibana_feature_flags';
import * as i18n from './translations';
@ -25,8 +25,7 @@ const LastTimesPopoverComponent: React.FC<Props> = ({
successfulGenerations,
}) => {
const { euiTheme } = useEuiTheme();
const { theme } = useKibana().services;
const isDarkMode = useMemo(() => theme.getTheme().darkMode === true, [theme]);
const isDarkMode = useKibanaIsDarkMode();
const { attackDiscoveryAlertsEnabled } = useKibanaFeatureFlags();
const calculatedBy = attackDiscoveryAlertsEnabled

View file

@ -18,7 +18,7 @@ import { css } from '@emotion/react';
import React, { useCallback, useMemo, useState } from 'react';
import type { GenerationInterval } from '@kbn/elastic-assistant-common';
import { useKibana } from '../../../common/lib/kibana';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import { Countdown } from './countdown';
import { LoadingMessages } from './loading_messages';
import * as i18n from './translations';
@ -69,7 +69,7 @@ const LoadingCalloutComponent: React.FC<Props> = ({
successfulGenerations,
}) => {
const { euiTheme } = useEuiTheme();
const { theme } = useKibana().services;
const isDarkMode = useKibanaIsDarkMode();
const { attackDiscoveryAlertsEnabled } = useKibanaFeatureFlags();
const isTerminalState = useMemo(() => getIsTerminalState(status), [status]);
@ -122,8 +122,6 @@ const LoadingCalloutComponent: React.FC<Props> = ({
]
);
const isDarkMode = useMemo(() => theme.getTheme().darkMode === true, [theme]);
const backgroundColor = useMemo(() => {
const defaultBackgroundColor = isDarkMode ? BACKGROUND_COLOR_DARK : BACKGROUND_COLOR_LIGHT;
const successBackgroundColor = euiTheme.colors.backgroundBaseSuccess;

View file

@ -8,8 +8,8 @@
import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiPopoverTitle, EuiText } from '@elastic/eui';
import { css } from '@emotion/react';
import type { GenerationInterval } from '@kbn/elastic-assistant-common';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import React, { useMemo } from 'react';
import { useKibana } from '../../../../common/lib/kibana';
import { LastTimesPopover } from '../countdown/last_times_popover';
import {
@ -33,8 +33,7 @@ const InfoPopoverBodyComponent: React.FC<Props> = ({
connectorIntervals,
successfulGenerations,
}) => {
const { theme } = useKibana().services;
const isDarkMode = useMemo(() => theme.getTheme().darkMode === true, [theme]);
const isDarkMode = useKibanaIsDarkMode();
const { attackDiscoveryAlertsEnabled } = useKibanaFeatureFlags();
const averageIntervalSeconds = useMemo(() => {
if (attackDiscoveryAlertsEnabled) {

View file

@ -12,7 +12,8 @@ import { DEFAULT_ATTACK_DISCOVERY_MAX_ALERTS } from '@kbn/elastic-assistant';
import React, { useMemo } from 'react';
import { getAttackDiscoveryLoadingMessage } from '@kbn/elastic-assistant-common';
import { useDateFormat, useKibana } from '../../../../common/lib/kibana';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import { useDateFormat } from '../../../../common/lib/kibana';
import { getCanceledResultMessage } from './get_canceled_result_message';
import { getFormattedDate } from './get_formatted_time';
import { getIsTerminalState } from '../get_is_terminal_state';
@ -49,7 +50,7 @@ const LoadingMessagesComponent: React.FC<Props> = ({
start,
status,
}) => {
const { theme } = useKibana().services;
const isDarkMode = useKibanaIsDarkMode();
const dateFormat = useDateFormat();
const formattedStart = useMemo(
@ -76,8 +77,6 @@ const LoadingMessagesComponent: React.FC<Props> = ({
localStorageAttackDiscoveryMaxAlerts,
});
const isDarkMode = theme.getTheme().darkMode === true;
const isTerminalState = useMemo(() => getIsTerminalState(status), [status]);
const progressMessage = useMemo(

View file

@ -6,7 +6,8 @@
*/
import React, { type PropsWithChildren } from 'react';
import { css, type CSSInterpolation } from '@emotion/css';
import { EuiText, useEuiTheme, COLOR_MODES_STANDARD, type EuiTextProps } from '@elastic/eui';
import { EuiText, useEuiTheme, type EuiTextProps } from '@elastic/eui';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
export interface PanelTextProps extends PropsWithChildren<EuiTextProps> {
subdued?: true;
@ -15,8 +16,8 @@ export interface PanelTextProps extends PropsWithChildren<EuiTextProps> {
}
export const PanelText = React.memo<PanelTextProps>(
({ children, subdued, semiBold, cursive, ...props }) => {
const { euiTheme, colorMode } = useEuiTheme();
const isDarkMode = colorMode === COLOR_MODES_STANDARD.dark;
const { euiTheme } = useEuiTheme();
const isDarkMode = useKibanaIsDarkMode();
let color;
if (subdued && !isDarkMode) {

View file

@ -85,9 +85,6 @@ export const useKibana = jest.fn().mockReturnValue({
});
export const useUiSetting = jest.fn(createUseUiSettingMock());
export const useUiSetting$ = jest.fn(createUseUiSetting$Mock());
export const useDarkMode = jest
.fn()
.mockImplementation((defaultValue?: boolean) => defaultValue ?? false);
export const useHttp = jest.fn().mockReturnValue(createStartServicesMock().http);
export const useTimeZone = jest.fn();
export const useDateFormat = jest.fn().mockReturnValue('MMM D, YYYY @ HH:mm:ss.SSS');

View file

@ -10,7 +10,6 @@ import {
useKibana,
useUiSetting,
useUiSetting$,
useDarkMode,
withKibana,
} from '@kbn/kibana-react-plugin/public';
import type { ApmBase } from '@elastic/apm-rum';
@ -24,6 +23,5 @@ export {
useTypedKibana as useKibana,
useUiSetting,
useUiSetting$,
useDarkMode,
withKibana,
};

View file

@ -1,15 +0,0 @@
/*
* 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 { euiLightVars as lightTheme, euiDarkVars as darkTheme } from '@kbn/ui-theme';
import { useDarkMode } from '../kibana';
export const useEuiTheme = () => {
const darkMode = useDarkMode();
return darkMode ? darkTheme : lightTheme;
};

View file

@ -10,7 +10,7 @@ import React, { memo, useMemo } from 'react';
import { Provider } from 'react-redux';
import { Router } from '@kbn/shared-ux-router';
import type { History } from 'history';
import useObservable from 'react-use/lib/useObservable';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import type { Store } from 'redux';
import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common';
import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render';
@ -37,9 +37,7 @@ export const AppRootProvider = memo<{
queryClient: QueryClient;
children: ReactNode | ReactNode[];
}>(({ store, history, coreStart, depsStart, queryClient, startServices, children }) => {
const { theme: themeStart } = coreStart;
const theme = useObservable(themeStart.theme$, themeStart.getTheme());
const isDarkMode = theme.darkMode;
const isDarkMode = useKibanaIsDarkMode();
const services = useMemo(() => {
return {
...depsStart,

View file

@ -5,11 +5,10 @@
* 2.0.
*/
import { EuiAvatar, EuiIcon } from '@elastic/eui';
import { EuiAvatar, EuiIcon, useEuiTheme } from '@elastic/eui';
import React, { memo } from 'react';
import styled from 'styled-components';
import { useEuiTheme } from '../../../../common/lib/theme/use_eui_theme';
import type { RuleStatusType } from '../../../common/types';
export interface RuleStatusIconProps {
@ -27,12 +26,16 @@ const RuleStatusIconStyled = styled.div`
`;
const RuleStatusIconComponent: React.FC<RuleStatusIconProps> = ({ name, type }) => {
const theme = useEuiTheme();
const color = type === 'passive' ? theme.euiColorLightestShade : theme.euiColorPrimary;
const { euiTheme } = useEuiTheme();
const color =
type === 'passive' ? euiTheme.colors.backgroundBaseDisabled : euiTheme.colors.primary;
return (
<RuleStatusIconStyled>
<EuiAvatar color={color} name={type === 'valid' ? '' : name} size="l" aria-label={name} />
{type === 'valid' ? <EuiIcon type="check" color={theme.euiColorEmptyShade} size="l" /> : null}
{type === 'valid' ? (
<EuiIcon type="check" color={euiTheme.colors.backgroundBasePlain} size="l" />
) : null}
</RuleStatusIconStyled>
);
};

View file

@ -8,8 +8,8 @@
import { euiDarkVars as darkTheme, euiLightVars as lightTheme } from '@kbn/ui-theme';
import React from 'react';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import type { DescriptionList } from '../../../../../common/utility_types';
import { useDarkMode } from '../../../../common/lib/kibana';
import type {
FlowTargetSourceDest,
NetworkDetailsStrategyResponse,
@ -79,7 +79,7 @@ export const IpOverview = React.memo<IpOverviewProps>(
}) => {
const capabilities = useMlCapabilities();
const userPermissions = hasMlUserPermissions(capabilities);
const darkMode = useDarkMode();
const darkMode = useKibanaIsDarkMode();
const typeData = data[flowTarget];
const column: DescriptionList[] = [
{

View file

@ -6,12 +6,12 @@
*/
import React, { type PropsWithChildren } from 'react';
import { EuiText, useEuiTheme, COLOR_MODES_STANDARD, type EuiTextProps } from '@elastic/eui';
import { EuiText, type EuiTextProps } from '@elastic/eui';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
export type CardSubduedTextProps = PropsWithChildren<EuiTextProps>;
export const CardSubduedText = React.memo<CardSubduedTextProps>(({ children, ...props }) => {
const { colorMode } = useEuiTheme();
const isDarkMode = colorMode === COLOR_MODES_STANDARD.dark;
const isDarkMode = useKibanaIsDarkMode();
return (
<EuiText {...props} color={isDarkMode ? 'text' : 'subdued'}>
{children}

View file

@ -5,15 +5,16 @@
* 2.0.
*/
import { COLOR_MODES_STANDARD, useEuiTheme } from '@elastic/eui';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import { useEuiTheme } from '@elastic/eui';
import { css } from '@emotion/css';
export const HEIGHT_ANIMATION_DURATION = 250;
export const useCardPanelStyles = () => {
const { euiTheme, colorMode } = useEuiTheme();
const { euiTheme } = useEuiTheme();
const isDarkMode = useKibanaIsDarkMode();
const successBackgroundColor = euiTheme.colors.backgroundBaseSuccess;
const isDarkMode = colorMode === COLOR_MODES_STANDARD.dark;
const darkModeStyles = useDarkPanelStyles(isDarkMode);
return css`

View file

@ -13,9 +13,9 @@ import type { OnboardingCardId } from '../../constants';
import { TestProviders } from '../../../common/mock/test_providers';
const mockUseDarkMode = jest.fn(() => false);
jest.mock('@kbn/kibana-react-plugin/public', () => ({
...jest.requireActual('@kbn/kibana-react-plugin/public'),
useDarkMode: () => mockUseDarkMode(),
jest.mock('@kbn/react-kibana-context-theme', () => ({
...jest.requireActual('@kbn/react-kibana-context-theme'),
useKibanaIsDarkMode: () => mockUseDarkMode(),
}));
jest.mock('@elastic/eui', () => ({

View file

@ -17,7 +17,7 @@ import {
EuiTitle,
} from '@elastic/eui';
import classnames from 'classnames';
import { useDarkMode } from '@kbn/kibana-react-plugin/public';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import type { OnboardingCardId } from '../../constants';
import type { CheckCompleteResult, CardBadge } from '../../types';
import { CARD_COMPLETE_BADGE, EXPAND_CARD_BUTTON_LABEL } from './translations';
@ -55,7 +55,7 @@ export const OnboardingCardPanel = React.memo<PropsWithChildren<OnboardingCardPa
'onboardingCardPanel-expanded': isExpanded,
'onboardingCardPanel-completed': isComplete,
});
const isDarkMode = useDarkMode();
const isDarkMode = useKibanaIsDarkMode();
const iconType = useMemo(
() => (iconDark && isDarkMode ? iconDark : icon),
[isDarkMode, iconDark, icon]

View file

@ -5,12 +5,14 @@
* 2.0.
*/
import { COLOR_MODES_STANDARD, useEuiTheme } from '@elastic/eui';
import { useEuiTheme } from '@elastic/eui';
import { css } from '@emotion/css';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
export const useCardStyles = () => {
const { euiTheme, colorMode } = useEuiTheme();
const isDarkMode = colorMode === COLOR_MODES_STANDARD.dark;
const { euiTheme } = useEuiTheme();
const isDarkMode = useKibanaIsDarkMode();
return css`
min-width: 315px;

View file

@ -6,16 +6,9 @@
*/
import React, { useMemo } from 'react';
import {
COLOR_MODES_STANDARD,
EuiFlexGroup,
EuiFlexItem,
EuiImage,
EuiSpacer,
EuiText,
EuiTitle,
useEuiTheme,
} from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, EuiImage, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import { useCurrentUser } from '../../../common/lib/kibana/hooks';
import { OnboardingHeaderTopicSelector } from './onboarding_header_topic_selector';
import { useOnboardingHeaderStyles } from './onboarding_header.styles';
@ -30,8 +23,7 @@ import { useKibana } from '../../../common/lib/kibana';
export const OnboardingHeader = React.memo(() => {
const currentUser = useCurrentUser();
const { colorMode } = useEuiTheme();
const isDarkMode = colorMode === COLOR_MODES_STANDARD.dark;
const isDarkMode = useKibanaIsDarkMode();
const styles = useOnboardingHeaderStyles();

View file

@ -10,6 +10,7 @@ import { euiDarkVars as darkTheme, euiLightVars as lightTheme } from '@kbn/ui-th
import { getOr } from 'lodash/fp';
import React, { useCallback, useMemo } from 'react';
import styled from '@emotion/styled';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import { RiskScoreHeaderTitle } from '../../../entity_analytics/components/risk_score_header_title';
import { useGlobalTime } from '../../../common/containers/use_global_time';
import { useQueryInspector } from '../../../common/components/page/manage_query';
@ -18,7 +19,6 @@ import { useRiskScore } from '../../../entity_analytics/api/hooks/use_risk_score
import { buildHostNamesFilter, type HostItem } from '../../../../common/search_strategy';
import { EntityType } from '../../../../common/entity_analytics/types';
import type { DescriptionList } from '../../../../common/utility_types';
import { useDarkMode } from '../../../common/lib/kibana';
import { getEmptyTagValue } from '../../../common/components/empty_value';
import { hostIdRenderer } from '../../../timelines/components/field_renderers/field_renderers';
import { DefaultFieldRenderer } from '../../../timelines/components/field_renderers/default_renderer';
@ -85,7 +85,7 @@ export const HostOverview = React.memo<HostSummaryProps>(
}) => {
const capabilities = useMlCapabilities();
const userPermissions = hasMlUserPermissions(capabilities);
const darkMode = useDarkMode();
const darkMode = useKibanaIsDarkMode();
const filterQuery = useMemo(
() => (hostName ? buildHostNamesFilter([hostName]) : undefined),
[hostName]

View file

@ -10,6 +10,7 @@ import { euiDarkVars as darkTheme, euiLightVars as lightTheme } from '@kbn/ui-th
import { getOr } from 'lodash/fp';
import React, { useCallback, useMemo } from 'react';
import styled from '@emotion/styled';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import { buildUserNamesFilter } from '../../../../common/search_strategy';
import { RiskScoreHeaderTitle } from '../../../entity_analytics/components/risk_score_header_title';
import { useGlobalTime } from '../../../common/containers/use_global_time';
@ -18,7 +19,6 @@ import { useQueryInspector } from '../../../common/components/page/manage_query'
import { useRiskScore } from '../../../entity_analytics/api/hooks/use_risk_score';
import { EntityType } from '../../../../common/entity_analytics/types';
import type { DescriptionList } from '../../../../common/utility_types';
import { useDarkMode } from '../../../common/lib/kibana';
import { getEmptyTagValue } from '../../../common/components/empty_value';
import { DefaultFieldRenderer } from '../../../timelines/components/field_renderers/default_renderer';
import {
@ -86,7 +86,7 @@ export const UserOverview = React.memo<UserSummaryProps>(
}) => {
const capabilities = useMlCapabilities();
const userPermissions = hasMlUserPermissions(capabilities);
const darkMode = useDarkMode();
const darkMode = useKibanaIsDarkMode();
const filterQuery = useMemo(
() => (userName ? buildUserNamesFilter([userName]) : undefined),
[userName]

View file

@ -8,7 +8,7 @@
import React, { memo } from 'react';
import styled from 'styled-components';
import { i18n } from '@kbn/i18n';
import { useDarkMode } from '@kbn/kibana-react-plugin/public';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import { useSymbolIDs } from './use_symbol_ids';
import { usePaintServerIDs } from './use_paint_server_ids';
@ -435,7 +435,7 @@ const SymbolsAndShapes = memo(({ id, isDarkMode }: { id: string; isDarkMode: boo
*/
// eslint-disable-next-line react/display-name
export const SymbolDefinitions = memo(({ id }: { id: string }) => {
const isDarkMode = useDarkMode();
const isDarkMode = useKibanaIsDarkMode();
return (
<HiddenSVG>
<defs>

View file

@ -5,13 +5,13 @@
* 2.0.
*/
import React from 'react';
import { useDarkMode } from '@kbn/kibana-react-plugin/public';
import { EuiIcon, type EuiIconProps } from '@elastic/eui';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import SiemMigrationsIconSVG from './siem_migrations.svg';
import SiemMigrationsIconDarkSVG from './siem_migrations_dark.svg';
export const SiemMigrationsIcon = React.memo<Omit<EuiIconProps, 'type'>>((props) => {
const isDark = useDarkMode();
const isDark = useKibanaIsDarkMode();
if (isDark) {
return <EuiIcon type={SiemMigrationsIconDarkSVG} {...props} />;
}

View file

@ -22,9 +22,9 @@ import {
EuiBadge,
type EuiBasicTableColumn,
useEuiTheme,
COLOR_MODES_STANDARD,
} from '@elastic/eui';
import { Chart, BarSeries, Settings, ScaleType } from '@elastic/charts';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import { SecurityPageName } from '@kbn/security-solution-navigation';
import { AssistantIcon } from '@kbn/ai-assistant-icon';
import { useElasticChartsTheme } from '@kbn/charts-theme';
@ -52,8 +52,8 @@ const headerStyle = css`
`;
const useCompleteBadgeStyles = () => {
const { euiTheme, colorMode } = useEuiTheme();
const isDarkMode = colorMode === COLOR_MODES_STANDARD.dark;
const { euiTheme } = useEuiTheme();
const isDarkMode = useKibanaIsDarkMode();
return css`
background-color: ${isDarkMode
? euiTheme.colors.success

View file

@ -249,5 +249,6 @@
"@kbn/actions-types",
"@kbn/triggers-actions-ui-types",
"@kbn/unified-histogram",
"@kbn/react-kibana-context-theme",
]
}

View file

@ -8,7 +8,7 @@
import { EuiDataGridCellValueElementProps } from '@elastic/eui';
import React, { useContext, useEffect } from 'react';
import { euiDarkVars as themeDark, euiLightVars as themeLight } from '@kbn/ui-theme';
import { useDarkMode } from '@kbn/kibana-react-plugin/public';
import { useKibanaIsDarkMode } from '@kbn/react-kibana-context-theme';
import { useStyles } from './styles';
import { Indicator } from '../../../../../common/types/indicator';
import { IndicatorFieldValue } from '../common/field_value';
@ -25,7 +25,7 @@ export const cellRendererFactory = (from: number) => {
throw new Error('this can only be used inside indicators table');
}
const darkMode = useDarkMode();
const darkMode = useKibanaIsDarkMode();
const { indicators, expanded } = indicatorsTableContext;

View file

@ -35,7 +35,8 @@
"@kbn/core-ui-settings-browser",
"@kbn/search-types",
"@kbn/response-ops-alerts-fields-browser",
"@kbn/charts-theme"
"@kbn/charts-theme",
"@kbn/react-kibana-context-theme"
],
"exclude": ["target/**/*"]
}