diff --git a/x-pack/legacy/plugins/ml/public/_hacks.scss b/x-pack/legacy/plugins/ml/public/_hacks.scss
index b0a8a43d23096d..39740360d8a840 100644
--- a/x-pack/legacy/plugins/ml/public/_hacks.scss
+++ b/x-pack/legacy/plugins/ml/public/_hacks.scss
@@ -1,21 +1,10 @@
.tab-datavisualizer_index_select,
.tab-timeseriesexplorer,
-.tab-explorer,
-.tab-jobs {
+.tab-explorer, {
// Make all page background white until More of the pages use EuiPage to wrap in panel-like components
background-color: $euiColorEmptyShade;
}
-.tab-jobs {
- label {
- display: inline-block;
- }
-
- .validation-error {
- margin-top: $euiSizeXS;
- }
-}
-
// ML specific bootstrap hacks
.button-wrapper {
display: inline;
diff --git a/x-pack/legacy/plugins/ml/public/breadcrumbs.js b/x-pack/legacy/plugins/ml/public/breadcrumbs.ts
similarity index 76%
rename from x-pack/legacy/plugins/ml/public/breadcrumbs.js
rename to x-pack/legacy/plugins/ml/public/breadcrumbs.ts
index bdde734be7c1a3..ba4703d4818ff5 100644
--- a/x-pack/legacy/plugins/ml/public/breadcrumbs.js
+++ b/x-pack/legacy/plugins/ml/public/breadcrumbs.ts
@@ -8,28 +8,28 @@ import { i18n } from '@kbn/i18n';
export const ML_BREADCRUMB = Object.freeze({
text: i18n.translate('xpack.ml.machineLearningBreadcrumbLabel', {
- defaultMessage: 'Machine Learning'
+ defaultMessage: 'Machine Learning',
}),
- href: '#/'
+ href: '#/',
});
export const SETTINGS = Object.freeze({
text: i18n.translate('xpack.ml.settingsBreadcrumbLabel', {
- defaultMessage: 'Settings'
+ defaultMessage: 'Settings',
}),
- href: '#/settings?'
+ href: '#/settings?',
});
export const ANOMALY_DETECTION_BREADCRUMB = Object.freeze({
text: i18n.translate('xpack.ml.anomalyDetectionBreadcrumbLabel', {
- defaultMessage: 'Anomaly Detection'
+ defaultMessage: 'Anomaly Detection',
}),
- href: '#/jobs?'
+ href: '#/jobs?',
});
export const DATA_VISUALIZER_BREADCRUMB = Object.freeze({
text: i18n.translate('xpack.ml.datavisualizerBreadcrumbLabel', {
- defaultMessage: 'Data Visualizer'
+ defaultMessage: 'Data Visualizer',
}),
- href: '#/datavisualizer?'
+ href: '#/datavisualizer?',
});
diff --git a/x-pack/legacy/plugins/ml/public/components/create_job_link_card/create_job_link_card.tsx b/x-pack/legacy/plugins/ml/public/components/create_job_link_card/create_job_link_card.tsx
index 6549df35ba381c..07a924caae7724 100644
--- a/x-pack/legacy/plugins/ml/public/components/create_job_link_card/create_job_link_card.tsx
+++ b/x-pack/legacy/plugins/ml/public/components/create_job_link_card/create_job_link_card.tsx
@@ -4,25 +4,77 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import React, { FC } from 'react';
+import React, { FC, ReactElement } from 'react';
-import { EuiCard, EuiIcon, IconType } from '@elastic/eui';
+import {
+ EuiIcon,
+ IconType,
+ EuiText,
+ EuiTitle,
+ EuiFlexItem,
+ EuiFlexGroup,
+ EuiPanel,
+ EuiLink,
+} from '@elastic/eui';
interface Props {
- iconType: IconType;
- title: string;
- description: string;
- onClick(): void;
+ icon: IconType | ReactElement;
+ iconAreaLabel?: string;
+ title: any;
+ description: any;
+ href?: string;
+ onClick?: () => void;
+ isDisabled?: boolean;
+ 'data-test-subj'?: string;
}
// Component for rendering a card which links to the Create Job page, displaying an
// icon, card title, description and link.
-export const CreateJobLinkCard: FC = ({ iconType, title, description, onClick }) => (
- }
- title={title}
- description={description}
- onClick={onClick}
- />
-);
+export const CreateJobLinkCard: FC = ({
+ icon,
+ iconAreaLabel,
+ title,
+ description,
+ onClick,
+ href,
+ isDisabled,
+ 'data-test-subj': dateTestSubj,
+}) => {
+ const linkHrefAndOnClickProps = {
+ ...(href ? { href } : {}),
+ ...(onClick ? { onClick } : {}),
+ };
+ return (
+
+
+
+
+ {typeof icon === 'string' ? (
+
+ ) : (
+ icon
+ )}
+
+
+
+ {title}
+
+
+ {description}
+
+
+
+
+
+ );
+};
diff --git a/x-pack/legacy/plugins/ml/public/components/data_recognizer/_data_recognizer.scss b/x-pack/legacy/plugins/ml/public/components/data_recognizer/_data_recognizer.scss
deleted file mode 100644
index b915be2ab84536..00000000000000
--- a/x-pack/legacy/plugins/ml/public/components/data_recognizer/_data_recognizer.scss
+++ /dev/null
@@ -1,31 +0,0 @@
-ml-data-recognizer {
- .ml-data-recognizer-logo {
- width: $euiSizeXL;
- }
-}
-
-// Moved here from /home since it's no longer being used there
-.synopsis {
- display: flex;
- flex-grow: 1;
- cursor: pointer;
-
- &:hover,
- &:focus {
- text-decoration: none;
-
- .synopsisTitle {
- text-decoration: underline;
- }
- }
-}
-
-.synopsisTitle {
- font-size: $euiSize;
- font-weight: normal;
- color: $euiColorPrimary;
-}
-
-.synopsisIcon {
- padding-top: $euiSizeS;
-}
diff --git a/x-pack/legacy/plugins/ml/public/components/data_recognizer/_index.scss b/x-pack/legacy/plugins/ml/public/components/data_recognizer/_index.scss
deleted file mode 100644
index 67cc4372ea6225..00000000000000
--- a/x-pack/legacy/plugins/ml/public/components/data_recognizer/_index.scss
+++ /dev/null
@@ -1 +0,0 @@
-@import 'data_recognizer';
\ No newline at end of file
diff --git a/x-pack/legacy/plugins/ml/public/components/data_recognizer/data_recognizer.d.ts b/x-pack/legacy/plugins/ml/public/components/data_recognizer/data_recognizer.d.ts
index c8a7bba2d189f5..e7d191a31e034e 100644
--- a/x-pack/legacy/plugins/ml/public/components/data_recognizer/data_recognizer.d.ts
+++ b/x-pack/legacy/plugins/ml/public/components/data_recognizer/data_recognizer.d.ts
@@ -7,9 +7,14 @@
import { FC } from 'react';
import { IndexPattern } from 'ui/index_patterns';
+import { SavedSearch } from 'src/legacy/core_plugins/kibana/public/discover/types';
declare const DataRecognizer: FC<{
indexPattern: IndexPattern;
- results: any;
- className: string;
+ savedSearch?: SavedSearch;
+ results: {
+ count: number;
+ onChange?: Function;
+ };
+ className?: string;
}>;
diff --git a/x-pack/legacy/plugins/ml/public/components/data_recognizer/data_recognizer.js b/x-pack/legacy/plugins/ml/public/components/data_recognizer/data_recognizer.js
index fd754ee5191046..b303ed9b7f008b 100644
--- a/x-pack/legacy/plugins/ml/public/components/data_recognizer/data_recognizer.js
+++ b/x-pack/legacy/plugins/ml/public/components/data_recognizer/data_recognizer.js
@@ -57,9 +57,9 @@ export class DataRecognizer extends Component {
render() {
return (
-
+ <>
{this.state.results}
-
+ >
);
}
}
diff --git a/x-pack/legacy/plugins/ml/public/components/data_recognizer/recognized_result.js b/x-pack/legacy/plugins/ml/public/components/data_recognizer/recognized_result.js
index 60dc38f2291f89..6f511abf89e310 100644
--- a/x-pack/legacy/plugins/ml/public/components/data_recognizer/recognized_result.js
+++ b/x-pack/legacy/plugins/ml/public/components/data_recognizer/recognized_result.js
@@ -11,7 +11,9 @@ import PropTypes from 'prop-types';
import {
EuiIcon,
+ EuiFlexItem
} from '@elastic/eui';
+import { CreateJobLinkCard } from '../create_job_link_card';
export const RecognizedResult = ({
config,
@@ -28,35 +30,23 @@ export const RecognizedResult = ({
// if a logo is available, use that, otherwise display the id
// the logo should be a base64 encoded image or an eui icon
if(config.logo && config.logo.icon) {
- logo =
;
+ logo = ;
} else if (config.logo && config.logo.src) {
- logo = ;
+ logo =
;
} else {
logo = {config.id}
;
}
return (
-
+
+
+
);
};
diff --git a/x-pack/legacy/plugins/ml/public/datavisualizer/index_based/components/actions_panel/actions_panel.tsx b/x-pack/legacy/plugins/ml/public/datavisualizer/index_based/components/actions_panel/actions_panel.tsx
index 9a291cabf558f9..c8295a1e3d8db3 100644
--- a/x-pack/legacy/plugins/ml/public/datavisualizer/index_based/components/actions_panel/actions_panel.tsx
+++ b/x-pack/legacy/plugins/ml/public/datavisualizer/index_based/components/actions_panel/actions_panel.tsx
@@ -11,7 +11,7 @@ import { i18n } from '@kbn/i18n';
import { IndexPattern } from 'ui/index_patterns';
-import { EuiPanel, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui';
+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';
@@ -63,11 +63,9 @@ export const ActionsPanel: FC = ({ indexPattern }) => {
-
+
+
+
@@ -80,7 +78,7 @@ export const ActionsPanel: FC = ({ indexPattern }) => {
= ({ 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}`}
/>
);
diff --git a/x-pack/legacy/plugins/ml/public/index.scss b/x-pack/legacy/plugins/ml/public/index.scss
index 4cab633d5fa569..a3fefb7b1fac86 100644
--- a/x-pack/legacy/plugins/ml/public/index.scss
+++ b/x-pack/legacy/plugins/ml/public/index.scss
@@ -36,7 +36,6 @@
@import 'components/chart_tooltip/index';
@import 'components/confirm_modal/index';
@import 'components/controls/index';
- @import 'components/data_recognizer/index';
@import 'components/documentation_help_link/index';
@import 'components/entity_cell/index';
@import 'components/field_title_bar/index';
diff --git a/x-pack/legacy/plugins/ml/public/jobs/breadcrumbs.js b/x-pack/legacy/plugins/ml/public/jobs/breadcrumbs.ts
similarity index 55%
rename from x-pack/legacy/plugins/ml/public/jobs/breadcrumbs.js
rename to x-pack/legacy/plugins/ml/public/jobs/breadcrumbs.ts
index d066a524d70aab..35e9c3326a4ccf 100644
--- a/x-pack/legacy/plugins/ml/public/jobs/breadcrumbs.js
+++ b/x-pack/legacy/plugins/ml/public/jobs/breadcrumbs.ts
@@ -4,12 +4,15 @@
* you may not use this file except in compliance with the Elastic License.
*/
-
-import { ML_BREADCRUMB, DATA_VISUALIZER_BREADCRUMB, ANOMALY_DETECTION_BREADCRUMB } from '../breadcrumbs';
import { i18n } from '@kbn/i18n';
+import { Breadcrumb } from 'ui/chrome';
+import {
+ ANOMALY_DETECTION_BREADCRUMB,
+ DATA_VISUALIZER_BREADCRUMB,
+ ML_BREADCRUMB,
+} from '../breadcrumbs';
-
-export function getJobManagementBreadcrumbs() {
+export function getJobManagementBreadcrumbs(): Breadcrumb[] {
// Whilst top level nav menu with tabs remains,
// use root ML breadcrumb.
return [
@@ -17,93 +20,93 @@ export function getJobManagementBreadcrumbs() {
ANOMALY_DETECTION_BREADCRUMB,
{
text: i18n.translate('xpack.ml.anomalyDetection.jobManagementLabel', {
- defaultMessage: 'Job Management'
+ defaultMessage: 'Job Management',
}),
- href: ''
- }
+ href: '',
+ },
];
}
-export function getCreateJobBreadcrumbs() {
+export function getCreateJobBreadcrumbs(): Breadcrumb[] {
return [
ML_BREADCRUMB,
ANOMALY_DETECTION_BREADCRUMB,
{
text: i18n.translate('xpack.ml.jobsBreadcrumbs.createJobLabel', {
- defaultMessage: 'Create job'
+ defaultMessage: 'Create job',
}),
- href: '#/jobs/new_job'
- }
+ href: '#/jobs/new_job',
+ },
];
}
-export function getCreateSingleMetricJobBreadcrumbs() {
+export function getCreateSingleMetricJobBreadcrumbs(): Breadcrumb[] {
return [
...getCreateJobBreadcrumbs(),
{
text: i18n.translate('xpack.ml.jobsBreadcrumbs.singleMetricLabel', {
- defaultMessage: 'Single metric'
+ defaultMessage: 'Single metric',
}),
- href: ''
- }
+ href: '',
+ },
];
}
-export function getCreateMultiMetricJobBreadcrumbs() {
+export function getCreateMultiMetricJobBreadcrumbs(): Breadcrumb[] {
return [
...getCreateJobBreadcrumbs(),
{
text: i18n.translate('xpack.ml.jobsBreadcrumbs.multiMetricLabel', {
- defaultMessage: 'Multi metric'
+ defaultMessage: 'Multi metric',
}),
- href: ''
- }
+ href: '',
+ },
];
}
-export function getCreatePopulationJobBreadcrumbs() {
+export function getCreatePopulationJobBreadcrumbs(): Breadcrumb[] {
return [
...getCreateJobBreadcrumbs(),
{
text: i18n.translate('xpack.ml.jobsBreadcrumbs.populationLabel', {
- defaultMessage: 'Population'
+ defaultMessage: 'Population',
}),
- href: ''
- }
+ href: '',
+ },
];
}
-export function getAdvancedJobConfigurationBreadcrumbs() {
+export function getAdvancedJobConfigurationBreadcrumbs(): Breadcrumb[] {
return [
...getCreateJobBreadcrumbs(),
{
text: i18n.translate('xpack.ml.jobsBreadcrumbs.advancedConfigurationLabel', {
- defaultMessage: 'Advanced configuration'
+ defaultMessage: 'Advanced configuration',
}),
- href: ''
- }
+ href: '',
+ },
];
}
-export function getCreateRecognizerJobBreadcrumbs($routeParams) {
+export function getCreateRecognizerJobBreadcrumbs($routeParams: any): Breadcrumb[] {
return [
...getCreateJobBreadcrumbs(),
{
text: $routeParams.id,
- href: ''
- }
+ href: '',
+ },
];
}
-export function getDataVisualizerIndexOrSearchBreadcrumbs() {
+export function getDataVisualizerIndexOrSearchBreadcrumbs(): Breadcrumb[] {
return [
ML_BREADCRUMB,
DATA_VISUALIZER_BREADCRUMB,
{
text: i18n.translate('xpack.ml.jobsBreadcrumbs.selectIndexOrSearchLabel', {
- defaultMessage: 'Select index or search'
+ defaultMessage: 'Select index or search',
}),
- href: ''
- }
+ href: '',
+ },
];
}
diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job/wizard/_wizard.scss b/x-pack/legacy/plugins/ml/public/jobs/new_job/wizard/_wizard.scss
index 7eadb9a8ce77a0..def24f6d6a7476 100644
--- a/x-pack/legacy/plugins/ml/public/jobs/new_job/wizard/_wizard.scss
+++ b/x-pack/legacy/plugins/ml/public/jobs/new_job/wizard/_wizard.scss
@@ -1,56 +1,3 @@
-.job-type-gallery {
- width: 100%;
- padding-right: $euiSizeS;
- padding-left: $euiSizeS;
- background-color: $euiColorLightestShade;
- flex: 1 0 auto;
-
- .job-types-content {
- max-width: 1200px; // SASSTODO: Proper calc
- margin-right: auto;
- margin-left: auto;
- }
-
- .synopsis {
- display: flex;
- flex-grow: 1;
-
- .synopsisTitle {
- font-size: $euiFontSize;
- font-weight: normal;
- color: $euiColorPrimary;
- }
-
- .synopsisIcon {
- padding-top: $euiSizeS;
- }
- }
-
- .synopsis:hover {
- text-decoration: none;
-
- .synopsisTitle {
- text-decoration: underline;
- }
- }
-
- .euiFlexItem.disabled {
- cursor: not-allowed;
- }
-
- .synopsis.disabled {
- pointer-events: none;
-
- .synopsisTitle {
- color: $euiColorDarkShade;
- }
- }
-
- .index-warning {
- border: $euiBorderThin;
- }
-}
-
.index-or-saved-search-selection {
.kuiBarSection .kuiButtonGroup {
display: none;
diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job/wizard/index.js b/x-pack/legacy/plugins/ml/public/jobs/new_job/wizard/index.js
index c2fb4646306692..61ce488f69014b 100644
--- a/x-pack/legacy/plugins/ml/public/jobs/new_job/wizard/index.js
+++ b/x-pack/legacy/plugins/ml/public/jobs/new_job/wizard/index.js
@@ -9,5 +9,4 @@
// SASS TODO: Import wizard.scss instead
// import 'plugins/kibana/visualize/wizard/wizard.less';
import './steps/index_or_search';
-import './steps/job_type';
import 'plugins/ml/components/data_recognizer';
diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job/wizard/steps/job_type/__tests__/job_type_controller.js b/x-pack/legacy/plugins/ml/public/jobs/new_job/wizard/steps/job_type/__tests__/job_type_controller.js
deleted file mode 100644
index f8fd13b2ae36e1..00000000000000
--- a/x-pack/legacy/plugins/ml/public/jobs/new_job/wizard/steps/job_type/__tests__/job_type_controller.js
+++ /dev/null
@@ -1,46 +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 'plugins/ml/util/index_utils';
-
-describe('ML - Job Type Controller', () => {
- beforeEach(() => {
- ngMock.module('kibana');
- });
-
- it('Initialize Job Type Controller', (done) => {
- const stub = sinon.stub(indexUtils, 'timeBasedIndexCheck').callsFake(() => false);
- ngMock.inject(function ($rootScope, $controller, $route) {
- // Set up the $route current props required for the tests.
- $route.current = {
- locals: {
- indexPattern: {
- id: 'test_id',
- title: 'test_pattern'
- },
- savedSearch: {}
- }
- };
-
- const scope = $rootScope.$new();
-
- expect(() => {
- $controller('MlNewJobStepJobType', { $scope: scope });
- }).to.not.throwError();
-
- expect(scope.indexWarningTitle).to.eql('Index pattern test_pattern is not time based');
- stub.restore();
- done();
- });
- });
-});
diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job/wizard/steps/job_type/index.js b/x-pack/legacy/plugins/ml/public/jobs/new_job/wizard/steps/job_type/index.js
deleted file mode 100644
index 9a9fa7e73b9f1e..00000000000000
--- a/x-pack/legacy/plugins/ml/public/jobs/new_job/wizard/steps/job_type/index.js
+++ /dev/null
@@ -1,9 +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 './job_type_controller';
diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job/wizard/steps/job_type/job_type.html b/x-pack/legacy/plugins/ml/public/jobs/new_job/wizard/steps/job_type/job_type.html
deleted file mode 100644
index 1dc3aea215d93a..00000000000000
--- a/x-pack/legacy/plugins/ml/public/jobs/new_job/wizard/steps/job_type/job_type.html
+++ /dev/null
@@ -1,274 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job/wizard/steps/job_type/job_type_controller.js b/x-pack/legacy/plugins/ml/public/jobs/new_job/wizard/steps/job_type/job_type_controller.js
deleted file mode 100644
index df7768ee9f0c84..00000000000000
--- a/x-pack/legacy/plugins/ml/public/jobs/new_job/wizard/steps/job_type/job_type_controller.js
+++ /dev/null
@@ -1,103 +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.
- */
-
-
-
-/*
- * Controller for the second step in the Create Job wizard, allowing
- * the user to select the type of job they wish to create.
- */
-
-import uiRoutes from 'ui/routes';
-import { i18n } from '@kbn/i18n';
-import { checkLicenseExpired } from 'plugins/ml/license/check_license';
-import { checkCreateJobsPrivilege } from 'plugins/ml/privilege/check_privilege';
-import { getCreateJobBreadcrumbs } from 'plugins/ml/jobs/breadcrumbs';
-import { SearchItemsProvider } from 'plugins/ml/jobs/new_job/utils/new_job_utils';
-import { loadCurrentIndexPattern, loadCurrentSavedSearch, timeBasedIndexCheck } from 'plugins/ml/util/index_utils';
-import { addItemToRecentlyAccessed } from 'plugins/ml/util/recently_accessed';
-import { checkMlNodesAvailable } from 'plugins/ml/ml_nodes_check/check_ml_nodes';
-import template from './job_type.html';
-import { timefilter } from 'ui/timefilter';
-
-uiRoutes
- .when('/jobs/new_job/step/job_type', {
- template,
- k7Breadcrumbs: getCreateJobBreadcrumbs,
- resolve: {
- CheckLicense: checkLicenseExpired,
- privileges: checkCreateJobsPrivilege,
- indexPattern: loadCurrentIndexPattern,
- savedSearch: loadCurrentSavedSearch,
- checkMlNodesAvailable,
- }
- });
-
-
-import { uiModules } from 'ui/modules';
-const module = uiModules.get('apps/ml');
-
-module.controller('MlNewJobStepJobType',
- function ($scope, Private) {
-
- timefilter.disableTimeRangeSelector(); // remove time picker from top of page
- timefilter.disableAutoRefreshSelector(); // remove time picker from top of page
-
- const createSearchItems = Private(SearchItemsProvider);
- const {
- indexPattern,
- savedSearch } = createSearchItems();
-
- // check to see that the index pattern is time based.
- // if it isn't, display a warning and disable all links
- $scope.indexWarningTitle = '';
- $scope.isTimeBasedIndex = timeBasedIndexCheck(indexPattern);
- if ($scope.isTimeBasedIndex === false) {
- $scope.indexWarningTitle = (savedSearch.id === undefined) ?
- i18n.translate('xpack.ml.newJob.wizard.jobType.indexPatternNotTimeBasedMessage', {
- defaultMessage: 'Index pattern {indexPatternTitle} is not time based',
- values: { indexPatternTitle: indexPattern.title }
- })
- : i18n.translate('xpack.ml.newJob.wizard.jobType.indexPatternFromSavedSearchNotTimeBasedMessage', {
- defaultMessage: '{savedSearchTitle} uses index pattern {indexPatternTitle} which is not time based',
- values: {
- savedSearchTitle: savedSearch.title,
- indexPatternTitle: indexPattern.title
- }
- });
- }
-
- $scope.indexPattern = indexPattern;
- $scope.savedSearch = savedSearch;
- $scope.recognizerResults = {
- count: 0,
- onChange() {
- $scope.$applyAsync();
- }
- };
-
- $scope.pageTitleLabel = (savedSearch.id !== undefined) ?
- i18n.translate('xpack.ml.newJob.wizard.jobType.savedSearchPageTitleLabel', {
- defaultMessage: 'saved search {savedSearchTitle}',
- values: { savedSearchTitle: savedSearch.title }
- })
- : i18n.translate('xpack.ml.newJob.wizard.jobType.indexPatternPageTitleLabel', {
- defaultMessage: 'index pattern {indexPatternTitle}',
- values: { indexPatternTitle: indexPattern.title }
- });
-
- $scope.getUrl = function (basePath) {
- return (savedSearch.id === undefined) ? `${basePath}?index=${indexPattern.id}` :
- `${basePath}?savedSearchId=${savedSearch.id}`;
- };
-
- $scope.addSelectionToRecentlyAccessed = function () {
- const title = (savedSearch.id === undefined) ? indexPattern.title : savedSearch.title;
- const url = $scope.getUrl('');
- addItemToRecentlyAccessed('jobs/new_job/datavisualizer', title, url);
- };
-
- });
diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/index.ts
index d3feaf087524c8..2366f2c655000d 100644
--- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/index.ts
+++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/index.ts
@@ -6,3 +6,5 @@
import './pages/new_job/route';
import './pages/new_job/directive';
+import './pages/job_type/route';
+import './pages/job_type/directive';
diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/job_type/__test__/directive.js b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/job_type/__test__/directive.js
new file mode 100644
index 00000000000000..5be526f2eb2c02
--- /dev/null
+++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/job_type/__test__/directive.js
@@ -0,0 +1,45 @@
+/*
+ * 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 'plugins/ml/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('')($scope);
+ }).to.not.throwError();
+
+ // directive has scope: false
+ const scope = $element.isolateScope();
+ expect(scope).to.eql(undefined);
+ done();
+ });
+ });
+});
diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/job_type/directive.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/job_type/directive.tsx
new file mode 100644
index 00000000000000..4ad689a943160c
--- /dev/null
+++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/job_type/directive.tsx
@@ -0,0 +1,65 @@
+/*
+ * 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 { IndexPatterns } from 'ui/index_patterns';
+
+import { I18nContext } from 'ui/i18n';
+import { IPrivate } from 'ui/private';
+import { InjectorService } from '../../../../../common/types/angular';
+
+import { SearchItemsProvider } from '../../../new_job/utils/new_job_utils';
+import { Page } from './page';
+
+import { KibanaContext, KibanaConfigTypeFix } from '../../../../contexts/kibana';
+
+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('indexPatterns');
+ const kbnBaseUrl = $injector.get('kbnBaseUrl');
+ const kibanaConfig = $injector.get('config');
+ const Private = $injector.get('Private');
+
+ const createSearchItems = Private(SearchItemsProvider);
+ const { indexPattern, savedSearch, combinedQuery } = createSearchItems();
+ const kibanaContext = {
+ combinedQuery,
+ currentIndexPattern: indexPattern,
+ currentSavedSearch: savedSearch,
+ indexPatterns,
+ kbnBaseUrl,
+ kibanaConfig,
+ };
+
+ ReactDOM.render(
+
+
+ {React.createElement(Page)}
+
+ ,
+ element[0]
+ );
+
+ element.on('$destroy', () => {
+ ReactDOM.unmountComponentAtNode(element[0]);
+ scope.$destroy();
+ });
+ },
+ };
+});
diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/job_type/page.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/job_type/page.tsx
new file mode 100644
index 00000000000000..4991039ffa2886
--- /dev/null
+++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/job_type/page.tsx
@@ -0,0 +1,308 @@
+/*
+ * 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, useState } from 'react';
+import { i18n } from '@kbn/i18n';
+import {
+ EuiPage,
+ EuiPageBody,
+ EuiTitle,
+ EuiSpacer,
+ EuiCallOut,
+ EuiText,
+ EuiFlexGrid,
+ EuiFlexItem,
+ EuiLink,
+} from '@elastic/eui';
+import { FormattedMessage } from '@kbn/i18n/react';
+import { useKibanaContext } from '../../../../contexts/kibana';
+import { DataRecognizer } from '../../../../components/data_recognizer';
+import { addItemToRecentlyAccessed } from '../../../../util/recently_accessed';
+import { timeBasedIndexCheck } from '../../../../util/index_utils';
+import { CreateJobLinkCard } from '../../../../components/create_job_link_card';
+
+export const Page: FC = () => {
+ const kibanaContext = useKibanaContext();
+ const [recognizerResultsCount, setRecognizerResultsCount] = useState(0);
+
+ const { currentSavedSearch, currentIndexPattern } = kibanaContext;
+
+ 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(
+ 'xpack.ml.newJob.wizard.jobType.indexPatternFromSavedSearchNotTimeBasedMessage',
+ {
+ defaultMessage:
+ '{savedSearchTitle} uses index pattern {indexPatternTitle} which is not time based',
+ values: {
+ savedSearchTitle: currentSavedSearch.title,
+ 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}',
+ values: { indexPatternTitle: currentIndexPattern.title },
+ });
+
+ const recognizerResults = {
+ count: 0,
+ onChange() {
+ setRecognizerResultsCount(recognizerResults.count);
+ },
+ };
+
+ const getUrl = (basePath: string) => {
+ return currentSavedSearch.id === undefined
+ ? `${basePath}?index=${currentIndexPattern.id}`
+ : `${basePath}?savedSearchId=${currentSavedSearch.id}`;
+ };
+
+ const addSelectionToRecentlyAccessed = () => {
+ const title =
+ currentSavedSearch.id === undefined ? currentIndexPattern.title : currentSavedSearch.title;
+ const url = getUrl('');
+ addItemToRecentlyAccessed('jobs/new_job/datavisualizer', title, url);
+
+ window.location.href = getUrl('#jobs/new_job/datavisualizer');
+ };
+
+ const jobTypes = [
+ {
+ href: getUrl('#jobs/new_job/single_metric'),
+ icon: {
+ type: 'createSingleMetricJob',
+ ariaLabel: i18n.translate('xpack.ml.newJob.wizard.jobType.singleMetricAriaLabel', {
+ defaultMessage: 'Single metric job',
+ }),
+ },
+ title: i18n.translate('xpack.ml.newJob.wizard.jobType.singleMetricTitle', {
+ defaultMessage: 'Single metric',
+ }),
+ description: i18n.translate('xpack.ml.newJob.wizard.jobType.singleMetricDescription', {
+ defaultMessage: 'Detect anomalies in a single time series.',
+ }),
+ id: 'mlJobTypeLinkSingleMetricJob',
+ },
+ {
+ href: getUrl('#jobs/new_job/multi_metric'),
+ icon: {
+ type: 'createMultiMetricJob',
+ ariaLabel: i18n.translate('xpack.ml.newJob.wizard.jobType.multiMetricAriaLabel', {
+ defaultMessage: 'Multi metric job',
+ }),
+ },
+ title: i18n.translate('xpack.ml.newJob.wizard.jobType.multiMetricTitle', {
+ defaultMessage: 'Multi metric',
+ }),
+ description: i18n.translate('xpack.ml.newJob.wizard.jobType.multiMetricDescription', {
+ defaultMessage:
+ 'Detect anomalies in multiple metrics by splitting a time series by a categorical field.',
+ }),
+ id: 'mlJobTypeLinkMultiMetricJob',
+ },
+ {
+ href: getUrl('#jobs/new_job/population'),
+ icon: {
+ type: 'createPopulationJob',
+ ariaLabel: i18n.translate('xpack.ml.newJob.wizard.jobType.populationAriaLabel', {
+ defaultMessage: 'Population job',
+ }),
+ },
+ title: i18n.translate('xpack.ml.newJob.wizard.jobType.populationTitle', {
+ defaultMessage: 'Population',
+ }),
+ description: i18n.translate('xpack.ml.newJob.wizard.jobType.populationDescription', {
+ defaultMessage:
+ 'Detect activity that is unusual compared to the behavior of the population.',
+ }),
+ id: 'mlJobTypeLinkPopulationJob',
+ },
+ {
+ href: getUrl('#jobs/new_job/advanced'),
+ icon: {
+ type: 'createAdvancedJob',
+ ariaLabel: i18n.translate('xpack.ml.newJob.wizard.jobType.advancedAriaLabel', {
+ defaultMessage: 'Advanced job',
+ }),
+ },
+ title: i18n.translate('xpack.ml.newJob.wizard.jobType.advancedTitle', {
+ defaultMessage: 'Advanced',
+ }),
+ description: i18n.translate('xpack.ml.newJob.wizard.jobType.advancedDescription', {
+ defaultMessage:
+ 'Use the full range of options to create a job for more advanced use cases.',
+ }),
+ id: 'mlJobTypeLinkAdvancedJob',
+ },
+ ];
+
+ return (
+
+
+
+
+
+
+
+
+
+ {isTimeBasedIndex === false && (
+ <>
+
+
+
+
+
+
+
+
+ >
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {jobTypes.map(({ href, icon, title, description, id }) => (
+
+
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ description={
+
+ }
+ onClick={addSelectionToRecentlyAccessed}
+ href={getUrl('#jobs/new_job/datavisualizer')}
+ />
+
+
+
+
+ );
+};
diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/job_type/route.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/job_type/route.ts
new file mode 100644
index 00000000000000..b61424998705d6
--- /dev/null
+++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/job_type/route.ts
@@ -0,0 +1,27 @@
+/*
+ * 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';
+
+// @ts-ignore
+import { checkMlNodesAvailable } from 'plugins/ml/ml_nodes_check/check_ml_nodes';
+// @ts-ignore
+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: '',
+ k7Breadcrumbs: getCreateJobBreadcrumbs,
+ resolve: {
+ CheckLicense: checkLicenseExpired,
+ privileges: checkCreateJobsPrivilege,
+ indexPattern: loadCurrentIndexPattern,
+ savedSearch: loadCurrentSavedSearch,
+ checkMlNodesAvailable,
+ },
+});
diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/new_job/route.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/new_job/route.ts
index cdca3a810fcdd8..08f05e6884bb35 100644
--- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/new_job/route.ts
+++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/new_job/route.ts
@@ -9,14 +9,12 @@ import uiRoutes from 'ui/routes';
// @ts-ignore
import { checkFullLicense } from '../../../../license/check_license';
import { checkGetJobsPrivilege } from '../../../../privilege/check_privilege';
-// @ts-ignore
import { loadCurrentIndexPattern, loadCurrentSavedSearch } from '../../../../util/index_utils';
import {
getCreateSingleMetricJobBreadcrumbs,
getCreateMultiMetricJobBreadcrumbs,
getCreatePopulationJobBreadcrumbs,
- // @ts-ignore
} from '../../../breadcrumbs';
import { Route } from '../../../../../common/types/kibana';
diff --git a/x-pack/legacy/plugins/ml/public/util/index_utils.js b/x-pack/legacy/plugins/ml/public/util/index_utils.js
deleted file mode 100644
index dfc6a7735616a6..00000000000000
--- a/x-pack/legacy/plugins/ml/public/util/index_utils.js
+++ /dev/null
@@ -1,108 +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 { toastNotifications } from 'ui/notify';
-import { SavedObjectsClientProvider } from 'ui/saved_objects';
-import { i18n } from '@kbn/i18n';
-
-let indexPatternCache = [];
-let fullIndexPatterns = [];
-let currentIndexPattern = null;
-let currentSavedSearch = null;
-
-export let refreshIndexPatterns = null;
-
-export function loadIndexPatterns(Private, indexPatterns) {
- fullIndexPatterns = indexPatterns;
- const savedObjectsClient = Private(SavedObjectsClientProvider);
- return savedObjectsClient.find({
- type: 'index-pattern',
- fields: ['id', 'title', 'type', 'fields'],
- perPage: 10000
- }).then((response) => {
- indexPatternCache = response.savedObjects;
-
- if (refreshIndexPatterns === null) {
- refreshIndexPatterns = () => {
- return new Promise((resolve, reject) => {
- loadIndexPatterns(Private, indexPatterns)
- .then((resp) => {
- resolve(resp);
- })
- .catch((error) => {
- reject(error);
- });
- });
- };
- }
-
- return indexPatternCache;
- });
-}
-
-export function getIndexPatterns() {
- return indexPatternCache;
-}
-
-export function getIndexPatternNames() {
- return indexPatternCache.map(i => (i.attributes && i.attributes.title));
-}
-
-export function getIndexPatternIdFromName(name) {
- for (let j = 0; j < indexPatternCache.length; j++) {
- if (indexPatternCache[j].get('title') === name) {
- return indexPatternCache[j].id;
- }
- }
- return name;
-}
-
-export function loadCurrentIndexPattern(indexPatterns, $route) {
- fullIndexPatterns = indexPatterns;
- currentIndexPattern = fullIndexPatterns.get($route.current.params.index);
- return currentIndexPattern;
-}
-
-export function getIndexPatternById(id) {
- return fullIndexPatterns.get(id);
-}
-
-export function loadCurrentSavedSearch(savedSearches, $route) {
- currentSavedSearch = savedSearches.get($route.current.params.savedSearchId);
- return currentSavedSearch;
-}
-
-export function getCurrentIndexPattern() {
- return currentIndexPattern;
-}
-
-export function getCurrentSavedSearch() {
- return currentSavedSearch;
-}
-
-// returns true if the index passed in is time based
-// an optional flag will trigger the display a notification at the top of the page
-// warning that the index is not time based
-export function timeBasedIndexCheck(indexPattern, showNotification = false) {
- if (indexPattern.isTimeBased() === false) {
- if (showNotification) {
- toastNotifications.addWarning({
- title: i18n.translate('xpack.ml.indexPatternNotBasedOnTimeSeriesNotificationTitle', {
- defaultMessage: 'The index pattern {indexPatternTitle} is not based on a time series',
- values: { indexPatternTitle: indexPattern.title }
- }),
- text: i18n.translate('xpack.ml.indexPatternNotBasedOnTimeSeriesNotificationDescription', {
- defaultMessage: 'Anomaly detection only runs over time-based indices'
- }),
- });
- }
- return false;
- } else {
- return true;
- }
-}
diff --git a/x-pack/legacy/plugins/ml/public/util/index_utils.ts b/x-pack/legacy/plugins/ml/public/util/index_utils.ts
new file mode 100644
index 00000000000000..41dd13555726c4
--- /dev/null
+++ b/x-pack/legacy/plugins/ml/public/util/index_utils.ts
@@ -0,0 +1,110 @@
+/*
+ * 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 { toastNotifications } from 'ui/notify';
+import { i18n } from '@kbn/i18n';
+import { IndexPattern, IndexPatterns } from 'ui/index_patterns';
+import { SavedObjectAttributes, SimpleSavedObject } from 'kibana/public';
+import chrome from 'ui/chrome';
+import { SavedSearchLoader } from '../../../../../../src/legacy/core_plugins/kibana/public/discover/types';
+import { setup as data } from '../../../../../../src/legacy/core_plugins/data/public/legacy';
+
+type IndexPatternSavedObject = SimpleSavedObject;
+
+let indexPatternCache: IndexPatternSavedObject[] = [];
+let fullIndexPatterns: IndexPatterns | null = null;
+
+export let refreshIndexPatterns: (() => Promise) | null = null;
+
+export function loadIndexPatterns() {
+ fullIndexPatterns = data.indexPatterns.indexPatterns;
+ const savedObjectsClient = chrome.getSavedObjectsClient();
+ return savedObjectsClient
+ .find({
+ type: 'index-pattern',
+ fields: ['id', 'title', 'type', 'fields'],
+ perPage: 10000,
+ })
+ .then(response => {
+ indexPatternCache = response.savedObjects;
+ if (refreshIndexPatterns === null) {
+ refreshIndexPatterns = () => {
+ return new Promise((resolve, reject) => {
+ loadIndexPatterns()
+ .then(resp => {
+ resolve(resp);
+ })
+ .catch(error => {
+ reject(error);
+ });
+ });
+ };
+ }
+
+ return indexPatternCache;
+ });
+}
+
+export function getIndexPatterns() {
+ return indexPatternCache;
+}
+
+export function getIndexPatternNames() {
+ return indexPatternCache.map(i => i.attributes && i.attributes.title);
+}
+
+export function getIndexPatternIdFromName(name: string) {
+ for (let j = 0; j < indexPatternCache.length; j++) {
+ if (indexPatternCache[j].get('title') === name) {
+ return indexPatternCache[j].id;
+ }
+ }
+ return name;
+}
+
+export function loadCurrentIndexPattern(indexPatterns: IndexPatterns, $route: Record) {
+ fullIndexPatterns = indexPatterns;
+ return fullIndexPatterns.get($route.current.params.index);
+}
+
+export function getIndexPatternById(id: string): IndexPattern {
+ if (fullIndexPatterns !== null) {
+ return fullIndexPatterns.get(id);
+ } else {
+ throw new Error('Index patterns are not initialized!');
+ }
+}
+
+export function loadCurrentSavedSearch(
+ savedSearches: SavedSearchLoader,
+ $route: Record
+) {
+ return savedSearches.get($route.current.params.savedSearchId);
+}
+
+/**
+ * Returns true if the index passed in is time based
+ * an optional flag will trigger the display a notification at the top of the page
+ * warning that the index is not time based
+ */
+export function timeBasedIndexCheck(indexPattern: IndexPattern, showNotification = false) {
+ if (!indexPattern.isTimeBased()) {
+ if (showNotification) {
+ toastNotifications.addWarning({
+ title: i18n.translate('xpack.ml.indexPatternNotBasedOnTimeSeriesNotificationTitle', {
+ defaultMessage: 'The index pattern {indexPatternTitle} is not based on a time series',
+ values: { indexPatternTitle: indexPattern.title },
+ }),
+ text: i18n.translate('xpack.ml.indexPatternNotBasedOnTimeSeriesNotificationDescription', {
+ defaultMessage: 'Anomaly detection only runs over time-based indices',
+ }),
+ });
+ }
+ return false;
+ } else {
+ return true;
+ }
+}
diff --git a/x-pack/legacy/plugins/ml/public/util/recently_accessed.js b/x-pack/legacy/plugins/ml/public/util/recently_accessed.ts
similarity index 80%
rename from x-pack/legacy/plugins/ml/public/util/recently_accessed.js
rename to x-pack/legacy/plugins/ml/public/util/recently_accessed.ts
index b642be7d1226a1..9a3d3089dff2bf 100644
--- a/x-pack/legacy/plugins/ml/public/util/recently_accessed.js
+++ b/x-pack/legacy/plugins/ml/public/util/recently_accessed.ts
@@ -4,38 +4,36 @@
* you may not use this file except in compliance with the Elastic License.
*/
-
-
// utility functions for managing which links get added to kibana's recently accessed list
import { recentlyAccessed } from 'ui/persisted_log';
import { i18n } from '@kbn/i18n';
-export function addItemToRecentlyAccessed(page, itemId, url) {
+export function addItemToRecentlyAccessed(page: string, itemId: string, url: string) {
let pageLabel = '';
let id = `ml-job-${itemId}`;
switch (page) {
case 'explorer':
pageLabel = i18n.translate('xpack.ml.anomalyExplorerPageLabel', {
- defaultMessage: 'Anomaly Explorer'
+ defaultMessage: 'Anomaly Explorer',
});
break;
case 'timeseriesexplorer':
pageLabel = i18n.translate('xpack.ml.singleMetricViewerPageLabel', {
- defaultMessage: 'Single Metric Viewer'
+ defaultMessage: 'Single Metric Viewer',
});
break;
case 'jobs/new_job/datavisualizer':
pageLabel = i18n.translate('xpack.ml.dataVisualizerPageLabel', {
- defaultMessage: 'Data Visualizer'
+ defaultMessage: 'Data Visualizer',
});
id = `ml-datavisualizer-${itemId}`;
break;
default:
+ // eslint-disable-next-line no-console
console.error('addItemToRecentlyAccessed - No page specified');
return;
- break;
}
url = `ml#/${page}/${url}`;