mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[ML] Replacing angular routing (#51842)
* [ML] Replacing angular routing * removing old files * changing overview * renaming overview route * adding df analytics routes * adding timeseriesexplorer route * removing old files * adding route for explorer * adding access denied page * adding module view or create redirect * fixing job cloning * adding breadcrumb system * removing old breadcrumbs files * fix include * enabling management section * injecting app dependencies * fixing missed dependencies * fixing saved searches * fixing type errors * removing included data start * code clean up * updating translations * fixing router test failures * fixing functional tests * removing last use of SavedSearch * removing comment * fixing bug in line chart query * improving saved search jobs * fixing data viz functional test * adding comment * dealing with time range error * removing unnecessary chrome imports * cleaning up code * moving resolver to own file * changes based on review * fixing index data viz on basic license * fixing edit calendar * adding create job breadcrumb * fixing results appstate * fixing management links * updating new job constants file * fixing rebase conflicts * removing commented out code * adding additional text to the resolver error
This commit is contained in:
parent
16447626c9
commit
4f2a6f8362
179 changed files with 2198 additions and 2437 deletions
7
x-pack/legacy/plugins/ml/common/constants/app.ts
Normal file
7
x-pack/legacy/plugins/ml/common/constants/app.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export const API_BASE_PATH = '/api/transform/';
|
|
@ -9,6 +9,5 @@
|
|||
// indices and aliases exist. Based on that the final setting will be available
|
||||
// as an injectedVar on the client side and can be accessed like:
|
||||
//
|
||||
// import chrome from 'ui/chrome';
|
||||
// const mlAnnotationsEnabled = chrome.getInjected('mlAnnotationsEnabled', false);
|
||||
|
||||
export const FEATURE_ANNOTATIONS_ENABLED = true;
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
// custom edits or fixes for default kibana types which are incomplete
|
||||
|
||||
import { SavedObjectAttributes, SimpleSavedObject } from 'kibana/public';
|
||||
|
||||
export type IndexPatternTitle = string;
|
||||
|
||||
export type callWithRequestType = (action: string, params?: any) => Promise<any>;
|
||||
|
@ -14,3 +16,12 @@ export interface Route {
|
|||
id: string;
|
||||
k7Breadcrumbs: () => any;
|
||||
}
|
||||
|
||||
export type IndexPatternSavedObject = SimpleSavedObject<SavedObjectAttributes>;
|
||||
export type SavedSearchSavedObject = SimpleSavedObject<SavedObjectAttributes>;
|
||||
|
||||
export function isSavedSearchSavedObject(
|
||||
ss: SavedSearchSavedObject | null
|
||||
): ss is SavedSearchSavedObject {
|
||||
return ss !== null;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import numeral from '@elastic/numeral';
|
|||
import { ALLOWED_DATA_UNITS, JOB_ID_MAX_LENGTH } from '../constants/validation';
|
||||
import { parseInterval } from './parse_interval';
|
||||
import { maxLengthValidator } from './validators';
|
||||
import { CREATED_BY_LABEL } from '../../public/application/jobs/new_job/common/job_creator/util/constants';
|
||||
import { CREATED_BY_LABEL } from '../../common/constants/new_job';
|
||||
|
||||
// work out the default frequency based on the bucket_span in seconds
|
||||
export function calculateDatafeedFrequencyDefaultSeconds(bucketSpanSeconds) {
|
||||
|
|
|
@ -41,9 +41,9 @@ export const ml = (kibana: any) => {
|
|||
}),
|
||||
icon: 'plugins/ml/application/ml.svg',
|
||||
euiIconType: 'machineLearningApp',
|
||||
main: 'plugins/ml/application/app',
|
||||
main: 'plugins/ml/legacy',
|
||||
},
|
||||
styleSheetPaths: resolve(__dirname, 'public/index.scss'),
|
||||
styleSheetPaths: resolve(__dirname, 'public/application/index.scss'),
|
||||
hacks: ['plugins/ml/application/hacks/toggle_app_link_in_nav'],
|
||||
savedObjectSchemas: {
|
||||
'ml-telemetry': {
|
||||
|
|
8
x-pack/legacy/plugins/ml/kibana.json
Normal file
8
x-pack/legacy/plugins/ml/kibana.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"id": "ml",
|
||||
"version": "0.0.1",
|
||||
"kibanaVersion": "kibana",
|
||||
"configPath": ["ml"],
|
||||
"server": true,
|
||||
"ui": true
|
||||
}
|
|
@ -4,36 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import uiRoutes from 'ui/routes';
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
// @ts-ignore
|
||||
import { uiModules } from 'ui/modules';
|
||||
import { AccessDeniedPage } from './page';
|
||||
|
||||
const module = uiModules.get('apps/ml', ['react']);
|
||||
|
||||
const template = `<access-denied />`;
|
||||
|
||||
uiRoutes.when('/access-denied', {
|
||||
template,
|
||||
});
|
||||
|
||||
module.directive('accessDenied', function() {
|
||||
return {
|
||||
scope: {},
|
||||
restrict: 'E',
|
||||
link: async (scope: ng.IScope, element: ng.IAugmentedJQuery) => {
|
||||
ReactDOM.render(
|
||||
<I18nContext>{React.createElement(AccessDeniedPage)}</I18nContext>,
|
||||
element[0]
|
||||
);
|
||||
|
||||
element.on('$destroy', () => {
|
||||
ReactDOM.unmountComponentAtNode(element[0]);
|
||||
scope.$destroy();
|
||||
});
|
||||
},
|
||||
};
|
||||
});
|
||||
export { Page } from './page';
|
||||
|
|
|
@ -21,7 +21,7 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import { NavigationMenu } from '../components/navigation_menu';
|
||||
|
||||
export const AccessDeniedPage = () => (
|
||||
export const Page = () => (
|
||||
<Fragment>
|
||||
<NavigationMenu tabId="access-denied" />
|
||||
<EuiPage>
|
||||
|
|
|
@ -1,36 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
|
||||
import 'uiExports/savedObjectTypes';
|
||||
|
||||
import 'ui/autoload/all';
|
||||
|
||||
// needed to make syntax highlighting work in ace editors
|
||||
import 'ace';
|
||||
|
||||
import './access_denied';
|
||||
import './jobs';
|
||||
import './overview';
|
||||
import './services/calendar_service';
|
||||
import './data_frame_analytics';
|
||||
import './datavisualizer';
|
||||
import './explorer';
|
||||
import './timeseriesexplorer';
|
||||
import './components/navigation_menu';
|
||||
import './components/loading_indicator';
|
||||
import './settings';
|
||||
|
||||
import uiRoutes from 'ui/routes';
|
||||
|
||||
if (typeof uiRoutes.enable === 'function') {
|
||||
uiRoutes.enable();
|
||||
}
|
||||
|
||||
uiRoutes
|
||||
.otherwise({
|
||||
redirectTo: '/overview'
|
||||
});
|
53
x-pack/legacy/plugins/ml/public/application/app.tsx
Normal file
53
x-pack/legacy/plugins/ml/public/application/app.tsx
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { FC } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import 'uiExports/savedObjectTypes';
|
||||
|
||||
import 'ui/autoload/all';
|
||||
|
||||
// needed to make syntax highlighting work in ace editors
|
||||
import 'ace';
|
||||
|
||||
import { AppMountContext, AppMountParameters } from 'kibana/public';
|
||||
import {
|
||||
IndexPatternsContract,
|
||||
Plugin as DataPlugin,
|
||||
} from '../../../../../../src/plugins/data/public';
|
||||
|
||||
import { KibanaConfigTypeFix } from './contexts/kibana';
|
||||
|
||||
import { MlRouter } from './routing';
|
||||
|
||||
export interface MlDependencies extends AppMountParameters {
|
||||
npData: ReturnType<DataPlugin['start']>;
|
||||
indexPatterns: IndexPatternsContract;
|
||||
}
|
||||
|
||||
interface AppProps {
|
||||
context: AppMountContext;
|
||||
indexPatterns: IndexPatternsContract;
|
||||
}
|
||||
|
||||
const App: FC<AppProps> = ({ context, indexPatterns }) => {
|
||||
const config = (context.core.uiSettings as never) as KibanaConfigTypeFix; // TODO - make this UiSettingsClientContract, get rid of KibanaConfigTypeFix
|
||||
|
||||
return (
|
||||
<MlRouter
|
||||
config={config}
|
||||
setBreadcrumbs={context.core.chrome.setBreadcrumbs}
|
||||
indexPatterns={indexPatterns}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const renderApp = (context: AppMountContext, { element, indexPatterns }: MlDependencies) => {
|
||||
ReactDOM.render(<App context={context} indexPatterns={indexPatterns} />, element);
|
||||
|
||||
return () => ReactDOM.unmountComponentAtNode(element);
|
||||
};
|
|
@ -35,7 +35,6 @@ import {
|
|||
} from '@elastic/eui/lib/services';
|
||||
|
||||
import { formatDate } from '@elastic/eui/lib/services/format';
|
||||
import chrome from 'ui/chrome';
|
||||
|
||||
import { addItemToRecentlyAccessed } from '../../../util/recently_accessed';
|
||||
import { ml } from '../../../services/ml_api_service';
|
||||
|
@ -206,7 +205,7 @@ const AnnotationsTable = injectI18n(class AnnotationsTable extends Component {
|
|||
|
||||
const url = `?_g=${_g}&_a=${_a}`;
|
||||
addItemToRecentlyAccessed('timeseriesexplorer', job.job_id, url);
|
||||
window.open(`${chrome.getBasePath()}/app/ml#/timeseriesexplorer${url}`, '_self');
|
||||
window.open(`#/timeseriesexplorer${url}`, '_self');
|
||||
}
|
||||
|
||||
onMouseOverRow = (record) => {
|
||||
|
|
|
@ -205,7 +205,7 @@ export const LinksMenu = injectI18n(class LinksMenu extends Component {
|
|||
});
|
||||
|
||||
// Need to encode the _a parameter in case any entities contain unsafe characters such as '+'.
|
||||
let path = `${chrome.getBasePath()}/app/ml#/timeseriesexplorer`;
|
||||
let path = '#/timeseriesexplorer';
|
||||
path += `?_g=${_g}&_a=${encodeURIComponent(_a)}`;
|
||||
window.open(path, '_blank');
|
||||
}
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
import { FC } from 'react';
|
||||
|
||||
import { IndexPattern } from 'ui/index_patterns';
|
||||
import { SavedSearch } from 'src/legacy/core_plugins/kibana/public/discover/types';
|
||||
import { SavedSearchSavedObject } from '../../../../common/types/kibana';
|
||||
|
||||
declare const DataRecognizer: FC<{
|
||||
indexPattern: IndexPattern;
|
||||
savedSearch?: SavedSearch;
|
||||
savedSearch?: SavedSearchSavedObject | null;
|
||||
results: {
|
||||
count: number;
|
||||
onChange?: Function;
|
||||
|
|
|
@ -20,7 +20,7 @@ export const RecognizedResult = ({
|
|||
indexPattern,
|
||||
savedSearch
|
||||
}) => {
|
||||
const id = (savedSearch === undefined || savedSearch.id === undefined) ?
|
||||
const id = (savedSearch === null) ?
|
||||
`index=${indexPattern.id}` :
|
||||
`savedSearchId=${savedSearch.id}`;
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
import React, { FC, useState } from 'react';
|
||||
import { EuiTabs, EuiTab, EuiLink } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import chrome from 'ui/chrome';
|
||||
import { TabId } from './navigation_menu';
|
||||
|
||||
export interface Tab {
|
||||
|
@ -82,7 +81,7 @@ export const MainTabs: FC<Props> = ({ tabId, disableLinks }) => {
|
|||
return (
|
||||
<EuiLink
|
||||
data-test-subj={testSubject + (id === selectedTabId ? ' selected' : '')}
|
||||
href={`${chrome.getBasePath()}/app/ml#/${defaultPathId}`}
|
||||
href={`#/${defaultPathId}`}
|
||||
key={`${id}-key`}
|
||||
color="text"
|
||||
>
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
import React, { FC, useState } from 'react';
|
||||
import { EuiTabs, EuiTab, EuiLink } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import chrome from 'ui/chrome';
|
||||
import { Tab } from './main_tabs';
|
||||
import { TabId } from './navigation_menu';
|
||||
|
||||
|
@ -84,7 +83,7 @@ export const Tabs: FC<Props> = ({ tabId, mainTabId, disableLinks }) => {
|
|||
data-test-subj={
|
||||
TAB_TEST_SUBJECT[id as TAB_TEST_SUBJECTS] + (id === selectedTabId ? ' selected' : '')
|
||||
}
|
||||
href={`${chrome.getBasePath()}/app/ml#/${id}`}
|
||||
href={`#/${id}`}
|
||||
key={`${id}-key`}
|
||||
color="text"
|
||||
>
|
||||
|
|
|
@ -4,14 +4,23 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { searchSourceMock } from '../../../../../../../../../src/legacy/ui/public/courier/search_source/mocks';
|
||||
import { SearchSourceContract } from '../../../../../../../../../src/legacy/ui/public/courier';
|
||||
|
||||
export const savedSearchMock = {
|
||||
export const savedSearchMock: any = {
|
||||
id: 'the-saved-search-id',
|
||||
title: 'the-saved-search-title',
|
||||
searchSource: searchSourceMock as SearchSourceContract,
|
||||
columns: [],
|
||||
sort: [],
|
||||
destroy: () => {},
|
||||
type: 'search',
|
||||
attributes: {
|
||||
title: 'the-saved-search-title',
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON:
|
||||
'{"highlightAll":true,"version":true,"query":{"query":"foo : \\"bar\\" ","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}',
|
||||
},
|
||||
},
|
||||
references: [
|
||||
{
|
||||
name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
||||
type: 'index-pattern',
|
||||
id: 'the-index-pattern-id',
|
||||
},
|
||||
],
|
||||
migrationVersion: { search: '7.5.0' },
|
||||
error: undefined,
|
||||
};
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
import React from 'react';
|
||||
|
||||
import { KibanaConfig } from 'src/legacy/server/kbn_server';
|
||||
import { SavedSearch } from 'src/legacy/core_plugins/kibana/public/discover/types';
|
||||
|
||||
import {
|
||||
IndexPattern,
|
||||
IndexPatternsContract,
|
||||
} from '../../../../../../../../src/plugins/data/public';
|
||||
import { SavedSearchSavedObject } from '../../../../common/types/kibana';
|
||||
|
||||
// set() method is missing in original d.ts
|
||||
export interface KibanaConfigTypeFix extends KibanaConfig {
|
||||
|
@ -21,8 +20,8 @@ export interface KibanaConfigTypeFix extends KibanaConfig {
|
|||
|
||||
export interface KibanaContextValue {
|
||||
combinedQuery: any;
|
||||
currentIndexPattern: IndexPattern;
|
||||
currentSavedSearch: SavedSearch;
|
||||
currentIndexPattern: IndexPattern; // TODO this should be IndexPattern or null
|
||||
currentSavedSearch: SavedSearchSavedObject | null;
|
||||
indexPatterns: IndexPatternsContract;
|
||||
kibanaConfig: KibanaConfigTypeFix;
|
||||
}
|
||||
|
|
|
@ -1,21 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { ML_BREADCRUMB } from '../../breadcrumbs';
|
||||
|
||||
export function getDataFrameAnalyticsBreadcrumbs() {
|
||||
return [
|
||||
ML_BREADCRUMB,
|
||||
{
|
||||
text: i18n.translate('xpack.ml.dataFrameAnalyticsBreadcrumbs.dataFrameLabel', {
|
||||
defaultMessage: 'Data Frame Analytics',
|
||||
}),
|
||||
href: '',
|
||||
},
|
||||
];
|
||||
}
|
|
@ -1,69 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
// @ts-ignore
|
||||
import { uiModules } from 'ui/modules';
|
||||
const module = uiModules.get('apps/ml', ['react']);
|
||||
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
import { IndexPatternsContract } from '../../../../../../../../../src/plugins/data/public';
|
||||
|
||||
import { InjectorService } from '../../../../../common/types/angular';
|
||||
import { createSearchItems } from '../../../jobs/new_job/utils/new_job_utils';
|
||||
|
||||
import { KibanaConfigTypeFix, KibanaContext } from '../../../contexts/kibana';
|
||||
|
||||
import { Page } from './page';
|
||||
|
||||
module.directive('mlDataFrameAnalyticsExploration', ($injector: InjectorService) => {
|
||||
return {
|
||||
scope: {},
|
||||
restrict: 'E',
|
||||
link: (scope: ng.IScope, element: ng.IAugmentedJQuery) => {
|
||||
const globalState = $injector.get<any>('globalState');
|
||||
globalState.fetch();
|
||||
|
||||
const indexPatterns = $injector.get<IndexPatternsContract>('indexPatterns');
|
||||
const kibanaConfig = $injector.get<KibanaConfigTypeFix>('config');
|
||||
const $route = $injector.get<any>('$route');
|
||||
|
||||
const { indexPattern, savedSearch, combinedQuery } = createSearchItems(
|
||||
kibanaConfig,
|
||||
$route.current.locals.indexPattern,
|
||||
$route.current.locals.savedSearch
|
||||
);
|
||||
|
||||
const kibanaContext = {
|
||||
combinedQuery,
|
||||
currentIndexPattern: indexPattern,
|
||||
currentSavedSearch: savedSearch,
|
||||
indexPatterns,
|
||||
kibanaConfig,
|
||||
};
|
||||
|
||||
ReactDOM.render(
|
||||
<I18nContext>
|
||||
<KibanaContext.Provider value={kibanaContext}>
|
||||
<Page
|
||||
jobId={globalState.ml.jobId}
|
||||
analysisType={globalState.ml.analysisType}
|
||||
jobStatus={globalState.ml.jobStatus}
|
||||
/>
|
||||
</KibanaContext.Provider>
|
||||
</I18nContext>,
|
||||
element[0]
|
||||
);
|
||||
|
||||
element.on('$destroy', () => {
|
||||
ReactDOM.unmountComponentAtNode(element[0]);
|
||||
scope.$destroy();
|
||||
});
|
||||
},
|
||||
};
|
||||
});
|
|
@ -4,5 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
|
||||
import './directive';
|
||||
export { Page } from './page';
|
|
@ -1,30 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import uiRoutes from 'ui/routes';
|
||||
|
||||
import { checkFullLicense } from '../../../license/check_license';
|
||||
import { checkGetJobsPrivilege } from '../../../privilege/check_privilege';
|
||||
import {
|
||||
loadCurrentIndexPattern,
|
||||
loadCurrentSavedSearch,
|
||||
loadIndexPatterns,
|
||||
} from '../../../util/index_utils';
|
||||
import { getDataFrameAnalyticsBreadcrumbs } from '../../breadcrumbs';
|
||||
|
||||
const template = `<ml-data-frame-analytics-exploration />`;
|
||||
|
||||
uiRoutes.when('/data_frame_analytics/exploration?', {
|
||||
template,
|
||||
k7Breadcrumbs: getDataFrameAnalyticsBreadcrumbs,
|
||||
resolve: {
|
||||
CheckLicense: checkFullLicense,
|
||||
privileges: checkGetJobsPrivilege,
|
||||
indexPattern: loadCurrentIndexPattern,
|
||||
indexPatterns: loadIndexPatterns,
|
||||
savedSearch: loadCurrentSavedSearch,
|
||||
},
|
||||
});
|
|
@ -1,61 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
// @ts-ignore
|
||||
import { uiModules } from 'ui/modules';
|
||||
const module = uiModules.get('apps/ml', ['react']);
|
||||
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
import { InjectorService } from '../../../../../common/types/angular';
|
||||
import { createSearchItems } from '../../../jobs/new_job/utils/new_job_utils';
|
||||
import { IndexPatternsContract } from '../../../../../../../../../src/plugins/data/public';
|
||||
|
||||
import { KibanaConfigTypeFix, KibanaContext } from '../../../contexts/kibana';
|
||||
|
||||
import { Page } from './page';
|
||||
|
||||
module.directive('mlDataFrameAnalyticsManagement', ($injector: InjectorService) => {
|
||||
return {
|
||||
scope: {},
|
||||
restrict: 'E',
|
||||
link: (scope: ng.IScope, element: ng.IAugmentedJQuery) => {
|
||||
const indexPatterns = $injector.get<IndexPatternsContract>('indexPatterns');
|
||||
const kibanaConfig = $injector.get<KibanaConfigTypeFix>('config');
|
||||
const $route = $injector.get<any>('$route');
|
||||
|
||||
const { indexPattern, savedSearch, combinedQuery } = createSearchItems(
|
||||
kibanaConfig,
|
||||
$route.current.locals.indexPattern,
|
||||
$route.current.locals.savedSearch
|
||||
);
|
||||
|
||||
const kibanaContext = {
|
||||
combinedQuery,
|
||||
currentIndexPattern: indexPattern,
|
||||
currentSavedSearch: savedSearch,
|
||||
indexPatterns,
|
||||
kibanaConfig,
|
||||
};
|
||||
|
||||
ReactDOM.render(
|
||||
<I18nContext>
|
||||
<KibanaContext.Provider value={kibanaContext}>
|
||||
<Page />
|
||||
</KibanaContext.Provider>
|
||||
</I18nContext>,
|
||||
element[0]
|
||||
);
|
||||
|
||||
element.on('$destroy', () => {
|
||||
ReactDOM.unmountComponentAtNode(element[0]);
|
||||
scope.$destroy();
|
||||
});
|
||||
},
|
||||
};
|
||||
});
|
|
@ -4,7 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
import './list';
|
||||
import './edit';
|
||||
export { Page } from './page';
|
|
@ -1,29 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import uiRoutes from 'ui/routes';
|
||||
|
||||
import { checkFullLicense } from '../../../license/check_license';
|
||||
import { checkGetJobsPrivilege } from '../../../privilege/check_privilege';
|
||||
import { loadMlServerInfo } from '../../../services/ml_server_info';
|
||||
import { getMlNodeCount } from '../../../ml_nodes_check/check_ml_nodes';
|
||||
import { loadCurrentIndexPattern, loadCurrentSavedSearch } from '../../../util/index_utils';
|
||||
import { getDataFrameAnalyticsBreadcrumbs } from '../../breadcrumbs';
|
||||
|
||||
const template = `<ml-data-frame-analytics-management />`;
|
||||
|
||||
uiRoutes.when('/data_frame_analytics/?', {
|
||||
template,
|
||||
k7Breadcrumbs: getDataFrameAnalyticsBreadcrumbs,
|
||||
resolve: {
|
||||
CheckLicense: checkFullLicense,
|
||||
privileges: checkGetJobsPrivilege,
|
||||
indexPattern: loadCurrentIndexPattern,
|
||||
savedSearch: loadCurrentSavedSearch,
|
||||
mlNodeCount: getMlNodeCount,
|
||||
loadMlServerInfo,
|
||||
},
|
||||
});
|
|
@ -1,13 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { ML_BREADCRUMB, DATA_VISUALIZER_BREADCRUMB } from '../../breadcrumbs';
|
||||
|
||||
export function getDataVisualizerBreadcrumbs() {
|
||||
// Whilst top level nav menu with tabs remains,
|
||||
// use root ML breadcrumb.
|
||||
return [ML_BREADCRUMB, DATA_VISUALIZER_BREADCRUMB];
|
||||
}
|
|
@ -57,7 +57,7 @@ export const DatavisualizerSelector: FC = () => {
|
|||
return (
|
||||
<Fragment>
|
||||
<NavigationMenu tabId="datavisualizer" />
|
||||
<EuiPage restrictWidth={1000}>
|
||||
<EuiPage restrictWidth={1000} data-test-subj="mlPageDataVisualizerSelector">
|
||||
<EuiPageBody>
|
||||
<EuiFlexGroup gutterSize="xl">
|
||||
<EuiFlexItem grow={false}>
|
||||
|
@ -145,7 +145,7 @@ export const DatavisualizerSelector: FC = () => {
|
|||
footer={
|
||||
<EuiButton
|
||||
target="_self"
|
||||
href="#datavisualizer_index_select"
|
||||
href="#/datavisualizer_index_select"
|
||||
data-test-subj="mlDataVisualizerSelectIndexButton"
|
||||
>
|
||||
<FormattedMessage
|
||||
|
|
|
@ -1,54 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
|
||||
// @ts-ignore
|
||||
import { uiModules } from 'ui/modules';
|
||||
const module = uiModules.get('apps/ml', ['react']);
|
||||
|
||||
import uiRoutes from 'ui/routes';
|
||||
import { getDataVisualizerBreadcrumbs } from './breadcrumbs';
|
||||
import { checkBasicLicense } from '../license/check_license';
|
||||
import { checkFindFileStructurePrivilege } from '../privilege/check_privilege';
|
||||
|
||||
const template = `
|
||||
<div class="euiSpacer euiSpacer--s" />
|
||||
<datavisualizer-selector data-test-subj="mlPageDataVisualizerSelector" />
|
||||
`;
|
||||
|
||||
uiRoutes.when('/datavisualizer', {
|
||||
template,
|
||||
k7Breadcrumbs: getDataVisualizerBreadcrumbs,
|
||||
resolve: {
|
||||
CheckLicense: checkBasicLicense,
|
||||
privileges: checkFindFileStructurePrivilege,
|
||||
},
|
||||
});
|
||||
|
||||
import { DatavisualizerSelector } from './datavisualizer_selector';
|
||||
|
||||
module.directive('datavisualizerSelector', function() {
|
||||
return {
|
||||
scope: {},
|
||||
restrict: 'E',
|
||||
link: (scope: ng.IScope, element: ng.IAugmentedJQuery) => {
|
||||
ReactDOM.render(
|
||||
<I18nContext>
|
||||
<DatavisualizerSelector />
|
||||
</I18nContext>,
|
||||
element[0]
|
||||
);
|
||||
|
||||
element.on('$destroy', () => {
|
||||
ReactDOM.unmountComponentAtNode(element[0]);
|
||||
scope.$destroy();
|
||||
});
|
||||
},
|
||||
};
|
||||
});
|
|
@ -1,23 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { ML_BREADCRUMB, DATA_VISUALIZER_BREADCRUMB } from '../../../breadcrumbs';
|
||||
|
||||
export function getFileDataVisualizerBreadcrumbs() {
|
||||
// Whilst top level nav menu with tabs remains,
|
||||
// use root ML breadcrumb.
|
||||
return [
|
||||
ML_BREADCRUMB,
|
||||
DATA_VISUALIZER_BREADCRUMB,
|
||||
{
|
||||
text: i18n.translate('xpack.ml.dataVisualizer.fileBasedLabel', {
|
||||
defaultMessage: 'File',
|
||||
}),
|
||||
href: '',
|
||||
},
|
||||
];
|
||||
}
|
|
@ -359,7 +359,7 @@ export class ImportView extends Component {
|
|||
}
|
||||
|
||||
async loadIndexPatternNames() {
|
||||
await loadIndexPatterns();
|
||||
await loadIndexPatterns(this.props.indexPatterns);
|
||||
const indexPatternNames = getIndexPatternNames();
|
||||
this.setState({ indexPatternNames });
|
||||
}
|
||||
|
|
|
@ -121,7 +121,7 @@ export class ResultsLinks extends Component {
|
|||
/>
|
||||
}
|
||||
description=""
|
||||
href={`${uiChrome.getBasePath()}/app/ml#/jobs/new_job/step/job_type?index=${indexPatternId}${_g}`}
|
||||
href={`#/jobs/new_job/step/job_type?index=${indexPatternId}${_g}`}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ export class ResultsLinks extends Component {
|
|||
/>
|
||||
}
|
||||
description=""
|
||||
href={`${uiChrome.getBasePath()}/app/ml#/jobs/new_job/datavisualizer?index=${indexPatternId}${_g}`}
|
||||
href={`#/jobs/new_job/datavisualizer?index=${indexPatternId}${_g}`}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
}
|
||||
|
|
|
@ -6,26 +6,22 @@
|
|||
|
||||
import React, { FC, Fragment } from 'react';
|
||||
import { timefilter } from 'ui/timefilter';
|
||||
import { IndexPatternsContract } from '../../../../../../../../src/plugins/data/public';
|
||||
|
||||
import { KibanaConfigTypeFix } from '../../contexts/kibana';
|
||||
import { NavigationMenu } from '../../components/navigation_menu';
|
||||
import { getIndexPatternsContract } from '../../util/index_utils';
|
||||
|
||||
// @ts-ignore
|
||||
import { FileDataVisualizerView } from './components/file_datavisualizer_view/index';
|
||||
|
||||
export interface FileDataVisualizerPageProps {
|
||||
indexPatterns: IndexPatternsContract;
|
||||
kibanaConfig: KibanaConfigTypeFix;
|
||||
}
|
||||
|
||||
export const FileDataVisualizerPage: FC<FileDataVisualizerPageProps> = ({
|
||||
indexPatterns,
|
||||
kibanaConfig,
|
||||
}) => {
|
||||
export const FileDataVisualizerPage: FC<FileDataVisualizerPageProps> = ({ kibanaConfig }) => {
|
||||
timefilter.disableTimeRangeSelector();
|
||||
timefilter.disableAutoRefreshSelector();
|
||||
|
||||
const indexPatterns = getIndexPatternsContract();
|
||||
return (
|
||||
<Fragment>
|
||||
<NavigationMenu tabId="datavisualizer" />
|
||||
|
|
|
@ -1,68 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
|
||||
// @ts-ignore
|
||||
import { uiModules } from 'ui/modules';
|
||||
|
||||
const module = uiModules.get('apps/ml', ['react']);
|
||||
|
||||
import uiRoutes from 'ui/routes';
|
||||
import { KibanaConfigTypeFix } from '../../contexts/kibana';
|
||||
import { getFileDataVisualizerBreadcrumbs } from './breadcrumbs';
|
||||
import { InjectorService } from '../../../../common/types/angular';
|
||||
import { checkBasicLicense } from '../../license/check_license';
|
||||
import { checkFindFileStructurePrivilege } from '../../privilege/check_privilege';
|
||||
import { getMlNodeCount } from '../../ml_nodes_check/check_ml_nodes';
|
||||
import { loadMlServerInfo } from '../../services/ml_server_info';
|
||||
import { loadIndexPatterns } from '../../util/index_utils';
|
||||
import { FileDataVisualizerPage, FileDataVisualizerPageProps } from './file_datavisualizer';
|
||||
import { IndexPatternsContract } from '../../../../../../../../src/plugins/data/public';
|
||||
|
||||
const template = `
|
||||
<div class="euiSpacer euiSpacer--s" />
|
||||
<file-datavisualizer-page />
|
||||
`;
|
||||
|
||||
uiRoutes.when('/filedatavisualizer/?', {
|
||||
template,
|
||||
k7Breadcrumbs: getFileDataVisualizerBreadcrumbs,
|
||||
resolve: {
|
||||
CheckLicense: checkBasicLicense,
|
||||
privileges: checkFindFileStructurePrivilege,
|
||||
indexPatterns: loadIndexPatterns,
|
||||
mlNodeCount: getMlNodeCount,
|
||||
loadMlServerInfo,
|
||||
},
|
||||
});
|
||||
|
||||
module.directive('fileDatavisualizerPage', function($injector: InjectorService) {
|
||||
return {
|
||||
scope: {},
|
||||
restrict: 'E',
|
||||
link: (scope: ng.IScope, element: ng.IAugmentedJQuery) => {
|
||||
const indexPatterns = $injector.get<IndexPatternsContract>('indexPatterns');
|
||||
const kibanaConfig = $injector.get<KibanaConfigTypeFix>('config');
|
||||
|
||||
const props: FileDataVisualizerPageProps = {
|
||||
indexPatterns,
|
||||
kibanaConfig,
|
||||
};
|
||||
ReactDOM.render(
|
||||
<I18nContext>{React.createElement(FileDataVisualizerPage, props)}</I18nContext>,
|
||||
element[0]
|
||||
);
|
||||
|
||||
element.on('$destroy', () => {
|
||||
ReactDOM.unmountComponentAtNode(element[0]);
|
||||
scope.$destroy();
|
||||
});
|
||||
},
|
||||
};
|
||||
});
|
|
@ -4,4 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import './file_datavisualizer_directive';
|
||||
export { FileDataVisualizerPage } from './file_datavisualizer';
|
||||
|
|
|
@ -4,6 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import './directive';
|
||||
import './file_based';
|
||||
import './index_based';
|
||||
export { DatavisualizerSelector } from './datavisualizer_selector';
|
||||
|
|
|
@ -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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import {
|
||||
ML_BREADCRUMB,
|
||||
DATA_VISUALIZER_BREADCRUMB,
|
||||
// @ts-ignore
|
||||
} from '../../../breadcrumbs';
|
||||
|
||||
export function getDataVisualizerBreadcrumbs() {
|
||||
// Whilst top level nav menu with tabs remains,
|
||||
// use root ML breadcrumb.
|
||||
return [
|
||||
ML_BREADCRUMB,
|
||||
DATA_VISUALIZER_BREADCRUMB,
|
||||
{
|
||||
text: i18n.translate('xpack.ml.dataFrameAnalyticsBreadcrumbs.indexLabel', {
|
||||
defaultMessage: 'Index',
|
||||
}),
|
||||
href: '',
|
||||
},
|
||||
];
|
||||
}
|
|
@ -13,7 +13,6 @@ import { IndexPattern } from 'ui/index_patterns';
|
|||
|
||||
import { EuiPanel, EuiSpacer, EuiText, EuiTitle, EuiFlexGroup } from '@elastic/eui';
|
||||
|
||||
import { useUiChromeContext } from '../../../../contexts/ui/use_ui_chrome_context';
|
||||
import { CreateJobLinkCard } from '../../../../components/create_job_link_card';
|
||||
import { DataRecognizer } from '../../../../components/data_recognizer';
|
||||
|
||||
|
@ -31,12 +30,10 @@ export const ActionsPanel: FC<Props> = ({ indexPattern }) => {
|
|||
},
|
||||
};
|
||||
|
||||
const basePath = useUiChromeContext().getBasePath();
|
||||
|
||||
function openAdvancedJobWizard() {
|
||||
// TODO - pass the search string to the advanced job page as well as the index pattern
|
||||
// (add in with new advanced job wizard?)
|
||||
window.open(`${basePath}/app/ml#/jobs/new_job/advanced?index=${indexPattern}`, '_self');
|
||||
window.open(`#/jobs/new_job/advanced?index=${indexPattern}`, '_self');
|
||||
}
|
||||
|
||||
// Note we use display:none for the DataRecognizer section as it needs to be
|
||||
|
@ -87,7 +84,7 @@ export const ActionsPanel: FC<Props> = ({ indexPattern }) => {
|
|||
'Use the full range of options to create a job for more advanced use cases',
|
||||
})}
|
||||
onClick={openAdvancedJobWizard}
|
||||
href={`${basePath}/app/ml#/jobs/new_job/advanced?index=${indexPattern}`}
|
||||
href={`#/jobs/new_job/advanced?index=${indexPattern}`}
|
||||
/>
|
||||
</EuiPanel>
|
||||
);
|
||||
|
|
|
@ -1,61 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
// @ts-ignore
|
||||
import { uiModules } from 'ui/modules';
|
||||
const module = uiModules.get('apps/ml', ['react']);
|
||||
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
import { IndexPatternsContract } from '../../../../../../../../src/plugins/data/public';
|
||||
import { InjectorService } from '../../../../common/types/angular';
|
||||
|
||||
import { KibanaConfigTypeFix, KibanaContext } from '../../contexts/kibana/kibana_context';
|
||||
import { createSearchItems } from '../../jobs/new_job/utils/new_job_utils';
|
||||
|
||||
import { Page } from './page';
|
||||
|
||||
module.directive('mlDataVisualizer', ($injector: InjectorService) => {
|
||||
return {
|
||||
scope: {},
|
||||
restrict: 'E',
|
||||
link: (scope: ng.IScope, element: ng.IAugmentedJQuery) => {
|
||||
const indexPatterns = $injector.get<IndexPatternsContract>('indexPatterns');
|
||||
const kibanaConfig = $injector.get<KibanaConfigTypeFix>('config');
|
||||
const $route = $injector.get<any>('$route');
|
||||
|
||||
const { indexPattern, savedSearch, combinedQuery } = createSearchItems(
|
||||
kibanaConfig,
|
||||
$route.current.locals.indexPattern,
|
||||
$route.current.locals.savedSearch
|
||||
);
|
||||
|
||||
const kibanaContext = {
|
||||
combinedQuery,
|
||||
currentIndexPattern: indexPattern,
|
||||
currentSavedSearch: savedSearch,
|
||||
indexPatterns,
|
||||
kibanaConfig,
|
||||
};
|
||||
|
||||
ReactDOM.render(
|
||||
<I18nContext>
|
||||
<KibanaContext.Provider value={kibanaContext}>
|
||||
<Page />
|
||||
</KibanaContext.Provider>
|
||||
</I18nContext>,
|
||||
element[0]
|
||||
);
|
||||
|
||||
element.on('$destroy', () => {
|
||||
ReactDOM.unmountComponentAtNode(element[0]);
|
||||
scope.$destroy();
|
||||
});
|
||||
},
|
||||
};
|
||||
});
|
|
@ -4,5 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import './directive';
|
||||
import './route';
|
||||
export { Page } from './page';
|
||||
|
|
|
@ -31,7 +31,7 @@ import { FullTimeRangeSelector } from '../../components/full_time_range_selector
|
|||
import { mlTimefilterRefresh$ } from '../../services/timefilter_refresh_service';
|
||||
import { useKibanaContext, SavedSearchQuery } from '../../contexts/kibana';
|
||||
import { kbnTypeToMLJobType } from '../../util/field_types_utils';
|
||||
import { timeBasedIndexCheck } from '../../util/index_utils';
|
||||
import { timeBasedIndexCheck, getQueryFromSavedSearch } from '../../util/index_utils';
|
||||
import { TimeBuckets } from '../../util/time_buckets';
|
||||
import { FieldRequestConfig, FieldVisConfig } from './common';
|
||||
import { ActionsPanel } from './components/actions_panel';
|
||||
|
@ -173,9 +173,8 @@ export const Page: FC = () => {
|
|||
|
||||
useEffect(() => {
|
||||
// Check for a saved search being passed in.
|
||||
const searchSource = currentSavedSearch.searchSource;
|
||||
const query = searchSource.getField('query');
|
||||
if (query !== undefined) {
|
||||
if (currentSavedSearch !== null) {
|
||||
const { query } = getQueryFromSavedSearch(currentSavedSearch);
|
||||
const queryLanguage = query.language as SEARCH_QUERY_LANGUAGE;
|
||||
const qryString = query.query;
|
||||
let qry;
|
||||
|
|
|
@ -1,28 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
// @ts-ignore
|
||||
import uiRoutes from 'ui/routes';
|
||||
import { checkBasicLicense } from '../../license/check_license';
|
||||
import { checkGetJobsPrivilege } from '../../privilege/check_privilege';
|
||||
import { loadCurrentIndexPattern, loadCurrentSavedSearch } from '../../util/index_utils';
|
||||
|
||||
import { checkMlNodesAvailable } from '../../ml_nodes_check';
|
||||
import { getDataVisualizerBreadcrumbs } from './breadcrumbs';
|
||||
|
||||
const template = `<ml-data-visualizer />`;
|
||||
|
||||
uiRoutes.when('/jobs/new_job/datavisualizer', {
|
||||
template,
|
||||
k7Breadcrumbs: getDataVisualizerBreadcrumbs,
|
||||
resolve: {
|
||||
CheckLicense: checkBasicLicense,
|
||||
privileges: checkGetJobsPrivilege,
|
||||
indexPattern: loadCurrentIndexPattern,
|
||||
savedSearch: loadCurrentSavedSearch,
|
||||
checkMlNodesAvailable,
|
||||
},
|
||||
});
|
|
@ -1,23 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { ML_BREADCRUMB, ANOMALY_DETECTION_BREADCRUMB } from '../../breadcrumbs';
|
||||
|
||||
export function getAnomalyExplorerBreadcrumbs() {
|
||||
// Whilst top level nav menu with tabs remains,
|
||||
// use root ML breadcrumb.
|
||||
return [
|
||||
ML_BREADCRUMB,
|
||||
ANOMALY_DETECTION_BREADCRUMB,
|
||||
{
|
||||
text: i18n.translate('xpack.ml.anomalyDetection.anomalyExplorerLabel', {
|
||||
defaultMessage: 'Anomaly Explorer',
|
||||
}),
|
||||
href: '',
|
||||
},
|
||||
];
|
||||
}
|
|
@ -93,7 +93,7 @@ function mapSwimlaneOptionsToEuiOptions(options) {
|
|||
}
|
||||
|
||||
const ExplorerPage = ({ children, jobSelectorProps, resizeRef }) => (
|
||||
<div ref={resizeRef}>
|
||||
<div ref={resizeRef} data-test-subj="mlPageAnomalyExplorer">
|
||||
<NavigationMenu tabId="explorer" />
|
||||
<JobSelector {...jobSelectorProps} />
|
||||
{children}
|
||||
|
@ -117,7 +117,6 @@ export const Explorer = injectI18n(injectObservablesAsProps(
|
|||
};
|
||||
|
||||
_unsubscribeAll = new Subject();
|
||||
|
||||
// make sure dragSelect is only available if the mouse pointer is actually over a swimlane
|
||||
disableDragSelectOnMouseLeave = true;
|
||||
|
||||
|
|
|
@ -1,110 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* AngularJS directive wrapper for rendering Anomaly Explorer's React component.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
import { IRootElementService, IRootScopeService, IScope } from 'angular';
|
||||
|
||||
// @ts-ignore
|
||||
import { uiModules } from 'ui/modules';
|
||||
const module = uiModules.get('apps/ml');
|
||||
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
import { State } from 'ui/state_management/state';
|
||||
import { AppState as IAppState, AppStateClass } from 'ui/state_management/app_state';
|
||||
|
||||
import { jobSelectServiceFactory } from '../components/job_selector/job_select_service_utils';
|
||||
|
||||
import { interval$ } from '../components/controls/select_interval';
|
||||
import { severity$ } from '../components/controls/select_severity';
|
||||
import { showCharts$ } from '../components/controls/checkbox_showcharts';
|
||||
import { subscribeAppStateToObservable } from '../util/app_state_utils';
|
||||
|
||||
import { Explorer } from './explorer';
|
||||
import { explorerService } from './explorer_dashboard_service';
|
||||
import { getExplorerDefaultAppState, ExplorerAppState } from './reducers';
|
||||
|
||||
interface ExplorerScope extends IScope {
|
||||
appState: IAppState;
|
||||
}
|
||||
|
||||
module.directive('mlAnomalyExplorer', function(
|
||||
globalState: State,
|
||||
$rootScope: IRootScopeService,
|
||||
AppState: AppStateClass
|
||||
) {
|
||||
function link($scope: ExplorerScope, element: IRootElementService) {
|
||||
const subscriptions = new Subscription();
|
||||
|
||||
const { jobSelectService$, unsubscribeFromGlobalState } = jobSelectServiceFactory(globalState);
|
||||
|
||||
ReactDOM.render(
|
||||
<I18nContext>
|
||||
<Explorer
|
||||
{...{
|
||||
globalState,
|
||||
jobSelectService$,
|
||||
}}
|
||||
/>
|
||||
</I18nContext>,
|
||||
element[0]
|
||||
);
|
||||
|
||||
// Initialize the AppState in which to store swimlane and filter settings.
|
||||
// AppState is used to store state in the URL.
|
||||
$scope.appState = new AppState(getExplorerDefaultAppState());
|
||||
const { mlExplorerFilter, mlExplorerSwimlane } = $scope.appState;
|
||||
|
||||
// Pass the current URL AppState on to anomaly explorer's reactive state.
|
||||
// After this hand-off, the appState stored in explorerState$ is the single
|
||||
// source of truth.
|
||||
explorerService.setAppState({ mlExplorerSwimlane, mlExplorerFilter });
|
||||
|
||||
// Now that appState in explorerState$ is the single source of truth,
|
||||
// subscribe to it and update the actual URL appState on changes.
|
||||
subscriptions.add(
|
||||
explorerService.appState$.subscribe((appState: ExplorerAppState) => {
|
||||
$scope.appState.fetch();
|
||||
$scope.appState.mlExplorerFilter = appState.mlExplorerFilter;
|
||||
$scope.appState.mlExplorerSwimlane = appState.mlExplorerSwimlane;
|
||||
$scope.appState.save();
|
||||
$scope.$applyAsync();
|
||||
})
|
||||
);
|
||||
|
||||
subscriptions.add(
|
||||
subscribeAppStateToObservable(AppState, 'mlShowCharts', showCharts$, () =>
|
||||
$rootScope.$applyAsync()
|
||||
)
|
||||
);
|
||||
subscriptions.add(
|
||||
subscribeAppStateToObservable(AppState, 'mlSelectInterval', interval$, () =>
|
||||
$rootScope.$applyAsync()
|
||||
)
|
||||
);
|
||||
subscriptions.add(
|
||||
subscribeAppStateToObservable(AppState, 'mlSelectSeverity', severity$, () =>
|
||||
$rootScope.$applyAsync()
|
||||
)
|
||||
);
|
||||
|
||||
element.on('$destroy', () => {
|
||||
ReactDOM.unmountComponentAtNode(element[0]);
|
||||
$scope.$destroy();
|
||||
subscriptions.unsubscribe();
|
||||
unsubscribeFromGlobalState();
|
||||
});
|
||||
}
|
||||
|
||||
return { link };
|
||||
});
|
|
@ -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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import uiRoutes from 'ui/routes';
|
||||
|
||||
import '../components/controls';
|
||||
|
||||
import { checkFullLicense } from '../license/check_license';
|
||||
import { checkGetJobsPrivilege } from '../privilege/check_privilege';
|
||||
import { mlJobService } from '../services/job_service';
|
||||
import { loadIndexPatterns } from '../util/index_utils';
|
||||
|
||||
import { getAnomalyExplorerBreadcrumbs } from './breadcrumbs';
|
||||
|
||||
uiRoutes.when('/explorer/?', {
|
||||
template: `<ml-anomaly-explorer class="ml-explorer" data-test-subj="mlPageAnomalyExplorer" />`,
|
||||
k7Breadcrumbs: getAnomalyExplorerBreadcrumbs,
|
||||
resolve: {
|
||||
CheckLicense: checkFullLicense,
|
||||
privileges: checkGetJobsPrivilege,
|
||||
indexPatterns: loadIndexPatterns,
|
||||
jobs: mlJobService.loadJobsWrapper,
|
||||
},
|
||||
});
|
|
@ -4,9 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import '../explorer/explorer_dashboard_service';
|
||||
import '../explorer/explorer_directive';
|
||||
import '../explorer/explorer_route';
|
||||
import '../explorer/explorer_charts';
|
||||
import '../explorer/select_limit';
|
||||
import '../components/job_selector';
|
||||
export { Explorer } from './explorer';
|
||||
|
|
45
x-pack/legacy/plugins/ml/public/application/index.scss
Normal file
45
x-pack/legacy/plugins/ml/public/application/index.scss
Normal file
|
@ -0,0 +1,45 @@
|
|||
// Should import both the EUI constants and any Kibana ones that are considered global
|
||||
@import 'src/legacy/ui/public/styles/styling_constants';
|
||||
|
||||
// ML has it's own variables for coloring
|
||||
@import 'variables';
|
||||
|
||||
// Kibana management page ML section
|
||||
#kibanaManagementMLSection {
|
||||
@import 'management/index';
|
||||
}
|
||||
|
||||
// Protect the rest of Kibana from ML generic namespacing
|
||||
// SASSTODO: Prefix ml selectors instead
|
||||
#ml-app {
|
||||
// App level
|
||||
@import 'app';
|
||||
|
||||
// Sub applications
|
||||
@import 'data_frame_analytics/index';
|
||||
@import 'datavisualizer/index';
|
||||
@import 'explorer/index'; // SASSTODO: This file needs to be rewritten
|
||||
@import 'jobs/index'; // SASSTODO: This collection of sass files has multiple problems
|
||||
@import 'overview/index';
|
||||
@import 'settings/index';
|
||||
@import 'timeseriesexplorer/index';
|
||||
|
||||
// Components
|
||||
@import 'components/annotations/annotation_description_list/index'; // SASSTODO: This file overwrites EUI directly
|
||||
@import 'components/anomalies_table/index'; // SASSTODO: This file overwrites EUI directly
|
||||
@import 'components/chart_tooltip/index';
|
||||
@import 'components/controls/index';
|
||||
@import 'components/entity_cell/index';
|
||||
@import 'components/field_title_bar/index';
|
||||
@import 'components/field_type_icon/index';
|
||||
@import 'components/influencers_list/index';
|
||||
@import 'components/items_grid/index';
|
||||
@import 'components/job_selector/index';
|
||||
@import 'components/loading_indicator/index'; // SASSTODO: This component should be replaced with EuiLoadingSpinner
|
||||
@import 'components/navigation_menu/index';
|
||||
@import 'components/rule_editor/index'; // SASSTODO: This file overwrites EUI directly
|
||||
@import 'components/stats_bar/index';
|
||||
|
||||
// Hacks are last so they can overwrite anything above if needed
|
||||
@import 'hacks';
|
||||
}
|
|
@ -1,112 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { Breadcrumb } from 'ui/chrome';
|
||||
import {
|
||||
ANOMALY_DETECTION_BREADCRUMB,
|
||||
DATA_VISUALIZER_BREADCRUMB,
|
||||
ML_BREADCRUMB,
|
||||
} from '../../breadcrumbs';
|
||||
|
||||
export function getJobManagementBreadcrumbs(): Breadcrumb[] {
|
||||
// Whilst top level nav menu with tabs remains,
|
||||
// use root ML breadcrumb.
|
||||
return [
|
||||
ML_BREADCRUMB,
|
||||
ANOMALY_DETECTION_BREADCRUMB,
|
||||
{
|
||||
text: i18n.translate('xpack.ml.anomalyDetection.jobManagementLabel', {
|
||||
defaultMessage: 'Job Management',
|
||||
}),
|
||||
href: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function getCreateJobBreadcrumbs(): Breadcrumb[] {
|
||||
return [
|
||||
ML_BREADCRUMB,
|
||||
ANOMALY_DETECTION_BREADCRUMB,
|
||||
{
|
||||
text: i18n.translate('xpack.ml.jobsBreadcrumbs.createJobLabel', {
|
||||
defaultMessage: 'Create job',
|
||||
}),
|
||||
href: '#/jobs/new_job',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function getCreateSingleMetricJobBreadcrumbs(): Breadcrumb[] {
|
||||
return [
|
||||
...getCreateJobBreadcrumbs(),
|
||||
{
|
||||
text: i18n.translate('xpack.ml.jobsBreadcrumbs.singleMetricLabel', {
|
||||
defaultMessage: 'Single metric',
|
||||
}),
|
||||
href: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function getCreateMultiMetricJobBreadcrumbs(): Breadcrumb[] {
|
||||
return [
|
||||
...getCreateJobBreadcrumbs(),
|
||||
{
|
||||
text: i18n.translate('xpack.ml.jobsBreadcrumbs.multiMetricLabel', {
|
||||
defaultMessage: 'Multi metric',
|
||||
}),
|
||||
href: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function getCreatePopulationJobBreadcrumbs(): Breadcrumb[] {
|
||||
return [
|
||||
...getCreateJobBreadcrumbs(),
|
||||
{
|
||||
text: i18n.translate('xpack.ml.jobsBreadcrumbs.populationLabel', {
|
||||
defaultMessage: 'Population',
|
||||
}),
|
||||
href: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function getAdvancedJobConfigurationBreadcrumbs(): Breadcrumb[] {
|
||||
return [
|
||||
...getCreateJobBreadcrumbs(),
|
||||
{
|
||||
text: i18n.translate('xpack.ml.jobsBreadcrumbs.advancedConfigurationLabel', {
|
||||
defaultMessage: 'Advanced configuration',
|
||||
}),
|
||||
href: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function getCreateRecognizerJobBreadcrumbs($routeParams: any): Breadcrumb[] {
|
||||
return [
|
||||
...getCreateJobBreadcrumbs(),
|
||||
{
|
||||
text: $routeParams.id,
|
||||
href: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function getDataVisualizerIndexOrSearchBreadcrumbs(): Breadcrumb[] {
|
||||
return [
|
||||
ML_BREADCRUMB,
|
||||
DATA_VISUALIZER_BREADCRUMB,
|
||||
{
|
||||
text: i18n.translate('xpack.ml.jobsBreadcrumbs.selectIndexOrSearchLabel', {
|
||||
defaultMessage: 'Select index or search',
|
||||
}),
|
||||
href: '',
|
||||
},
|
||||
];
|
||||
}
|
|
@ -4,7 +4,5 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import './pages/analytics_exploration/directive';
|
||||
import './pages/analytics_exploration/route';
|
||||
import './pages/analytics_management/directive';
|
||||
import './pages/analytics_management/route';
|
||||
export { JobsPage } from './jobs_list';
|
||||
export {} from './new_job';
|
|
@ -7,20 +7,20 @@
|
|||
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import chrome from 'ui/chrome';
|
||||
|
||||
import {
|
||||
EuiButtonIcon,
|
||||
EuiToolTip,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
|
||||
import { mlJobService } from '../../../../services/job_service';
|
||||
import { injectI18n } from '@kbn/i18n/react';
|
||||
|
||||
export function getLink(location, jobs) {
|
||||
const resultsPageUrl = mlJobService.createResultsUrlForJobs(jobs, location);
|
||||
return `${chrome.getBasePath()}/app/${resultsPageUrl}`;
|
||||
return `${chrome.getBasePath()}/app/ml${resultsPageUrl}`;
|
||||
}
|
||||
|
||||
function ResultLinksUI({ jobs, intl }) {
|
||||
|
@ -39,6 +39,7 @@ function ResultLinksUI({ jobs, intl }) {
|
|||
const singleMetricVisible = (jobs.length < 2);
|
||||
const singleMetricEnabled = (jobs.length === 1 && jobs[0].isSingleMetricViewerJob);
|
||||
const jobActionsDisabled = (jobs.length === 1 && jobs[0].deleting === true);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{(singleMetricVisible) &&
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
import React from 'react';
|
||||
import { EuiLink } from '@elastic/eui';
|
||||
import chrome from 'ui/chrome';
|
||||
import { detectorToString } from '../../../../util/string_utils';
|
||||
import { formatValues, filterObjects } from './format_values';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
@ -62,7 +61,7 @@ export function extractJobDetails(job) {
|
|||
if (job.calendars) {
|
||||
calendars.items = job.calendars.map(c => [
|
||||
'',
|
||||
<EuiLink href={`${chrome.getBasePath()}/app/ml#/settings/calendars_list/edit_calendar/${c}?_g=()`}>{c}</EuiLink>,
|
||||
<EuiLink href={`#/settings/calendars_list/edit_calendar/${c}?_g=()`}>{c}</EuiLink>,
|
||||
]);
|
||||
// remove the calendars list from the general section
|
||||
// so not to show it twice.
|
||||
|
|
|
@ -23,7 +23,6 @@ import {
|
|||
EuiLoadingSpinner
|
||||
} from '@elastic/eui';
|
||||
import { formatDate, formatNumber } from '@elastic/eui/lib/services/format';
|
||||
import chrome from 'ui/chrome';
|
||||
|
||||
import { FORECAST_REQUEST_STATE } from '../../../../../../../common/constants/states';
|
||||
import { addItemToRecentlyAccessed } from '../../../../../util/recently_accessed';
|
||||
|
@ -128,7 +127,7 @@ class ForecastsTableUI extends Component {
|
|||
|
||||
const url = `?_g=${_g}&_a=${_a}`;
|
||||
addItemToRecentlyAccessed('timeseriesexplorer', this.props.job.job_id, url);
|
||||
window.open(`${chrome.getBasePath()}/app/ml#/timeseriesexplorer${url}`, '_self');
|
||||
window.open(`#/timeseriesexplorer${url}`, '_self');
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
|
@ -67,15 +67,6 @@ export class JobsListView extends Component {
|
|||
if (this.props.isManagementTable === true) {
|
||||
this.refreshJobSummaryList(true);
|
||||
} else {
|
||||
// The advanced job wizard is still angularjs based and triggers
|
||||
// broadcast events which it expects the jobs list to be subscribed to.
|
||||
this.props.angularWrapperScope.$on('jobsUpdated', () => {
|
||||
this.refreshJobSummaryList(true);
|
||||
});
|
||||
this.props.angularWrapperScope.$on('openCreateWatchWindow', (e, job) => {
|
||||
this.showCreateWatchFlyout(job.job_id);
|
||||
});
|
||||
|
||||
timefilter.disableTimeRangeSelector();
|
||||
timefilter.enableAutoRefreshSelector();
|
||||
|
||||
|
|
|
@ -1,59 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
|
||||
import ReactDOM from 'react-dom';
|
||||
import React from 'react';
|
||||
|
||||
import { uiModules } from 'ui/modules';
|
||||
const module = uiModules.get('apps/ml', ['react']);
|
||||
|
||||
import { loadIndexPatterns } from '../../util/index_utils';
|
||||
import { checkFullLicense } from '../../license/check_license';
|
||||
import { checkGetJobsPrivilege } from '../../privilege/check_privilege';
|
||||
import { getMlNodeCount } from '../../ml_nodes_check/check_ml_nodes';
|
||||
import { getJobManagementBreadcrumbs } from '../../jobs/breadcrumbs';
|
||||
import { loadMlServerInfo } from '../../services/ml_server_info';
|
||||
|
||||
import uiRoutes from 'ui/routes';
|
||||
|
||||
const template = `<jobs-page data-test-subj="mlPageJobManagement" />`;
|
||||
|
||||
uiRoutes
|
||||
.when('/jobs/?', {
|
||||
template,
|
||||
k7Breadcrumbs: getJobManagementBreadcrumbs,
|
||||
resolve: {
|
||||
CheckLicense: checkFullLicense,
|
||||
indexPatterns: loadIndexPatterns,
|
||||
privileges: checkGetJobsPrivilege,
|
||||
mlNodeCount: getMlNodeCount,
|
||||
loadMlServerInfo,
|
||||
}
|
||||
});
|
||||
|
||||
import { JobsPage } from './jobs';
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
|
||||
module.directive('jobsPage', function () {
|
||||
return {
|
||||
scope: {},
|
||||
restrict: 'E',
|
||||
link: (scope, element) => {
|
||||
ReactDOM.render(
|
||||
<I18nContext>
|
||||
<JobsPage angularWrapperScope={scope} />
|
||||
</I18nContext>,
|
||||
element[0]
|
||||
);
|
||||
|
||||
element.on('$destroy', () => {
|
||||
ReactDOM.unmountComponentAtNode(element[0]);
|
||||
scope.$destroy();
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
|
@ -4,7 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
import './jobs_list';
|
||||
import './new_job';
|
||||
export { JobsPage } from './jobs';
|
|
@ -4,15 +4,18 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { FC } from 'react';
|
||||
|
||||
import { NavigationMenu } from '../../components/navigation_menu';
|
||||
|
||||
// @ts-ignore
|
||||
import { JobsListView } from './components/jobs_list_view';
|
||||
|
||||
export const JobsPage = (props) => (
|
||||
<>
|
||||
<NavigationMenu tabId="jobs" />
|
||||
<JobsListView {...props} />
|
||||
</>
|
||||
);
|
||||
export const JobsPage: FC<{ props?: any }> = props => {
|
||||
return (
|
||||
<div data-test-subj="mlPageJobManagement">
|
||||
<NavigationMenu tabId="jobs" />
|
||||
<JobsListView {...props} />
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -4,14 +4,14 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { SavedSearch } from 'src/legacy/core_plugins/kibana/public/discover/types';
|
||||
import { IndexPattern } from 'ui/index_patterns';
|
||||
import { SavedSearchSavedObject } from '../../../../../../common/types/kibana';
|
||||
|
||||
import { JobCreator } from './job_creator';
|
||||
import { Field, Aggregation, SplitField } from '../../../../../../common/types/fields';
|
||||
import { Job, Datafeed, Detector, CustomRule } from './configs';
|
||||
import { createBasicDetector } from './util/default_configs';
|
||||
import { JOB_TYPE } from './util/constants';
|
||||
import { JOB_TYPE } from '../../../../../../common/constants/new_job';
|
||||
import { getRichDetectors } from './util/general';
|
||||
import { isValidJson } from '../../../../../../common/util/validation_utils';
|
||||
import { ml } from '../../../../services/ml_api_service';
|
||||
|
@ -32,7 +32,11 @@ export class AdvancedJobCreator extends JobCreator {
|
|||
private _richDetectors: RichDetector[] = [];
|
||||
private _queryString: string;
|
||||
|
||||
constructor(indexPattern: IndexPattern, savedSearch: SavedSearch, query: object) {
|
||||
constructor(
|
||||
indexPattern: IndexPattern,
|
||||
savedSearch: SavedSearchSavedObject | null,
|
||||
query: object
|
||||
) {
|
||||
super(indexPattern, savedSearch, query);
|
||||
|
||||
this._queryString = JSON.stringify(this._datafeed_config.query);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import { UrlConfig } from '../../../../../../../common/types/custom_urls';
|
||||
import { CREATED_BY_LABEL } from '../util/constants';
|
||||
import { CREATED_BY_LABEL } from '../../../../../../../common/constants/new_job';
|
||||
|
||||
export type JobId = string;
|
||||
export type BucketSpan = string;
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { SavedSearch } from 'src/legacy/core_plugins/kibana/public/discover/types';
|
||||
import { IndexPattern } from 'ui/index_patterns';
|
||||
import { SavedSearchSavedObject } from '../../../../../../common/types/kibana';
|
||||
import { UrlConfig } from '../../../../../../common/types/custom_urls';
|
||||
import { IndexPatternTitle } from '../../../../../../common/types/kibana';
|
||||
import { ML_JOB_AGGREGATION } from '../../../../../../common/constants/aggregation_types';
|
||||
|
@ -15,7 +15,11 @@ import { Aggregation, Field } from '../../../../../../common/types/fields';
|
|||
import { createEmptyJob, createEmptyDatafeed } from './util/default_configs';
|
||||
import { mlJobService } from '../../../../services/job_service';
|
||||
import { JobRunner, ProgressSubscriber } from '../job_runner';
|
||||
import { JOB_TYPE, CREATED_BY_LABEL, SHARED_RESULTS_INDEX_NAME } from './util/constants';
|
||||
import {
|
||||
JOB_TYPE,
|
||||
CREATED_BY_LABEL,
|
||||
SHARED_RESULTS_INDEX_NAME,
|
||||
} from '../../../../../../common/constants/new_job';
|
||||
import { isSparseDataJob } from './util/general';
|
||||
import { parseInterval } from '../../../../../../common/util/parse_interval';
|
||||
import { Calendar } from '../../../../../../common/types/calendars';
|
||||
|
@ -24,7 +28,7 @@ import { mlCalendarService } from '../../../../services/calendar_service';
|
|||
export class JobCreator {
|
||||
protected _type: JOB_TYPE = JOB_TYPE.SINGLE_METRIC;
|
||||
protected _indexPattern: IndexPattern;
|
||||
protected _savedSearch: SavedSearch;
|
||||
protected _savedSearch: SavedSearchSavedObject | null;
|
||||
protected _indexPatternTitle: IndexPatternTitle = '';
|
||||
protected _job_config: Job;
|
||||
protected _calendars: Calendar[];
|
||||
|
@ -44,7 +48,11 @@ export class JobCreator {
|
|||
stop: boolean;
|
||||
} = { stop: false };
|
||||
|
||||
constructor(indexPattern: IndexPattern, savedSearch: SavedSearch, query: object) {
|
||||
constructor(
|
||||
indexPattern: IndexPattern,
|
||||
savedSearch: SavedSearchSavedObject | null,
|
||||
query: object
|
||||
) {
|
||||
this._indexPattern = indexPattern;
|
||||
this._savedSearch = savedSearch;
|
||||
this._indexPatternTitle = indexPattern.title;
|
||||
|
|
|
@ -4,18 +4,18 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { SavedSearch } from 'src/legacy/core_plugins/kibana/public/discover/types';
|
||||
import { IndexPattern } from 'ui/index_patterns';
|
||||
import { SavedSearchSavedObject } from '../../../../../../common/types/kibana';
|
||||
import { SingleMetricJobCreator } from './single_metric_job_creator';
|
||||
import { MultiMetricJobCreator } from './multi_metric_job_creator';
|
||||
import { PopulationJobCreator } from './population_job_creator';
|
||||
import { AdvancedJobCreator } from './advanced_job_creator';
|
||||
|
||||
import { JOB_TYPE } from './util/constants';
|
||||
import { JOB_TYPE } from '../../../../../../common/constants/new_job';
|
||||
|
||||
export const jobCreatorFactory = (jobType: JOB_TYPE) => (
|
||||
indexPattern: IndexPattern,
|
||||
savedSearch: SavedSearch,
|
||||
savedSearch: SavedSearchSavedObject | null,
|
||||
query: object
|
||||
) => {
|
||||
let jc;
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { SavedSearch } from 'src/legacy/core_plugins/kibana/public/discover/types';
|
||||
import { IndexPattern } from 'ui/index_patterns';
|
||||
import { SavedSearchSavedObject } from '../../../../../../common/types/kibana';
|
||||
import { JobCreator } from './job_creator';
|
||||
import {
|
||||
Field,
|
||||
|
@ -15,7 +15,11 @@ import {
|
|||
} from '../../../../../../common/types/fields';
|
||||
import { Job, Datafeed, Detector } from './configs';
|
||||
import { createBasicDetector } from './util/default_configs';
|
||||
import { JOB_TYPE, CREATED_BY_LABEL, DEFAULT_MODEL_MEMORY_LIMIT } from './util/constants';
|
||||
import {
|
||||
JOB_TYPE,
|
||||
CREATED_BY_LABEL,
|
||||
DEFAULT_MODEL_MEMORY_LIMIT,
|
||||
} from '../../../../../../common/constants/new_job';
|
||||
import { ml } from '../../../../services/ml_api_service';
|
||||
import { getRichDetectors } from './util/general';
|
||||
|
||||
|
@ -26,7 +30,11 @@ export class MultiMetricJobCreator extends JobCreator {
|
|||
private _lastEstimatedModelMemoryLimit = DEFAULT_MODEL_MEMORY_LIMIT;
|
||||
protected _type: JOB_TYPE = JOB_TYPE.MULTI_METRIC;
|
||||
|
||||
constructor(indexPattern: IndexPattern, savedSearch: SavedSearch, query: object) {
|
||||
constructor(
|
||||
indexPattern: IndexPattern,
|
||||
savedSearch: SavedSearchSavedObject | null,
|
||||
query: object
|
||||
) {
|
||||
super(indexPattern, savedSearch, query);
|
||||
this.createdBy = CREATED_BY_LABEL.MULTI_METRIC;
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { SavedSearch } from 'src/legacy/core_plugins/kibana/public/discover/types';
|
||||
import { IndexPattern } from 'ui/index_patterns';
|
||||
import { SavedSearchSavedObject } from '../../../../../../common/types/kibana';
|
||||
import { JobCreator } from './job_creator';
|
||||
import {
|
||||
Field,
|
||||
|
@ -15,7 +15,7 @@ import {
|
|||
} from '../../../../../../common/types/fields';
|
||||
import { Job, Datafeed, Detector } from './configs';
|
||||
import { createBasicDetector } from './util/default_configs';
|
||||
import { JOB_TYPE, CREATED_BY_LABEL } from './util/constants';
|
||||
import { JOB_TYPE, CREATED_BY_LABEL } from '../../../../../../common/constants/new_job';
|
||||
import { getRichDetectors } from './util/general';
|
||||
|
||||
export class PopulationJobCreator extends JobCreator {
|
||||
|
@ -25,7 +25,11 @@ export class PopulationJobCreator extends JobCreator {
|
|||
private _byFields: SplitField[] = [];
|
||||
protected _type: JOB_TYPE = JOB_TYPE.POPULATION;
|
||||
|
||||
constructor(indexPattern: IndexPattern, savedSearch: SavedSearch, query: object) {
|
||||
constructor(
|
||||
indexPattern: IndexPattern,
|
||||
savedSearch: SavedSearchSavedObject | null,
|
||||
query: object
|
||||
) {
|
||||
super(indexPattern, savedSearch, query);
|
||||
this.createdBy = CREATED_BY_LABEL.POPULATION;
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { SavedSearch } from 'src/legacy/core_plugins/kibana/public/discover/types';
|
||||
import { IndexPattern } from 'ui/index_patterns';
|
||||
import { SavedSearchSavedObject } from '../../../../../../common/types/kibana';
|
||||
import { parseInterval } from '../../../../../../common/util/parse_interval';
|
||||
import { JobCreator } from './job_creator';
|
||||
import { Field, Aggregation, AggFieldPair } from '../../../../../../common/types/fields';
|
||||
|
@ -15,13 +15,17 @@ import {
|
|||
ML_JOB_AGGREGATION,
|
||||
ES_AGGREGATION,
|
||||
} from '../../../../../../common/constants/aggregation_types';
|
||||
import { JOB_TYPE, CREATED_BY_LABEL } from './util/constants';
|
||||
import { JOB_TYPE, CREATED_BY_LABEL } from '../../../../../../common/constants/new_job';
|
||||
import { getRichDetectors } from './util/general';
|
||||
|
||||
export class SingleMetricJobCreator extends JobCreator {
|
||||
protected _type: JOB_TYPE = JOB_TYPE.SINGLE_METRIC;
|
||||
|
||||
constructor(indexPattern: IndexPattern, savedSearch: SavedSearch, query: object) {
|
||||
constructor(
|
||||
indexPattern: IndexPattern,
|
||||
savedSearch: SavedSearchSavedObject | null,
|
||||
query: object
|
||||
) {
|
||||
super(indexPattern, savedSearch, query);
|
||||
this.createdBy = CREATED_BY_LABEL.SINGLE_METRIC;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import { SingleMetricJobCreator } from './single_metric_job_creator';
|
|||
import { MultiMetricJobCreator } from './multi_metric_job_creator';
|
||||
import { PopulationJobCreator } from './population_job_creator';
|
||||
import { AdvancedJobCreator } from './advanced_job_creator';
|
||||
import { JOB_TYPE } from './util/constants';
|
||||
import { JOB_TYPE } from '../../../../../../common/constants/new_job';
|
||||
|
||||
export type JobCreatorType =
|
||||
| SingleMetricJobCreator
|
||||
|
|
|
@ -19,7 +19,7 @@ import {
|
|||
} from '../../../../../../../common/types/fields';
|
||||
import { mlJobService } from '../../../../../services/job_service';
|
||||
import { JobCreatorType, isMultiMetricJobCreator, isPopulationJobCreator } from '../index';
|
||||
import { CREATED_BY_LABEL, JOB_TYPE } from './constants';
|
||||
import { CREATED_BY_LABEL, JOB_TYPE } from '../../../../../../../common/constants/new_job';
|
||||
|
||||
const getFieldByIdFactory = (scriptFields: Field[]) => (id: string) => {
|
||||
let field = newJobCapsService.getFieldById(id);
|
||||
|
|
|
@ -12,8 +12,8 @@ import { getSeverityType } from '../../../../../../common/util/anomaly_utils';
|
|||
import { parseInterval } from '../../../../../../common/util/parse_interval';
|
||||
import { ANOMALY_SEVERITY } from '../../../../../../common/constants/anomalies';
|
||||
import { getScoresByRecord } from './searches';
|
||||
import { JOB_TYPE } from '../job_creator/util/constants';
|
||||
import { ChartLoader } from '../chart_loader';
|
||||
import { JOB_TYPE } from '../../../../../../common/constants/new_job';
|
||||
import { ES_AGGREGATION } from '../../../../../../common/constants/aggregation_types';
|
||||
|
||||
export interface Results {
|
||||
|
|
|
@ -1,14 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import './pages/new_job/route';
|
||||
import './pages/new_job/directive';
|
||||
import './pages/job_type/route';
|
||||
import './pages/job_type/directive';
|
||||
import './pages/index_or_search/route';
|
||||
import './pages/index_or_search/directive';
|
||||
import './recognize/route';
|
||||
import './recognize/directive';
|
|
@ -9,7 +9,7 @@ import { EuiFieldText } from '@elastic/eui';
|
|||
import { JobCreatorContext } from '../../../job_creator_context';
|
||||
import { Description } from './description';
|
||||
import { useStringifiedValue } from '../hooks';
|
||||
import { DEFAULT_QUERY_DELAY } from '../../../../../common/job_creator/util/constants';
|
||||
import { DEFAULT_QUERY_DELAY } from '../../../../../../../../../common/constants/new_job';
|
||||
|
||||
export const QueryDelayInput: FC = () => {
|
||||
const { jobCreator, jobCreatorUpdate, jobValidator, jobValidatorUpdated } = useContext(
|
||||
|
|
|
@ -17,7 +17,7 @@ import { ModelPlotSwitch } from './components/model_plot';
|
|||
import { DedicatedIndexSwitch } from './components/dedicated_index';
|
||||
import { ModelMemoryLimitInput } from '../../../common/model_memory_limit';
|
||||
import { JobCreatorContext } from '../../../job_creator_context';
|
||||
import { JOB_TYPE } from '../../../../../common/job_creator/util/constants';
|
||||
import { JOB_TYPE } from '../../../../../../../../../common/constants/new_job';
|
||||
|
||||
const ButtonContent = i18n.translate(
|
||||
'xpack.ml.newJob.wizard.jobDetailsStep.advancedSectionButton',
|
||||
|
|
|
@ -11,7 +11,7 @@ import { AggFieldPair, SplitField } from '../../../../../../../../../common/type
|
|||
import { ChartSettings } from '../../../charts/common/settings';
|
||||
import { LineChartData } from '../../../../../common/chart_loader';
|
||||
import { ModelItem, Anomaly } from '../../../../../common/results_loader';
|
||||
import { JOB_TYPE } from '../../../../../common/job_creator/util/constants';
|
||||
import { JOB_TYPE } from '../../../../../../../../../common/constants/new_job';
|
||||
import { SplitCards, useAnimateSplit } from '../split_cards';
|
||||
import { DetectorTitle } from '../detector_title';
|
||||
import { AnomalyChart, CHART_TYPE } from '../../../charts/anomaly_chart';
|
||||
|
|
|
@ -11,7 +11,7 @@ import { AggFieldPair, SplitField } from '../../../../../../../../../common/type
|
|||
import { ChartSettings } from '../../../charts/common/settings';
|
||||
import { LineChartData } from '../../../../../common/chart_loader';
|
||||
import { ModelItem, Anomaly } from '../../../../../common/results_loader';
|
||||
import { JOB_TYPE } from '../../../../../common/job_creator/util/constants';
|
||||
import { JOB_TYPE } from '../../../../../../../../../common/constants/new_job';
|
||||
import { SplitCards, useAnimateSplit } from '../split_cards';
|
||||
import { DetectorTitle } from '../detector_title';
|
||||
import { ByFieldSelector } from '../split_field';
|
||||
|
|
|
@ -9,7 +9,7 @@ import { FormattedMessage } from '@kbn/i18n/react';
|
|||
import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiHorizontalRule, EuiSpacer } from '@elastic/eui';
|
||||
|
||||
import { SplitField } from '../../../../../../../../../common/types/fields';
|
||||
import { JOB_TYPE } from '../../../../../common/job_creator/util/constants';
|
||||
import { JOB_TYPE } from '../../../../../../../../../common/constants/new_job';
|
||||
|
||||
interface Props {
|
||||
fieldValues: string[];
|
||||
|
|
|
@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n';
|
|||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { EuiDescribedFormGroup, EuiFormRow } from '@elastic/eui';
|
||||
|
||||
import { JOB_TYPE } from '../../../../../common/job_creator/util/constants';
|
||||
import { JOB_TYPE } from '../../../../../../../../../common/constants/new_job';
|
||||
|
||||
interface Props {
|
||||
jobType: JOB_TYPE;
|
||||
|
|
|
@ -10,7 +10,7 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
|||
import { JobCreatorContext } from '../job_creator_context';
|
||||
import { WizardNav } from '../wizard_nav';
|
||||
import { WIZARD_STEPS, StepProps } from '../step_types';
|
||||
import { JOB_TYPE } from '../../../common/job_creator/util/constants';
|
||||
import { JOB_TYPE } from '../../../../../../../common/constants/new_job';
|
||||
import { SingleMetricView } from './components/single_metric_view';
|
||||
import { MultiMetricView } from './components/multi_metric_view';
|
||||
import { PopulationView } from './components/population_view';
|
||||
|
|
|
@ -10,7 +10,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiDescriptionList, EuiFormRow } from '@elas
|
|||
import { JobCreatorContext } from '../../../job_creator_context';
|
||||
import { MLJobEditor } from '../../../../../../jobs_list/components/ml_job_editor';
|
||||
import { calculateDatafeedFrequencyDefaultSeconds } from '../../../../../../../../../common/util/job_utils';
|
||||
import { DEFAULT_QUERY_DELAY } from '../../../../../common/job_creator/util/constants';
|
||||
import { DEFAULT_QUERY_DELAY } from '../../../../../../../../../common/constants/new_job';
|
||||
import { getNewJobDefaults } from '../../../../../../../services/ml_server_info';
|
||||
import { ListItems, defaultLabel, Italic } from '../common';
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import React, { Fragment, FC, useContext } from 'react';
|
||||
import { JobCreatorContext } from '../../../job_creator_context';
|
||||
import { JOB_TYPE } from '../../../../../common/job_creator/util/constants';
|
||||
import { JOB_TYPE } from '../../../../../../../../../common/constants/new_job';
|
||||
import { SingleMetricView } from '../../../pick_fields_step/components/single_metric_view';
|
||||
import { MultiMetricView } from '../../../pick_fields_step/components/multi_metric_view';
|
||||
import { PopulationView } from '../../../pick_fields_step/components/population_view';
|
||||
|
|
|
@ -23,7 +23,7 @@ import { JobRunner } from '../../../common/job_runner';
|
|||
import { mlJobService } from '../../../../../services/job_service';
|
||||
import { JsonEditorFlyout, EDITOR_MODE } from '../common/json_editor_flyout';
|
||||
import { DatafeedPreviewFlyout } from '../common/datafeed_preview_flyout';
|
||||
import { JOB_TYPE } from '../../../common/job_creator/util/constants';
|
||||
import { JOB_TYPE } from '../../../../../../../common/constants/new_job';
|
||||
import { isSingleMetricJobCreator, isAdvancedJobCreator } from '../../../common/job_creator';
|
||||
import { JobDetails } from './components/job_details';
|
||||
import { DatafeedDetails } from './components/datafeed_details';
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
*/
|
||||
|
||||
import React, { FC, Fragment, useContext, useEffect, useState } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui';
|
||||
|
||||
import { timefilter } from 'ui/timefilter';
|
||||
|
@ -16,7 +18,7 @@ import { useKibanaContext } from '../../../../../contexts/kibana';
|
|||
import { FullTimeRangeSelector } from '../../../../../components/full_time_range_selector';
|
||||
import { EventRateChart } from '../charts/event_rate_chart';
|
||||
import { LineChartPoint } from '../../../common/chart_loader';
|
||||
import { JOB_TYPE } from '../../../common/job_creator/util/constants';
|
||||
import { JOB_TYPE } from '../../../../../../../common/constants/new_job';
|
||||
import { GetTimeFieldRangeResponse } from '../../../../../services/ml_api_service';
|
||||
import { TimeRangePicker, TimeRange } from '../../../common/components';
|
||||
|
||||
|
@ -78,10 +80,18 @@ export const TimeRangeStep: FC<StepProps> = ({ setCurrentStep, isCurrentStep })
|
|||
}, [jobCreatorUpdated]);
|
||||
|
||||
function fullTimeRangeCallback(range: GetTimeFieldRangeResponse) {
|
||||
setTimeRange({
|
||||
start: range.start.epoch,
|
||||
end: range.end.epoch,
|
||||
});
|
||||
if (range.start.epoch !== null && range.end.epoch !== null) {
|
||||
setTimeRange({
|
||||
start: range.start.epoch,
|
||||
end: range.end.epoch,
|
||||
});
|
||||
} else {
|
||||
toastNotifications.addDanger(
|
||||
i18n.translate('xpack.ml.newJob.wizard.timeRangeStep.fullTimeRangeError', {
|
||||
defaultMessage: 'An error occurred obtaining the time range for the index',
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -10,7 +10,7 @@ import { WIZARD_STEPS, StepProps } from '../step_types';
|
|||
import { JobCreatorContext } from '../job_creator_context';
|
||||
import { mlJobService } from '../../../../../services/job_service';
|
||||
import { ValidateJob } from '../../../../../components/validate_job';
|
||||
import { JOB_TYPE } from '../../../common/job_creator/util/constants';
|
||||
import { JOB_TYPE } from '../../../../../../../common/constants/new_job';
|
||||
|
||||
const idFilterList = [
|
||||
'job_id_valid',
|
||||
|
|
|
@ -1,45 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import ngMock from 'ng_mock';
|
||||
import expect from '@kbn/expect';
|
||||
import sinon from 'sinon';
|
||||
|
||||
// Import this way to be able to stub/mock functions later on in the tests using sinon.
|
||||
import * as indexUtils from '../../../../../util/index_utils';
|
||||
|
||||
describe('ML - Index or Saved Search selection directive', () => {
|
||||
let $scope;
|
||||
let $compile;
|
||||
let $element;
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
beforeEach(() => {
|
||||
ngMock.inject(function ($injector) {
|
||||
$compile = $injector.get('$compile');
|
||||
const $rootScope = $injector.get('$rootScope');
|
||||
$scope = $rootScope.$new();
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
$scope.$destroy();
|
||||
});
|
||||
|
||||
it('Initialize Index or Saved Search selection directive', done => {
|
||||
sinon.stub(indexUtils, 'timeBasedIndexCheck').callsFake(() => false);
|
||||
ngMock.inject(function () {
|
||||
expect(() => {
|
||||
$element = $compile('<ml-index-or-search />')($scope);
|
||||
}).to.not.throwError();
|
||||
|
||||
// directive has scope: false
|
||||
const scope = $element.isolateScope();
|
||||
expect(scope).to.eql(undefined);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,42 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
// @ts-ignore
|
||||
import { uiModules } from 'ui/modules';
|
||||
const module = uiModules.get('apps/ml', ['react']);
|
||||
import { timefilter } from 'ui/timefilter';
|
||||
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
import { InjectorService } from '../../../../../../common/types/angular';
|
||||
import { Page } from './page';
|
||||
|
||||
module.directive('mlIndexOrSearch', ($injector: InjectorService) => {
|
||||
return {
|
||||
scope: {},
|
||||
restrict: 'E',
|
||||
link: async (scope: ng.IScope, element: ng.IAugmentedJQuery) => {
|
||||
// remove time picker from top of page
|
||||
timefilter.disableTimeRangeSelector();
|
||||
timefilter.disableAutoRefreshSelector();
|
||||
|
||||
const $route = $injector.get<any>('$route');
|
||||
const { nextStepPath } = $route.current.locals;
|
||||
|
||||
ReactDOM.render(
|
||||
<I18nContext>{React.createElement(Page, { nextStepPath })}</I18nContext>,
|
||||
element[0]
|
||||
);
|
||||
|
||||
element.on('$destroy', () => {
|
||||
ReactDOM.unmountComponentAtNode(element[0]);
|
||||
scope.$destroy();
|
||||
});
|
||||
},
|
||||
};
|
||||
});
|
|
@ -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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { Page } from './page';
|
||||
export { preConfiguredJobRedirect } from './preconfigured_job_redirect';
|
|
@ -4,16 +4,17 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { IndexPatternsContract } from '../../../../../../../../../../src/plugins/data/public';
|
||||
import { mlJobService } from '../../../../services/job_service';
|
||||
import { loadIndexPatterns, getIndexPatternIdFromName } from '../../../../util/index_utils';
|
||||
import { CombinedJob } from '../../common/job_creator/configs';
|
||||
import { CREATED_BY_LABEL, JOB_TYPE } from '../../common/job_creator/util/constants';
|
||||
import { CREATED_BY_LABEL, JOB_TYPE } from '../../../../../../common/constants/new_job';
|
||||
|
||||
export async function preConfiguredJobRedirect() {
|
||||
export async function preConfiguredJobRedirect(indexPatterns: IndexPatternsContract) {
|
||||
const { job } = mlJobService.tempJobCloningObjects;
|
||||
if (job) {
|
||||
try {
|
||||
await loadIndexPatterns();
|
||||
await loadIndexPatterns(indexPatterns);
|
||||
const redirectUrl = getWizardUrlFromCloningJob(job);
|
||||
window.location.href = `#/${redirectUrl}`;
|
||||
return Promise.reject();
|
||||
|
|
|
@ -1,47 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import uiRoutes from 'ui/routes';
|
||||
import { checkMlNodesAvailable } from '../../../../ml_nodes_check';
|
||||
import { preConfiguredJobRedirect } from './preconfigured_job_redirect';
|
||||
import { checkLicenseExpired, checkBasicLicense } from '../../../../license/check_license';
|
||||
import { loadIndexPatterns } from '../../../../util/index_utils';
|
||||
import {
|
||||
checkCreateJobsPrivilege,
|
||||
checkFindFileStructurePrivilege,
|
||||
} from '../../../../privilege/check_privilege';
|
||||
import {
|
||||
getCreateJobBreadcrumbs,
|
||||
getDataVisualizerIndexOrSearchBreadcrumbs,
|
||||
} from '../../../breadcrumbs';
|
||||
|
||||
uiRoutes.when('/jobs/new_job', {
|
||||
redirectTo: '/jobs/new_job/step/index_or_search',
|
||||
});
|
||||
|
||||
uiRoutes.when('/jobs/new_job/step/index_or_search', {
|
||||
template: '<ml-index-or-search />',
|
||||
k7Breadcrumbs: getCreateJobBreadcrumbs,
|
||||
resolve: {
|
||||
CheckLicense: checkLicenseExpired,
|
||||
privileges: checkCreateJobsPrivilege,
|
||||
indexPatterns: loadIndexPatterns,
|
||||
preConfiguredJobRedirect,
|
||||
checkMlNodesAvailable,
|
||||
nextStepPath: () => '#/jobs/new_job/step/job_type',
|
||||
},
|
||||
});
|
||||
|
||||
uiRoutes.when('/datavisualizer_index_select', {
|
||||
template: '<ml-index-or-search />',
|
||||
k7Breadcrumbs: getDataVisualizerIndexOrSearchBreadcrumbs,
|
||||
resolve: {
|
||||
CheckLicense: checkBasicLicense,
|
||||
privileges: checkFindFileStructurePrivilege,
|
||||
indexPatterns: loadIndexPatterns,
|
||||
nextStepPath: () => '#jobs/new_job/datavisualizer',
|
||||
},
|
||||
});
|
|
@ -1,45 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import ngMock from 'ng_mock';
|
||||
import expect from '@kbn/expect';
|
||||
import sinon from 'sinon';
|
||||
|
||||
// Import this way to be able to stub/mock functions later on in the tests using sinon.
|
||||
import * as indexUtils from '../../../../../util/index_utils';
|
||||
|
||||
describe('ML - Job Type Directive', () => {
|
||||
let $scope;
|
||||
let $compile;
|
||||
let $element;
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
beforeEach(() => {
|
||||
ngMock.inject(function ($injector) {
|
||||
$compile = $injector.get('$compile');
|
||||
const $rootScope = $injector.get('$rootScope');
|
||||
$scope = $rootScope.$new();
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
$scope.$destroy();
|
||||
});
|
||||
|
||||
it('Initialize Job Type Directive', done => {
|
||||
sinon.stub(indexUtils, 'timeBasedIndexCheck').callsFake(() => false);
|
||||
ngMock.inject(function () {
|
||||
expect(() => {
|
||||
$element = $compile('<ml-job-type-page />')($scope);
|
||||
}).to.not.throwError();
|
||||
|
||||
// directive has scope: false
|
||||
const scope = $element.isolateScope();
|
||||
expect(scope).to.eql(undefined);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,64 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
// @ts-ignore
|
||||
import { uiModules } from 'ui/modules';
|
||||
const module = uiModules.get('apps/ml', ['react']);
|
||||
import { timefilter } from 'ui/timefilter';
|
||||
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
import { InjectorService } from '../../../../../../common/types/angular';
|
||||
import { createSearchItems } from '../../utils/new_job_utils';
|
||||
import { Page } from './page';
|
||||
|
||||
import { KibanaContext, KibanaConfigTypeFix } from '../../../../contexts/kibana';
|
||||
import { IndexPatternsContract } from '../../../../../../../../../../src/plugins/data/public';
|
||||
|
||||
module.directive('mlJobTypePage', ($injector: InjectorService) => {
|
||||
return {
|
||||
scope: {},
|
||||
restrict: 'E',
|
||||
link: async (scope: ng.IScope, element: ng.IAugmentedJQuery) => {
|
||||
// remove time picker from top of page
|
||||
timefilter.disableTimeRangeSelector();
|
||||
timefilter.disableAutoRefreshSelector();
|
||||
|
||||
const indexPatterns = $injector.get<IndexPatternsContract>('indexPatterns');
|
||||
const kibanaConfig = $injector.get<KibanaConfigTypeFix>('config');
|
||||
const $route = $injector.get<any>('$route');
|
||||
|
||||
const { indexPattern, savedSearch, combinedQuery } = createSearchItems(
|
||||
kibanaConfig,
|
||||
$route.current.locals.indexPattern,
|
||||
$route.current.locals.savedSearch
|
||||
);
|
||||
const kibanaContext = {
|
||||
combinedQuery,
|
||||
currentIndexPattern: indexPattern,
|
||||
currentSavedSearch: savedSearch,
|
||||
indexPatterns,
|
||||
kibanaConfig,
|
||||
};
|
||||
|
||||
ReactDOM.render(
|
||||
<I18nContext>
|
||||
<KibanaContext.Provider value={kibanaContext}>
|
||||
{React.createElement(Page)}
|
||||
</KibanaContext.Provider>
|
||||
</I18nContext>,
|
||||
element[0]
|
||||
);
|
||||
|
||||
element.on('$destroy', () => {
|
||||
ReactDOM.unmountComponentAtNode(element[0]);
|
||||
scope.$destroy();
|
||||
});
|
||||
},
|
||||
};
|
||||
});
|
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { Page } from './page';
|
|
@ -19,6 +19,7 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { useKibanaContext } from '../../../../contexts/kibana';
|
||||
import { isSavedSearchSavedObject } from '../../../../../../common/types/kibana';
|
||||
import { DataRecognizer } from '../../../../components/data_recognizer';
|
||||
import { addItemToRecentlyAccessed } from '../../../../util/recently_accessed';
|
||||
import { timeBasedIndexCheck } from '../../../../util/index_utils';
|
||||
|
@ -32,33 +33,33 @@ export const Page: FC = () => {
|
|||
|
||||
const isTimeBasedIndex = timeBasedIndexCheck(currentIndexPattern);
|
||||
const indexWarningTitle =
|
||||
!isTimeBasedIndex && currentSavedSearch.id === undefined
|
||||
? i18n.translate('xpack.ml.newJob.wizard.jobType.indexPatternNotTimeBasedMessage', {
|
||||
defaultMessage: 'Index pattern {indexPatternTitle} is not time based',
|
||||
values: { indexPatternTitle: currentIndexPattern.title },
|
||||
})
|
||||
: i18n.translate(
|
||||
!isTimeBasedIndex && isSavedSearchSavedObject(currentSavedSearch)
|
||||
? i18n.translate(
|
||||
'xpack.ml.newJob.wizard.jobType.indexPatternFromSavedSearchNotTimeBasedMessage',
|
||||
{
|
||||
defaultMessage:
|
||||
'{savedSearchTitle} uses index pattern {indexPatternTitle} which is not time based',
|
||||
values: {
|
||||
savedSearchTitle: currentSavedSearch.title,
|
||||
savedSearchTitle: currentSavedSearch.attributes.title as string,
|
||||
indexPatternTitle: currentIndexPattern.title,
|
||||
},
|
||||
}
|
||||
);
|
||||
const pageTitleLabel =
|
||||
currentSavedSearch.id !== undefined
|
||||
? i18n.translate('xpack.ml.newJob.wizard.jobType.savedSearchPageTitleLabel', {
|
||||
defaultMessage: 'saved search {savedSearchTitle}',
|
||||
values: { savedSearchTitle: currentSavedSearch.title },
|
||||
})
|
||||
: i18n.translate('xpack.ml.newJob.wizard.jobType.indexPatternPageTitleLabel', {
|
||||
defaultMessage: 'index pattern {indexPatternTitle}',
|
||||
)
|
||||
: i18n.translate('xpack.ml.newJob.wizard.jobType.indexPatternNotTimeBasedMessage', {
|
||||
defaultMessage: 'Index pattern {indexPatternTitle} is not time based',
|
||||
values: { indexPatternTitle: currentIndexPattern.title },
|
||||
});
|
||||
|
||||
const pageTitleLabel = isSavedSearchSavedObject(currentSavedSearch)
|
||||
? i18n.translate('xpack.ml.newJob.wizard.jobType.savedSearchPageTitleLabel', {
|
||||
defaultMessage: 'saved search {savedSearchTitle}',
|
||||
values: { savedSearchTitle: currentSavedSearch.attributes.title as string },
|
||||
})
|
||||
: i18n.translate('xpack.ml.newJob.wizard.jobType.indexPatternPageTitleLabel', {
|
||||
defaultMessage: 'index pattern {indexPatternTitle}',
|
||||
values: { indexPatternTitle: currentIndexPattern.title },
|
||||
});
|
||||
|
||||
const recognizerResults = {
|
||||
count: 0,
|
||||
onChange() {
|
||||
|
@ -67,14 +68,15 @@ export const Page: FC = () => {
|
|||
};
|
||||
|
||||
const getUrl = (basePath: string) => {
|
||||
return currentSavedSearch.id === undefined
|
||||
return !isSavedSearchSavedObject(currentSavedSearch)
|
||||
? `${basePath}?index=${currentIndexPattern.id}`
|
||||
: `${basePath}?savedSearchId=${currentSavedSearch.id}`;
|
||||
};
|
||||
|
||||
const addSelectionToRecentlyAccessed = () => {
|
||||
const title =
|
||||
currentSavedSearch.id === undefined ? currentIndexPattern.title : currentSavedSearch.title;
|
||||
const title = !isSavedSearchSavedObject(currentSavedSearch)
|
||||
? currentIndexPattern.title
|
||||
: (currentSavedSearch.attributes.title as string);
|
||||
const url = getUrl('');
|
||||
addItemToRecentlyAccessed('jobs/new_job/datavisualizer', title, url);
|
||||
|
||||
|
|
|
@ -1,25 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import uiRoutes from 'ui/routes';
|
||||
|
||||
import { checkMlNodesAvailable } from '../../../../ml_nodes_check';
|
||||
import { checkLicenseExpired } from '../../../../license/check_license';
|
||||
import { checkCreateJobsPrivilege } from '../../../../privilege/check_privilege';
|
||||
import { loadCurrentIndexPattern, loadCurrentSavedSearch } from '../../../../util/index_utils';
|
||||
import { getCreateJobBreadcrumbs } from '../../../breadcrumbs';
|
||||
|
||||
uiRoutes.when('/jobs/new_job/step/job_type', {
|
||||
template: '<ml-job-type-page />',
|
||||
k7Breadcrumbs: getCreateJobBreadcrumbs,
|
||||
resolve: {
|
||||
CheckLicense: checkLicenseExpired,
|
||||
privileges: checkCreateJobsPrivilege,
|
||||
indexPattern: loadCurrentIndexPattern,
|
||||
savedSearch: loadCurrentSavedSearch,
|
||||
checkMlNodesAvailable,
|
||||
},
|
||||
});
|
|
@ -1,76 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
// @ts-ignore
|
||||
import { uiModules } from 'ui/modules';
|
||||
const module = uiModules.get('apps/ml', ['react']);
|
||||
import { timefilter } from 'ui/timefilter';
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
import { IndexPatternsContract } from '../../../../../../../../../../src/plugins/data/public';
|
||||
|
||||
import { InjectorService } from '../../../../../../common/types/angular';
|
||||
import { createSearchItems } from '../../utils/new_job_utils';
|
||||
import { Page, PageProps } from './page';
|
||||
import { JOB_TYPE } from '../../common/job_creator/util/constants';
|
||||
|
||||
import { KibanaContext, KibanaConfigTypeFix } from '../../../../contexts/kibana';
|
||||
|
||||
module.directive('mlNewJobPage', ($injector: InjectorService) => {
|
||||
return {
|
||||
scope: {},
|
||||
restrict: 'E',
|
||||
link: async (scope: ng.IScope, element: ng.IAugmentedJQuery) => {
|
||||
timefilter.disableTimeRangeSelector();
|
||||
timefilter.disableAutoRefreshSelector();
|
||||
|
||||
const indexPatterns = $injector.get<IndexPatternsContract>('indexPatterns');
|
||||
const kibanaConfig = $injector.get<KibanaConfigTypeFix>('config');
|
||||
const $route = $injector.get<any>('$route');
|
||||
const existingJobsAndGroups = $route.current.locals.existingJobsAndGroups;
|
||||
|
||||
if ($route.current.locals.jobType === undefined) {
|
||||
return;
|
||||
}
|
||||
const jobType: JOB_TYPE = $route.current.locals.jobType;
|
||||
|
||||
const { indexPattern, savedSearch, combinedQuery } = createSearchItems(
|
||||
kibanaConfig,
|
||||
$route.current.locals.indexPattern,
|
||||
$route.current.locals.savedSearch
|
||||
);
|
||||
|
||||
const kibanaContext = {
|
||||
combinedQuery,
|
||||
currentIndexPattern: indexPattern,
|
||||
currentSavedSearch: savedSearch,
|
||||
indexPatterns,
|
||||
kibanaConfig,
|
||||
};
|
||||
|
||||
const props: PageProps = {
|
||||
existingJobsAndGroups,
|
||||
jobType,
|
||||
};
|
||||
|
||||
ReactDOM.render(
|
||||
<I18nContext>
|
||||
<KibanaContext.Provider value={kibanaContext}>
|
||||
{React.createElement(Page, props)}
|
||||
</KibanaContext.Provider>
|
||||
</I18nContext>,
|
||||
element[0]
|
||||
);
|
||||
|
||||
element.on('$destroy', () => {
|
||||
ReactDOM.unmountComponentAtNode(element[0]);
|
||||
scope.$destroy();
|
||||
});
|
||||
},
|
||||
};
|
||||
});
|
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { Page } from './page';
|
|
@ -16,7 +16,7 @@ import {
|
|||
JOB_TYPE,
|
||||
DEFAULT_MODEL_MEMORY_LIMIT,
|
||||
DEFAULT_BUCKET_SPAN,
|
||||
} from '../../common/job_creator/util/constants';
|
||||
} from '../../../../../../common/constants/new_job';
|
||||
import { ChartLoader } from '../../common/chart_loader';
|
||||
import { ResultsLoader } from '../../common/results_loader';
|
||||
import { JobValidator } from '../../common/job_validator';
|
||||
|
@ -104,7 +104,7 @@ export const Page: FC<PageProps> = ({ existingJobsAndGroups, jobType }) => {
|
|||
jobCreator.modelPlot = true;
|
||||
}
|
||||
|
||||
if (kibanaContext.currentSavedSearch.id !== undefined) {
|
||||
if (kibanaContext.currentSavedSearch !== null) {
|
||||
// Jobs created from saved searches cannot be cloned in the wizard as the
|
||||
// ML job config holds no reference to the saved search ID.
|
||||
jobCreator.createdBy = null;
|
||||
|
|
|
@ -1,65 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import uiRoutes from 'ui/routes';
|
||||
|
||||
import { checkFullLicense } from '../../../../license/check_license';
|
||||
import { checkGetJobsPrivilege } from '../../../../privilege/check_privilege';
|
||||
import { loadCurrentIndexPattern, loadCurrentSavedSearch } from '../../../../util/index_utils';
|
||||
|
||||
import {
|
||||
getCreateSingleMetricJobBreadcrumbs,
|
||||
getCreateMultiMetricJobBreadcrumbs,
|
||||
getCreatePopulationJobBreadcrumbs,
|
||||
getAdvancedJobConfigurationBreadcrumbs,
|
||||
} from '../../../breadcrumbs';
|
||||
|
||||
import { Route } from '../../../../../../common/types/kibana';
|
||||
|
||||
import { loadNewJobCapabilities } from '../../../../services/new_job_capabilities_service';
|
||||
|
||||
import { loadMlServerInfo } from '../../../../services/ml_server_info';
|
||||
|
||||
import { mlJobService } from '../../../../services/job_service';
|
||||
import { JOB_TYPE } from '../../common/job_creator/util/constants';
|
||||
|
||||
const template = `<ml-new-job-page />`;
|
||||
|
||||
const routes: Route[] = [
|
||||
{
|
||||
id: JOB_TYPE.SINGLE_METRIC,
|
||||
k7Breadcrumbs: getCreateSingleMetricJobBreadcrumbs,
|
||||
},
|
||||
{
|
||||
id: JOB_TYPE.MULTI_METRIC,
|
||||
k7Breadcrumbs: getCreateMultiMetricJobBreadcrumbs,
|
||||
},
|
||||
{
|
||||
id: JOB_TYPE.POPULATION,
|
||||
k7Breadcrumbs: getCreatePopulationJobBreadcrumbs,
|
||||
},
|
||||
{
|
||||
id: JOB_TYPE.ADVANCED,
|
||||
k7Breadcrumbs: getAdvancedJobConfigurationBreadcrumbs,
|
||||
},
|
||||
];
|
||||
|
||||
routes.forEach((route: Route) => {
|
||||
uiRoutes.when(`/jobs/new_job/${route.id}`, {
|
||||
template,
|
||||
k7Breadcrumbs: route.k7Breadcrumbs,
|
||||
resolve: {
|
||||
CheckLicense: checkFullLicense,
|
||||
privileges: checkGetJobsPrivilege,
|
||||
indexPattern: loadCurrentIndexPattern,
|
||||
savedSearch: loadCurrentSavedSearch,
|
||||
loadNewJobCapabilities,
|
||||
loadMlServerInfo,
|
||||
existingJobsAndGroups: mlJobService.getJobAndGroupIds,
|
||||
jobType: () => route.id,
|
||||
},
|
||||
});
|
||||
});
|
|
@ -20,7 +20,7 @@ import { JobValidator } from '../../common/job_validator';
|
|||
import { newJobCapsService } from '../../../../services/new_job_capabilities_service';
|
||||
import { WizardSteps } from './wizard_steps';
|
||||
import { WizardHorizontalSteps } from './wizard_horizontal_steps';
|
||||
import { JOB_TYPE } from '../../common/job_creator/util/constants';
|
||||
import { JOB_TYPE } from '../../../../../../common/constants/new_job';
|
||||
|
||||
interface Props {
|
||||
jobCreator: JobCreatorType;
|
||||
|
|
|
@ -10,7 +10,7 @@ import { i18n } from '@kbn/i18n';
|
|||
|
||||
import { EuiStepsHorizontal } from '@elastic/eui';
|
||||
import { WIZARD_STEPS } from '../components/step_types';
|
||||
import { JOB_TYPE } from '../../common/job_creator/util/constants';
|
||||
import { JOB_TYPE } from '../../../../../../common/constants/new_job';
|
||||
|
||||
interface Props {
|
||||
currentStep: WIZARD_STEPS;
|
||||
|
|
|
@ -34,10 +34,10 @@ export const WizardSteps: FC<Props> = ({ currentStep, setCurrentStep }) => {
|
|||
const [additionalExpanded, setAdditionalExpanded] = useState(false);
|
||||
|
||||
function getSummaryStepTitle() {
|
||||
if (kibanaContext.currentSavedSearch.id !== undefined) {
|
||||
if (kibanaContext.currentSavedSearch !== null) {
|
||||
return i18n.translate('xpack.ml.newJob.wizard.stepComponentWrapper.summaryTitleSavedSearch', {
|
||||
defaultMessage: 'New job from saved search {title}',
|
||||
values: { title: kibanaContext.currentSavedSearch.title },
|
||||
values: { title: kibanaContext.currentSavedSearch.attributes.title as string },
|
||||
});
|
||||
} else if (kibanaContext.currentIndexPattern.id !== undefined) {
|
||||
return i18n.translate(
|
||||
|
|
|
@ -1,45 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import ngMock from 'ng_mock';
|
||||
import expect from '@kbn/expect';
|
||||
import sinon from 'sinon';
|
||||
|
||||
// Import this way to be able to stub/mock functions later on in the tests using sinon.
|
||||
import * as indexUtils from '../../../../util/index_utils';
|
||||
|
||||
describe('ML - Recognize job directive', () => {
|
||||
let $scope;
|
||||
let $compile;
|
||||
let $element;
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
beforeEach(() => {
|
||||
ngMock.inject(function ($injector) {
|
||||
$compile = $injector.get('$compile');
|
||||
const $rootScope = $injector.get('$rootScope');
|
||||
$scope = $rootScope.$new();
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
$scope.$destroy();
|
||||
});
|
||||
|
||||
it('Initialize Recognize job directive', done => {
|
||||
sinon.stub(indexUtils, 'timeBasedIndexCheck').callsFake(() => false);
|
||||
ngMock.inject(function () {
|
||||
expect(() => {
|
||||
$element = $compile('<ml-recognize-page />')($scope);
|
||||
}).to.not.throwError();
|
||||
|
||||
// directive has scope: false
|
||||
const scope = $element.isolateScope();
|
||||
expect(scope).to.eql(undefined);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,68 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
// @ts-ignore
|
||||
import { uiModules } from 'ui/modules';
|
||||
const module = uiModules.get('apps/ml', ['react']);
|
||||
import { timefilter } from 'ui/timefilter';
|
||||
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
import { InjectorService } from '../../../../../common/types/angular';
|
||||
|
||||
import { createSearchItems } from '../utils/new_job_utils';
|
||||
import { Page } from './page';
|
||||
|
||||
import { KibanaContext, KibanaConfigTypeFix } from '../../../contexts/kibana';
|
||||
import { IndexPatternsContract } from '../../../../../../../../../src/plugins/data/public';
|
||||
|
||||
module.directive('mlRecognizePage', ($injector: InjectorService) => {
|
||||
return {
|
||||
scope: {},
|
||||
restrict: 'E',
|
||||
link: async (scope: ng.IScope, element: ng.IAugmentedJQuery) => {
|
||||
// remove time picker from top of page
|
||||
timefilter.disableTimeRangeSelector();
|
||||
timefilter.disableAutoRefreshSelector();
|
||||
|
||||
const indexPatterns = $injector.get<IndexPatternsContract>('indexPatterns');
|
||||
const kibanaConfig = $injector.get<KibanaConfigTypeFix>('config');
|
||||
const $route = $injector.get<any>('$route');
|
||||
|
||||
const moduleId = $route.current.params.id;
|
||||
const existingGroupIds: string[] = $route.current.locals.existingJobsAndGroups.groupIds;
|
||||
|
||||
const { indexPattern, savedSearch, combinedQuery } = createSearchItems(
|
||||
kibanaConfig,
|
||||
$route.current.locals.indexPattern,
|
||||
$route.current.locals.savedSearch
|
||||
);
|
||||
const kibanaContext = {
|
||||
combinedQuery,
|
||||
currentIndexPattern: indexPattern,
|
||||
currentSavedSearch: savedSearch,
|
||||
indexPatterns,
|
||||
kibanaConfig,
|
||||
};
|
||||
|
||||
ReactDOM.render(
|
||||
<I18nContext>
|
||||
<KibanaContext.Provider value={kibanaContext}>
|
||||
{React.createElement(Page, { moduleId, existingGroupIds })}
|
||||
</KibanaContext.Provider>
|
||||
</I18nContext>,
|
||||
element[0]
|
||||
);
|
||||
|
||||
element.on('$destroy', () => {
|
||||
ReactDOM.unmountComponentAtNode(element[0]);
|
||||
scope.$destroy();
|
||||
});
|
||||
},
|
||||
};
|
||||
});
|
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { Page } from './page';
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue