From dd5f7db7f4179c40cac618100d23f5a8b5bc50e7 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Mon, 18 Nov 2019 16:00:23 +0000 Subject: [PATCH] [ML] Injectables refactor (#50512) (#50910) * [ML] Injectables refactor * removing unrelated files * additional typescript conversion * more typescript conversion * adding some return types * fixing eui errors * typescripting license checks * updated based on review * fixing merge conflict error * converting tests to jest * fixing types --- .../common/util/__tests__/parse_interval.js | 70 --------------- .../ml/common/util/group_color_utils.d.ts | 6 -- ...up_color_utils.js => group_color_utils.ts} | 26 ++++-- .../plugins/ml/common/util/job_utils.d.ts | 2 + .../ml/common/util/parse_interval.test.ts | 34 +++++++ .../{parse_interval.js => parse_interval.ts} | 27 +++--- .../plugins/ml/common/util/string_utils.d.ts | 8 -- .../string_utils.js => string_utils.test.ts} | 19 ++-- .../util/{string_utils.js => string_utils.ts} | 21 +---- .../ml/common/util/validation_utils.d.ts | 7 -- .../ml/common/util/validation_utils.js | 54 ----------- .../ml/common/util/validation_utils.ts | 33 +++++++ x-pack/legacy/plugins/ml/index.ts | 0 .../components/anomalies_table/links_menu.js | 11 +-- .../kibana/__mocks__/kibana_context_value.ts | 1 - .../public/contexts/kibana/kibana_context.ts | 1 - .../contexts/kibana/use_kibana_context.ts | 1 - .../pages/analytics_exploration/directive.tsx | 14 +-- .../pages/analytics_management/directive.tsx | 15 ++-- .../{directive.js => directive.tsx} | 50 +++++++---- .../file_datavisualizer_view.js | 2 +- .../components/import_view/import_view.js | 4 +- .../file_datavisualizer_directive.js | 49 ---------- .../file_datavisualizer_directive.tsx | 75 ++++++++++++++++ .../file_based/{index.js => index.ts} | 1 - .../datavisualizer/index_based/directive.tsx | 14 +-- .../ml/public/explorer/explorer_controller.js | 4 +- .../dedicated_index_switch.tsx | 1 - .../model_plot/model_plot_switch.tsx | 1 - .../sparse_data/sparse_data_switch.tsx | 1 - .../new_job_new/pages/job_type/directive.tsx | 15 ++-- .../new_job_new/pages/new_job/directive.tsx | 14 ++- .../components/job_settings_form.tsx | 1 - .../jobs/new_job_new/recognize/directive.tsx | 13 ++- .../jobs/new_job_new/recognize/resolvers.ts | 10 +-- .../jobs/new_job_new/utils/new_job_utils.ts | 79 ++++++++-------- .../{check_license.js => check_license.tsx} | 73 ++++++--------- .../ml/public/privilege/check_privilege.ts | 18 ++-- ...mat_service.js => field_format_service.ts} | 89 +++++++++---------- .../ml/public/services/job_service.d.ts | 1 + .../{breadcrumbs.js => breadcrumbs.ts} | 46 +++++----- .../edit/{directive.js => directive.tsx} | 21 +++-- .../edit/index.js => calendars/edit/index.ts} | 1 - .../settings/calendars/edit/new_calendar.d.ts | 13 +++ .../calendars/list/calendars_list.d.ts | 12 +++ .../list/{directive.js => directive.tsx} | 12 +-- .../{edit/index.js => list/index.ts} | 2 - .../edit/{directive.js => directive.tsx} | 24 ++--- .../filter_lists/edit/edit_filter_list.d.ts | 13 +++ .../{list/index.js => edit/index.ts} | 2 - .../filter_lists/{index.js => index.ts} | 1 - .../list/{directive.js => directive.tsx} | 41 +++++---- .../filter_lists/list/filter_lists.d.ts} | 7 +- .../index.js => filter_lists/list/index.ts} | 2 - .../ml/public/settings/{index.js => index.ts} | 2 - ...gs_directive.js => settings_directive.tsx} | 37 ++++---- .../timeseriesexplorer/timeseriesexplorer.js | 3 +- .../plugins/ml/public/util/index_utils.ts | 18 +--- .../{check_license.js => check_license.ts} | 44 +++++---- .../lib/check_license/check_license.d.ts | 17 ---- .../{check_license.js => check_license.ts} | 40 +++++---- .../job_validation/validate_bucket_span.js | 2 +- .../job_validation/validate_time_range.js | 2 +- 63 files changed, 571 insertions(+), 656 deletions(-) delete mode 100644 x-pack/legacy/plugins/ml/common/util/__tests__/parse_interval.js delete mode 100644 x-pack/legacy/plugins/ml/common/util/group_color_utils.d.ts rename x-pack/legacy/plugins/ml/common/util/{group_color_utils.js => group_color_utils.ts} (56%) create mode 100644 x-pack/legacy/plugins/ml/common/util/parse_interval.test.ts rename x-pack/legacy/plugins/ml/common/util/{parse_interval.js => parse_interval.ts} (73%) delete mode 100644 x-pack/legacy/plugins/ml/common/util/string_utils.d.ts rename x-pack/legacy/plugins/ml/common/util/{__tests__/string_utils.js => string_utils.test.ts} (63%) rename x-pack/legacy/plugins/ml/common/util/{string_utils.js => string_utils.ts} (59%) delete mode 100644 x-pack/legacy/plugins/ml/common/util/validation_utils.d.ts delete mode 100644 x-pack/legacy/plugins/ml/common/util/validation_utils.js create mode 100644 x-pack/legacy/plugins/ml/common/util/validation_utils.ts mode change 100644 => 100755 x-pack/legacy/plugins/ml/index.ts rename x-pack/legacy/plugins/ml/public/datavisualizer/{directive.js => directive.tsx} (50%) delete mode 100644 x-pack/legacy/plugins/ml/public/datavisualizer/file_based/file_datavisualizer_directive.js create mode 100644 x-pack/legacy/plugins/ml/public/datavisualizer/file_based/file_datavisualizer_directive.tsx rename x-pack/legacy/plugins/ml/public/datavisualizer/file_based/{index.js => index.ts} (99%) rename x-pack/legacy/plugins/ml/public/license/{check_license.js => check_license.tsx} (67%) rename x-pack/legacy/plugins/ml/public/services/{field_format_service.js => field_format_service.ts} (65%) rename x-pack/legacy/plugins/ml/public/settings/{breadcrumbs.js => breadcrumbs.ts} (74%) rename x-pack/legacy/plugins/ml/public/settings/calendars/edit/{directive.js => directive.tsx} (87%) rename x-pack/legacy/plugins/ml/public/settings/{filter_lists/edit/index.js => calendars/edit/index.ts} (99%) create mode 100644 x-pack/legacy/plugins/ml/public/settings/calendars/edit/new_calendar.d.ts create mode 100644 x-pack/legacy/plugins/ml/public/settings/calendars/list/calendars_list.d.ts rename x-pack/legacy/plugins/ml/public/settings/calendars/list/{directive.js => directive.tsx} (92%) rename x-pack/legacy/plugins/ml/public/settings/calendars/{edit/index.js => list/index.ts} (99%) rename x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/{directive.js => directive.tsx} (81%) create mode 100644 x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/edit_filter_list.d.ts rename x-pack/legacy/plugins/ml/public/settings/filter_lists/{list/index.js => edit/index.ts} (99%) rename x-pack/legacy/plugins/ml/public/settings/filter_lists/{index.js => index.ts} (99%) rename x-pack/legacy/plugins/ml/public/settings/filter_lists/list/{directive.js => directive.tsx} (64%) rename x-pack/legacy/plugins/ml/{common/util/parse_interval.d.ts => public/settings/filter_lists/list/filter_lists.d.ts} (67%) rename x-pack/legacy/plugins/ml/public/settings/{calendars/list/index.js => filter_lists/list/index.ts} (99%) rename x-pack/legacy/plugins/ml/public/settings/{index.js => index.ts} (99%) rename x-pack/legacy/plugins/ml/public/settings/{settings_directive.js => settings_directive.tsx} (80%) rename x-pack/legacy/plugins/ml/server/lib/check_license/__tests__/{check_license.js => check_license.ts} (80%) delete mode 100644 x-pack/legacy/plugins/ml/server/lib/check_license/check_license.d.ts rename x-pack/legacy/plugins/ml/server/lib/check_license/{check_license.js => check_license.ts} (66%) diff --git a/x-pack/legacy/plugins/ml/common/util/__tests__/parse_interval.js b/x-pack/legacy/plugins/ml/common/util/__tests__/parse_interval.js deleted file mode 100644 index d06e1412b5090..0000000000000 --- a/x-pack/legacy/plugins/ml/common/util/__tests__/parse_interval.js +++ /dev/null @@ -1,70 +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 { parseInterval } from '../parse_interval'; -import expect from '@kbn/expect'; - -describe('ML parse interval util', function () { - it('correctly parses an interval containing unit and value', function () { - let duration = parseInterval('1d'); - expect(duration.as('d')).to.be(1); - - duration = parseInterval('2y'); - expect(duration.as('y')).to.be(2); - - duration = parseInterval('5M'); - expect(duration.as('M')).to.be(5); - - duration = parseInterval('5m'); - expect(duration.as('m')).to.be(5); - - duration = parseInterval('250ms'); - expect(duration.as('ms')).to.be(250); - - duration = parseInterval('100s'); - expect(duration.as('s')).to.be(100); - - duration = parseInterval('23d'); - expect(duration.as('d')).to.be(23); - - duration = parseInterval('52w'); - expect(duration.as('w')).to.be(52); - - duration = parseInterval('0s'); - expect(duration.as('s')).to.be(0); - - duration = parseInterval('0h'); - expect(duration.as('h')).to.be(0); - - }); - - it('correctly handles zero value intervals', function () { - let duration = parseInterval('0h'); - expect(duration.as('h')).to.be(0); - - duration = parseInterval('0d'); - expect(duration).to.not.be.ok(); - }); - - it('returns null for an invalid interval', function () { - let duration = parseInterval(''); - expect(duration).to.not.be.ok(); - - duration = parseInterval(null); - expect(duration).to.not.be.ok(); - - duration = parseInterval('234asdf'); - expect(duration).to.not.be.ok(); - - duration = parseInterval('m'); - expect(duration).to.not.be.ok(); - - duration = parseInterval('1.5h'); - expect(duration).to.not.be.ok(); - }); -}); diff --git a/x-pack/legacy/plugins/ml/common/util/group_color_utils.d.ts b/x-pack/legacy/plugins/ml/common/util/group_color_utils.d.ts deleted file mode 100644 index 4a1a6ebb8fdf3..0000000000000 --- a/x-pack/legacy/plugins/ml/common/util/group_color_utils.d.ts +++ /dev/null @@ -1,6 +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. - */ -export function tabColor(name: string): string; diff --git a/x-pack/legacy/plugins/ml/common/util/group_color_utils.js b/x-pack/legacy/plugins/ml/common/util/group_color_utils.ts similarity index 56% rename from x-pack/legacy/plugins/ml/common/util/group_color_utils.js rename to x-pack/legacy/plugins/ml/common/util/group_color_utils.ts index 51afa2aff4d95..92f5c6b2c1347 100644 --- a/x-pack/legacy/plugins/ml/common/util/group_color_utils.js +++ b/x-pack/legacy/plugins/ml/common/util/group_color_utils.ts @@ -4,9 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import * as euiVars from '@elastic/eui/dist/eui_theme_dark.json'; -import { stringHash } from './string_utils'; - +import euiVars from '@elastic/eui/dist/eui_theme_dark.json'; const COLORS = [ euiVars.euiColorVis0, @@ -20,18 +18,32 @@ const COLORS = [ euiVars.euiColorVis8, euiVars.euiColorVis9, euiVars.euiColorDarkShade, - euiVars.euiColorPrimary + euiVars.euiColorPrimary, ]; -const colorMap = {}; +const colorMap: Record = {}; -export function tabColor(name) { +export function tabColor(name: string): string { if (colorMap[name] === undefined) { const n = stringHash(name); - const color = COLORS[(n % COLORS.length)]; + const color = COLORS[n % COLORS.length]; colorMap[name] = color; return color; } else { return colorMap[name]; } } + +function stringHash(str: string): number { + let hash = 0; + let chr = 0; + if (str.length === 0) { + return hash; + } + for (let i = 0; i < str.length; i++) { + chr = str.charCodeAt(i); + hash = (hash << 5) - hash + chr; // eslint-disable-line no-bitwise + hash |= 0; // eslint-disable-line no-bitwise + } + return hash < 0 ? hash * -2 : hash; +} diff --git a/x-pack/legacy/plugins/ml/common/util/job_utils.d.ts b/x-pack/legacy/plugins/ml/common/util/job_utils.d.ts index 3e4db7f34bde2..e2ea6c163b6ce 100644 --- a/x-pack/legacy/plugins/ml/common/util/job_utils.d.ts +++ b/x-pack/legacy/plugins/ml/common/util/job_utils.d.ts @@ -33,3 +33,5 @@ export const ML_DATA_PREVIEW_COUNT: number; export function isJobIdValid(jobId: string): boolean; export function processCreatedBy(customSettings: { created_by?: string }): void; + +export function mlFunctionToESAggregation(functionName: string): string | null; diff --git a/x-pack/legacy/plugins/ml/common/util/parse_interval.test.ts b/x-pack/legacy/plugins/ml/common/util/parse_interval.test.ts new file mode 100644 index 0000000000000..1717b2f0dd80b --- /dev/null +++ b/x-pack/legacy/plugins/ml/common/util/parse_interval.test.ts @@ -0,0 +1,34 @@ +/* + * 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 { parseInterval } from './parse_interval'; + +describe('ML parse interval util', () => { + test('correctly parses an interval containing unit and value', () => { + expect(parseInterval('1d')!.as('d')).toBe(1); + expect(parseInterval('2y')!.as('y')).toBe(2); + expect(parseInterval('5M')!.as('M')).toBe(5); + expect(parseInterval('5m')!.as('m')).toBe(5); + expect(parseInterval('250ms')!.as('ms')).toBe(250); + expect(parseInterval('100s')!.as('s')).toBe(100); + expect(parseInterval('23d')!.as('d')).toBe(23); + expect(parseInterval('52w')!.as('w')).toBe(52); + expect(parseInterval('0s')!.as('s')).toBe(0); + expect(parseInterval('0s')!.as('h')).toBe(0); + }); + + test('correctly handles zero value intervals', () => { + expect(parseInterval('0h')!.as('h')).toBe(0); + expect(parseInterval('0d')).toBe(null); + }); + + test('returns null for an invalid interval', () => { + expect(parseInterval('')).toBe(null); + expect(parseInterval('234asdf')).toBe(null); + expect(parseInterval('m')).toBe(null); + expect(parseInterval('1.5h')).toBe(null); + }); +}); diff --git a/x-pack/legacy/plugins/ml/common/util/parse_interval.js b/x-pack/legacy/plugins/ml/common/util/parse_interval.ts similarity index 73% rename from x-pack/legacy/plugins/ml/common/util/parse_interval.js rename to x-pack/legacy/plugins/ml/common/util/parse_interval.ts index bff1d3ca05e70..98a41be96941b 100644 --- a/x-pack/legacy/plugins/ml/common/util/parse_interval.js +++ b/x-pack/legacy/plugins/ml/common/util/parse_interval.ts @@ -4,17 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ - - -import moment from 'moment'; +import { duration, Duration, unitOfTime } from 'moment'; import dateMath from '@elastic/datemath'; +type SupportedUnits = unitOfTime.Base; + // Assume interval is in the form (value)(unit), such as "1h" const INTERVAL_STRING_RE = new RegExp('^([0-9]*)\\s*(' + dateMath.units.join('|') + ')$'); // moment.js is only designed to allow fractional values between 0 and 1 // for units of hour or less. -const SUPPORT_ZERO_DURATION_UNITS = ['ms', 's', 'm', 'h']; +const SUPPORT_ZERO_DURATION_UNITS: SupportedUnits[] = ['ms', 's', 'm', 'h']; // Parses an interval String, such as 7d, 1h or 30m to a moment duration. // Differs from the Kibana ui/utils/parse_interval in the following ways: @@ -25,22 +25,25 @@ const SUPPORT_ZERO_DURATION_UNITS = ['ms', 's', 'm', 'h']; // to work with units less than 'day'. // 3. Fractional intervals e.g. 1.5h or 4.5d are not allowed, in line with the behaviour // of the Elasticsearch date histogram aggregation. -export function parseInterval(interval) { - const matches = String(interval).trim().match(INTERVAL_STRING_RE); - if (!Array.isArray(matches)) return null; - if (matches.length < 3) return null; +export function parseInterval(interval: string): Duration | null { + const matches = String(interval) + .trim() + .match(INTERVAL_STRING_RE); + if (!Array.isArray(matches) || matches.length < 3) { + return null; + } try { - const value = parseInt(matches[1]); - const unit = matches[2]; + const value = parseInt(matches[1], 10); + const unit = matches[2] as SupportedUnits; // In line with moment.js, only allow zero value intervals when the unit is less than 'day'. // And check for isNaN as e.g. valueless 'm' will pass the regex test. - if (isNaN(value) || (value < 1 && SUPPORT_ZERO_DURATION_UNITS.indexOf(unit) === -1)) { + if (isNaN(value) || (value < 1 && SUPPORT_ZERO_DURATION_UNITS.indexOf(unit) === -1)) { return null; } - return moment.duration(value, unit); + return duration(value, unit); } catch (e) { return null; } diff --git a/x-pack/legacy/plugins/ml/common/util/string_utils.d.ts b/x-pack/legacy/plugins/ml/common/util/string_utils.d.ts deleted file mode 100644 index f8dbc00643d07..0000000000000 --- a/x-pack/legacy/plugins/ml/common/util/string_utils.d.ts +++ /dev/null @@ -1,8 +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. - */ - -export function renderTemplate(str: string, data: string): string; -export function stringHash(str: string): string; diff --git a/x-pack/legacy/plugins/ml/common/util/__tests__/string_utils.js b/x-pack/legacy/plugins/ml/common/util/string_utils.test.ts similarity index 63% rename from x-pack/legacy/plugins/ml/common/util/__tests__/string_utils.js rename to x-pack/legacy/plugins/ml/common/util/string_utils.test.ts index e2a791c74bd7b..aba2dbd230ada 100644 --- a/x-pack/legacy/plugins/ml/common/util/__tests__/string_utils.js +++ b/x-pack/legacy/plugins/ml/common/util/string_utils.test.ts @@ -4,29 +4,24 @@ * you may not use this file except in compliance with the Elastic License. */ - - -import expect from '@kbn/expect'; -import { renderTemplate } from '../string_utils'; +import { renderTemplate } from './string_utils'; describe('ML - string utils', () => { describe('renderTemplate', () => { - - it('returns plain string', () => { + test('returns plain string', () => { const templateString = 'plain string'; const result = renderTemplate(templateString); - expect(result).to.be(result); + expect(result).toBe(result); }); - it('returns rendered template with one replacement', () => { + test('returns rendered template with one replacement', () => { const templateString = 'string with {{one}} replacement'; const result = renderTemplate(templateString, { one: '1' }); - expect(result).to.be('string with 1 replacement'); + expect(result).toBe('string with 1 replacement'); }); - it('returns rendered template with two replacements', () => { + test('returns rendered template with two replacements', () => { const templateString = 'string with {{one}} replacement, and a {{two}} one.'; const result = renderTemplate(templateString, { one: '1', two: '2nd' }); - expect(result).to.be('string with 1 replacement, and a 2nd one.'); + expect(result).toBe('string with 1 replacement, and a 2nd one.'); }); - }); }); diff --git a/x-pack/legacy/plugins/ml/common/util/string_utils.js b/x-pack/legacy/plugins/ml/common/util/string_utils.ts similarity index 59% rename from x-pack/legacy/plugins/ml/common/util/string_utils.js rename to x-pack/legacy/plugins/ml/common/util/string_utils.ts index 383c77f151b72..432baabe773cc 100644 --- a/x-pack/legacy/plugins/ml/common/util/string_utils.js +++ b/x-pack/legacy/plugins/ml/common/util/string_utils.ts @@ -4,15 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ - - - // A simple template renderer, it replaces mustache/angular style {{...}} tags with // the values provided via the data object -export function renderTemplate(str, data) { +export function renderTemplate(str: string, data?: Record): string { const matches = str.match(/{{(.*?)}}/g); - if (Array.isArray(matches)) { + if (Array.isArray(matches) && data !== undefined) { matches.forEach(v => { str = str.replace(v, data[v.replace(/{{|}}/g, '')]); }); @@ -20,17 +17,3 @@ export function renderTemplate(str, data) { return str; } - -export function stringHash(str) { - let hash = 0; - let chr = ''; - if (str.length === 0) { - return hash; - } - for (let i = 0; i < str.length; i++) { - chr = str.charCodeAt(i); - hash = ((hash << 5) - hash) + chr; - hash |= 0; - } - return hash < 0 ? hash * -2 : hash; -} diff --git a/x-pack/legacy/plugins/ml/common/util/validation_utils.d.ts b/x-pack/legacy/plugins/ml/common/util/validation_utils.d.ts deleted file mode 100644 index 073b111dbb498..0000000000000 --- a/x-pack/legacy/plugins/ml/common/util/validation_utils.d.ts +++ /dev/null @@ -1,7 +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. - */ - -export function isValidJson(json: string): boolean; diff --git a/x-pack/legacy/plugins/ml/common/util/validation_utils.js b/x-pack/legacy/plugins/ml/common/util/validation_utils.js deleted file mode 100644 index 140a8bca45ca2..0000000000000 --- a/x-pack/legacy/plugins/ml/common/util/validation_utils.js +++ /dev/null @@ -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 { VALIDATION_STATUS } from '../constants/validation'; - -// get the most severe status level from a list of messages -const contains = (arr, str) => arr.findIndex(v => v === str) >= 0; -export function getMostSevereMessageStatus(messages) { - const statuses = messages.map(m => m.status); - return [ - VALIDATION_STATUS.INFO, - VALIDATION_STATUS.WARNING, - VALIDATION_STATUS.ERROR - ].reduce((previous, current) => { - return contains(statuses, current) ? current : previous; - }, VALIDATION_STATUS.SUCCESS); -} - -// extends an angular directive's scope with the necessary methods -// needed to embed the job validation button -export function addJobValidationMethods($scope, service) { - $scope.getDuration = () => ({ - start: $scope.formConfig.start, - end: $scope.formConfig.end - }); - - // isCurrentJobConfig is used to track if the form configuration - // changed since the last job validation was done - $scope.isCurrentJobConfig = false; - // need to pass true as third argument here to track granular changes - $scope.$watch('formConfig', () => { $scope.isCurrentJobConfig = false; }, true); - $scope.getJobConfig = () => { - $scope.isCurrentJobConfig = true; - return service.getJobFromConfig($scope.formConfig); - }; -} - -export function isValidJson(json) { - if(json === null) { - return false; - } - - try { - JSON.parse(json); - return true; - } catch (error) { - return false; - } -} diff --git a/x-pack/legacy/plugins/ml/common/util/validation_utils.ts b/x-pack/legacy/plugins/ml/common/util/validation_utils.ts new file mode 100644 index 0000000000000..1ae5a899a4b4d --- /dev/null +++ b/x-pack/legacy/plugins/ml/common/util/validation_utils.ts @@ -0,0 +1,33 @@ +/* + * 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 { VALIDATION_STATUS } from '../constants/validation'; + +// get the most severe status level from a list of messages +const contains = (arr: string[], str: string) => arr.indexOf(str) >= 0; + +export function getMostSevereMessageStatus(messages: Array<{ status: string }>): VALIDATION_STATUS { + const statuses = messages.map(m => m.status); + return [VALIDATION_STATUS.INFO, VALIDATION_STATUS.WARNING, VALIDATION_STATUS.ERROR].reduce( + (previous, current) => { + return contains(statuses, current) ? current : previous; + }, + VALIDATION_STATUS.SUCCESS + ); +} + +export function isValidJson(json: string) { + if (json === null) { + return false; + } + + try { + JSON.parse(json); + return true; + } catch (error) { + return false; + } +} diff --git a/x-pack/legacy/plugins/ml/index.ts b/x-pack/legacy/plugins/ml/index.ts old mode 100644 new mode 100755 diff --git a/x-pack/legacy/plugins/ml/public/components/anomalies_table/links_menu.js b/x-pack/legacy/plugins/ml/public/components/anomalies_table/links_menu.js index d0522e61f3fd8..dfa12e34928d2 100644 --- a/x-pack/legacy/plugins/ml/public/components/anomalies_table/links_menu.js +++ b/x-pack/legacy/plugins/ml/public/components/anomalies_table/links_menu.js @@ -33,7 +33,7 @@ import { ml } from '../../services/ml_api_service'; import { mlJobService } from '../../services/job_service'; import { getUrlForRecord, openCustomUrlWindow } from '../../util/custom_url_utils'; import { formatHumanReadableDateTimeSeconds } from '../../util/date_utils'; -import { getIndexPatterns } from '../../util/index_utils'; +import { getIndexPatternIdFromName } from '../../util/index_utils'; import { replaceStringTokens } from '../../util/string_utils'; @@ -214,7 +214,6 @@ export const LinksMenu = injectI18n(class LinksMenu extends Component { const { intl } = this.props; const categoryId = this.props.anomaly.entityValue; const record = this.props.anomaly.source; - const indexPatterns = getIndexPatterns(); const job = mlJobService.getJob(this.props.anomaly.jobId); if (job === undefined) { @@ -260,13 +259,7 @@ export const LinksMenu = injectI18n(class LinksMenu extends Component { // index configured in the datafeed. If a Kibana index pattern has not been created // for this index, then the user will see a warning message on the Discover tab advising // them that no matching index pattern has been configured. - let indexPatternId = index; - for (let j = 0; j < indexPatterns.length; j++) { - if (indexPatterns[j].get('title') === index) { - indexPatternId = indexPatterns[j].id; - break; - } - } + const indexPatternId = getIndexPatternIdFromName(index) || index; // Get the definition of the category and use the terms or regex to view the // matching events in the Kibana Discover tab depending on whether the diff --git a/x-pack/legacy/plugins/ml/public/contexts/kibana/__mocks__/kibana_context_value.ts b/x-pack/legacy/plugins/ml/public/contexts/kibana/__mocks__/kibana_context_value.ts index 8f54c7f1ad656..0b85769b423f9 100644 --- a/x-pack/legacy/plugins/ml/public/contexts/kibana/__mocks__/kibana_context_value.ts +++ b/x-pack/legacy/plugins/ml/public/contexts/kibana/__mocks__/kibana_context_value.ts @@ -17,6 +17,5 @@ export const kibanaContextValueMock = { currentIndexPattern: indexPatternMock, currentSavedSearch: savedSearchMock, indexPatterns: indexPatternsMock, - kbnBaseUrl: 'url', kibanaConfig: kibanaConfigMock, }; diff --git a/x-pack/legacy/plugins/ml/public/contexts/kibana/kibana_context.ts b/x-pack/legacy/plugins/ml/public/contexts/kibana/kibana_context.ts index afa2a53ef5dcf..aed230a53f62a 100644 --- a/x-pack/legacy/plugins/ml/public/contexts/kibana/kibana_context.ts +++ b/x-pack/legacy/plugins/ml/public/contexts/kibana/kibana_context.ts @@ -21,7 +21,6 @@ export interface KibanaContextValue { currentIndexPattern: IndexPattern; currentSavedSearch: SavedSearch; indexPatterns: IndexPatterns; - kbnBaseUrl: string; kibanaConfig: KibanaConfigTypeFix; } diff --git a/x-pack/legacy/plugins/ml/public/contexts/kibana/use_kibana_context.ts b/x-pack/legacy/plugins/ml/public/contexts/kibana/use_kibana_context.ts index 1cc670875dff3..658a6980aa1ae 100644 --- a/x-pack/legacy/plugins/ml/public/contexts/kibana/use_kibana_context.ts +++ b/x-pack/legacy/plugins/ml/public/contexts/kibana/use_kibana_context.ts @@ -16,7 +16,6 @@ export const useKibanaContext = () => { context.currentIndexPattern === undefined || context.currentSavedSearch === undefined || context.indexPatterns === undefined || - context.kbnBaseUrl === undefined || context.kibanaConfig === undefined ) { throw new Error('required attribute is undefined'); diff --git a/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_exploration/directive.tsx b/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_exploration/directive.tsx index 4a28e0b0b881e..0a44a7a442980 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_exploration/directive.tsx +++ b/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_exploration/directive.tsx @@ -13,10 +13,9 @@ const module = uiModules.get('apps/ml', ['react']); 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 '../../../jobs/new_job_new/utils/new_job_utils'; +import { createSearchItems } from '../../../jobs/new_job_new/utils/new_job_utils'; import { KibanaConfigTypeFix, KibanaContext } from '../../../contexts/kibana'; @@ -31,19 +30,20 @@ module.directive('mlDataFrameAnalyticsExploration', ($injector: InjectorService) globalState.fetch(); const indexPatterns = $injector.get('indexPatterns'); - const kbnBaseUrl = $injector.get('kbnBaseUrl'); const kibanaConfig = $injector.get('config'); - const Private = $injector.get('Private'); + const $route = $injector.get('$route'); - const createSearchItems = Private(SearchItemsProvider); - const { indexPattern, savedSearch, combinedQuery } = createSearchItems(); + const { indexPattern, savedSearch, combinedQuery } = createSearchItems( + kibanaConfig, + $route.current.locals.indexPattern, + $route.current.locals.savedSearch + ); const kibanaContext = { combinedQuery, currentIndexPattern: indexPattern, currentSavedSearch: savedSearch, indexPatterns, - kbnBaseUrl, kibanaConfig, }; diff --git a/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/directive.tsx b/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/directive.tsx index 5eb1981e9a5aa..a60afbbcfae48 100644 --- a/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/directive.tsx +++ b/x-pack/legacy/plugins/ml/public/data_frame_analytics/pages/analytics_management/directive.tsx @@ -13,10 +13,8 @@ const module = uiModules.get('apps/ml', ['react']); 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 '../../../jobs/new_job_new/utils/new_job_utils'; +import { createSearchItems } from '../../../jobs/new_job_new/utils/new_job_utils'; import { KibanaConfigTypeFix, KibanaContext } from '../../../contexts/kibana'; @@ -28,19 +26,20 @@ module.directive('mlDataFrameAnalyticsManagement', ($injector: InjectorService) restrict: 'E', link: (scope: ng.IScope, element: ng.IAugmentedJQuery) => { const indexPatterns = $injector.get('indexPatterns'); - const kbnBaseUrl = $injector.get('kbnBaseUrl'); const kibanaConfig = $injector.get('config'); - const Private = $injector.get('Private'); + const $route = $injector.get('$route'); - const createSearchItems = Private(SearchItemsProvider); - const { indexPattern, savedSearch, combinedQuery } = createSearchItems(); + const { indexPattern, savedSearch, combinedQuery } = createSearchItems( + kibanaConfig, + $route.current.locals.indexPattern, + $route.current.locals.savedSearch + ); const kibanaContext = { combinedQuery, currentIndexPattern: indexPattern, currentSavedSearch: savedSearch, indexPatterns, - kbnBaseUrl, kibanaConfig, }; diff --git a/x-pack/legacy/plugins/ml/public/datavisualizer/directive.js b/x-pack/legacy/plugins/ml/public/datavisualizer/directive.tsx similarity index 50% rename from x-pack/legacy/plugins/ml/public/datavisualizer/directive.js rename to x-pack/legacy/plugins/ml/public/datavisualizer/directive.tsx index 022f4ea536b44..130042b6dd730 100644 --- a/x-pack/legacy/plugins/ml/public/datavisualizer/directive.js +++ b/x-pack/legacy/plugins/ml/public/datavisualizer/directive.tsx @@ -4,38 +4,52 @@ * you may not use this file except in compliance with the Elastic License. */ -import 'ngreact'; +import React from 'react'; +import ReactDOM from 'react-dom'; +import { I18nContext } from 'ui/i18n'; -import { wrapInI18nContext } 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'; -import uiRoutes from 'ui/routes'; - const template = `
`; -uiRoutes - .when('/datavisualizer', { - template, - k7Breadcrumbs: getDataVisualizerBreadcrumbs, - resolve: { - CheckLicense: checkBasicLicense, - privileges: checkFindFileStructurePrivilege, - } - }); - +uiRoutes.when('/datavisualizer', { + template, + k7Breadcrumbs: getDataVisualizerBreadcrumbs, + resolve: { + CheckLicense: checkBasicLicense, + privileges: checkFindFileStructurePrivilege, + }, +}); +// @ts-ignore import { DatavisualizerSelector } from './datavisualizer_selector'; -module.directive('datavisualizerSelector', function ($injector) { - const reactDirective = $injector.get('reactDirective'); - - return reactDirective(wrapInI18nContext(DatavisualizerSelector), undefined, { restrict: 'E' }, { }); +module.directive('datavisualizerSelector', function() { + return { + scope: {}, + restrict: 'E', + link: (scope: ng.IScope, element: ng.IAugmentedJQuery) => { + ReactDOM.render( + + + , + element[0] + ); + + element.on('$destroy', () => { + ReactDOM.unmountComponentAtNode(element[0]); + scope.$destroy(); + }); + }, + }; }); diff --git a/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/components/file_datavisualizer_view/file_datavisualizer_view.js b/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/components/file_datavisualizer_view/file_datavisualizer_view.js index 94e9c2c2ac584..852f068ef419f 100644 --- a/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/components/file_datavisualizer_view/file_datavisualizer_view.js +++ b/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/components/file_datavisualizer_view/file_datavisualizer_view.js @@ -7,7 +7,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import React, { - Component, + Component } from 'react'; import { diff --git a/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/components/import_view/import_view.js b/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/components/import_view/import_view.js index c1ffcad948adb..c89f618aa835b 100644 --- a/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/components/import_view/import_view.js +++ b/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/components/import_view/import_view.js @@ -25,7 +25,7 @@ import { ImportErrors } from '../import_errors'; import { ImportSummary } from '../import_summary'; import { ImportSettings } from '../import_settings'; import { ExperimentalBadge } from '../experimental_badge'; -import { getIndexPatternNames, refreshIndexPatterns } from '../../../../util/index_utils'; +import { getIndexPatternNames, loadIndexPatterns } from '../../../../util/index_utils'; import { ml } from '../../../../services/ml_api_service'; import { hasImportPermission } from '../utils'; @@ -359,7 +359,7 @@ export class ImportView extends Component { } async loadIndexPatternNames() { - await refreshIndexPatterns(); + await loadIndexPatterns(); const indexPatternNames = getIndexPatternNames(); this.setState({ indexPatternNames }); } diff --git a/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/file_datavisualizer_directive.js b/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/file_datavisualizer_directive.js deleted file mode 100644 index 8b76e57029bd1..0000000000000 --- a/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/file_datavisualizer_directive.js +++ /dev/null @@ -1,49 +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 'ngreact'; - -import { wrapInI18nContext } from 'ui/i18n'; -import { uiModules } from 'ui/modules'; - -const module = uiModules.get('apps/ml', ['react']); - -import { getFileDataVisualizerBreadcrumbs } from './breadcrumbs'; -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 } from './file_datavisualizer'; - -import uiRoutes from 'ui/routes'; - -const template = ` -
- -`; - -uiRoutes - .when('/filedatavisualizer/?', { - template, - k7Breadcrumbs: getFileDataVisualizerBreadcrumbs, - resolve: { - CheckLicense: checkBasicLicense, - privileges: checkFindFileStructurePrivilege, - indexPatterns: loadIndexPatterns, - mlNodeCount: getMlNodeCount, - loadMlServerInfo, - } - }); - -module.directive('fileDatavisualizerPage', function ($injector) { - const reactDirective = $injector.get('reactDirective'); - const indexPatterns = $injector.get('indexPatterns'); - const kibanaConfig = $injector.get('config'); - - return reactDirective(wrapInI18nContext(FileDataVisualizerPage), undefined, { restrict: 'E' }, { indexPatterns, kibanaConfig }); -}); diff --git a/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/file_datavisualizer_directive.tsx b/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/file_datavisualizer_directive.tsx new file mode 100644 index 0000000000000..6b9c053b88d34 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/file_datavisualizer_directive.tsx @@ -0,0 +1,75 @@ +/* + * 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 { IndexPatterns } from 'ui/index_patterns'; +import { KibanaConfigTypeFix } from '../../contexts/kibana'; +// @ts-ignore +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'; +// @ts-ignore +import { FileDataVisualizerPage } from './file_datavisualizer'; + +const template = ` +
+ +`; + +uiRoutes.when('/filedatavisualizer/?', { + template, + k7Breadcrumbs: getFileDataVisualizerBreadcrumbs, + resolve: { + CheckLicense: checkBasicLicense, + privileges: checkFindFileStructurePrivilege, + indexPatterns: loadIndexPatterns, + mlNodeCount: getMlNodeCount, + loadMlServerInfo, + }, +}); + +interface Props { + indexPatterns: IndexPatterns; + kibanaConfig: KibanaConfigTypeFix; +} + +module.directive('fileDatavisualizerPage', function($injector: InjectorService) { + return { + scope: {}, + restrict: 'E', + link: (scope: ng.IScope, element: ng.IAugmentedJQuery) => { + const indexPatterns = $injector.get('indexPatterns'); + const kibanaConfig = $injector.get('config'); + + const props: Props = { + indexPatterns, + kibanaConfig, + }; + ReactDOM.render( + {React.createElement(FileDataVisualizerPage, props)}, + element[0] + ); + + element.on('$destroy', () => { + ReactDOM.unmountComponentAtNode(element[0]); + scope.$destroy(); + }); + }, + }; +}); diff --git a/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/index.js b/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/index.ts similarity index 99% rename from x-pack/legacy/plugins/ml/public/datavisualizer/file_based/index.js rename to x-pack/legacy/plugins/ml/public/datavisualizer/file_based/index.ts index cd7a23430202a..15796ea9ff0bd 100644 --- a/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/index.js +++ b/x-pack/legacy/plugins/ml/public/datavisualizer/file_based/index.ts @@ -4,5 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ - import './file_datavisualizer_directive'; diff --git a/x-pack/legacy/plugins/ml/public/datavisualizer/index_based/directive.tsx b/x-pack/legacy/plugins/ml/public/datavisualizer/index_based/directive.tsx index e621bdd1d8b92..9336986fa1556 100644 --- a/x-pack/legacy/plugins/ml/public/datavisualizer/index_based/directive.tsx +++ b/x-pack/legacy/plugins/ml/public/datavisualizer/index_based/directive.tsx @@ -13,11 +13,10 @@ const module = uiModules.get('apps/ml', ['react']); import { I18nContext } from 'ui/i18n'; import { IndexPatterns } from 'ui/index_patterns'; -import { IPrivate } from 'ui/private'; import { InjectorService } from '../../../common/types/angular'; import { KibanaConfigTypeFix, KibanaContext } from '../../contexts/kibana/kibana_context'; -import { SearchItemsProvider } from '../../jobs/new_job_new/utils/new_job_utils'; +import { createSearchItems } from '../../jobs/new_job_new/utils/new_job_utils'; import { Page } from './page'; @@ -27,19 +26,20 @@ module.directive('mlDataVisualizer', ($injector: InjectorService) => { restrict: 'E', link: (scope: ng.IScope, element: ng.IAugmentedJQuery) => { const indexPatterns = $injector.get('indexPatterns'); - const kbnBaseUrl = $injector.get('kbnBaseUrl'); const kibanaConfig = $injector.get('config'); - const Private = $injector.get('Private'); + const $route = $injector.get('$route'); - const createSearchItems = Private(SearchItemsProvider); - const { indexPattern, savedSearch, combinedQuery } = createSearchItems(); + const { indexPattern, savedSearch, combinedQuery } = createSearchItems( + kibanaConfig, + $route.current.locals.indexPattern, + $route.current.locals.savedSearch + ); const kibanaContext = { combinedQuery, currentIndexPattern: indexPattern, currentSavedSearch: savedSearch, indexPatterns, - kbnBaseUrl, kibanaConfig, }; diff --git a/x-pack/legacy/plugins/ml/public/explorer/explorer_controller.js b/x-pack/legacy/plugins/ml/public/explorer/explorer_controller.js index 6315dd95ea8e4..3bedd90f05c37 100644 --- a/x-pack/legacy/plugins/ml/public/explorer/explorer_controller.js +++ b/x-pack/legacy/plugins/ml/public/explorer/explorer_controller.js @@ -23,7 +23,7 @@ import { import { getAnomalyExplorerBreadcrumbs } from './breadcrumbs'; import { checkFullLicense } from '../license/check_license'; import { checkGetJobsPrivilege } from '../privilege/check_privilege'; -import { getIndexPatterns, loadIndexPatterns } from '../util/index_utils'; +import { loadIndexPatterns } from '../util/index_utils'; import { TimeBuckets } from 'plugins/ml/util/time_buckets'; import { explorer$ } from './explorer_dashboard_service'; import { mlTimefilterRefresh$ } from '../services/timefilter_refresh_service'; @@ -114,7 +114,7 @@ module.controller('MlExplorerController', function ( } // Populate the map of jobs / detectors / field formatters for the selected IDs. - mlFieldFormatService.populateFormats(selectedJobIds, getIndexPatterns()) + mlFieldFormatService.populateFormats(selectedJobIds) .catch((err) => { console.log('Error populating field formats:', err); }) diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/advanced_section/components/dedicated_index/dedicated_index_switch.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/advanced_section/components/dedicated_index/dedicated_index_switch.tsx index 5c8f346d71baf..b50a8e0affa2d 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/advanced_section/components/dedicated_index/dedicated_index_switch.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/advanced_section/components/dedicated_index/dedicated_index_switch.tsx @@ -30,7 +30,6 @@ export const DedicatedIndexSwitch: FC = () => { checked={useDedicatedIndex} onChange={toggleModelPlot} data-test-subj="mlJobWizardSwitchUseDedicatedIndex" - showLabel={false} label={i18n.translate( 'xpack.ml.newJob.wizard.jobDetailsStep.advancedSection.useDedicatedIndex.title', { diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/advanced_section/components/model_plot/model_plot_switch.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/advanced_section/components/model_plot/model_plot_switch.tsx index 41ac4311b71ce..226742bf3e97a 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/advanced_section/components/model_plot/model_plot_switch.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/job_details_step/components/advanced_section/components/model_plot/model_plot_switch.tsx @@ -30,7 +30,6 @@ export const ModelPlotSwitch: FC = () => { checked={modelPlotEnabled} onChange={toggleModelPlot} data-test-subj="mlJobWizardSwitchModelPlot" - showLabel={false} label={i18n.translate( 'xpack.ml.newJob.wizard.jobDetailsStep.advancedSection.enableModelPlot.title', { diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/sparse_data/sparse_data_switch.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/sparse_data/sparse_data_switch.tsx index 3f2c45f0c62bd..76461e1306333 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/sparse_data/sparse_data_switch.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/sparse_data/sparse_data_switch.tsx @@ -44,7 +44,6 @@ export const SparseDataSwitch: FC = () => { checked={sparseData} onChange={toggleSparseData} data-test-subj="mlJobWizardSwitchSparseData" - showLabel={false} label={i18n.translate('xpack.ml.newJob.wizard.pickFieldsStep.sparseData.title', { defaultMessage: 'Sparse data', })} 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 index 592dce3ce5b17..0b83c0eced240 100644 --- 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 @@ -14,10 +14,8 @@ 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_new/utils/new_job_utils'; +import { createSearchItems } from '../../../new_job_new/utils/new_job_utils'; import { Page } from './page'; import { KibanaContext, KibanaConfigTypeFix } from '../../../../contexts/kibana'; @@ -32,18 +30,19 @@ module.directive('mlJobTypePage', ($injector: InjectorService) => { timefilter.disableAutoRefreshSelector(); const indexPatterns = $injector.get('indexPatterns'); - const kbnBaseUrl = $injector.get('kbnBaseUrl'); const kibanaConfig = $injector.get('config'); - const Private = $injector.get('Private'); + const $route = $injector.get('$route'); - const createSearchItems = Private(SearchItemsProvider); - const { indexPattern, savedSearch, combinedQuery } = createSearchItems(); + const { indexPattern, savedSearch, combinedQuery } = createSearchItems( + kibanaConfig, + $route.current.locals.indexPattern, + $route.current.locals.savedSearch + ); const kibanaContext = { combinedQuery, currentIndexPattern: indexPattern, currentSavedSearch: savedSearch, indexPatterns, - kbnBaseUrl, kibanaConfig, }; diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/new_job/directive.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/new_job/directive.tsx index 815e0228882ce..1725211861c0c 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/new_job/directive.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/new_job/directive.tsx @@ -14,10 +14,8 @@ 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 '../../utils/new_job_utils'; +import { createSearchItems } from '../../utils/new_job_utils'; import { Page, PageProps } from './page'; import { JOB_TYPE } from '../../common/job_creator/util/constants'; @@ -32,9 +30,7 @@ module.directive('mlNewJobPage', ($injector: InjectorService) => { timefilter.disableAutoRefreshSelector(); const indexPatterns = $injector.get('indexPatterns'); - const kbnBaseUrl = $injector.get('kbnBaseUrl'); const kibanaConfig = $injector.get('config'); - const Private = $injector.get('Private'); const $route = $injector.get('$route'); const existingJobsAndGroups = $route.current.locals.existingJobsAndGroups; @@ -43,15 +39,17 @@ module.directive('mlNewJobPage', ($injector: InjectorService) => { } const jobType: JOB_TYPE = $route.current.locals.jobType; - const createSearchItems = Private(SearchItemsProvider); - const { indexPattern, savedSearch, combinedQuery } = createSearchItems(); + const { indexPattern, savedSearch, combinedQuery } = createSearchItems( + kibanaConfig, + $route.current.locals.indexPattern, + $route.current.locals.savedSearch + ); const kibanaContext = { combinedQuery, currentIndexPattern: indexPattern, currentSavedSearch: savedSearch, indexPatterns, - kbnBaseUrl, kibanaConfig, }; diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/components/job_settings_form.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/components/job_settings_form.tsx index 8dda1415a0ab8..bae16d620af5b 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/components/job_settings_form.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/components/job_settings_form.tsx @@ -247,7 +247,6 @@ export const JobSettingsForm: FC = ({ useDedicatedIndex: checked, }); }} - showLabel={false} label={i18n.translate('xpack.ml.newJob.recognize.useDedicatedIndexLabel', { defaultMessage: 'Use dedicated index', })} diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/directive.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/directive.tsx index cf80cad30b7ca..5629fd63ce7ba 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/directive.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/directive.tsx @@ -14,10 +14,9 @@ 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_new/utils/new_job_utils'; +import { createSearchItems } from '../../new_job_new/utils/new_job_utils'; import { Page } from './page'; import { KibanaContext, KibanaConfigTypeFix } from '../../../contexts/kibana'; @@ -32,22 +31,22 @@ module.directive('mlRecognizePage', ($injector: InjectorService) => { timefilter.disableAutoRefreshSelector(); const indexPatterns = $injector.get('indexPatterns'); - const kbnBaseUrl = $injector.get('kbnBaseUrl'); const kibanaConfig = $injector.get('config'); - const Private = $injector.get('Private'); const $route = $injector.get('$route'); const moduleId = $route.current.params.id; const existingGroupIds: string[] = $route.current.locals.existingJobsAndGroups.groupIds; - const createSearchItems = Private(SearchItemsProvider); - const { indexPattern, savedSearch, combinedQuery } = createSearchItems(); + const { indexPattern, savedSearch, combinedQuery } = createSearchItems( + kibanaConfig, + $route.current.locals.indexPattern, + $route.current.locals.savedSearch + ); const kibanaContext = { combinedQuery, currentIndexPattern: indexPattern, currentSavedSearch: savedSearch, indexPatterns, - kbnBaseUrl, kibanaConfig, }; diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/resolvers.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/resolvers.ts index d92ec7152adf8..d2ca22972c201 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/resolvers.ts +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/recognize/resolvers.ts @@ -7,7 +7,6 @@ import chrome from 'ui/chrome'; import { i18n } from '@kbn/i18n'; import { toastNotifications } from 'ui/notify'; -import { IPrivate } from 'ui/private'; import { mlJobService } from '../../../services/job_service'; import { ml } from '../../../services/ml_api_service'; import { KibanaObjects } from './page'; @@ -17,12 +16,7 @@ import { KibanaObjects } from './page'; * Redirects to the Anomaly Explorer to view the jobs if they have been created, * or the recognizer job wizard for the module if not. */ -export function checkViewOrCreateJobs( - Private: IPrivate, - $route: any, - kbnBaseUrl: string, - kbnUrl: any -) { +export function checkViewOrCreateJobs($route: any) { return new Promise((resolve, reject) => { const moduleId = $route.current.params.id; const indexPatternId = $route.current.params.index; @@ -58,7 +52,7 @@ export function checkViewOrCreateJobs( }), }); - kbnUrl.redirect(`/jobs`); + window.location.href = '#/jobs'; reject(); }); }); diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/utils/new_job_utils.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/utils/new_job_utils.ts index 85beb32fffa3c..cb4e7a21997e6 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/utils/new_job_utils.ts +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/utils/new_job_utils.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ +import { IndexPattern } from 'ui/index_patterns'; import { SavedSearch } from 'src/legacy/core_plugins/kibana/public/discover/types'; import { KibanaConfigTypeFix } from '../../../contexts/kibana'; -import { InjectorService } from '../../../../common/types/angular'; import { esQuery, IIndexPattern } from '../../../../../../../../src/plugins/data/public'; export interface SearchItems { @@ -18,55 +18,50 @@ export interface SearchItems { // Provider for creating the items used for searching and job creation. // Uses the $route object to retrieve the indexPattern and savedSearch from the url -export function SearchItemsProvider($injector: InjectorService) { - const kibanaConfig = $injector.get('config'); - const $route = $injector.get('$route'); - function createSearchItems() { - let indexPattern = $route.current.locals.indexPattern; - - // query is only used by the data visualizer as it needs - // a lucene query_string. - // Using a blank query will cause match_all:{} to be used - // when passed through luceneStringToDsl - let query = { - query: '', - language: 'lucene', - }; - - let combinedQuery: any = { - bool: { - must: [ - { - match_all: {}, - }, - ], - }, - }; +export function createSearchItems( + kibanaConfig: KibanaConfigTypeFix, + indexPattern: IndexPattern, + savedSearch: SavedSearch +) { + // query is only used by the data visualizer as it needs + // a lucene query_string. + // Using a blank query will cause match_all:{} to be used + // when passed through luceneStringToDsl + let query = { + query: '', + language: 'lucene', + }; - const savedSearch = $route.current.locals.savedSearch; - if (indexPattern.id === undefined && savedSearch.id !== undefined) { - const searchSource = savedSearch.searchSource; - indexPattern = searchSource.getField('index'); + let combinedQuery: any = { + bool: { + must: [ + { + match_all: {}, + }, + ], + }, + }; - query = searchSource.getField('query'); - const fs = searchSource.getField('filter'); + if (indexPattern.id === undefined && savedSearch.id !== undefined) { + const searchSource = savedSearch.searchSource; + indexPattern = searchSource.getField('index'); - const filters = fs.length ? fs : []; + query = searchSource.getField('query'); + const fs = searchSource.getField('filter'); - const esQueryConfigs = esQuery.getEsQueryConfig(kibanaConfig); - combinedQuery = esQuery.buildEsQuery(indexPattern, [query], filters, esQueryConfigs); - } + const filters = fs.length ? fs : []; - return { - indexPattern, - savedSearch, - query, - combinedQuery, - }; + const esQueryConfigs = esQuery.getEsQueryConfig(kibanaConfig); + combinedQuery = esQuery.buildEsQuery(indexPattern, [query], filters, esQueryConfigs); } - return createSearchItems; + return { + indexPattern, + savedSearch, + query, + combinedQuery, + }; } // Only model plot cardinality relevant diff --git a/x-pack/legacy/plugins/ml/public/license/check_license.js b/x-pack/legacy/plugins/ml/public/license/check_license.tsx similarity index 67% rename from x-pack/legacy/plugins/ml/public/license/check_license.js rename to x-pack/legacy/plugins/ml/public/license/check_license.tsx index 9e86fa429b0da..8457e462567cc 100644 --- a/x-pack/legacy/plugins/ml/public/license/check_license.js +++ b/x-pack/legacy/plugins/ml/public/license/check_license.tsx @@ -4,51 +4,44 @@ * you may not use this file except in compliance with the Elastic License. */ - import React from 'react'; +// @ts-ignore No declaration file for module +import { banners } from 'ui/notify'; +import { EuiCallOut } from '@elastic/eui'; +// @ts-ignore No declaration file for module import { xpackInfo } from '../../../xpack_main/public/services/xpack_info'; -import { banners, addAppRedirectMessageToUrl } from 'ui/notify'; import { LICENSE_TYPE } from '../../common/constants/license'; import { LICENSE_STATUS_VALID } from '../../../../common/constants/license_status'; -import chrome from 'ui/chrome'; -import { EuiCallOut } from '@elastic/eui'; - let licenseHasExpired = true; -let licenseType = null; -let expiredLicenseBannerId; +let licenseType: LICENSE_TYPE | null = null; +let expiredLicenseBannerId: string; -export function checkFullLicense(kbnBaseUrl, kbnUrl) { +export function checkFullLicense() { const features = getFeatures(); licenseType = features.licenseType; if (features.isAvailable === false) { // ML is not enabled - return redirectToKibana(features, kbnBaseUrl); - + return redirectToKibana(); } else if (features.licenseType === LICENSE_TYPE.BASIC) { - // ML is enabled, but only with a basic or gold license - return redirectToBasic(kbnUrl); - + return redirectToBasic(); } else { - // ML is enabled setLicenseExpired(features); return Promise.resolve(features); } } -export function checkBasicLicense(kbnBaseUrl) { +export function checkBasicLicense() { const features = getFeatures(); licenseType = features.licenseType; if (features.isAvailable === false) { // ML is not enabled - return redirectToKibana(features, kbnBaseUrl); - + return redirectToKibana(); } else { - // ML is enabled setLicenseExpired(features); return Promise.resolve(features); @@ -58,38 +51,32 @@ export function checkBasicLicense(kbnBaseUrl) { // a wrapper for checkFullLicense which doesn't resolve if the license has expired. // this is used by all create jobs pages to redirect back to the jobs list // if the user's license has expired. -export function checkLicenseExpired(kbnBaseUrl, kbnUrl) { - return checkFullLicense(kbnBaseUrl, kbnUrl) - .then((features) => { +export function checkLicenseExpired() { + return checkFullLicense() + .then((features: any) => { if (features.hasExpired) { - kbnUrl.redirect('/jobs'); - return Promise.halt(); + window.location.href = '#/jobs'; + return Promise.reject(); } else { return Promise.resolve(features); } }) .catch(() => { - return Promise.halt(); + return Promise.reject(); }); } -function setLicenseExpired(features) { - licenseHasExpired = (features.hasExpired || false); +function setLicenseExpired(features: any) { + licenseHasExpired = features.hasExpired || false; // If the license has expired ML app will still work for 7 days and then // the job management endpoints (e.g. create job, start datafeed) will be restricted. // Therefore we need to keep the app enabled but show an info banner to the user. - if(licenseHasExpired) { + if (licenseHasExpired) { const message = features.message; if (expiredLicenseBannerId === undefined) { // Only show the banner once with no way to dismiss it expiredLicenseBannerId = banners.add({ - component: ( - - ), + component: , }); } } @@ -99,16 +86,14 @@ function getFeatures() { return xpackInfo.get('features.ml'); } -function redirectToKibana(features, kbnBaseUrl) { - const { message } = features; - const newUrl = addAppRedirectMessageToUrl(chrome.addBasePath(kbnBaseUrl), (message || '')); - window.location.href = newUrl; - return Promise.halt(); +function redirectToKibana() { + window.location.href = '/'; + return Promise.reject(); } -function redirectToBasic(kbnUrl) { - kbnUrl.redirect('/datavisualizer'); - return Promise.halt(); +function redirectToBasic() { + window.location.href = '#/datavisualizer'; + return Promise.reject(); } export function hasLicenseExpired() { @@ -116,10 +101,10 @@ export function hasLicenseExpired() { } export function isFullLicense() { - return (licenseType === LICENSE_TYPE.FULL); + return licenseType === LICENSE_TYPE.FULL; } -export function xpackFeatureAvailable(feature) { +export function xpackFeatureAvailable(feature: string) { // each plugin can register their own set of features. // so we need specific checks for each one. // this list can grow if we need to check other plugin's features. diff --git a/x-pack/legacy/plugins/ml/public/privilege/check_privilege.ts b/x-pack/legacy/plugins/ml/public/privilege/check_privilege.ts index d930763c3cac5..10842a2d15453 100644 --- a/x-pack/legacy/plugins/ml/public/privilege/check_privilege.ts +++ b/x-pack/legacy/plugins/ml/public/privilege/check_privilege.ts @@ -15,18 +15,18 @@ import { ACCESS_DENIED_PATH } from '../management/management_urls'; let privileges: Privileges = getDefaultPrivileges(); // manage_ml requires all monitor and admin cluster privileges: https://github.com/elastic/elasticsearch/blob/664a29c8905d8ce9ba8c18aa1ed5c5de93a0eabc/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/ClusterPrivilege.java#L53 -export function canGetManagementMlJobs(kbnUrl: any) { +export function canGetManagementMlJobs() { return new Promise((resolve, reject) => { getManageMlPrivileges().then( ({ capabilities, isPlatinumOrTrialLicense, mlFeatureEnabledInSpace }) => { privileges = capabilities; - // Loop through all privilages to ensure they are all set to true. + // Loop through all privileges to ensure they are all set to true. const isManageML = Object.values(privileges).every(p => p === true); if (isManageML === true && isPlatinumOrTrialLicense === true) { return resolve({ mlFeatureEnabledInSpace }); } else { - kbnUrl.redirect(ACCESS_DENIED_PATH); + window.location.href = ACCESS_DENIED_PATH; return reject(); } } @@ -34,7 +34,7 @@ export function canGetManagementMlJobs(kbnUrl: any) { }); } -export function checkGetJobsPrivilege(kbnUrl: any): Promise { +export function checkGetJobsPrivilege(): Promise { return new Promise((resolve, reject) => { getPrivileges().then(({ capabilities, isPlatinumOrTrialLicense }) => { privileges = capabilities; @@ -46,14 +46,14 @@ export function checkGetJobsPrivilege(kbnUrl: any): Promise { if (privileges.canGetJobs || isPlatinumOrTrialLicense === false) { return resolve(privileges); } else { - kbnUrl.redirect('/access-denied'); + window.location.href = '#/access-denied'; return reject(); } }); }); } -export function checkCreateJobsPrivilege(kbnUrl: any): Promise { +export function checkCreateJobsPrivilege(): Promise { return new Promise((resolve, reject) => { getPrivileges().then(({ capabilities, isPlatinumOrTrialLicense }) => { privileges = capabilities; @@ -65,14 +65,14 @@ export function checkCreateJobsPrivilege(kbnUrl: any): Promise { } else { // if the user has no permission to create a job, // redirect them back to the Transforms Management page - kbnUrl.redirect('/jobs'); + window.location.href = '#/jobs'; return reject(); } }); }); } -export function checkFindFileStructurePrivilege(kbnUrl: any): Promise { +export function checkFindFileStructurePrivilege(): Promise { return new Promise((resolve, reject) => { getPrivileges().then(({ capabilities }) => { privileges = capabilities; @@ -81,7 +81,7 @@ export function checkFindFileStructurePrivilege(kbnUrl: any): Promise; +type IndexPatternIdsByJob = Record; + // Service for accessing FieldFormat objects configured for a Kibana index pattern // for use in formatting the actual and typical values from anomalies. class FieldFormatService { - constructor() { - this.indexPatternIdsByJob = {}; - this.formatsByJob = {}; - } + indexPatternIdsByJob: IndexPatternIdsByJob = {}; + formatsByJob: FormatsByJobId = {}; // Populate the service with the FieldFormats for the list of jobs with the // specified IDs. List of Kibana index patterns is passed, with a title @@ -26,60 +24,57 @@ class FieldFormatService { // configured in the datafeed of each job. // Builds a map of Kibana FieldFormats (plugins/data/common/field_formats) // against detector index by job ID. - populateFormats(jobIds, indexPatterns) { + populateFormats(jobIds: string[]) { return new Promise((resolve, reject) => { // Populate a map of index pattern IDs against job ID, by finding the ID of the index // pattern with a title attribute which matches the index configured in the datafeed. // If a Kibana index pattern has not been created // for this index, then no custom field formatting will occur. - _.each(jobIds, (jobId) => { + jobIds.forEach(jobId => { const jobObj = mlJobService.getJob(jobId); const datafeedIndices = jobObj.datafeed_config.indices; - const indexPattern = _.find(indexPatterns, (index) => { - return _.find(datafeedIndices, (datafeedIndex) => { - return index.get('title') === datafeedIndex; - }); - }); - - // Check if index pattern has been configured to match the index in datafeed. - if (indexPattern !== undefined) { - this.indexPatternIdsByJob[jobId] = indexPattern.id; + const id = getIndexPatternIdFromName(datafeedIndices.length ? datafeedIndices[0] : ''); + if (id !== null) { + this.indexPatternIdsByJob[jobId] = id; } }); - const promises = jobIds.map(jobId => Promise.all([ - this.getFormatsForJob(jobId) - ])); + const promises = jobIds.map(jobId => Promise.all([this.getFormatsForJob(jobId)])); - Promise.all(promises).then((fmtsByJobByDetector) => { - _.each(fmtsByJobByDetector, (formatsByDetector, index) => { - this.formatsByJob[jobIds[index]] = formatsByDetector[0]; - }); - - resolve(this.formatsByJob); - }).catch(err => { - console.log('fieldFormatService error populating formats:', err); - reject({ formats: {}, err }); - }); + Promise.all(promises) + .then(fmtsByJobByDetector => { + fmtsByJobByDetector.forEach((formatsByDetector, i) => { + this.formatsByJob[jobIds[i]] = formatsByDetector[0]; + }); + resolve(this.formatsByJob); + }) + .catch(err => { + reject({ formats: {}, err }); + }); }); } // Return the FieldFormat to use for formatting values from // the detector from the job with the specified ID. - getFieldFormat(jobId, detectorIndex) { - return _.get(this.formatsByJob, [jobId, detectorIndex]); + getFieldFormat(jobId: string, detectorIndex: number) { + if (this.formatsByJob.hasOwnProperty(jobId)) { + return this.formatsByJob[jobId][detectorIndex]; + } } - // Utility for returning the FieldFormat from a full populated Kibana index pattern object // containing the list of fields by name with their formats. - getFieldFormatFromIndexPattern(fullIndexPattern, fieldName, esAggName) { + getFieldFormatFromIndexPattern( + fullIndexPattern: IndexPattern, + fieldName: string, + esAggName: string + ) { // Don't use the field formatter for distinct count detectors as // e.g. distinct_count(clientip) should be formatted as a count, not as an IP address. - let fieldFormat = undefined; + let fieldFormat; if (esAggName !== 'cardinality') { - const fieldList = _.get(fullIndexPattern, 'fields', []); + const fieldList = fullIndexPattern.fields; const field = fieldList.getByName(fieldName); if (field !== undefined) { fieldFormat = field.format; @@ -89,34 +84,34 @@ class FieldFormatService { return fieldFormat; } - getFormatsForJob(jobId) { + getFormatsForJob(jobId: string): Promise { return new Promise((resolve, reject) => { - const jobObj = mlJobService.getJob(jobId); const detectors = jobObj.analysis_config.detectors || []; - const formatsByDetector = {}; + const formatsByDetector: any[] = []; const indexPatternId = this.indexPatternIdsByJob[jobId]; if (indexPatternId !== undefined) { // Load the full index pattern configuration to obtain the formats of each field. getIndexPatternById(indexPatternId) - .then((indexPatternData) => { + .then(indexPatternData => { // Store the FieldFormat for each job by detector_index. - const fieldList = _.get(indexPatternData, 'fields', []); - _.each(detectors, (dtr) => { + const fieldList = indexPatternData.fields; + detectors.forEach(dtr => { const esAgg = mlFunctionToESAggregation(dtr.function); // distinct_count detectors should fall back to the default // formatter as the values are just counts. if (dtr.field_name !== undefined && esAgg !== 'cardinality') { const field = fieldList.getByName(dtr.field_name); if (field !== undefined) { - formatsByDetector[dtr.detector_index] = field.format; + formatsByDetector[dtr.detector_index!] = field.format; } } }); resolve(formatsByDetector); - }).catch(err => { + }) + .catch(err => { reject(err); }); } else { diff --git a/x-pack/legacy/plugins/ml/public/services/job_service.d.ts b/x-pack/legacy/plugins/ml/public/services/job_service.d.ts index 383932c812216..bbfe0061d13f9 100644 --- a/x-pack/legacy/plugins/ml/public/services/job_service.d.ts +++ b/x-pack/legacy/plugins/ml/public/services/job_service.d.ts @@ -34,6 +34,7 @@ declare interface JobService { createResultsUrl(jobId: string[], start: number, end: number, location: string): string; getJobAndGroupIds(): ExistingJobsAndGroups; searchPreview(job: CombinedJob): Promise>; + getJob(jobId: string): CombinedJob; } export const mlJobService: JobService; diff --git a/x-pack/legacy/plugins/ml/public/settings/breadcrumbs.js b/x-pack/legacy/plugins/ml/public/settings/breadcrumbs.ts similarity index 74% rename from x-pack/legacy/plugins/ml/public/settings/breadcrumbs.js rename to x-pack/legacy/plugins/ml/public/settings/breadcrumbs.ts index e4e37b67c1872..2cdfa5bfcf4d0 100644 --- a/x-pack/legacy/plugins/ml/public/settings/breadcrumbs.js +++ b/x-pack/legacy/plugins/ml/public/settings/breadcrumbs.ts @@ -4,19 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ - -import { ML_BREADCRUMB, ANOMALY_DETECTION_BREADCRUMB, SETTINGS } from '../breadcrumbs'; import { i18n } from '@kbn/i18n'; - +import { ML_BREADCRUMB, ANOMALY_DETECTION_BREADCRUMB, SETTINGS } from '../breadcrumbs'; export function getSettingsBreadcrumbs() { // Whilst top level nav menu with tabs remains, // use root ML breadcrumb. - return [ - ML_BREADCRUMB, - ANOMALY_DETECTION_BREADCRUMB, - SETTINGS - ]; + return [ML_BREADCRUMB, ANOMALY_DETECTION_BREADCRUMB, SETTINGS]; } export function getCalendarManagementBreadcrumbs() { @@ -24,10 +18,10 @@ export function getCalendarManagementBreadcrumbs() { ...getSettingsBreadcrumbs(), { text: i18n.translate('xpack.ml.settings.breadcrumbs.calendarManagementLabel', { - defaultMessage: 'Calendar management' + defaultMessage: 'Calendar management', }), - href: '#/settings/calendars_list' - } + href: '#/settings/calendars_list', + }, ]; } @@ -36,10 +30,10 @@ export function getCreateCalendarBreadcrumbs() { ...getCalendarManagementBreadcrumbs(), { text: i18n.translate('xpack.ml.settings.breadcrumbs.calendarManagement.createLabel', { - defaultMessage: 'Create' + defaultMessage: 'Create', }), - href: '#/settings/calendars_list/new_calendar' - } + href: '#/settings/calendars_list/new_calendar', + }, ]; } @@ -48,10 +42,10 @@ export function getEditCalendarBreadcrumbs() { ...getCalendarManagementBreadcrumbs(), { text: i18n.translate('xpack.ml.settings.breadcrumbs.calendarManagement.editLabel', { - defaultMessage: 'Edit' + defaultMessage: 'Edit', }), - href: '#/settings/calendars_list/edit_calendar' - } + href: '#/settings/calendars_list/edit_calendar', + }, ]; } @@ -60,10 +54,10 @@ export function getFilterListsBreadcrumbs() { ...getSettingsBreadcrumbs(), { text: i18n.translate('xpack.ml.settings.breadcrumbs.filterListsLabel', { - defaultMessage: 'Filter lists' + defaultMessage: 'Filter lists', }), - href: '#/settings/filter_lists' - } + href: '#/settings/filter_lists', + }, ]; } @@ -72,10 +66,10 @@ export function getCreateFilterListBreadcrumbs() { ...getFilterListsBreadcrumbs(), { text: i18n.translate('xpack.ml.settings.breadcrumbs.filterLists.createLabel', { - defaultMessage: 'Create' + defaultMessage: 'Create', }), - href: '#/settings/filter_lists/new' - } + href: '#/settings/filter_lists/new', + }, ]; } @@ -84,9 +78,9 @@ export function getEditFilterListBreadcrumbs() { ...getFilterListsBreadcrumbs(), { text: i18n.translate('xpack.ml.settings.breadcrumbs.filterLists.editLabel', { - defaultMessage: 'Edit' + defaultMessage: 'Edit', }), - href: '#/settings/filter_lists/edit' - } + href: '#/settings/filter_lists/edit', + }, ]; } diff --git a/x-pack/legacy/plugins/ml/public/settings/calendars/edit/directive.js b/x-pack/legacy/plugins/ml/public/settings/calendars/edit/directive.tsx similarity index 87% rename from x-pack/legacy/plugins/ml/public/settings/calendars/edit/directive.js rename to x-pack/legacy/plugins/ml/public/settings/calendars/edit/directive.tsx index 34b647ef370d5..cc1674848d374 100644 --- a/x-pack/legacy/plugins/ml/public/settings/calendars/edit/directive.js +++ b/x-pack/legacy/plugins/ml/public/settings/calendars/edit/directive.tsx @@ -4,21 +4,22 @@ * you may not use this file except in compliance with the Elastic License. */ - import 'ngreact'; import React from 'react'; import ReactDOM from 'react-dom'; +// @ts-ignore import { uiModules } from 'ui/modules'; const module = uiModules.get('apps/ml', ['react']); +import uiRoutes from 'ui/routes'; +import { I18nContext } from 'ui/i18n'; import { checkFullLicense } from '../../../license/check_license'; import { checkGetJobsPrivilege, checkPermission } from '../../../privilege/check_privilege'; import { checkMlNodesAvailable } from '../../../ml_nodes_check'; import { getCreateCalendarBreadcrumbs, getEditCalendarBreadcrumbs } from '../../breadcrumbs'; -import uiRoutes from 'ui/routes'; -import { I18nContext } from 'ui/i18n'; +import { NewCalendar } from './new_calendar'; const template = `
@@ -33,7 +34,7 @@ uiRoutes CheckLicense: checkFullLicense, privileges: checkGetJobsPrivilege, checkMlNodesAvailable, - } + }, }) .when('/settings/calendars_list/edit_calendar/:calendarId', { template, @@ -42,21 +43,19 @@ uiRoutes CheckLicense: checkFullLicense, privileges: checkGetJobsPrivilege, checkMlNodesAvailable, - } + }, }); -import { NewCalendar } from './new_calendar.js'; - -module.directive('mlNewCalendar', function ($route) { +module.directive('mlNewCalendar', function($route: any) { return { restrict: 'E', replace: false, scope: {}, - link: function (scope, element) { + link(scope: ng.IScope, element: ng.IAugmentedJQuery) { const props = { calendarId: $route.current.params.calendarId, canCreateCalendar: checkPermission('canCreateCalendar'), - canDeleteCalendar: checkPermission('canDeleteCalendar') + canDeleteCalendar: checkPermission('canDeleteCalendar'), }; ReactDOM.render( @@ -65,6 +64,6 @@ module.directive('mlNewCalendar', function ($route) { , element[0] ); - } + }, }; }); diff --git a/x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/index.js b/x-pack/legacy/plugins/ml/public/settings/calendars/edit/index.ts similarity index 99% rename from x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/index.js rename to x-pack/legacy/plugins/ml/public/settings/calendars/edit/index.ts index 3839017291326..aa8b2ec2c29c9 100644 --- a/x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/index.js +++ b/x-pack/legacy/plugins/ml/public/settings/calendars/edit/index.ts @@ -4,5 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ - import './directive'; diff --git a/x-pack/legacy/plugins/ml/public/settings/calendars/edit/new_calendar.d.ts b/x-pack/legacy/plugins/ml/public/settings/calendars/edit/new_calendar.d.ts new file mode 100644 index 0000000000000..d6de538d6388a --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/settings/calendars/edit/new_calendar.d.ts @@ -0,0 +1,13 @@ +/* + * 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 { FC } from 'react'; + +declare const NewCalendar: FC<{ + calendarId: string; + canCreateCalendar: boolean; + canDeleteCalendar: boolean; +}>; diff --git a/x-pack/legacy/plugins/ml/public/settings/calendars/list/calendars_list.d.ts b/x-pack/legacy/plugins/ml/public/settings/calendars/list/calendars_list.d.ts new file mode 100644 index 0000000000000..05debad543075 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/settings/calendars/list/calendars_list.d.ts @@ -0,0 +1,12 @@ +/* + * 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 { FC } from 'react'; + +declare const CalendarsList: FC<{ + canCreateCalendar: boolean; + canDeleteCalendar: boolean; +}>; diff --git a/x-pack/legacy/plugins/ml/public/settings/calendars/list/directive.js b/x-pack/legacy/plugins/ml/public/settings/calendars/list/directive.tsx similarity index 92% rename from x-pack/legacy/plugins/ml/public/settings/calendars/list/directive.js rename to x-pack/legacy/plugins/ml/public/settings/calendars/list/directive.tsx index 32085fa0e9939..1b90a27c07ada 100644 --- a/x-pack/legacy/plugins/ml/public/settings/calendars/list/directive.js +++ b/x-pack/legacy/plugins/ml/public/settings/calendars/list/directive.tsx @@ -8,16 +8,18 @@ import 'ngreact'; import React from 'react'; import ReactDOM from 'react-dom'; +// @ts-ignore import { uiModules } from 'ui/modules'; const module = uiModules.get('apps/ml', ['react']); +import uiRoutes from 'ui/routes'; +import { I18nContext } from 'ui/i18n'; import { checkFullLicense } from '../../../license/check_license'; import { checkGetJobsPrivilege, checkPermission } from '../../../privilege/check_privilege'; import { getMlNodeCount } from '../../../ml_nodes_check/check_ml_nodes'; import { getCalendarManagementBreadcrumbs } from '../../breadcrumbs'; -import uiRoutes from 'ui/routes'; -import { I18nContext } from 'ui/i18n'; +import { CalendarsList } from './calendars_list'; const template = `
@@ -34,14 +36,12 @@ uiRoutes.when('/settings/calendars_list', { }, }); -import { CalendarsList } from './calendars_list'; - -module.directive('mlCalendarsList', function () { +module.directive('mlCalendarsList', function() { return { restrict: 'E', replace: false, scope: {}, - link: function (scope, element) { + link(scope: ng.IScope, element: ng.IAugmentedJQuery) { const props = { canCreateCalendar: checkPermission('canCreateCalendar'), canDeleteCalendar: checkPermission('canDeleteCalendar'), diff --git a/x-pack/legacy/plugins/ml/public/settings/calendars/edit/index.js b/x-pack/legacy/plugins/ml/public/settings/calendars/list/index.ts similarity index 99% rename from x-pack/legacy/plugins/ml/public/settings/calendars/edit/index.js rename to x-pack/legacy/plugins/ml/public/settings/calendars/list/index.ts index fd75a9ceb9b49..aa8b2ec2c29c9 100644 --- a/x-pack/legacy/plugins/ml/public/settings/calendars/edit/index.js +++ b/x-pack/legacy/plugins/ml/public/settings/calendars/list/index.ts @@ -4,6 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ - - import './directive'; diff --git a/x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/directive.js b/x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/directive.tsx similarity index 81% rename from x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/directive.js rename to x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/directive.tsx index 1d6c72c13f9f2..b70b7eebfccc9 100644 --- a/x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/directive.js +++ b/x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/directive.tsx @@ -4,22 +4,22 @@ * you may not use this file except in compliance with the Elastic License. */ - import 'ngreact'; import React from 'react'; import ReactDOM from 'react-dom'; +// @ts-ignore import { uiModules } from 'ui/modules'; const module = uiModules.get('apps/ml', ['react']); -import { getCreateFilterListBreadcrumbs, getEditFilterListBreadcrumbs } from '../../breadcrumbs'; -import { checkFullLicense } from 'plugins/ml/license/check_license'; -import { checkGetJobsPrivilege, checkPermission } from 'plugins/ml/privilege/check_privilege'; -import { getMlNodeCount } from 'plugins/ml/ml_nodes_check/check_ml_nodes'; -import { EditFilterList } from './edit_filter_list'; - import uiRoutes from 'ui/routes'; import { I18nContext } from 'ui/i18n'; +import { getMlNodeCount } from '../../../ml_nodes_check/check_ml_nodes'; +import { checkGetJobsPrivilege, checkPermission } from '../../../privilege/check_privilege'; +import { checkFullLicense } from '../../../license/check_license'; +import { getCreateFilterListBreadcrumbs, getEditFilterListBreadcrumbs } from '../../breadcrumbs'; + +import { EditFilterList } from './edit_filter_list'; const template = `
@@ -34,7 +34,7 @@ uiRoutes CheckLicense: checkFullLicense, privileges: checkGetJobsPrivilege, mlNodeCount: getMlNodeCount, - } + }, }) .when('/settings/filter_lists/edit_filter_list/:filterId', { template, @@ -43,15 +43,15 @@ uiRoutes CheckLicense: checkFullLicense, privileges: checkGetJobsPrivilege, mlNodeCount: getMlNodeCount, - } + }, }); -module.directive('mlEditFilterList', function ($route) { +module.directive('mlEditFilterList', function($route: any) { return { restrict: 'E', replace: false, scope: {}, - link: function (scope, element) { + link(scope: ng.IScope, element: ng.IAugmentedJQuery) { const props = { filterId: $route.current.params.filterId, canCreateFilter: checkPermission('canCreateFilter'), @@ -64,6 +64,6 @@ module.directive('mlEditFilterList', function ($route) { , element[0] ); - } + }, }; }); diff --git a/x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/edit_filter_list.d.ts b/x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/edit_filter_list.d.ts new file mode 100644 index 0000000000000..71d82d7694cf0 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/edit_filter_list.d.ts @@ -0,0 +1,13 @@ +/* + * 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 { FC } from 'react'; + +declare const EditFilterList: FC<{ + filterId: string; + canCreateFilter: boolean; + canDeleteFilter: boolean; +}>; diff --git a/x-pack/legacy/plugins/ml/public/settings/filter_lists/list/index.js b/x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/index.ts similarity index 99% rename from x-pack/legacy/plugins/ml/public/settings/filter_lists/list/index.js rename to x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/index.ts index fd75a9ceb9b49..aa8b2ec2c29c9 100644 --- a/x-pack/legacy/plugins/ml/public/settings/filter_lists/list/index.js +++ b/x-pack/legacy/plugins/ml/public/settings/filter_lists/edit/index.ts @@ -4,6 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ - - import './directive'; diff --git a/x-pack/legacy/plugins/ml/public/settings/filter_lists/index.js b/x-pack/legacy/plugins/ml/public/settings/filter_lists/index.ts similarity index 99% rename from x-pack/legacy/plugins/ml/public/settings/filter_lists/index.js rename to x-pack/legacy/plugins/ml/public/settings/filter_lists/index.ts index 463b602c20c9a..6a942d5c251df 100644 --- a/x-pack/legacy/plugins/ml/public/settings/filter_lists/index.js +++ b/x-pack/legacy/plugins/ml/public/settings/filter_lists/index.ts @@ -4,6 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ - import './edit'; import './list'; diff --git a/x-pack/legacy/plugins/ml/public/settings/filter_lists/list/directive.js b/x-pack/legacy/plugins/ml/public/settings/filter_lists/list/directive.tsx similarity index 64% rename from x-pack/legacy/plugins/ml/public/settings/filter_lists/list/directive.js rename to x-pack/legacy/plugins/ml/public/settings/filter_lists/list/directive.tsx index 311bf1bcb358a..7b572344c603b 100644 --- a/x-pack/legacy/plugins/ml/public/settings/filter_lists/list/directive.js +++ b/x-pack/legacy/plugins/ml/public/settings/filter_lists/list/directive.tsx @@ -4,45 +4,44 @@ * you may not use this file except in compliance with the Elastic License. */ - import 'ngreact'; import React from 'react'; import ReactDOM from 'react-dom'; +// @ts-ignore import { uiModules } from 'ui/modules'; const module = uiModules.get('apps/ml', ['react']); -import { getFilterListsBreadcrumbs } from '../../breadcrumbs'; -import { checkFullLicense } from 'plugins/ml/license/check_license'; -import { checkGetJobsPrivilege, checkPermission } from 'plugins/ml/privilege/check_privilege'; -import { getMlNodeCount } from 'plugins/ml/ml_nodes_check/check_ml_nodes'; -import { FilterLists } from './filter_lists'; - import uiRoutes from 'ui/routes'; import { I18nContext } from 'ui/i18n'; +import { checkFullLicense } from '../../../license/check_license'; +import { checkGetJobsPrivilege, checkPermission } from '../../../privilege/check_privilege'; +import { getMlNodeCount } from '../../../ml_nodes_check/check_ml_nodes'; +import { getFilterListsBreadcrumbs } from '../../breadcrumbs'; + +import { FilterLists } from './filter_lists'; const template = `
`; -uiRoutes - .when('/settings/filter_lists', { - template, - k7Breadcrumbs: getFilterListsBreadcrumbs, - resolve: { - CheckLicense: checkFullLicense, - privileges: checkGetJobsPrivilege, - mlNodeCount: getMlNodeCount, - } - }); - -module.directive('mlFilterLists', function () { +uiRoutes.when('/settings/filter_lists', { + template, + k7Breadcrumbs: getFilterListsBreadcrumbs, + resolve: { + CheckLicense: checkFullLicense, + privileges: checkGetJobsPrivilege, + mlNodeCount: getMlNodeCount, + }, +}); + +module.directive('mlFilterLists', function() { return { restrict: 'E', replace: false, scope: {}, - link: function (scope, element) { + link(scope: ng.IScope, element: ng.IAugmentedJQuery) { const props = { canCreateFilter: checkPermission('canCreateFilter'), canDeleteFilter: checkPermission('canDeleteFilter'), @@ -54,6 +53,6 @@ module.directive('mlFilterLists', function () { , element[0] ); - } + }, }; }); diff --git a/x-pack/legacy/plugins/ml/common/util/parse_interval.d.ts b/x-pack/legacy/plugins/ml/public/settings/filter_lists/list/filter_lists.d.ts similarity index 67% rename from x-pack/legacy/plugins/ml/common/util/parse_interval.d.ts rename to x-pack/legacy/plugins/ml/public/settings/filter_lists/list/filter_lists.d.ts index 7c4f40cc6c9d7..b14b19594e0b5 100644 --- a/x-pack/legacy/plugins/ml/common/util/parse_interval.d.ts +++ b/x-pack/legacy/plugins/ml/public/settings/filter_lists/list/filter_lists.d.ts @@ -4,6 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Duration } from 'moment'; +import { FC } from 'react'; -export function parseInterval(interval: string): Duration; +declare const FilterLists: FC<{ + canCreateFilter: boolean; + canDeleteFilter: boolean; +}>; diff --git a/x-pack/legacy/plugins/ml/public/settings/calendars/list/index.js b/x-pack/legacy/plugins/ml/public/settings/filter_lists/list/index.ts similarity index 99% rename from x-pack/legacy/plugins/ml/public/settings/calendars/list/index.js rename to x-pack/legacy/plugins/ml/public/settings/filter_lists/list/index.ts index fd75a9ceb9b49..aa8b2ec2c29c9 100644 --- a/x-pack/legacy/plugins/ml/public/settings/calendars/list/index.js +++ b/x-pack/legacy/plugins/ml/public/settings/filter_lists/list/index.ts @@ -4,6 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ - - import './directive'; diff --git a/x-pack/legacy/plugins/ml/public/settings/index.js b/x-pack/legacy/plugins/ml/public/settings/index.ts similarity index 99% rename from x-pack/legacy/plugins/ml/public/settings/index.js rename to x-pack/legacy/plugins/ml/public/settings/index.ts index 659f135d98c50..d9fc996ae4a30 100644 --- a/x-pack/legacy/plugins/ml/public/settings/index.js +++ b/x-pack/legacy/plugins/ml/public/settings/index.ts @@ -4,8 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ - - import './settings_directive'; import './calendars'; import './filter_lists'; diff --git a/x-pack/legacy/plugins/ml/public/settings/settings_directive.js b/x-pack/legacy/plugins/ml/public/settings/settings_directive.tsx similarity index 80% rename from x-pack/legacy/plugins/ml/public/settings/settings_directive.js rename to x-pack/legacy/plugins/ml/public/settings/settings_directive.tsx index 8692d903b1bd0..5102c7650a7b1 100644 --- a/x-pack/legacy/plugins/ml/public/settings/settings_directive.js +++ b/x-pack/legacy/plugins/ml/public/settings/settings_directive.tsx @@ -4,44 +4,41 @@ * you may not use this file except in compliance with the Elastic License. */ - import 'ngreact'; 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 uiRoutes from 'ui/routes'; +import { timefilter } from 'ui/timefilter'; import { checkFullLicense } from '../license/check_license'; import { checkGetJobsPrivilege, checkPermission } from '../privilege/check_privilege'; import { getMlNodeCount } from '../ml_nodes_check/check_ml_nodes'; import { getSettingsBreadcrumbs } from './breadcrumbs'; -import { I18nContext } from 'ui/i18n'; -import uiRoutes from 'ui/routes'; -import { timefilter } from 'ui/timefilter'; - const template = `
`; -uiRoutes - .when('/settings', { - template, - k7Breadcrumbs: getSettingsBreadcrumbs, - resolve: { - CheckLicense: checkFullLicense, - privileges: checkGetJobsPrivilege, - mlNodeCount: getMlNodeCount, - } - }); - +uiRoutes.when('/settings', { + template, + k7Breadcrumbs: getSettingsBreadcrumbs, + resolve: { + CheckLicense: checkFullLicense, + privileges: checkGetJobsPrivilege, + mlNodeCount: getMlNodeCount, + }, +}); +// @ts-ignore import { Settings } from './settings.js'; -module.directive('mlSettings', function () { - +module.directive('mlSettings', function() { const canGetFilters = checkPermission('canGetFilters'); const canGetCalendars = checkPermission('canGetCalendars'); @@ -49,7 +46,7 @@ module.directive('mlSettings', function () { restrict: 'E', replace: false, scope: {}, - link: function (scope, element) { + link(scope: ng.IScope, element: ng.IAugmentedJQuery) { timefilter.disableTimeRangeSelector(); timefilter.disableAutoRefreshSelector(); @@ -59,6 +56,6 @@ module.directive('mlSettings', function () { , element[0] ); - } + }, }; }); diff --git a/x-pack/legacy/plugins/ml/public/timeseriesexplorer/timeseriesexplorer.js b/x-pack/legacy/plugins/ml/public/timeseriesexplorer/timeseriesexplorer.js index 857e12cbbe942..1dec12a396578 100644 --- a/x-pack/legacy/plugins/ml/public/timeseriesexplorer/timeseriesexplorer.js +++ b/x-pack/legacy/plugins/ml/public/timeseriesexplorer/timeseriesexplorer.js @@ -68,7 +68,6 @@ import { mlJobService } from '../services/job_service'; import { mlResultsService } from '../services/results_service'; import { mlTimefilterRefresh$ } from '../services/timefilter_refresh_service'; -import { getIndexPatterns } from '../util/index_utils'; import { getBoundsRoundedToInterval } from '../util/time_buckets'; import { APP_STATE_ACTION, CHARTS_POINT_TARGET, TIME_FIELD_NAME } from './timeseriesexplorer_constants'; @@ -827,7 +826,7 @@ export class TimeSeriesExplorer extends React.Component { () => { this.updateControlsForDetector(() => { // Populate the map of jobs / detectors / field formatters for the selected IDs and refresh. - mlFieldFormatService.populateFormats([jobId], getIndexPatterns()) + mlFieldFormatService.populateFormats([jobId]) .catch((err) => { console.log('Error populating field formats:', err); }) // Load the data - if the FieldFormats failed to populate // the default formatting will be used for metric values. diff --git a/x-pack/legacy/plugins/ml/public/util/index_utils.ts b/x-pack/legacy/plugins/ml/public/util/index_utils.ts index 8a1cfda54a5f4..5c15cdd6b8df0 100644 --- a/x-pack/legacy/plugins/ml/public/util/index_utils.ts +++ b/x-pack/legacy/plugins/ml/public/util/index_utils.ts @@ -17,8 +17,6 @@ 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(); @@ -30,20 +28,6 @@ export function loadIndexPatterns() { }) .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; }); } @@ -62,7 +46,7 @@ export function getIndexPatternIdFromName(name: string) { return indexPatternCache[j].id; } } - return name; + return null; } export function loadCurrentIndexPattern(indexPatterns: IndexPatterns, $route: Record) { diff --git a/x-pack/legacy/plugins/ml/server/lib/check_license/__tests__/check_license.js b/x-pack/legacy/plugins/ml/server/lib/check_license/__tests__/check_license.ts similarity index 80% rename from x-pack/legacy/plugins/ml/server/lib/check_license/__tests__/check_license.js rename to x-pack/legacy/plugins/ml/server/lib/check_license/__tests__/check_license.ts index 25411bb2775d5..5a8b4fdcc76db 100644 --- a/x-pack/legacy/plugins/ml/server/lib/check_license/__tests__/check_license.js +++ b/x-pack/legacy/plugins/ml/server/lib/check_license/__tests__/check_license.ts @@ -4,20 +4,18 @@ * you may not use this file except in compliance with the Elastic License. */ - - import expect from '@kbn/expect'; import sinon from 'sinon'; import { set } from 'lodash'; +import { XPackInfo } from '../../../../../../../legacy/plugins/xpack_main/server/lib/xpack_info'; import { checkLicense } from '../check_license'; describe('check_license', () => { - - let mockLicenseInfo; - beforeEach(() => mockLicenseInfo = {}); + let mockLicenseInfo: XPackInfo; + beforeEach(() => (mockLicenseInfo = {} as XPackInfo)); describe('license information is undefined', () => { - beforeEach(() => mockLicenseInfo = undefined); + beforeEach(() => (mockLicenseInfo = {} as XPackInfo)); it('should set isAvailable to false', () => { expect(checkLicense(mockLicenseInfo).isAvailable).to.be(false); @@ -37,7 +35,7 @@ describe('check_license', () => { }); describe('license information is not available', () => { - beforeEach(() => mockLicenseInfo.isAvailable = () => false); + beforeEach(() => (mockLicenseInfo.isAvailable = () => false)); it('should set isAvailable to false', () => { expect(checkLicense(mockLicenseInfo).isAvailable).to.be(false); @@ -64,14 +62,21 @@ describe('check_license', () => { describe('& ML is disabled in Elasticsearch', () => { beforeEach(() => { - set(mockLicenseInfo, 'feature', sinon.stub().withArgs('ml').returns({ isEnabled: () => false })); + set( + mockLicenseInfo, + 'feature', + sinon + .stub() + .withArgs('ml') + .returns({ isEnabled: () => false }) + ); }); - it ('should set showLinks to false', () => { + it('should set showLinks to false', () => { expect(checkLicense(mockLicenseInfo).showLinks).to.be(false); }); - it ('should set isAvailable to false', () => { + it('should set isAvailable to false', () => { expect(checkLicense(mockLicenseInfo).isAvailable).to.be(false); }); @@ -86,7 +91,14 @@ describe('check_license', () => { describe('& ML is enabled in Elasticsearch', () => { beforeEach(() => { - set(mockLicenseInfo, 'feature', sinon.stub().withArgs('ml').returns({ isEnabled: () => true })); + set( + mockLicenseInfo, + 'feature', + sinon + .stub() + .withArgs('ml') + .returns({ isEnabled: () => true }) + ); }); describe('& license is trial or platinum', () => { @@ -99,11 +111,11 @@ describe('check_license', () => { expect(checkLicense(mockLicenseInfo).isAvailable).to.be(true); }); - it ('should set showLinks to true', () => { + it('should set showLinks to true', () => { expect(checkLicense(mockLicenseInfo).showLinks).to.be(true); }); - it ('should set enableLinks to true', () => { + it('should set enableLinks to true', () => { expect(checkLicense(mockLicenseInfo).enableLinks).to.be(true); }); @@ -119,11 +131,11 @@ describe('check_license', () => { expect(checkLicense(mockLicenseInfo).isAvailable).to.be(true); }); - it ('should set showLinks to true', () => { + it('should set showLinks to true', () => { expect(checkLicense(mockLicenseInfo).showLinks).to.be(true); }); - it ('should set enableLinks to true', () => { + it('should set enableLinks to true', () => { expect(checkLicense(mockLicenseInfo).enableLinks).to.be(true); }); @@ -143,7 +155,7 @@ describe('check_license', () => { expect(checkLicense(mockLicenseInfo).isAvailable).to.be(true); }); - it ('should set showLinks to true', () => { + it('should set showLinks to true', () => { expect(checkLicense(mockLicenseInfo).showLinks).to.be(true); }); }); diff --git a/x-pack/legacy/plugins/ml/server/lib/check_license/check_license.d.ts b/x-pack/legacy/plugins/ml/server/lib/check_license/check_license.d.ts deleted file mode 100644 index 6987df3c3c0ba..0000000000000 --- a/x-pack/legacy/plugins/ml/server/lib/check_license/check_license.d.ts +++ /dev/null @@ -1,17 +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 { LICENSE_TYPE } from '../../../common/constants/license'; -interface Response { - isAvailable: boolean; - showLinks: boolean; - enableLinks: boolean; - licenseType: LICENSE_TYPE; - hasExpired: boolean; - message: string; -} - -export function checkLicense(xpackLicenseInfo: any): Response; diff --git a/x-pack/legacy/plugins/ml/server/lib/check_license/check_license.js b/x-pack/legacy/plugins/ml/server/lib/check_license/check_license.ts similarity index 66% rename from x-pack/legacy/plugins/ml/server/lib/check_license/check_license.js rename to x-pack/legacy/plugins/ml/server/lib/check_license/check_license.ts index b64bc98539ffd..bb92705880dde 100644 --- a/x-pack/legacy/plugins/ml/server/lib/check_license/check_license.js +++ b/x-pack/legacy/plugins/ml/server/lib/check_license/check_license.ts @@ -4,11 +4,20 @@ * you may not use this file except in compliance with the Elastic License. */ - -import { LICENSE_TYPE } from '../../../common/constants/license'; import { i18n } from '@kbn/i18n'; +import { LICENSE_TYPE } from '../../../common/constants/license'; +import { XPackInfo } from '../../../../../../legacy/plugins/xpack_main/server/lib/xpack_info'; + +interface Response { + isAvailable: boolean; + showLinks: boolean; + enableLinks: boolean; + licenseType?: LICENSE_TYPE; + hasExpired?: boolean; + message?: string; +} -export function checkLicense(xpackLicenseInfo) { +export function checkLicense(xpackLicenseInfo: XPackInfo): Response { // If, for some reason, we cannot get the license information // from Elasticsearch, assume worst case and disable the Machine Learning UI if (!xpackLicenseInfo || !xpackLicenseInfo.isAvailable()) { @@ -16,9 +25,13 @@ export function checkLicense(xpackLicenseInfo) { isAvailable: false, showLinks: true, enableLinks: false, - message: i18n.translate('xpack.ml.checkLicense.licenseInformationNotAvailableThisTimeMessage', { - defaultMessage: 'You cannot use Machine Learning because license information is not available at this time.' - }) + message: i18n.translate( + 'xpack.ml.checkLicense.licenseInformationNotAvailableThisTimeMessage', + { + defaultMessage: + 'You cannot use Machine Learning because license information is not available at this time.', + } + ), }; } @@ -29,18 +42,15 @@ export function checkLicense(xpackLicenseInfo) { showLinks: false, enableLinks: false, message: i18n.translate('xpack.ml.checkLicense.mlIsUnavailableMessage', { - defaultMessage: 'Machine Learning is unavailable' - }) + defaultMessage: 'Machine Learning is unavailable', + }), }; } - const VALID_FULL_LICENSE_MODES = [ - 'trial', - 'platinum' - ]; + const VALID_FULL_LICENSE_MODES = ['trial', 'platinum']; const isLicenseModeValid = xpackLicenseInfo.license.isOneOf(VALID_FULL_LICENSE_MODES); - const licenseType = (isLicenseModeValid === true) ? LICENSE_TYPE.FULL : LICENSE_TYPE.BASIC; + const licenseType = isLicenseModeValid === true ? LICENSE_TYPE.FULL : LICENSE_TYPE.BASIC; const isLicenseActive = xpackLicenseInfo.license.isActive(); const licenseTypeName = xpackLicenseInfo.license.getType(); @@ -54,8 +64,8 @@ export function checkLicense(xpackLicenseInfo) { licenseType, message: i18n.translate('xpack.ml.checkLicense.licenseHasExpiredMessage', { defaultMessage: 'Your {licenseTypeName} Machine Learning license has expired.', - values: { licenseTypeName } - }) + values: { licenseTypeName }, + }), }; } diff --git a/x-pack/legacy/plugins/ml/server/models/job_validation/validate_bucket_span.js b/x-pack/legacy/plugins/ml/server/models/job_validation/validate_bucket_span.js index 2a9d3064ee825..c80c4851bde59 100644 --- a/x-pack/legacy/plugins/ml/server/models/job_validation/validate_bucket_span.js +++ b/x-pack/legacy/plugins/ml/server/models/job_validation/validate_bucket_span.js @@ -9,7 +9,7 @@ import { estimateBucketSpanFactory } from '../../models/bucket_span_estimator'; import { mlFunctionToESAggregation } from '../../../common/util/job_utils'; import { SKIP_BUCKET_SPAN_ESTIMATION } from '../../../common/constants/validation'; -import { parseInterval } from '../../../common/util/parse_interval.js'; +import { parseInterval } from '../../../common/util/parse_interval'; import { validateJobObject } from './validate_job_object'; diff --git a/x-pack/legacy/plugins/ml/server/models/job_validation/validate_time_range.js b/x-pack/legacy/plugins/ml/server/models/job_validation/validate_time_range.js index 9c48fae1739b9..bffad443b4c14 100644 --- a/x-pack/legacy/plugins/ml/server/models/job_validation/validate_time_range.js +++ b/x-pack/legacy/plugins/ml/server/models/job_validation/validate_time_range.js @@ -9,7 +9,7 @@ import _ from 'lodash'; import { ES_FIELD_TYPES } from '../../../../../../../src/plugins/data/server'; -import { parseInterval } from '../../../common/util/parse_interval.js'; +import { parseInterval } from '../../../common/util/parse_interval'; import { validateJobObject } from './validate_job_object'; const BUCKET_SPAN_COMPARE_FACTOR = 25;