mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
wip: dataVis to 1 item. Add ML section to management nav.
This commit is contained in:
parent
f349f61cbc
commit
817063d1aa
15 changed files with 742 additions and 87 deletions
|
@ -34,6 +34,14 @@ const insightsAndAlertingTip = i18n.translate('management.sections.insightsAndAl
|
|||
defaultMessage: 'Manage how to detect changes in your data',
|
||||
});
|
||||
|
||||
const machineLearningTitle = i18n.translate('management.sections.machineLearningTitle', {
|
||||
defaultMessage: 'Machine Learning',
|
||||
});
|
||||
|
||||
const machineLearningTip = i18n.translate('management.sections.machineLearningTip', {
|
||||
defaultMessage: 'Manage the detection of anomalies in your data',
|
||||
});
|
||||
|
||||
const sectionTitle = i18n.translate('management.sections.section.title', {
|
||||
defaultMessage: 'Security',
|
||||
});
|
||||
|
@ -79,6 +87,13 @@ export const InsightsAndAlertingSection = {
|
|||
order: 2,
|
||||
};
|
||||
|
||||
export const MachineLearningSection = {
|
||||
id: ManagementSectionId.MachineLearning,
|
||||
title: machineLearningTitle,
|
||||
tip: machineLearningTip,
|
||||
order: 4,
|
||||
};
|
||||
|
||||
export const SecuritySection = {
|
||||
id: 'security',
|
||||
title: sectionTitle,
|
||||
|
@ -104,6 +119,7 @@ export const managementSections = [
|
|||
IngestSection,
|
||||
DataSection,
|
||||
InsightsAndAlertingSection,
|
||||
MachineLearningSection,
|
||||
SecuritySection,
|
||||
KibanaSection,
|
||||
StackSection,
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
IngestSection,
|
||||
DataSection,
|
||||
InsightsAndAlertingSection,
|
||||
MachineLearningSection,
|
||||
SecuritySection,
|
||||
KibanaSection,
|
||||
StackSection,
|
||||
|
@ -41,6 +42,7 @@ export class ManagementSectionsService {
|
|||
ingest: this.registerSection(IngestSection),
|
||||
data: this.registerSection(DataSection),
|
||||
insightsAndAlerting: this.registerSection(InsightsAndAlertingSection),
|
||||
machineLearning: this.registerSection(MachineLearningSection),
|
||||
security: this.registerSection(SecuritySection),
|
||||
kibana: this.registerSection(KibanaSection),
|
||||
stack: this.registerSection(StackSection),
|
||||
|
|
|
@ -31,6 +31,7 @@ export interface DefinedSections {
|
|||
ingest: ManagementSection;
|
||||
data: ManagementSection;
|
||||
insightsAndAlerting: ManagementSection;
|
||||
machineLearning: ManagementSection;
|
||||
security: ManagementSection;
|
||||
kibana: ManagementSection;
|
||||
stack: ManagementSection;
|
||||
|
@ -65,6 +66,7 @@ export enum ManagementSectionId {
|
|||
Ingest = 'ingest',
|
||||
Data = 'data',
|
||||
InsightsAndAlerting = 'insightsAndAlerting',
|
||||
MachineLearning = 'ml',
|
||||
Security = 'security',
|
||||
Kibana = 'kibana',
|
||||
Stack = 'stack',
|
||||
|
|
|
@ -84,6 +84,15 @@ export function useSideNavItems(activeRoute: MlRoute | undefined) {
|
|||
disabled: disableLinks,
|
||||
testSubj: 'mlMainTab overview',
|
||||
},
|
||||
{
|
||||
id: 'datavisualizer',
|
||||
name: i18n.translate('xpack.ml.navMenu.dataVisualizerTabLinkText', {
|
||||
defaultMessage: 'Data Visualizer',
|
||||
}),
|
||||
disabled: false,
|
||||
pathId: ML_PAGES.DATA_VISUALIZER,
|
||||
testSubj: 'mlMainTab dataVisualizer',
|
||||
},
|
||||
{
|
||||
id: 'notifications',
|
||||
pathId: ML_PAGES.NOTIFICATIONS,
|
||||
|
@ -220,54 +229,6 @@ export function useSideNavItems(activeRoute: MlRoute | undefined) {
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'datavisualizer',
|
||||
name: i18n.translate('xpack.ml.navMenu.dataVisualizerTabLinkText', {
|
||||
defaultMessage: 'Data Visualizer',
|
||||
}),
|
||||
disabled: false,
|
||||
pathId: ML_PAGES.DATA_VISUALIZER,
|
||||
testSubj: 'mlMainTab dataVisualizer',
|
||||
items: [
|
||||
{
|
||||
id: 'filedatavisualizer',
|
||||
pathId: ML_PAGES.DATA_VISUALIZER_FILE,
|
||||
name: i18n.translate('xpack.ml.navMenu.fileDataVisualizerLinkText', {
|
||||
defaultMessage: 'File',
|
||||
}),
|
||||
disabled: false,
|
||||
testSubj: 'mlMainTab fileDataVisualizer',
|
||||
},
|
||||
{
|
||||
id: 'data_view_datavisualizer',
|
||||
pathId: ML_PAGES.DATA_VISUALIZER_INDEX_SELECT,
|
||||
name: i18n.translate('xpack.ml.navMenu.dataViewDataVisualizerLinkText', {
|
||||
defaultMessage: 'Data View',
|
||||
}),
|
||||
disabled: false,
|
||||
testSubj: 'mlMainTab indexDataVisualizer',
|
||||
},
|
||||
{
|
||||
id: 'esql_datavisualizer',
|
||||
pathId: ML_PAGES.DATA_VISUALIZER_ESQL,
|
||||
name: i18n.translate('xpack.ml.navMenu.esqlDataVisualizerLinkText', {
|
||||
defaultMessage: 'ES|QL',
|
||||
}),
|
||||
disabled: false,
|
||||
testSubj: 'mlMainTab esqlDataVisualizer',
|
||||
},
|
||||
|
||||
{
|
||||
id: 'data_drift',
|
||||
pathId: ML_PAGES.DATA_DRIFT_INDEX_SELECT,
|
||||
name: i18n.translate('xpack.ml.navMenu.dataComparisonText', {
|
||||
defaultMessage: 'Data Drift',
|
||||
}),
|
||||
disabled: disableLinks,
|
||||
testSubj: 'mlMainTab dataDrift',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
mlTabs.push({
|
||||
|
|
|
@ -95,7 +95,7 @@ export const DatavisualizerSelector: FC = () => {
|
|||
<EuiText color="subdued">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.selector.dataVisualizerDescription"
|
||||
defaultMessage="The Machine Learning Data Visualizer tool helps you understand your data,
|
||||
defaultMessage="The Machine Learning Data Visualizer tool helps you understand your data
|
||||
by analyzing the metrics and fields in a log file or an existing Elasticsearch index."
|
||||
/>
|
||||
</EuiText>
|
||||
|
@ -211,6 +211,52 @@ export const DatavisualizerSelector: FC = () => {
|
|||
/>
|
||||
</EuiFlexItem>
|
||||
) : null}
|
||||
<EuiFlexItem>
|
||||
<EuiCard
|
||||
hasBorder
|
||||
icon={<EuiIcon size="xxl" type="visTagCloud" />}
|
||||
title={
|
||||
<>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.selector.selectDataDriftTitle"
|
||||
defaultMessage="Visualize data using data drift"
|
||||
/>{' '}
|
||||
<EuiBetaBadge
|
||||
label=""
|
||||
iconType="beaker"
|
||||
size="m"
|
||||
color="hollow"
|
||||
tooltipContent={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.selector.dataDriftTechnicalPreviewBadge.titleMsg"
|
||||
defaultMessage="Data drift visualizer is in technical preview."
|
||||
/>
|
||||
}
|
||||
tooltipPosition={'right'}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
description={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.selector.dataDriftDescription"
|
||||
defaultMessage="Visualize changes in the model input data."
|
||||
/>
|
||||
}
|
||||
footer={
|
||||
<EuiButton
|
||||
target="_self"
|
||||
onClick={() => navigateToPath('/data_drift_index_select')}
|
||||
data-test-subj="mlDataVisualizerSelectDataDriftButton"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.selector.selectDataViewButtonLabel"
|
||||
defaultMessage="Select data view"
|
||||
/>
|
||||
</EuiButton>
|
||||
}
|
||||
data-test-subj="mlDataVisualizerCardDataDriftData"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGrid>
|
||||
{startTrialVisible === true && (
|
||||
<Fragment>
|
||||
|
|
|
@ -15,10 +15,10 @@ import { JobsListView } from './components/jobs_list_view';
|
|||
import { ML_PAGES } from '../../../../common/constants/locator';
|
||||
import { HelpMenu } from '../../components/help_menu';
|
||||
import { useMlKibana } from '../../contexts/kibana';
|
||||
import { MlPageHeader } from '../../components/page_header';
|
||||
import { HeaderMenuPortal } from '../../components/header_menu_portal';
|
||||
import { JobsActionMenu } from '../components/jobs_action_menu';
|
||||
import { useEnabledFeatures } from '../../contexts/ml';
|
||||
import { getMlNodeCount } from '../../ml_nodes_check/check_ml_nodes';
|
||||
|
||||
interface PageUrlState {
|
||||
pageKey: typeof ML_PAGES.ANOMALY_DETECTION_JOBS_MANAGE;
|
||||
|
@ -43,17 +43,18 @@ export const JobsPage: FC<JobsPageProps> = ({ isMlEnabledInSpace, lastRefresh })
|
|||
getDefaultAnomalyDetectionJobsListState()
|
||||
);
|
||||
const {
|
||||
services: { docLinks },
|
||||
services: {
|
||||
docLinks,
|
||||
mlServices: { mlApi },
|
||||
},
|
||||
} = useMlKibana();
|
||||
const { euiTheme } = useEuiTheme();
|
||||
getMlNodeCount(mlApi);
|
||||
|
||||
const { showNodeInfo } = useEnabledFeatures();
|
||||
const helpLink = docLinks.links.ml.anomalyDetection;
|
||||
return (
|
||||
<>
|
||||
<MlPageHeader>
|
||||
<FormattedMessage id="xpack.ml.jobsList.title" defaultMessage="Anomaly Detection Jobs" />
|
||||
</MlPageHeader>
|
||||
<HeaderMenuPortal>
|
||||
<JobsActionMenu />
|
||||
</HeaderMenuPortal>
|
||||
|
|
|
@ -14,34 +14,64 @@ import type { ManagementAppMountParams } from '@kbn/management-plugin/public';
|
|||
import type { MlFeatures } from '../../../common/constants/app';
|
||||
import type { MlStartDependencies } from '../../plugin';
|
||||
|
||||
export function registerManagementSection(
|
||||
export function registerManagementSections(
|
||||
management: ManagementSetup,
|
||||
core: CoreSetup<MlStartDependencies>,
|
||||
deps: { usageCollection?: UsageCollectionSetup },
|
||||
isServerless: boolean,
|
||||
mlFeatures: MlFeatures
|
||||
) {
|
||||
const appName = i18n.translate('xpack.ml.management.jobsListTitle', {
|
||||
defaultMessage: 'Machine Learning',
|
||||
const overviewTitle = i18n.translate('xpack.ml.management.overviewTitle', {
|
||||
defaultMessage: 'Overview',
|
||||
});
|
||||
const anomalyDetectionJobsTitle = i18n.translate(
|
||||
'xpack.ml.management.anomalyDetectionJobsTitle',
|
||||
{
|
||||
defaultMessage: 'Anomaly Detection Jobs',
|
||||
}
|
||||
);
|
||||
|
||||
return management.sections.section.insightsAndAlerting.registerApp({
|
||||
id: 'jobsListLink',
|
||||
title: appName,
|
||||
order: 4,
|
||||
async mount(params: ManagementAppMountParams) {
|
||||
const [{ chrome }] = await core.getStartServices();
|
||||
const { docTitle } = chrome;
|
||||
management.sections.section.machineLearning
|
||||
.registerApp({
|
||||
id: 'jobsListLink', // TODO: will need to update this
|
||||
title: overviewTitle,
|
||||
order: 1,
|
||||
async mount(params: ManagementAppMountParams) {
|
||||
const [{ chrome }] = await core.getStartServices();
|
||||
const { docTitle } = chrome;
|
||||
|
||||
docTitle.change(appName);
|
||||
docTitle.change(overviewTitle);
|
||||
|
||||
const { mountApp } = await import('./jobs_list');
|
||||
const unmountAppCallback = await mountApp(core, params, deps, isServerless, mlFeatures);
|
||||
const { mountApp } = await import('./overview');
|
||||
const unmountAppCallback = await mountApp(core, params, deps, isServerless, mlFeatures);
|
||||
|
||||
return () => {
|
||||
docTitle.reset();
|
||||
unmountAppCallback();
|
||||
};
|
||||
},
|
||||
});
|
||||
return () => {
|
||||
docTitle.reset();
|
||||
unmountAppCallback();
|
||||
};
|
||||
},
|
||||
})
|
||||
.enable();
|
||||
|
||||
management.sections.section.machineLearning
|
||||
.registerApp({
|
||||
id: 'anomalyDetectionJobsLink',
|
||||
title: anomalyDetectionJobsTitle,
|
||||
order: 2,
|
||||
async mount(params: ManagementAppMountParams) {
|
||||
const [{ chrome }] = await core.getStartServices();
|
||||
const { docTitle } = chrome;
|
||||
|
||||
docTitle.change(overviewTitle);
|
||||
|
||||
const { mountApp } = await import('./anomaly_detection_jobs');
|
||||
const unmountAppCallback = await mountApp(core, params, deps, isServerless, mlFeatures);
|
||||
|
||||
return () => {
|
||||
docTitle.reset();
|
||||
unmountAppCallback();
|
||||
};
|
||||
},
|
||||
})
|
||||
.enable();
|
||||
}
|
||||
|
|
|
@ -27,8 +27,6 @@ import { UpgradeWarning } from '../components/upgrade';
|
|||
import { HelpMenu } from '../components/help_menu';
|
||||
import { useMlKibana, useMlLink } from '../contexts/kibana';
|
||||
import { NodesList } from '../memory_usage/nodes_overview';
|
||||
import { MlPageHeader } from '../components/page_header';
|
||||
import { PageTitle } from '../components/page_title';
|
||||
import { getMlNodesCount } from '../ml_nodes_check/check_ml_nodes';
|
||||
|
||||
export const overviewPanelDefaultState = Object.freeze({
|
||||
|
@ -62,13 +60,6 @@ export const OverviewPage: FC = () => {
|
|||
|
||||
return (
|
||||
<div>
|
||||
<MlPageHeader>
|
||||
<PageTitle
|
||||
title={i18n.translate('xpack.ml.overview.overviewLabel', {
|
||||
defaultMessage: 'Overview',
|
||||
})}
|
||||
/>
|
||||
</MlPageHeader>
|
||||
<NodeAvailableWarning />
|
||||
<JobsAwaitingNodeWarning jobCount={adLazyJobCount + dfaLazyJobCount} />
|
||||
<SavedObjectsWarning
|
||||
|
@ -82,7 +73,6 @@ export const OverviewPage: FC = () => {
|
|||
}}
|
||||
/>
|
||||
<UpgradeWarning />
|
||||
|
||||
{canViewMlNodes ? (
|
||||
<>
|
||||
<CollapsiblePanel
|
||||
|
@ -121,7 +111,6 @@ export const OverviewPage: FC = () => {
|
|||
<EuiSpacer size="m" />
|
||||
</>
|
||||
) : null}
|
||||
|
||||
<OverviewContent
|
||||
createAnomalyDetectionJobDisabled={disableCreateAnomalyDetectionJob}
|
||||
setAdLazyJobCount={setAdLazyJobCount}
|
||||
|
|
|
@ -54,7 +54,7 @@ import type { FieldFormatsRegistry } from '@kbn/field-formats-plugin/common';
|
|||
import { ENABLE_ESQL } from '@kbn/esql-utils';
|
||||
import type { MlSharedServices } from './application/services/get_shared_ml_services';
|
||||
import { getMlSharedServices } from './application/services/get_shared_ml_services';
|
||||
import { registerManagementSection } from './application/management';
|
||||
import { registerManagementSections } from './application/management';
|
||||
import type { MlLocatorParams } from './locator';
|
||||
import { MlLocatorDefinition, type MlLocator } from './locator';
|
||||
import { registerHomeFeature } from './register_home_feature';
|
||||
|
@ -227,7 +227,7 @@ export class MlPlugin implements Plugin<MlPluginSetup, MlPluginStart> {
|
|||
}
|
||||
|
||||
if (pluginsSetup.management) {
|
||||
registerManagementSection(
|
||||
registerManagementSections(
|
||||
pluginsSetup.management,
|
||||
core,
|
||||
{
|
||||
|
@ -235,7 +235,7 @@ export class MlPlugin implements Plugin<MlPluginSetup, MlPluginStart> {
|
|||
},
|
||||
this.isServerless,
|
||||
this.enabledFeatures
|
||||
).enable();
|
||||
);
|
||||
}
|
||||
|
||||
const licensing = pluginsSetup.licensing.license$.pipe(take(1));
|
||||
|
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* 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 { FC } from 'react';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { Router } from '@kbn/shared-ux-router';
|
||||
import { FormattedMessage, I18nProvider } from '@kbn/i18n-react';
|
||||
import type { CoreStart } from '@kbn/core/public';
|
||||
import { pick } from 'lodash';
|
||||
|
||||
import { EuiPageTemplate, EuiSpacer } from '@elastic/eui';
|
||||
|
||||
import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public';
|
||||
import { DatePickerContextProvider, type DatePickerDependencies } from '@kbn/ml-date-picker';
|
||||
import { UI_SETTINGS } from '@kbn/data-plugin/common';
|
||||
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import type { ManagementAppMountParams } from '@kbn/management-plugin/public';
|
||||
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 type { SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import type { SpacesContextProps, SpacesPluginStart } from '@kbn/spaces-plugin/public';
|
||||
import type { ChartsPluginStart } from '@kbn/charts-plugin/public';
|
||||
import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public';
|
||||
import { UpgradeWarning } from '../../../components/upgrade/upgrade_warning';
|
||||
import { getMlGlobalServices } from '../../../util/get_services';
|
||||
import { EnabledFeaturesContextProvider } from '../../../contexts/ml';
|
||||
import { type MlFeatures, PLUGIN_ID } from '../../../../../common/constants/app';
|
||||
|
||||
import { checkGetManagementMlJobsResolver } from '../../../capabilities/check_capabilities';
|
||||
|
||||
import { AccessDeniedPage } from '../../jobs_list/components/access_denied_page';
|
||||
import { InsufficientLicensePage } from '../../jobs_list/components/insufficient_license_page';
|
||||
// import { DocsLink } from '../../jobs_list/components/jobs_list_page/docs_link';
|
||||
import { JobsPage } from '../../../jobs/jobs_list';
|
||||
|
||||
const getEmptyFunctionComponent: React.FC<SpacesContextProps> = ({ children }) => <>{children}</>;
|
||||
|
||||
interface Props {
|
||||
coreStart: CoreStart;
|
||||
share: SharePluginStart;
|
||||
history: ManagementAppMountParams['history'];
|
||||
spacesApi?: SpacesPluginStart;
|
||||
data: DataPublicPluginStart;
|
||||
charts: ChartsPluginStart;
|
||||
usageCollection?: UsageCollectionSetup;
|
||||
fieldFormats: FieldFormatsStart;
|
||||
isServerless: boolean;
|
||||
mlFeatures: MlFeatures;
|
||||
}
|
||||
|
||||
export const AnomalyDetectionJobsPage: FC<Props> = ({
|
||||
coreStart,
|
||||
share,
|
||||
history,
|
||||
spacesApi,
|
||||
data,
|
||||
charts,
|
||||
usageCollection,
|
||||
fieldFormats,
|
||||
isServerless,
|
||||
mlFeatures,
|
||||
}) => {
|
||||
const [initialized, setInitialized] = useState(false);
|
||||
const [accessDenied, setAccessDenied] = useState(false);
|
||||
const [isUpgradeInProgress, setIsUpgradeInProgress] = useState(false);
|
||||
const [isPlatinumOrTrialLicense, setIsPlatinumOrTrialLicense] = useState(true);
|
||||
|
||||
const mlServices = useMemo(
|
||||
() => getMlGlobalServices(coreStart, data.dataViews, usageCollection),
|
||||
[coreStart, data.dataViews, usageCollection]
|
||||
);
|
||||
|
||||
const datePickerDeps: DatePickerDependencies = {
|
||||
...pick(coreStart, ['http', 'notifications', 'theme', 'uiSettings', 'i18n']),
|
||||
data,
|
||||
uiSettingsKeys: UI_SETTINGS,
|
||||
showFrozenDataTierChoice: false,
|
||||
};
|
||||
|
||||
const check = async () => {
|
||||
try {
|
||||
await checkGetManagementMlJobsResolver(mlServices);
|
||||
} catch (e) {
|
||||
if (e.mlFeatureEnabledInSpace && e.isPlatinumOrTrialLicense === false) {
|
||||
setIsPlatinumOrTrialLicense(false);
|
||||
} else if (e.isUpgradeInProgress) {
|
||||
setIsUpgradeInProgress(true);
|
||||
} else {
|
||||
setAccessDenied(true);
|
||||
}
|
||||
}
|
||||
setInitialized(true);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
check();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const ContextWrapper = useCallback(
|
||||
spacesApi ? spacesApi.ui.components.getSpacesContextProvider : getEmptyFunctionComponent,
|
||||
[spacesApi]
|
||||
);
|
||||
|
||||
if (initialized === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isUpgradeInProgress) {
|
||||
return (
|
||||
<I18nProvider>
|
||||
<KibanaRenderContextProvider {...coreStart}>
|
||||
<KibanaContextProvider
|
||||
services={{
|
||||
...coreStart,
|
||||
share,
|
||||
data,
|
||||
usageCollection,
|
||||
fieldFormats,
|
||||
spacesApi,
|
||||
mlServices,
|
||||
}}
|
||||
>
|
||||
<UpgradeWarning />
|
||||
</KibanaContextProvider>
|
||||
</KibanaRenderContextProvider>
|
||||
</I18nProvider>
|
||||
);
|
||||
}
|
||||
|
||||
if (accessDenied) {
|
||||
return (
|
||||
<I18nProvider>
|
||||
<KibanaRenderContextProvider {...coreStart}>
|
||||
<AccessDeniedPage />
|
||||
</KibanaRenderContextProvider>
|
||||
</I18nProvider>
|
||||
);
|
||||
}
|
||||
|
||||
if (isPlatinumOrTrialLicense === false) {
|
||||
return (
|
||||
<I18nProvider>
|
||||
<KibanaRenderContextProvider {...coreStart}>
|
||||
<InsufficientLicensePage basePath={coreStart.http.basePath} />
|
||||
</KibanaRenderContextProvider>
|
||||
</I18nProvider>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<I18nProvider>
|
||||
<KibanaRenderContextProvider {...coreStart}>
|
||||
<RedirectAppLinks
|
||||
coreStart={{
|
||||
application: coreStart.application,
|
||||
}}
|
||||
>
|
||||
<KibanaContextProvider
|
||||
services={{
|
||||
...coreStart,
|
||||
share,
|
||||
data,
|
||||
charts,
|
||||
usageCollection,
|
||||
fieldFormats,
|
||||
spacesApi,
|
||||
mlServices,
|
||||
}}
|
||||
>
|
||||
<DatePickerContextProvider {...datePickerDeps}>
|
||||
<ContextWrapper feature={PLUGIN_ID}>
|
||||
<EnabledFeaturesContextProvider isServerless={isServerless} mlFeatures={mlFeatures}>
|
||||
<Router history={history}>
|
||||
<EuiPageTemplate.Header
|
||||
pageTitle={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.management.overview.anomalyDetectionJobsPageTitle"
|
||||
defaultMessage="Anomaly Detection Jobs"
|
||||
/>
|
||||
}
|
||||
description={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.management.jobsList.jobsListTagline"
|
||||
defaultMessage="Identify, analyze, and process your data using advanced analysis techniques."
|
||||
/>
|
||||
}
|
||||
// rightSideItems={[<DocsLink currentTabId={currentTabId} />]}
|
||||
bottomBorder
|
||||
paddingSize={'none'}
|
||||
/>
|
||||
|
||||
<EuiSpacer size="l" />
|
||||
|
||||
<EuiPageTemplate.Section
|
||||
paddingSize={'none'}
|
||||
id="kibanaManagementMLSection"
|
||||
data-test-subj="mlPageStackManagementJobsList"
|
||||
>
|
||||
<JobsPage />
|
||||
</EuiPageTemplate.Section>
|
||||
</Router>
|
||||
</EnabledFeaturesContextProvider>
|
||||
</ContextWrapper>
|
||||
</DatePickerContextProvider>
|
||||
</KibanaContextProvider>
|
||||
</RedirectAppLinks>
|
||||
</KibanaRenderContextProvider>
|
||||
</I18nProvider>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
export { AnomalyDetectionJobsPage } from './anomaly_detection_jobs';
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* 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 ReactDOM, { unmountComponentAtNode } from 'react-dom';
|
||||
import React from 'react';
|
||||
import type { CoreSetup, CoreStart } from '@kbn/core/public';
|
||||
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public';
|
||||
import type { ManagementAppMountParams } from '@kbn/management-plugin/public';
|
||||
import type { SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import type { SpacesPluginStart } from '@kbn/spaces-plugin/public';
|
||||
import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public';
|
||||
import type { ChartsPluginStart } from '@kbn/charts-plugin/public';
|
||||
import type { MlFeatures } from '../../../../common/constants/app';
|
||||
import type { MlStartDependencies } from '../../../plugin';
|
||||
import { AnomalyDetectionJobsPage } from './components';
|
||||
import { getJobsListBreadcrumbs } from '../breadcrumbs';
|
||||
|
||||
const renderApp = (
|
||||
element: HTMLElement,
|
||||
history: ManagementAppMountParams['history'],
|
||||
coreStart: CoreStart,
|
||||
share: SharePluginStart,
|
||||
data: DataPublicPluginStart,
|
||||
fieldFormats: FieldFormatsStart,
|
||||
charts: ChartsPluginStart,
|
||||
isServerless: boolean,
|
||||
mlFeatures: MlFeatures,
|
||||
spacesApi?: SpacesPluginStart,
|
||||
usageCollection?: UsageCollectionSetup
|
||||
) => {
|
||||
ReactDOM.render(
|
||||
React.createElement(AnomalyDetectionJobsPage, {
|
||||
coreStart,
|
||||
history,
|
||||
share,
|
||||
data,
|
||||
charts,
|
||||
spacesApi,
|
||||
usageCollection,
|
||||
fieldFormats,
|
||||
isServerless,
|
||||
mlFeatures,
|
||||
}),
|
||||
element
|
||||
);
|
||||
return () => {
|
||||
unmountComponentAtNode(element);
|
||||
};
|
||||
};
|
||||
|
||||
export async function mountApp(
|
||||
core: CoreSetup<MlStartDependencies>,
|
||||
params: ManagementAppMountParams,
|
||||
deps: { usageCollection?: UsageCollectionSetup },
|
||||
isServerless: boolean,
|
||||
mlFeatures: MlFeatures
|
||||
) {
|
||||
const [coreStart, pluginsStart] = await core.getStartServices();
|
||||
|
||||
params.setBreadcrumbs(getJobsListBreadcrumbs()); // TODO: update this
|
||||
return renderApp(
|
||||
params.element,
|
||||
params.history,
|
||||
coreStart,
|
||||
pluginsStart.share,
|
||||
pluginsStart.data,
|
||||
pluginsStart.fieldFormats,
|
||||
pluginsStart.charts,
|
||||
isServerless,
|
||||
mlFeatures,
|
||||
pluginsStart.spaces,
|
||||
deps.usageCollection
|
||||
);
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
export { OverviewPage } from './overview_page';
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* 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 { FC } from 'react';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { Router } from '@kbn/shared-ux-router';
|
||||
import { FormattedMessage, I18nProvider } from '@kbn/i18n-react';
|
||||
import type { CoreStart } from '@kbn/core/public';
|
||||
import { pick } from 'lodash';
|
||||
|
||||
import { EuiPageTemplate, EuiSpacer } from '@elastic/eui';
|
||||
|
||||
import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public';
|
||||
import { DatePickerContextProvider, type DatePickerDependencies } from '@kbn/ml-date-picker';
|
||||
import { UI_SETTINGS } from '@kbn/data-plugin/common';
|
||||
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import type { ManagementAppMountParams } from '@kbn/management-plugin/public';
|
||||
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 type { SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import type { SpacesContextProps, SpacesPluginStart } from '@kbn/spaces-plugin/public';
|
||||
import type { ChartsPluginStart } from '@kbn/charts-plugin/public';
|
||||
import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public';
|
||||
import { UpgradeWarning } from '../../../components/upgrade/upgrade_warning';
|
||||
import { getMlGlobalServices } from '../../../util/get_services';
|
||||
import { EnabledFeaturesContextProvider } from '../../../contexts/ml';
|
||||
import { type MlFeatures, PLUGIN_ID } from '../../../../../common/constants/app';
|
||||
|
||||
import { checkGetManagementMlJobsResolver } from '../../../capabilities/check_capabilities';
|
||||
|
||||
import { AccessDeniedPage } from '../../jobs_list/components/access_denied_page';
|
||||
import { InsufficientLicensePage } from '../../jobs_list/components/insufficient_license_page';
|
||||
// import { DocsLink } from '../../jobs_list/components/jobs_list_page/docs_link';
|
||||
import { OverviewPage as OverviewPageContent } from '../../../overview/overview_page';
|
||||
|
||||
const getEmptyFunctionComponent: React.FC<SpacesContextProps> = ({ children }) => <>{children}</>;
|
||||
|
||||
interface Props {
|
||||
coreStart: CoreStart;
|
||||
share: SharePluginStart;
|
||||
history: ManagementAppMountParams['history'];
|
||||
spacesApi?: SpacesPluginStart;
|
||||
data: DataPublicPluginStart;
|
||||
charts: ChartsPluginStart;
|
||||
usageCollection?: UsageCollectionSetup;
|
||||
fieldFormats: FieldFormatsStart;
|
||||
isServerless: boolean;
|
||||
mlFeatures: MlFeatures;
|
||||
}
|
||||
|
||||
export const OverviewPage: FC<Props> = ({
|
||||
coreStart,
|
||||
share,
|
||||
history,
|
||||
spacesApi,
|
||||
data,
|
||||
charts,
|
||||
usageCollection,
|
||||
fieldFormats,
|
||||
isServerless,
|
||||
mlFeatures,
|
||||
}) => {
|
||||
const [initialized, setInitialized] = useState(false);
|
||||
const [accessDenied, setAccessDenied] = useState(false);
|
||||
const [isUpgradeInProgress, setIsUpgradeInProgress] = useState(false);
|
||||
const [isPlatinumOrTrialLicense, setIsPlatinumOrTrialLicense] = useState(true);
|
||||
|
||||
const mlServices = useMemo(
|
||||
() => getMlGlobalServices(coreStart, data.dataViews, usageCollection),
|
||||
[coreStart, data.dataViews, usageCollection]
|
||||
);
|
||||
|
||||
const datePickerDeps: DatePickerDependencies = {
|
||||
...pick(coreStart, ['http', 'notifications', 'theme', 'uiSettings', 'i18n']),
|
||||
data,
|
||||
uiSettingsKeys: UI_SETTINGS,
|
||||
showFrozenDataTierChoice: false,
|
||||
};
|
||||
|
||||
const check = async () => {
|
||||
try {
|
||||
await checkGetManagementMlJobsResolver(mlServices);
|
||||
} catch (e) {
|
||||
if (e.mlFeatureEnabledInSpace && e.isPlatinumOrTrialLicense === false) {
|
||||
setIsPlatinumOrTrialLicense(false);
|
||||
} else if (e.isUpgradeInProgress) {
|
||||
setIsUpgradeInProgress(true);
|
||||
} else {
|
||||
setAccessDenied(true);
|
||||
}
|
||||
}
|
||||
setInitialized(true);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
check();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const ContextWrapper = useCallback(
|
||||
spacesApi ? spacesApi.ui.components.getSpacesContextProvider : getEmptyFunctionComponent,
|
||||
[spacesApi]
|
||||
);
|
||||
|
||||
if (initialized === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isUpgradeInProgress) {
|
||||
return (
|
||||
<I18nProvider>
|
||||
<KibanaRenderContextProvider {...coreStart}>
|
||||
<KibanaContextProvider
|
||||
services={{
|
||||
...coreStart,
|
||||
share,
|
||||
data,
|
||||
usageCollection,
|
||||
fieldFormats,
|
||||
spacesApi,
|
||||
mlServices,
|
||||
}}
|
||||
>
|
||||
<UpgradeWarning />
|
||||
</KibanaContextProvider>
|
||||
</KibanaRenderContextProvider>
|
||||
</I18nProvider>
|
||||
);
|
||||
}
|
||||
|
||||
if (accessDenied) {
|
||||
return (
|
||||
<I18nProvider>
|
||||
<KibanaRenderContextProvider {...coreStart}>
|
||||
<AccessDeniedPage />
|
||||
</KibanaRenderContextProvider>
|
||||
</I18nProvider>
|
||||
);
|
||||
}
|
||||
|
||||
if (isPlatinumOrTrialLicense === false) {
|
||||
return (
|
||||
<I18nProvider>
|
||||
<KibanaRenderContextProvider {...coreStart}>
|
||||
<InsufficientLicensePage basePath={coreStart.http.basePath} />
|
||||
</KibanaRenderContextProvider>
|
||||
</I18nProvider>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<I18nProvider>
|
||||
<KibanaRenderContextProvider {...coreStart}>
|
||||
<RedirectAppLinks
|
||||
coreStart={{
|
||||
application: coreStart.application,
|
||||
}}
|
||||
>
|
||||
<KibanaContextProvider
|
||||
services={{
|
||||
...coreStart,
|
||||
share,
|
||||
data,
|
||||
charts,
|
||||
usageCollection,
|
||||
fieldFormats,
|
||||
spacesApi,
|
||||
mlServices,
|
||||
}}
|
||||
>
|
||||
<DatePickerContextProvider {...datePickerDeps}>
|
||||
<ContextWrapper feature={PLUGIN_ID}>
|
||||
<EnabledFeaturesContextProvider isServerless={isServerless} mlFeatures={mlFeatures}>
|
||||
<Router history={history}>
|
||||
<EuiPageTemplate.Header
|
||||
pageTitle={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.management.overview.overviewPageTitle"
|
||||
defaultMessage="Overview"
|
||||
/>
|
||||
}
|
||||
description={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.management.jobsList.jobsListTagline"
|
||||
defaultMessage="Identify, analyze, and process your data using advanced analysis techniques."
|
||||
/>
|
||||
}
|
||||
// rightSideItems={[<DocsLink currentTabId={currentTabId} />]}
|
||||
bottomBorder
|
||||
paddingSize={'none'}
|
||||
/>
|
||||
|
||||
<EuiSpacer size="l" />
|
||||
|
||||
<EuiPageTemplate.Section
|
||||
paddingSize={'none'}
|
||||
id="kibanaManagementMLSection"
|
||||
data-test-subj="mlPageStackManagementJobsList"
|
||||
>
|
||||
<OverviewPageContent />
|
||||
</EuiPageTemplate.Section>
|
||||
</Router>
|
||||
</EnabledFeaturesContextProvider>
|
||||
</ContextWrapper>
|
||||
</DatePickerContextProvider>
|
||||
</KibanaContextProvider>
|
||||
</RedirectAppLinks>
|
||||
</KibanaRenderContextProvider>
|
||||
</I18nProvider>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* 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 ReactDOM, { unmountComponentAtNode } from 'react-dom';
|
||||
import React from 'react';
|
||||
import type { CoreSetup, CoreStart } from '@kbn/core/public';
|
||||
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public';
|
||||
import type { ManagementAppMountParams } from '@kbn/management-plugin/public';
|
||||
import type { SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import type { SpacesPluginStart } from '@kbn/spaces-plugin/public';
|
||||
import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public';
|
||||
import type { ChartsPluginStart } from '@kbn/charts-plugin/public';
|
||||
import type { MlFeatures } from '../../../../common/constants/app';
|
||||
import type { MlStartDependencies } from '../../../plugin';
|
||||
import { OverviewPage } from './components';
|
||||
import { getJobsListBreadcrumbs } from '../breadcrumbs';
|
||||
|
||||
const renderApp = (
|
||||
element: HTMLElement,
|
||||
history: ManagementAppMountParams['history'],
|
||||
coreStart: CoreStart,
|
||||
share: SharePluginStart,
|
||||
data: DataPublicPluginStart,
|
||||
fieldFormats: FieldFormatsStart,
|
||||
charts: ChartsPluginStart,
|
||||
isServerless: boolean,
|
||||
mlFeatures: MlFeatures,
|
||||
spacesApi?: SpacesPluginStart,
|
||||
usageCollection?: UsageCollectionSetup
|
||||
) => {
|
||||
ReactDOM.render(
|
||||
React.createElement(OverviewPage, {
|
||||
coreStart,
|
||||
history,
|
||||
share,
|
||||
data,
|
||||
charts,
|
||||
spacesApi,
|
||||
usageCollection,
|
||||
fieldFormats,
|
||||
isServerless,
|
||||
mlFeatures,
|
||||
}),
|
||||
element
|
||||
);
|
||||
return () => {
|
||||
unmountComponentAtNode(element);
|
||||
};
|
||||
};
|
||||
|
||||
export async function mountApp(
|
||||
core: CoreSetup<MlStartDependencies>,
|
||||
params: ManagementAppMountParams,
|
||||
deps: { usageCollection?: UsageCollectionSetup },
|
||||
isServerless: boolean,
|
||||
mlFeatures: MlFeatures
|
||||
) {
|
||||
const [coreStart, pluginsStart] = await core.getStartServices();
|
||||
|
||||
params.setBreadcrumbs(getJobsListBreadcrumbs()); // TODO: update this
|
||||
return renderApp(
|
||||
params.element,
|
||||
params.history,
|
||||
coreStart,
|
||||
pluginsStart.share,
|
||||
pluginsStart.data,
|
||||
pluginsStart.fieldFormats,
|
||||
pluginsStart.charts,
|
||||
isServerless,
|
||||
mlFeatures,
|
||||
pluginsStart.spaces,
|
||||
deps.usageCollection
|
||||
);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue