[ML] Fixes dark mode in flyouts and modals (#164399)

A recent EUI change has caused a problem with the theme when using the
deprecated `toMountPoint` inside `overlays.openFlyout` to create
flyouts.
This causes the contents of the rendered flyout to not know the current
theme, this is obvious when running in dark mode.

The fix is to switch to the non-deprecated version of `toMountPoint`.

Flyouts:
Create anomaly detection job from Lens flyout in Dashboard.
Anomaly swim lane and anomaly chart job embeddables job selection flyout
in Dashboard.
Log pattern analysis flyout in Discover.

Modals:
Trained models start deployment modal.
Trained models force stop deployment modal.
Trained models stop deployment modal when there are multiple
deployments.

Misc:
Page not found banner.
Jobs list header, which contains the settings button.
DFA clone job warning toast when the original data view no longer
exists.
Components in ml's date picker package

Fixes https://github.com/elastic/kibana/issues/164379

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Dima Arnautov <arnautov.dima@gmail.com>
This commit is contained in:
James Gowdy 2023-08-23 11:47:18 +01:00 committed by GitHub
parent 5eca8618ea
commit af440aae4b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 247 additions and 304 deletions

View file

@ -77,8 +77,7 @@ const mockContextFactory = (addWarning: jest.Mock<void, []>) => {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { of } = require('rxjs');
const mockedUiSettingsKeys = {} as typeof UI_SETTINGS;
const mockedToMountPoint = jest.fn();
const mockedWrapWithTheme = jest.fn();
const mockedI18n = jest.fn();
return () => ({
notifications: {
@ -121,8 +120,7 @@ const mockContextFactory = (addWarning: jest.Mock<void, []>) => {
theme$: of(),
},
uiSettingsKeys: mockedUiSettingsKeys,
toMountPoint: mockedToMountPoint,
wrapWithTheme: mockedWrapWithTheme,
i18n: mockedI18n,
});
};

View file

@ -25,6 +25,7 @@ import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import type { TimeHistoryContract } from '@kbn/data-plugin/public';
import { useUrlState } from '@kbn/ml-url-state';
import { toMountPoint } from '@kbn/react-kibana-mount';
import { useRefreshIntervalUpdates, useTimeRangeUpdates } from '../hooks/use_timefilter';
import { useDatePickerContext } from '../hooks/use_date_picker_context';
@ -103,11 +104,10 @@ export const DatePickerWrapper: FC<DatePickerWrapperProps> = (props) => {
const {
data,
notifications: { toasts },
theme: { theme$ },
uiSettings: config,
uiSettingsKeys,
wrapWithTheme,
toMountPoint,
theme,
i18n: i18nStart,
} = useDatePickerContext();
const isWithinLBreakpoint = useIsWithinMaxBreakpoint('l');
@ -184,23 +184,21 @@ export const DatePickerWrapper: FC<DatePickerWrapperProps> = (props) => {
'The refresh interval in Advanced Settings is shorter than the minimum supported interval.',
}),
text: toMountPoint(
wrapWithTheme(
<EuiButton
onClick={setRefreshInterval.bind(null, {
pause: refreshInterval.pause,
value: DEFAULT_REFRESH_INTERVAL_MS,
})}
>
<FormattedMessage
id="xpack.ml.datePicker.pageRefreshResetButton"
defaultMessage="Set to {defaultInterval}"
values={{
defaultInterval: `${DEFAULT_REFRESH_INTERVAL_MS / 1000}s`,
}}
/>
</EuiButton>,
theme$
)
<EuiButton
onClick={setRefreshInterval.bind(null, {
pause: refreshInterval.pause,
value: DEFAULT_REFRESH_INTERVAL_MS,
})}
>
<FormattedMessage
id="xpack.ml.datePicker.pageRefreshResetButton"
defaultMessage="Set to {defaultInterval}"
values={{
defaultInterval: `${DEFAULT_REFRESH_INTERVAL_MS / 1000}s`,
}}
/>
</EuiButton>,
{ theme, i18n: i18nStart }
),
},
{ toastLifeTimeMs: 30000 }

View file

@ -9,9 +9,8 @@ import React, { createContext, useContext, type FC } from 'react';
import type { UI_SETTINGS } from '@kbn/data-plugin/common';
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
import type { CoreSetup, IUiSettingsClient, ThemeServiceStart } from '@kbn/core/public';
import type { CoreSetup, I18nStart, IUiSettingsClient, ThemeServiceStart } from '@kbn/core/public';
import type { HttpStart } from '@kbn/core/public';
import type { toMountPoint, wrapWithTheme } from '@kbn/kibana-react-plugin/public';
/**
* Date Picker Dependencies to be passed on via `DatePickerContextProvider`.
@ -42,13 +41,9 @@ export interface DatePickerDependencies {
*/
uiSettingsKeys: typeof UI_SETTINGS;
/**
* helper to be used with notifications.
* Internationalisation service
*/
wrapWithTheme: typeof wrapWithTheme;
/**
* helper to be used with notifications.
*/
toMountPoint: typeof toMountPoint;
i18n: I18nStart;
}
/**

View file

@ -25,7 +25,7 @@
"@kbn/core",
"@kbn/data-views-plugin",
"@kbn/ml-is-populated-object",
"@kbn/kibana-react-plugin",
"@kbn/ml-query-utils",
"@kbn/react-kibana-mount",
]
}

View file

@ -18,7 +18,6 @@ import { UrlStateProvider } from '@kbn/ml-url-state';
import { Storage } from '@kbn/kibana-utils-plugin/public';
import { DatePickerContextProvider, mlTimefilterRefresh$ } from '@kbn/ml-date-picker';
import { UI_SETTINGS } from '@kbn/data-plugin/common';
import { toMountPoint, wrapWithTheme } from '@kbn/kibana-react-plugin/public';
import { type Observable } from 'rxjs';
import { DataSourceContext } from '../../hooks/use_data_source';
@ -55,9 +54,7 @@ export const ChangePointDetectionAppState: FC<ChangePointDetectionAppStateProps>
appDependencies,
}) => {
const datePickerDeps = {
...pick(appDependencies, ['data', 'http', 'notifications', 'theme', 'uiSettings']),
toMountPoint,
wrapWithTheme,
...pick(appDependencies, ['data', 'http', 'notifications', 'theme', 'uiSettings', 'i18n']),
uiSettingsKeys: UI_SETTINGS,
};

View file

@ -14,7 +14,6 @@ import { UrlStateProvider } from '@kbn/ml-url-state';
import { Storage } from '@kbn/kibana-utils-plugin/public';
import { DatePickerContextProvider } from '@kbn/ml-date-picker';
import { UI_SETTINGS } from '@kbn/data-plugin/common';
import { toMountPoint, wrapWithTheme } from '@kbn/kibana-react-plugin/public';
import { DataSourceContext } from '../../hooks/use_data_source';
import type { AiopsAppDependencies } from '../../hooks/use_aiops_app_context';
@ -52,9 +51,7 @@ export const LogCategorizationAppState: FC<LogCategorizationAppStateProps> = ({
}
const datePickerDeps = {
...pick(appDependencies, ['data', 'http', 'notifications', 'theme', 'uiSettings']),
toMountPoint,
wrapWithTheme,
...pick(appDependencies, ['data', 'http', 'notifications', 'theme', 'uiSettings', 'i18n']),
uiSettingsKeys: UI_SETTINGS,
};

View file

@ -12,14 +12,11 @@ import { pick } from 'lodash';
import type { CoreStart } from '@kbn/core/public';
import { Storage } from '@kbn/kibana-utils-plugin/public';
import {
toMountPoint,
wrapWithTheme,
KibanaContextProvider,
} from '@kbn/kibana-react-plugin/public';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { toMountPoint } from '@kbn/react-kibana-mount';
import type { DataViewField, DataView } from '@kbn/data-views-plugin/common';
import { UI_SETTINGS } from '@kbn/data-plugin/public';
import { DatePickerContextProvider } from '@kbn/ml-date-picker';
import { DatePickerContextProvider, type DatePickerDependencies } from '@kbn/ml-date-picker';
import { StorageContextProvider } from '@kbn/ml-local-storage';
import type { AiopsPluginStartDeps } from '../../types';
import { AiopsAppContext } from '../../hooks/use_aiops_app_context';
@ -34,7 +31,7 @@ export async function showCategorizeFlyout(
coreStart: CoreStart,
plugins: AiopsPluginStartDeps
): Promise<void> {
const { http, theme, overlays, application, notifications, uiSettings } = coreStart;
const { http, theme, overlays, application, notifications, uiSettings, i18n } = coreStart;
return new Promise(async (resolve, reject) => {
try {
@ -49,38 +46,36 @@ export async function showCategorizeFlyout(
http,
theme,
application,
i18n,
...plugins,
};
const datePickerDeps = {
const datePickerDeps: DatePickerDependencies = {
...pick(appDependencies, ['data', 'http', 'notifications', 'theme', 'uiSettings']),
toMountPoint,
wrapWithTheme,
i18n,
uiSettingsKeys: UI_SETTINGS,
};
const flyoutSession = overlays.openFlyout(
toMountPoint(
wrapWithTheme(
<KibanaContextProvider
services={{
...coreStart,
}}
>
<AiopsAppContext.Provider value={appDependencies}>
<DatePickerContextProvider {...datePickerDeps}>
<StorageContextProvider storage={localStorage} storageKeys={AIOPS_STORAGE_KEYS}>
<LogCategorizationFlyout
dataView={dataView}
savedSearch={null}
selectedField={field}
onClose={onFlyoutClose}
/>
</StorageContextProvider>
</DatePickerContextProvider>
</AiopsAppContext.Provider>
</KibanaContextProvider>,
theme.theme$
)
<KibanaContextProvider
services={{
...coreStart,
}}
>
<AiopsAppContext.Provider value={appDependencies}>
<DatePickerContextProvider {...datePickerDeps}>
<StorageContextProvider storage={localStorage} storageKeys={AIOPS_STORAGE_KEYS}>
<LogCategorizationFlyout
dataView={dataView}
savedSearch={null}
selectedField={field}
onClose={onFlyoutClose}
/>
</StorageContextProvider>
</DatePickerContextProvider>
</AiopsAppContext.Provider>
</KibanaContextProvider>,
{ theme, i18n }
),
{
'data-test-subj': 'aiopsCategorizeFlyout',

View file

@ -15,7 +15,6 @@ import { UrlStateProvider } from '@kbn/ml-url-state';
import { Storage } from '@kbn/kibana-utils-plugin/public';
import { DatePickerContextProvider } from '@kbn/ml-date-picker';
import { UI_SETTINGS } from '@kbn/data-plugin/common';
import { toMountPoint, wrapWithTheme } from '@kbn/kibana-react-plugin/public';
import type { AiopsAppDependencies } from '../../hooks/use_aiops_app_context';
import { AiopsAppContext } from '../../hooks/use_aiops_app_context';
@ -58,9 +57,7 @@ export const LogRateAnalysisAppState: FC<LogRateAnalysisAppStateProps> = ({
}
const datePickerDeps = {
...pick(appDependencies, ['data', 'http', 'notifications', 'theme', 'uiSettings']),
toMountPoint,
wrapWithTheme,
...pick(appDependencies, ['data', 'http', 'notifications', 'theme', 'uiSettings', 'i18n']),
uiSettingsKeys: UI_SETTINGS,
};

View file

@ -18,7 +18,6 @@ import { UrlStateProvider } from '@kbn/ml-url-state';
import { Storage } from '@kbn/kibana-utils-plugin/public';
import { DatePickerContextProvider } from '@kbn/ml-date-picker';
import { UI_SETTINGS } from '@kbn/data-plugin/common';
import { toMountPoint, wrapWithTheme } from '@kbn/kibana-react-plugin/public';
import { timeSeriesDataViewWarning } from '../../../application/utils/time_series_dataview_check';
import { AiopsAppContext, type AiopsAppDependencies } from '../../../hooks/use_aiops_app_context';
@ -81,9 +80,7 @@ export const LogRateAnalysisContentWrapper: FC<LogRateAnalysisContentWrapperProp
}
const datePickerDeps = {
...pick(appDependencies, ['data', 'http', 'notifications', 'theme', 'uiSettings']),
toMountPoint,
wrapWithTheme,
...pick(appDependencies, ['data', 'http', 'notifications', 'theme', 'uiSettings', 'i18n']),
uiSettingsKeys: UI_SETTINGS,
};

View file

@ -13,7 +13,7 @@ import {
EmbeddableOutput,
IContainer,
} from '@kbn/embeddable-plugin/public';
import { KibanaThemeProvider, toMountPoint, wrapWithTheme } from '@kbn/kibana-react-plugin/public';
import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public';
import { ThemeServiceStart } from '@kbn/core-theme-browser';
import { DataPublicPluginStart, UI_SETTINGS } from '@kbn/data-plugin/public';
import { type CoreStart, IUiSettingsClient } from '@kbn/core/public';
@ -95,9 +95,7 @@ export class EmbeddableChangePointChart extends AbstractEmbeddable<
const I18nContext = this.deps.i18n.Context;
const datePickerDeps = {
...pick(this.deps, ['data', 'http', 'notifications', 'theme', 'uiSettings']),
toMountPoint,
wrapWithTheme,
...pick(this.deps, ['data', 'http', 'notifications', 'theme', 'uiSettings', 'i18n']),
uiSettingsKeys: UI_SETTINGS,
};

View file

@ -92,6 +92,10 @@ export interface AiopsAppDependencies {
* Used to create lens embeddables.
*/
lens: LensPublicStart;
/**
* Internationalisation service
*/
i18n: CoreStart['i18n'];
/**
* Deps for unified fields stats.
*/

View file

@ -15,12 +15,7 @@ import { UrlStateProvider } from '@kbn/ml-url-state';
import { Storage } from '@kbn/kibana-utils-plugin/public';
import { DatePickerContextProvider } from '@kbn/ml-date-picker';
import { UI_SETTINGS } from '@kbn/data-plugin/common';
import {
KibanaContextProvider,
KibanaThemeProvider,
toMountPoint,
wrapWithTheme,
} from '@kbn/kibana-react-plugin/public';
import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public';
import { DV_STORAGE_KEYS } from '../index_data_visualizer/types/storage';
import { getCoreStart, getPluginsStart } from '../../kibana_services';
@ -77,9 +72,7 @@ export const DataComparisonDetectionAppState: FC<DataComparisonDetectionAppState
...coreStart,
};
const datePickerDeps = {
...pick(services, ['data', 'http', 'notifications', 'theme', 'uiSettings']),
toMountPoint,
wrapWithTheme,
...pick(services, ['data', 'http', 'notifications', 'theme', 'uiSettings', 'i18n']),
uiSettingsKeys: UI_SETTINGS,
};

View file

@ -22,7 +22,6 @@ import {
IContainer,
} from '@kbn/embeddable-plugin/public';
import { UI_SETTINGS } from '@kbn/data-plugin/common';
import { toMountPoint, wrapWithTheme } from '@kbn/kibana-react-plugin/public';
import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public';
import type { Query } from '@kbn/es-query';
import { DataView, DataViewField } from '@kbn/data-views-plugin/public';
@ -221,9 +220,7 @@ export class DataVisualizerGridEmbeddable extends Embeddable<
const services = { ...this.services[0], ...this.services[1] };
const datePickerDeps = {
...pick(services, ['data', 'http', 'notifications', 'theme', 'uiSettings']),
toMountPoint,
wrapWithTheme,
...pick(services, ['data', 'http', 'notifications', 'theme', 'uiSettings', 'i18n']),
uiSettingsKeys: UI_SETTINGS,
};

View file

@ -13,12 +13,7 @@ import { isEqual } from 'lodash';
import { encode } from '@kbn/rison';
import { i18n } from '@kbn/i18n';
import { Storage } from '@kbn/kibana-utils-plugin/public';
import {
KibanaContextProvider,
KibanaThemeProvider,
toMountPoint,
wrapWithTheme,
} from '@kbn/kibana-react-plugin/public';
import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public';
import { StorageContextProvider } from '@kbn/ml-local-storage';
import { DataView } from '@kbn/data-views-plugin/public';
import { getNestedProperty } from '@kbn/ml-nested-property';
@ -302,9 +297,7 @@ export const IndexDataVisualizer: FC<{
...coreStart,
};
const datePickerDeps = {
...pick(services, ['data', 'http', 'notifications', 'theme', 'uiSettings']),
toMountPoint,
wrapWithTheme,
...pick(services, ['data', 'http', 'notifications', 'theme', 'uiSettings', 'i18n']),
uiSettingsKeys: UI_SETTINGS,
};

View file

@ -6,7 +6,6 @@
*/
import React, { FC, useEffect, useMemo, useState } from 'react';
import { pick, orderBy } from 'lodash';
import moment from 'moment';
import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiTitle } from '@elastic/eui';
@ -29,6 +28,7 @@ import {
import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types';
import { i18n } from '@kbn/i18n';
import { ALERT_END } from '@kbn/rule-data-utils';
import { pick, orderBy } from 'lodash';
import { Color, colorTransformer } from '../../../../../../common/color_palette';
import { useKibanaContextForPlugin } from '../../../../../hooks/use_kibana';
import {
@ -289,6 +289,7 @@ export const LogRateAnalysis: FC<AlertDetailsLogRateAnalysisSectionProps> = ({ r
'unifiedSearch',
'theme',
'lens',
'i18n',
])}
/>
</EuiFlexItem>

View file

@ -63,6 +63,7 @@ export const ChangePointDetectionPage: FC = () => {
'presentationUtil',
'embeddable',
'cases',
'i18n',
]),
fieldStats: { useFieldStatsTrigger, FieldStatsFlyoutProvider },
}}

View file

@ -54,6 +54,7 @@ export const LogCategorizationPage: FC = () => {
'unifiedSearch',
'theme',
'lens',
'i18n',
])}
/>
)}

View file

@ -57,6 +57,7 @@ export const LogRateAnalysisPage: FC = () => {
'unifiedSearch',
'theme',
'lens',
'i18n',
])}
/>
)}

View file

@ -15,12 +15,7 @@ import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public';
import { DatePickerContextProvider } from '@kbn/ml-date-picker';
import { Storage } from '@kbn/kibana-utils-plugin/public';
import { UI_SETTINGS } from '@kbn/data-plugin/common';
import {
KibanaContextProvider,
KibanaThemeProvider,
toMountPoint,
wrapWithTheme,
} from '@kbn/kibana-react-plugin/public';
import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public';
import { StorageContextProvider } from '@kbn/ml-local-storage';
import useLifecycles from 'react-use/lib/useLifecycles';
import useObservable from 'react-use/lib/useObservable';
@ -128,9 +123,7 @@ const App: FC<AppProps> = ({ coreStart, deps, appMountParams }) => {
if (!licenseReady || !mlCapabilities) return null;
const datePickerDeps = {
...pick(services, ['data', 'http', 'notifications', 'theme', 'uiSettings']),
toMountPoint,
wrapWithTheme,
...pick(services, ['data', 'http', 'notifications', 'theme', 'uiSettings', 'i18n']),
uiSettingsKeys: UI_SETTINGS,
};

View file

@ -7,7 +7,8 @@
import React, { FC, ReactNode, useContext, useEffect, useMemo } from 'react';
import { createHtmlPortalNode, InPortal, OutPortal } from 'react-reverse-portal';
import { KibanaContextProvider, toMountPoint } from '@kbn/kibana-react-plugin/public';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { toMountPoint } from '@kbn/react-kibana-mount';
import { useMlKibana } from '../../contexts/kibana';
import { MlPageControlsContext } from '../ml_page';
@ -17,6 +18,7 @@ export interface HeaderMenuPortalProps {
export const HeaderMenuPortal: FC<HeaderMenuPortalProps> = ({ children }) => {
const { services } = useMlKibana();
const { theme, i18n } = services;
const { setHeaderActionMenu } = useContext(MlPageControlsContext);
@ -32,7 +34,7 @@ export const HeaderMenuPortal: FC<HeaderMenuPortalProps> = ({ children }) => {
<KibanaContextProvider services={services}>
<OutPortal node={portalNode} />
</KibanaContextProvider>,
{ theme$: services.theme.theme$ }
{ theme, i18n }
);
return mount(element);
});

View file

@ -10,7 +10,6 @@ import React, { FC } from 'react';
import { cloneDeep, isEqual } from 'lodash';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { toMountPoint, wrapWithTheme } from '@kbn/kibana-react-plugin/public';
import { extractErrorMessage } from '@kbn/ml-error-utils';
import {
isClassificationAnalysis,
@ -19,6 +18,7 @@ import {
DEFAULT_RESULTS_FIELD,
type DataFrameAnalyticsConfig,
} from '@kbn/ml-data-frame-analytics-utils';
import { toMountPoint } from '@kbn/react-kibana-mount';
import { DeepReadonly } from '../../../../../../../common/types/common';
import { useMlKibana, useNavigateToPath } from '../../../../../contexts/kibana';
import { DEFAULT_NUM_TOP_FEATURE_IMPORTANCE_VALUES } from '../../hooks/use_create_analytics_form';
@ -414,9 +414,9 @@ export const useNavigateToWizardWithClonedJob = () => {
http: { basePath },
application: { capabilities },
theme,
i18n: i18nStart,
},
} = useMlKibana();
const theme$ = theme.theme$;
const navigateToPath = useNavigateToPath();
const canCreateDataView =
capabilities.savedObjectsManagement.edit === true || capabilities.indexPatterns.save === true;
@ -434,38 +434,36 @@ export const useNavigateToWizardWithClonedJob = () => {
} else {
toasts.addDanger({
title: toMountPoint(
wrapWithTheme(
<>
<FormattedMessage
id="xpack.ml.dataframe.analyticsList.noSourceDataViewForClone"
defaultMessage="Unable to clone the analytics job. No data view exists for index {sourceIndex}."
values={{ sourceIndex }}
/>
{canCreateDataView ? (
<EuiText size="xs" color="text">
<FormattedMessage
id="xpack.ml.dataframe.analytics.cloneAction.dataViewPromptLink"
defaultMessage="{linkToDataViewManagement}"
values={{
linkToDataViewManagement: (
<EuiLink
href={`${basePath.get()}/app/management/kibana/dataViews/create`}
target="_blank"
>
<FormattedMessage
id="xpack.ml.dataframe.analytics.cloneAction.dataViewPromptLinkText"
defaultMessage="Create a data view for {sourceIndex}"
values={{ sourceIndex }}
/>
</EuiLink>
),
}}
/>
</EuiText>
) : null}
</>,
theme$
)
<>
<FormattedMessage
id="xpack.ml.dataframe.analyticsList.noSourceDataViewForClone"
defaultMessage="Unable to clone the analytics job. No data view exists for index {sourceIndex}."
values={{ sourceIndex }}
/>
{canCreateDataView ? (
<EuiText size="xs" color="text">
<FormattedMessage
id="xpack.ml.dataframe.analytics.cloneAction.dataViewPromptLink"
defaultMessage="{linkToDataViewManagement}"
values={{
linkToDataViewManagement: (
<EuiLink
href={`${basePath.get()}/app/management/kibana/dataViews/create`}
target="_blank"
>
<FormattedMessage
id="xpack.ml.dataframe.analytics.cloneAction.dataViewPromptLinkText"
defaultMessage="Create a data view for {sourceIndex}"
values={{ sourceIndex }}
/>
</EuiLink>
),
}}
/>
</EuiText>
) : null}
</>,
{ theme, i18n: i18nStart }
),
});
}

View file

@ -27,11 +27,10 @@ import {
EuiSelect,
EuiSpacer,
} from '@elastic/eui';
import { toMountPoint, wrapWithTheme } from '@kbn/kibana-react-plugin/public';
import type { Observable } from 'rxjs';
import type { CoreTheme, OverlayStart } from '@kbn/core/public';
import type { I18nStart, OverlayStart, ThemeServiceStart } from '@kbn/core/public';
import { css } from '@emotion/react';
import { numberValidator } from '@kbn/ml-agg-utils';
import { toMountPoint } from '@kbn/react-kibana-mount';
import { isCloudTrial } from '../services/ml_server_info';
import {
composeValidators,
@ -497,7 +496,12 @@ export const StartUpdateDeploymentModal: FC<StartDeploymentModalProps> = ({
* @param theme$
*/
export const getUserInputModelDeploymentParamsProvider =
(overlays: OverlayStart, theme$: Observable<CoreTheme>, startModelDeploymentDocUrl: string) =>
(
overlays: OverlayStart,
theme: ThemeServiceStart,
i18nStart: I18nStart,
startModelDeploymentDocUrl: string
) =>
(
model: ModelItem,
initialParams?: ThreadingParams,
@ -507,30 +511,28 @@ export const getUserInputModelDeploymentParamsProvider =
try {
const modalSession = overlays.openModal(
toMountPoint(
wrapWithTheme(
<StartUpdateDeploymentModal
startModelDeploymentDocUrl={startModelDeploymentDocUrl}
initialParams={initialParams}
modelAndDeploymentIds={deploymentIds}
model={model}
onConfigChange={(config) => {
modalSession.close();
<StartUpdateDeploymentModal
startModelDeploymentDocUrl={startModelDeploymentDocUrl}
initialParams={initialParams}
modelAndDeploymentIds={deploymentIds}
model={model}
onConfigChange={(config) => {
modalSession.close();
const resultConfig = { ...config };
if (resultConfig.priority === 'low') {
resultConfig.numOfAllocations = 1;
resultConfig.threadsPerAllocations = 1;
}
const resultConfig = { ...config };
if (resultConfig.priority === 'low') {
resultConfig.numOfAllocations = 1;
resultConfig.threadsPerAllocations = 1;
}
resolve(resultConfig);
}}
onClose={() => {
modalSession.close();
resolve();
}}
/>,
theme$
)
resolve(resultConfig);
}}
onClose={() => {
modalSession.close();
resolve();
}}
/>,
{ theme, i18n: i18nStart }
)
);
} catch (e) {

View file

@ -15,10 +15,10 @@ import {
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';
import type { OverlayStart, ThemeServiceStart } from '@kbn/core/public';
import { toMountPoint, wrapWithTheme } from '@kbn/kibana-react-plugin/public';
import type { I18nStart, OverlayStart, ThemeServiceStart } from '@kbn/core/public';
import { isPopulatedObject } from '@kbn/ml-is-populated-object';
import { isDefined } from '@kbn/ml-is-defined';
import { toMountPoint } from '@kbn/react-kibana-mount';
import type { ModelItem } from './models_list';
interface ForceStopModelConfirmDialogProps {
@ -165,26 +165,24 @@ export const StopModelDeploymentsConfirmDialog: FC<ForceStopModelConfirmDialogPr
};
export const getUserConfirmationProvider =
(overlays: OverlayStart, theme: ThemeServiceStart) =>
(overlays: OverlayStart, theme: ThemeServiceStart, i18nStart: I18nStart) =>
async (forceStopModel: ModelItem): Promise<string[]> => {
return new Promise(async (resolve, reject) => {
try {
const modalSession = overlays.openModal(
toMountPoint(
wrapWithTheme(
<StopModelDeploymentsConfirmDialog
model={forceStopModel}
onCancel={() => {
modalSession.close();
reject();
}}
onConfirm={(deploymentIds: string[]) => {
modalSession.close();
resolve(deploymentIds);
}}
/>,
theme.theme$
)
<StopModelDeploymentsConfirmDialog
model={forceStopModel}
onCancel={() => {
modalSession.close();
reject();
}}
onConfirm={(deploymentIds: string[]) => {
modalSession.close();
resolve(deploymentIds);
}}
/>,
{ theme, i18n: i18nStart }
)
);
} catch (e) {

View file

@ -54,6 +54,7 @@ export function useModelActions({
application: { navigateToUrl, capabilities },
overlays,
theme,
i18n: i18nStart,
docLinks,
mlServices: { mlApiServices },
},
@ -93,14 +94,19 @@ export function useModelActions({
}, [mlApiServices]);
const getUserConfirmation = useMemo(
() => getUserConfirmationProvider(overlays, theme),
[overlays, theme]
() => getUserConfirmationProvider(overlays, theme, i18nStart),
[i18nStart, overlays, theme]
);
const getUserInputModelDeploymentParams = useMemo(
() =>
getUserInputModelDeploymentParamsProvider(overlays, theme.theme$, startModelDeploymentDocUrl),
[overlays, theme.theme$, startModelDeploymentDocUrl]
getUserInputModelDeploymentParamsProvider(
overlays,
theme,
i18nStart,
startModelDeploymentDocUrl
),
[overlays, theme, i18nStart, startModelDeploymentDocUrl]
);
const isBuiltInModel = useCallback(

View file

@ -8,9 +8,10 @@
import { useLocation, useRouteMatch } from 'react-router-dom';
import { keyBy } from 'lodash';
import React, { useEffect, useMemo, useRef } from 'react';
import { toMountPoint, useExecutionContext } from '@kbn/kibana-react-plugin/public';
import { useExecutionContext } from '@kbn/kibana-react-plugin/public';
import { EuiCallOut } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { toMountPoint } from '@kbn/react-kibana-mount';
import { PLUGIN_ID } from '../../../common/constants/app';
import { useMlKibana } from '../contexts/kibana';
import type { MlRoute } from './router';
@ -23,7 +24,7 @@ export const useActiveRoute = (routesList: MlRoute[]): MlRoute => {
const { pathname } = useLocation();
const {
services: { executionContext, overlays, theme },
services: { executionContext, overlays, theme, i18n },
} = useMlKibana();
/**
@ -77,7 +78,7 @@ export const useActiveRoute = (routesList: MlRoute[]): MlRoute => {
/>
</p>
</EuiCallOut>,
{ theme$: theme.theme$ }
{ theme, i18n }
)
);
@ -89,7 +90,7 @@ export const useActiveRoute = (routesList: MlRoute[]): MlRoute => {
}, 15000);
}
},
[activeRoute, overlays, theme, pathname]
[activeRoute, overlays, theme, pathname, i18n]
);
useExecutionContext(executionContext, {

View file

@ -7,7 +7,7 @@
import React from 'react';
import type { CoreStart } from '@kbn/core/public';
import { toMountPoint, wrapWithTheme } from '@kbn/kibana-react-plugin/public';
import { toMountPoint } from '@kbn/react-kibana-mount';
import { extractInfluencers } from '../../../common/util/job_utils';
import { VIEW_BY_JOB_LABEL } from '../../application/explorer/explorer_constants';
import { getDefaultExplorerChartsPanelTitle } from './anomaly_charts_embeddable';
@ -21,7 +21,7 @@ export async function resolveEmbeddableAnomalyChartsUserInput(
coreStart: CoreStart,
input?: AnomalyChartsEmbeddableInput
): Promise<Partial<AnomalyChartsEmbeddableInput>> {
const { http, overlays } = coreStart;
const { http, overlays, theme, i18n } = coreStart;
const { getJobs } = mlApiServicesProvider(new HttpService(http));
@ -32,28 +32,25 @@ export async function resolveEmbeddableAnomalyChartsUserInput(
const { jobs } = await getJobs({ jobId: jobIds.join(',') });
const influencers = extractInfluencers(jobs);
influencers.push(VIEW_BY_JOB_LABEL);
const { theme$ } = coreStart.theme;
const modalSession = overlays.openModal(
toMountPoint(
wrapWithTheme(
<AnomalyChartsInitializer
defaultTitle={title}
initialInput={input}
onCreate={({ panelTitle, maxSeriesToPlot }) => {
modalSession.close();
resolve({
jobIds,
title: panelTitle,
maxSeriesToPlot,
});
}}
onCancel={() => {
modalSession.close();
reject();
}}
/>,
theme$
)
<AnomalyChartsInitializer
defaultTitle={title}
initialInput={input}
onCreate={({ panelTitle, maxSeriesToPlot }) => {
modalSession.close();
resolve({
jobIds,
title: panelTitle,
maxSeriesToPlot,
});
}}
onCancel={() => {
modalSession.close();
reject();
}}
/>,
{ theme, i18n }
)
);
} catch (error) {

View file

@ -7,7 +7,7 @@
import React from 'react';
import type { CoreStart } from '@kbn/core/public';
import { toMountPoint, wrapWithTheme } from '@kbn/kibana-react-plugin/public';
import { toMountPoint } from '@kbn/react-kibana-mount';
import { extractInfluencers } from '../../../common/util/job_utils';
import { VIEW_BY_JOB_LABEL } from '../../application/explorer/explorer_constants';
import { AnomalySwimlaneInitializer } from './anomaly_swimlane_initializer';
@ -21,7 +21,7 @@ export async function resolveAnomalySwimlaneUserInput(
coreStart: CoreStart,
input?: AnomalySwimlaneEmbeddableInput
): Promise<Partial<AnomalySwimlaneEmbeddableInput>> {
const { http, overlays } = coreStart;
const { http, overlays, theme, i18n } = coreStart;
const { getJobs } = mlApiServicesProvider(new HttpService(http));
@ -32,29 +32,26 @@ export async function resolveAnomalySwimlaneUserInput(
const { jobs } = await getJobs({ jobId: jobIds.join(',') });
const influencers = extractInfluencers(jobs);
influencers.push(VIEW_BY_JOB_LABEL);
const { theme$ } = coreStart.theme;
const modalSession = overlays.openModal(
toMountPoint(
wrapWithTheme(
<AnomalySwimlaneInitializer
defaultTitle={title}
influencers={influencers}
initialInput={input}
onCreate={(explicitInput) => {
modalSession.close();
resolve({
jobIds,
title: explicitInput.panelTitle,
...explicitInput,
});
}}
onCancel={() => {
modalSession.close();
reject();
}}
/>,
theme$
)
<AnomalySwimlaneInitializer
defaultTitle={title}
influencers={influencers}
initialInput={input}
onCreate={(explicitInput) => {
modalSession.close();
resolve({
jobIds,
title: explicitInput.panelTitle,
...explicitInput,
});
}}
onCancel={() => {
modalSession.close();
reject();
}}
/>,
{ theme, i18n }
)
);
} catch (error) {

View file

@ -9,14 +9,11 @@ import moment from 'moment';
import { takeUntil, distinctUntilChanged, skip } from 'rxjs/operators';
import { from } from 'rxjs';
import React from 'react';
import {
KibanaContextProvider,
toMountPoint,
wrapWithTheme,
} from '@kbn/kibana-react-plugin/public';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { toMountPoint } from '@kbn/react-kibana-mount';
import { getInitialGroupsMap } from '../../application/components/job_selector/job_selector';
import { getMlGlobalServices } from '../../application/app';
import { JobId } from '../../../common/types/anomaly_detection_jobs';
import type { JobId } from '../../../common/types/anomaly_detection_jobs';
import { JobSelectorFlyout } from './components/job_selector_flyout';
/**
@ -35,6 +32,7 @@ export async function resolveJobSelection(
http,
uiSettings,
theme,
i18n,
application: { currentAppId$ },
} = coreStart;
@ -71,23 +69,19 @@ export async function resolveJobSelection(
const flyoutSession = coreStart.overlays.openFlyout(
toMountPoint(
wrapWithTheme(
<KibanaContextProvider
services={{ ...coreStart, mlServices: getMlGlobalServices(http) }}
>
<JobSelectorFlyout
selectedIds={selectedJobIds}
withTimeRangeSelector={false}
dateFormatTz={dateFormatTz}
singleSelection={false}
timeseriesOnly={true}
onFlyoutClose={onFlyoutClose}
onSelectionConfirmed={onSelectionConfirmed}
maps={maps}
/>
</KibanaContextProvider>,
theme.theme$
)
<KibanaContextProvider services={{ ...coreStart, mlServices: getMlGlobalServices(http) }}>
<JobSelectorFlyout
selectedIds={selectedJobIds}
withTimeRangeSelector={false}
dateFormatTz={dateFormatTz}
singleSelection={false}
timeseriesOnly={true}
onFlyoutClose={onFlyoutClose}
onSelectionConfirmed={onSelectionConfirmed}
maps={maps}
/>
</KibanaContextProvider>,
{ theme, i18n }
),
{
'data-test-subj': 'mlFlyoutJobSelector',

View file

@ -8,11 +8,8 @@
import React from 'react';
import { takeUntil, distinctUntilChanged, skip } from 'rxjs/operators';
import { from } from 'rxjs';
import {
toMountPoint,
wrapWithTheme,
KibanaContextProvider,
} from '@kbn/kibana-react-plugin/public';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { toMountPoint } from '@kbn/react-kibana-mount';
import type { SharePluginStart } from '@kbn/share-plugin/public';
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
import type { CoreStart } from '@kbn/core/public';
@ -34,7 +31,8 @@ export function createFlyout(
): Promise<void> {
const {
http,
theme: { theme$ },
theme,
i18n,
overlays,
application: { currentAppId$ },
} = coreStart;
@ -48,27 +46,25 @@ export function createFlyout(
const flyoutSession = overlays.openFlyout(
toMountPoint(
wrapWithTheme(
<KibanaContextProvider
services={{
...coreStart,
share,
data,
lens,
dashboardService,
mlServices: getMlGlobalServices(http),
<KibanaContextProvider
services={{
...coreStart,
share,
data,
lens,
dashboardService,
mlServices: getMlGlobalServices(http),
}}
>
<FlyoutComponent
embeddable={embeddable}
onClose={() => {
onFlyoutClose();
resolve();
}}
>
<FlyoutComponent
embeddable={embeddable}
onClose={() => {
onFlyoutClose();
resolve();
}}
/>
</KibanaContextProvider>,
theme$
)
/>
</KibanaContextProvider>,
{ theme, i18n }
),
{
'data-test-subj': 'mlFlyoutLayerSelector',

View file

@ -18,7 +18,6 @@ import {
EuiTitle,
EuiSpacer,
EuiText,
useEuiTheme,
} from '@elastic/eui';
import { Layer } from './layer';
@ -32,7 +31,6 @@ interface Props {
}
export const LensLayerSelectionFlyout: FC<Props> = ({ onClose, embeddable }) => {
const { euiTheme } = useEuiTheme();
const {
services: { data, lens },
} = useMlFromLensKibanaContext();
@ -72,7 +70,7 @@ export const LensLayerSelectionFlyout: FC<Props> = ({ onClose, embeddable }) =>
/>
</EuiText>
</EuiFlyoutHeader>
<EuiFlyoutBody css={{ backgroundColor: euiTheme.colors.lightestShade }}>
<EuiFlyoutBody>
{layerResults.map((layer, i) => (
<Layer layer={layer} layerIndex={i} key={layer.id} embeddable={embeddable} />
))}

View file

@ -103,5 +103,6 @@
"@kbn/content-management-plugin",
"@kbn/ml-in-memory-table",
"@kbn/presentation-util-plugin",
"@kbn/react-kibana-mount",
],
}

View file

@ -17,7 +17,6 @@ import { Storage } from '@kbn/kibana-utils-plugin/public';
import { StorageContextProvider } from '@kbn/ml-local-storage';
import { UrlStateProvider } from '@kbn/ml-url-state';
import { UI_SETTINGS } from '@kbn/data-plugin/common';
import { toMountPoint, wrapWithTheme } from '@kbn/kibana-react-plugin/public';
import type { FieldStatsServices } from '@kbn/unified-field-list/src/components/field_stats';
import type { RuntimeMappings } from '@kbn/ml-runtime-field-utils';
@ -228,9 +227,7 @@ export const Wizard: FC<WizardProps> = React.memo(({ cloneConfig, searchItems })
const stepsConfig = [stepDefine, stepDetails, stepCreate];
const datePickerDeps = {
...pick(appDependencies, ['data', 'http', 'notifications', 'theme', 'uiSettings']),
toMountPoint,
wrapWithTheme,
...pick(appDependencies, ['data', 'http', 'notifications', 'theme', 'uiSettings', 'i18n']),
uiSettingsKeys: UI_SETTINGS,
};