From d0a9f7fff267703e9a4b2968e4c514965caa2ed0 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Wed, 11 Dec 2019 15:58:11 +0000 Subject: [PATCH] [ML] Replacing angular routing (#51842) * [ML] Replacing angular routing * removing old files * changing overview * renaming overview route * adding df analytics routes * adding timeseriesexplorer route * removing old files * adding route for explorer * adding access denied page * adding module view or create redirect * fixing job cloning * adding breadcrumb system * removing old breadcrumbs files * fix include * enabling management section * injecting app dependencies * fixing missed dependencies * fixing saved searches * fixing type errors * removing included data start * code clean up * updating translations * fixing router test failures * fixing functional tests * removing last use of SavedSearch * removing comment * fixing bug in line chart query * improving saved search jobs * fixing data viz functional test * adding comment * dealing with time range error * removing unnecessary chrome imports * cleaning up code * moving resolver to own file * changes based on review * fixing index data viz on basic license * fixing edit calendar * adding create job breadcrumb * fixing results appstate * fixing management links * updating new job constants file * fixing rebase conflicts * removing commented out code * adding additional text to the resolver error --- .../legacy/plugins/ml/common/constants/app.ts | 7 + .../ml/common/constants/feature_flags.ts | 3 +- .../constants/new_job.ts} | 0 .../legacy/plugins/ml/common/types/kibana.ts | 11 ++ .../plugins/ml/common/util/job_utils.js | 2 +- x-pack/legacy/plugins/ml/index.ts | 4 +- x-pack/legacy/plugins/ml/kibana.json | 8 + .../application/access_denied/index.tsx | 34 +--- .../public/application/access_denied/page.tsx | 2 +- .../plugins/ml/public/application/app.js | 36 ---- .../plugins/ml/public/application/app.tsx | 53 ++++++ .../annotations_table/annotations_table.js | 3 +- .../components/anomalies_table/links_menu.js | 2 +- .../data_recognizer/data_recognizer.d.ts | 4 +- .../data_recognizer/recognized_result.js | 2 +- .../components/navigation_menu/main_tabs.tsx | 3 +- .../components/navigation_menu/tabs.tsx | 3 +- .../contexts/kibana/__mocks__/saved_search.ts | 27 ++- .../contexts/kibana/kibana_context.ts | 7 +- .../data_frame_analytics/breadcrumbs.ts | 21 --- .../pages/analytics_exploration/directive.tsx | 69 -------- .../pages/analytics_exploration/index.ts} | 3 +- .../pages/analytics_exploration/route.ts | 30 ---- .../pages/analytics_management/directive.tsx | 61 ------- .../pages/analytics_management/index.ts} | 5 +- .../pages/analytics_management/route.ts | 29 ---- .../application/datavisualizer/breadcrumbs.ts | 13 -- .../datavisualizer_selector.tsx | 4 +- .../application/datavisualizer/directive.tsx | 54 ------ .../datavisualizer/file_based/breadcrumbs.ts | 23 --- .../components/import_view/import_view.js | 2 +- .../components/results_links/results_links.js | 4 +- .../file_based/file_datavisualizer.tsx | 10 +- .../file_datavisualizer_directive.tsx | 68 -------- .../datavisualizer/file_based/index.ts | 2 +- .../application/datavisualizer/index.ts | 4 +- .../datavisualizer/index_based/breadcrumbs.ts | 27 --- .../actions_panel/actions_panel.tsx | 7 +- .../datavisualizer/index_based/directive.tsx | 61 ------- .../datavisualizer/index_based/index.ts | 3 +- .../datavisualizer/index_based/page.tsx | 7 +- .../datavisualizer/index_based/route.ts | 28 ---- .../application/explorer/breadcrumbs.ts | 23 --- .../public/application/explorer/explorer.js | 3 +- .../explorer/explorer_directive.tsx | 110 ------------ .../application/explorer/explorer_route.ts | 27 --- .../ml/public/application/explorer/index.ts | 7 +- .../plugins/ml/public/application/index.scss | 45 +++++ .../ml/public/application/jobs/breadcrumbs.ts | 112 ------------- .../{data_frame_analytics => jobs}/index.ts | 6 +- .../components/job_actions/results.js | 5 +- .../job_details/extract_job_details.js | 3 +- .../forecasts_table/forecasts_table.js | 3 +- .../jobs_list_view/jobs_list_view.js | 9 - .../application/jobs/jobs_list/directive.js | 59 ------- .../jobs/{index.js => jobs_list/index.ts} | 5 +- .../jobs/jobs_list/{jobs.js => jobs.tsx} | 17 +- .../job_creator/advanced_job_creator.ts | 10 +- .../new_job/common/job_creator/configs/job.ts | 2 +- .../new_job/common/job_creator/job_creator.ts | 16 +- .../common/job_creator/job_creator_factory.ts | 6 +- .../job_creator/multi_metric_job_creator.ts | 14 +- .../job_creator/population_job_creator.ts | 10 +- .../job_creator/single_metric_job_creator.ts | 10 +- .../new_job/common/job_creator/type_guards.ts | 2 +- .../common/job_creator/util/general.ts | 2 +- .../common/results_loader/results_loader.ts | 2 +- .../public/application/jobs/new_job/index.ts | 14 -- .../query_delay/query_delay_input.tsx | 2 +- .../advanced_section/advanced_section.tsx | 2 +- .../multi_metric_view/chart_grid.tsx | 2 +- .../components/population_view/chart_grid.tsx | 2 +- .../components/split_cards/split_cards.tsx | 2 +- .../components/split_field/description.tsx | 2 +- .../pick_fields_step/pick_fields.tsx | 2 +- .../datafeed_details/datafeed_details.tsx | 2 +- .../detector_chart/detector_chart.tsx | 2 +- .../pages/components/summary_step/summary.tsx | 2 +- .../components/time_range_step/time_range.tsx | 20 ++- .../components/validation_step/validation.tsx | 2 +- .../index_or_search/__test__/directive.js | 45 ----- .../pages/index_or_search/directive.tsx | 42 ----- .../new_job/pages/index_or_search/index.ts | 8 + .../preconfigured_job_redirect.ts | 7 +- .../new_job/pages/index_or_search/route.ts | 47 ------ .../pages/job_type/__test__/directive.js | 45 ----- .../jobs/new_job/pages/job_type/directive.tsx | 64 ------- .../jobs/new_job/pages/job_type/index.ts | 7 + .../jobs/new_job/pages/job_type/page.tsx | 40 ++--- .../jobs/new_job/pages/job_type/route.ts | 25 --- .../jobs/new_job/pages/new_job/directive.tsx | 76 --------- .../jobs/new_job/pages/new_job/index.ts | 7 + .../jobs/new_job/pages/new_job/page.tsx | 4 +- .../jobs/new_job/pages/new_job/route.ts | 65 -------- .../jobs/new_job/pages/new_job/wizard.tsx | 2 +- .../pages/new_job/wizard_horizontal_steps.tsx | 2 +- .../new_job/pages/new_job/wizard_steps.tsx | 4 +- .../new_job/recognize/__test__/directive.js | 45 ----- .../jobs/new_job/recognize/directive.tsx | 68 -------- .../jobs/new_job/recognize/index.ts | 7 + .../jobs/new_job/recognize/page.tsx | 8 +- .../jobs/new_job/recognize/resolvers.ts | 11 +- .../jobs/new_job/recognize/route.ts | 34 ---- .../jobs/new_job/utils/new_job_utils.ts | 50 +++--- .../application/overview/breadcrumbs.ts | 23 --- .../public/application/overview/directive.tsx | 38 ----- .../ml/public/application/overview/index.ts | 3 +- .../{ => application/routing}/breadcrumbs.ts | 15 +- .../ml/public/application/routing/index.ts | 7 + .../route.ts => routing/resolvers.ts} | 31 ++-- .../ml/public/application/routing/router.tsx | 71 ++++++++ .../routing/routes/access_denied.tsx | 36 ++++ .../analytics_job_exploration.tsx | 57 +++++++ .../analytics_jobs_list.tsx | 39 +++++ .../routes/data_frame_analytics/index.ts | 8 + .../routes/datavisualizer/datavisualizer.tsx | 40 +++++ .../routes/datavisualizer/file_based.tsx | 55 ++++++ .../routing/routes/datavisualizer/index.ts | 9 + .../routes/datavisualizer/index_based.tsx | 53 ++++++ .../application/routing/routes/explorer.tsx | 156 ++++++++++++++++++ .../application/routing/routes/index.ts | 15 ++ .../application/routing/routes/jobs_list.tsx | 40 +++++ .../routing/routes/new_job/index.ts | 11 ++ .../routes/new_job/index_or_search.tsx | 90 ++++++++++ .../routing/routes/new_job/job_type.tsx | 43 +++++ .../routing/routes/new_job/new_job.tsx | 33 ++++ .../routing/routes/new_job/recognize.tsx | 66 ++++++++ .../routing/routes/new_job/wizard.tsx | 121 ++++++++++++++ .../application/routing/routes/overview.tsx | 60 +++++++ .../routing/routes/settings/calendar_list.tsx | 56 +++++++ .../routes/settings/calendar_new_edit.tsx | 92 +++++++++++ .../routing/routes/settings/filter_list.tsx | 57 +++++++ .../routes/settings/filter_list_new_edit.tsx | 98 +++++++++++ .../routing/routes/settings/index.ts | 11 ++ .../routing/routes/settings/settings.tsx | 46 ++++++ .../routing/routes/timeseriesexplorer.tsx | 155 +++++++++++++++++ .../application/routing/use_resolver.ts | 70 ++++++++ .../application/services/job_service.d.ts | 4 +- .../application/services/job_service.js | 2 +- .../services/new_job_capabilities_service.ts | 21 +-- .../application/settings/breadcrumbs.ts | 86 ---------- .../__snapshots__/calendar_form.test.js.snap | 2 +- .../edit/calendar_form/calendar_form.js | 3 +- .../settings/calendars/edit/directive.tsx | 69 -------- .../settings/calendars/edit/index.ts | 2 +- .../settings/calendars/edit/new_calendar.d.ts | 2 +- .../settings/calendars/edit/new_calendar.js | 5 +- .../application/settings/calendars/index.ts | 8 + .../settings/calendars/list/directive.tsx | 58 ------- .../settings/calendars/list/index.ts | 2 +- .../table/__snapshots__/table.test.js.snap | 2 +- .../settings/calendars/list/table/table.js | 6 +- .../settings/filter_lists/edit/directive.tsx | 69 -------- .../filter_lists/edit/edit_filter_list.d.ts | 2 +- .../settings/filter_lists/edit/index.ts | 2 +- .../settings/filter_lists/index.ts | 4 +- .../settings/filter_lists/list/directive.tsx | 58 ------- .../settings/filter_lists/list/index.ts | 2 +- .../settings/filter_lists/list/table.js | 5 +- .../ml/public/application/settings/index.ts | 4 +- .../public/application/settings/settings.tsx | 7 +- .../settings/settings_directive.tsx | 60 ------- .../timeseriesexplorer/breadcrumbs.js | 27 --- .../application/timeseriesexplorer/index.js | 11 -- .../application/timeseriesexplorer/index.ts | 7 + .../timeseriesexplorer.d.ts | 15 ++ .../timeseriesexplorer/timeseriesexplorer.js | 2 +- .../timeseriesexplorer_directive.js | 111 ------------- .../timeseriesexplorer_route.js | 30 ---- .../ml/public/application/util/chart_utils.js | 3 +- .../application/util/chart_utils.test.js | 2 +- .../ml/public/application/util/index_utils.ts | 80 ++++++--- x-pack/legacy/plugins/ml/public/index.scss | 45 ----- x-pack/legacy/plugins/ml/public/index.ts | 12 ++ x-pack/legacy/plugins/ml/public/legacy.ts | 17 ++ x-pack/legacy/plugins/ml/public/plugin.ts | 46 ++++++ .../models/job_service/new_job/line_chart.ts | 8 + .../translations/translations/ja-JP.json | 3 - .../translations/translations/zh-CN.json | 3 - 179 files changed, 2198 insertions(+), 2437 deletions(-) create mode 100644 x-pack/legacy/plugins/ml/common/constants/app.ts rename x-pack/legacy/plugins/ml/{public/application/jobs/new_job/common/job_creator/util/constants.ts => common/constants/new_job.ts} (100%) create mode 100644 x-pack/legacy/plugins/ml/kibana.json delete mode 100644 x-pack/legacy/plugins/ml/public/application/app.js create mode 100644 x-pack/legacy/plugins/ml/public/application/app.tsx delete mode 100644 x-pack/legacy/plugins/ml/public/application/data_frame_analytics/breadcrumbs.ts delete mode 100644 x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/directive.tsx rename x-pack/legacy/plugins/ml/public/application/{jobs/jobs_list/index.js => data_frame_analytics/pages/analytics_exploration/index.ts} (88%) delete mode 100644 x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/route.ts delete mode 100644 x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/directive.tsx rename x-pack/legacy/plugins/ml/public/application/{settings/calendars/index.js => data_frame_analytics/pages/analytics_management/index.ts} (87%) delete mode 100644 x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/route.ts delete mode 100644 x-pack/legacy/plugins/ml/public/application/datavisualizer/breadcrumbs.ts delete mode 100644 x-pack/legacy/plugins/ml/public/application/datavisualizer/directive.tsx delete mode 100644 x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/breadcrumbs.ts delete mode 100644 x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/file_datavisualizer_directive.tsx delete mode 100644 x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/breadcrumbs.ts delete mode 100644 x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/directive.tsx delete mode 100644 x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/route.ts delete mode 100644 x-pack/legacy/plugins/ml/public/application/explorer/breadcrumbs.ts delete mode 100644 x-pack/legacy/plugins/ml/public/application/explorer/explorer_directive.tsx delete mode 100644 x-pack/legacy/plugins/ml/public/application/explorer/explorer_route.ts create mode 100644 x-pack/legacy/plugins/ml/public/application/index.scss delete mode 100644 x-pack/legacy/plugins/ml/public/application/jobs/breadcrumbs.ts rename x-pack/legacy/plugins/ml/public/application/{data_frame_analytics => jobs}/index.ts (56%) delete mode 100644 x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/directive.js rename x-pack/legacy/plugins/ml/public/application/jobs/{index.js => jobs_list/index.ts} (84%) rename x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/{jobs.js => jobs.tsx} (59%) delete mode 100644 x-pack/legacy/plugins/ml/public/application/jobs/new_job/index.ts delete mode 100644 x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/index_or_search/__test__/directive.js delete mode 100644 x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/index_or_search/directive.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/index_or_search/index.ts delete mode 100644 x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/index_or_search/route.ts delete mode 100644 x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/job_type/__test__/directive.js delete mode 100644 x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/job_type/directive.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/job_type/index.ts delete mode 100644 x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/job_type/route.ts delete mode 100644 x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/directive.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/index.ts delete mode 100644 x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/route.ts delete mode 100644 x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/__test__/directive.js delete mode 100644 x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/directive.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/index.ts delete mode 100644 x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/route.ts delete mode 100644 x-pack/legacy/plugins/ml/public/application/overview/breadcrumbs.ts delete mode 100644 x-pack/legacy/plugins/ml/public/application/overview/directive.tsx rename x-pack/legacy/plugins/ml/public/{ => application/routing}/breadcrumbs.ts (64%) create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/index.ts rename x-pack/legacy/plugins/ml/public/application/{overview/route.ts => routing/resolvers.ts} (50%) create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/router.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/routes/access_denied.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/routes/data_frame_analytics/analytics_job_exploration.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/routes/data_frame_analytics/analytics_jobs_list.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/routes/data_frame_analytics/index.ts create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/routes/datavisualizer/datavisualizer.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/routes/datavisualizer/file_based.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/routes/datavisualizer/index.ts create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/routes/datavisualizer/index_based.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/routes/explorer.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/routes/index.ts create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/routes/jobs_list.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/routes/new_job/index.ts create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/routes/new_job/index_or_search.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/routes/new_job/job_type.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/routes/new_job/new_job.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/routes/new_job/recognize.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/routes/new_job/wizard.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/routes/overview.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/routes/settings/calendar_list.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/routes/settings/calendar_new_edit.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/routes/settings/filter_list.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/routes/settings/filter_list_new_edit.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/routes/settings/index.ts create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/routes/settings/settings.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/routes/timeseriesexplorer.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/routing/use_resolver.ts delete mode 100644 x-pack/legacy/plugins/ml/public/application/settings/breadcrumbs.ts delete mode 100644 x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/directive.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/settings/calendars/index.ts delete mode 100644 x-pack/legacy/plugins/ml/public/application/settings/calendars/list/directive.tsx delete mode 100644 x-pack/legacy/plugins/ml/public/application/settings/filter_lists/edit/directive.tsx delete mode 100644 x-pack/legacy/plugins/ml/public/application/settings/filter_lists/list/directive.tsx delete mode 100644 x-pack/legacy/plugins/ml/public/application/settings/settings_directive.tsx delete mode 100644 x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/breadcrumbs.js delete mode 100644 x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/index.js create mode 100644 x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/index.ts create mode 100644 x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.d.ts delete mode 100644 x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_directive.js delete mode 100644 x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_route.js delete mode 100644 x-pack/legacy/plugins/ml/public/index.scss create mode 100755 x-pack/legacy/plugins/ml/public/index.ts create mode 100644 x-pack/legacy/plugins/ml/public/legacy.ts create mode 100644 x-pack/legacy/plugins/ml/public/plugin.ts diff --git a/x-pack/legacy/plugins/ml/common/constants/app.ts b/x-pack/legacy/plugins/ml/common/constants/app.ts new file mode 100644 index 000000000000000..140a709b0c42be4 --- /dev/null +++ b/x-pack/legacy/plugins/ml/common/constants/app.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export const API_BASE_PATH = '/api/transform/'; diff --git a/x-pack/legacy/plugins/ml/common/constants/feature_flags.ts b/x-pack/legacy/plugins/ml/common/constants/feature_flags.ts index 96a46c92cb602e3..48e88e79f967400 100644 --- a/x-pack/legacy/plugins/ml/common/constants/feature_flags.ts +++ b/x-pack/legacy/plugins/ml/common/constants/feature_flags.ts @@ -9,6 +9,5 @@ // indices and aliases exist. Based on that the final setting will be available // as an injectedVar on the client side and can be accessed like: // -// import chrome from 'ui/chrome'; -// const mlAnnotationsEnabled = chrome.getInjected('mlAnnotationsEnabled', false); + export const FEATURE_ANNOTATIONS_ENABLED = true; diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/util/constants.ts b/x-pack/legacy/plugins/ml/common/constants/new_job.ts similarity index 100% rename from x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/util/constants.ts rename to x-pack/legacy/plugins/ml/common/constants/new_job.ts diff --git a/x-pack/legacy/plugins/ml/common/types/kibana.ts b/x-pack/legacy/plugins/ml/common/types/kibana.ts index 86db2ce59d7e78b..d647bd882162b7b 100644 --- a/x-pack/legacy/plugins/ml/common/types/kibana.ts +++ b/x-pack/legacy/plugins/ml/common/types/kibana.ts @@ -6,6 +6,8 @@ // custom edits or fixes for default kibana types which are incomplete +import { SavedObjectAttributes, SimpleSavedObject } from 'kibana/public'; + export type IndexPatternTitle = string; export type callWithRequestType = (action: string, params?: any) => Promise; @@ -14,3 +16,12 @@ export interface Route { id: string; k7Breadcrumbs: () => any; } + +export type IndexPatternSavedObject = SimpleSavedObject; +export type SavedSearchSavedObject = SimpleSavedObject; + +export function isSavedSearchSavedObject( + ss: SavedSearchSavedObject | null +): ss is SavedSearchSavedObject { + return ss !== null; +} diff --git a/x-pack/legacy/plugins/ml/common/util/job_utils.js b/x-pack/legacy/plugins/ml/common/util/job_utils.js index 999eb44b372bcd1..cef3475a9654f00 100644 --- a/x-pack/legacy/plugins/ml/common/util/job_utils.js +++ b/x-pack/legacy/plugins/ml/common/util/job_utils.js @@ -12,7 +12,7 @@ import numeral from '@elastic/numeral'; import { ALLOWED_DATA_UNITS, JOB_ID_MAX_LENGTH } from '../constants/validation'; import { parseInterval } from './parse_interval'; import { maxLengthValidator } from './validators'; -import { CREATED_BY_LABEL } from '../../public/application/jobs/new_job/common/job_creator/util/constants'; +import { CREATED_BY_LABEL } from '../../common/constants/new_job'; // work out the default frequency based on the bucket_span in seconds export function calculateDatafeedFrequencyDefaultSeconds(bucketSpanSeconds) { diff --git a/x-pack/legacy/plugins/ml/index.ts b/x-pack/legacy/plugins/ml/index.ts index 9b42998c814fd72..3078a0c812ff1b1 100755 --- a/x-pack/legacy/plugins/ml/index.ts +++ b/x-pack/legacy/plugins/ml/index.ts @@ -41,9 +41,9 @@ export const ml = (kibana: any) => { }), icon: 'plugins/ml/application/ml.svg', euiIconType: 'machineLearningApp', - main: 'plugins/ml/application/app', + main: 'plugins/ml/legacy', }, - styleSheetPaths: resolve(__dirname, 'public/index.scss'), + styleSheetPaths: resolve(__dirname, 'public/application/index.scss'), hacks: ['plugins/ml/application/hacks/toggle_app_link_in_nav'], savedObjectSchemas: { 'ml-telemetry': { diff --git a/x-pack/legacy/plugins/ml/kibana.json b/x-pack/legacy/plugins/ml/kibana.json new file mode 100644 index 000000000000000..f36b48481869063 --- /dev/null +++ b/x-pack/legacy/plugins/ml/kibana.json @@ -0,0 +1,8 @@ +{ + "id": "ml", + "version": "0.0.1", + "kibanaVersion": "kibana", + "configPath": ["ml"], + "server": true, + "ui": true +} diff --git a/x-pack/legacy/plugins/ml/public/application/access_denied/index.tsx b/x-pack/legacy/plugins/ml/public/application/access_denied/index.tsx index 883754896487e81..7e2d651439ae30b 100644 --- a/x-pack/legacy/plugins/ml/public/application/access_denied/index.tsx +++ b/x-pack/legacy/plugins/ml/public/application/access_denied/index.tsx @@ -4,36 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; -import ReactDOM from 'react-dom'; -import uiRoutes from 'ui/routes'; -import { I18nContext } from 'ui/i18n'; -// @ts-ignore -import { uiModules } from 'ui/modules'; -import { AccessDeniedPage } from './page'; - -const module = uiModules.get('apps/ml', ['react']); - -const template = ``; - -uiRoutes.when('/access-denied', { - template, -}); - -module.directive('accessDenied', function() { - return { - scope: {}, - restrict: 'E', - link: async (scope: ng.IScope, element: ng.IAugmentedJQuery) => { - ReactDOM.render( - {React.createElement(AccessDeniedPage)}, - element[0] - ); - - element.on('$destroy', () => { - ReactDOM.unmountComponentAtNode(element[0]); - scope.$destroy(); - }); - }, - }; -}); +export { Page } from './page'; diff --git a/x-pack/legacy/plugins/ml/public/application/access_denied/page.tsx b/x-pack/legacy/plugins/ml/public/application/access_denied/page.tsx index 1c908e114cbebc2..32b2ade5dc9dce6 100644 --- a/x-pack/legacy/plugins/ml/public/application/access_denied/page.tsx +++ b/x-pack/legacy/plugins/ml/public/application/access_denied/page.tsx @@ -21,7 +21,7 @@ import { } from '@elastic/eui'; import { NavigationMenu } from '../components/navigation_menu'; -export const AccessDeniedPage = () => ( +export const Page = () => ( diff --git a/x-pack/legacy/plugins/ml/public/application/app.js b/x-pack/legacy/plugins/ml/public/application/app.js deleted file mode 100644 index 722e2c8d05e9b91..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/app.js +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - - -import 'uiExports/savedObjectTypes'; - -import 'ui/autoload/all'; - -// needed to make syntax highlighting work in ace editors -import 'ace'; - -import './access_denied'; -import './jobs'; -import './overview'; -import './services/calendar_service'; -import './data_frame_analytics'; -import './datavisualizer'; -import './explorer'; -import './timeseriesexplorer'; -import './components/navigation_menu'; -import './components/loading_indicator'; -import './settings'; - -import uiRoutes from 'ui/routes'; - -if (typeof uiRoutes.enable === 'function') { - uiRoutes.enable(); -} - -uiRoutes - .otherwise({ - redirectTo: '/overview' - }); diff --git a/x-pack/legacy/plugins/ml/public/application/app.tsx b/x-pack/legacy/plugins/ml/public/application/app.tsx new file mode 100644 index 000000000000000..c790f1072571626 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/app.tsx @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC } from 'react'; +import ReactDOM from 'react-dom'; + +import 'uiExports/savedObjectTypes'; + +import 'ui/autoload/all'; + +// needed to make syntax highlighting work in ace editors +import 'ace'; + +import { AppMountContext, AppMountParameters } from 'kibana/public'; +import { + IndexPatternsContract, + Plugin as DataPlugin, +} from '../../../../../../src/plugins/data/public'; + +import { KibanaConfigTypeFix } from './contexts/kibana'; + +import { MlRouter } from './routing'; + +export interface MlDependencies extends AppMountParameters { + npData: ReturnType; + indexPatterns: IndexPatternsContract; +} + +interface AppProps { + context: AppMountContext; + indexPatterns: IndexPatternsContract; +} + +const App: FC = ({ context, indexPatterns }) => { + const config = (context.core.uiSettings as never) as KibanaConfigTypeFix; // TODO - make this UiSettingsClientContract, get rid of KibanaConfigTypeFix + + return ( + + ); +}; + +export const renderApp = (context: AppMountContext, { element, indexPatterns }: MlDependencies) => { + ReactDOM.render(, element); + + return () => ReactDOM.unmountComponentAtNode(element); +}; diff --git a/x-pack/legacy/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js b/x-pack/legacy/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js index 909abfd4abc233a..640ae8f962eed63 100644 --- a/x-pack/legacy/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js +++ b/x-pack/legacy/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js @@ -35,7 +35,6 @@ import { } from '@elastic/eui/lib/services'; import { formatDate } from '@elastic/eui/lib/services/format'; -import chrome from 'ui/chrome'; import { addItemToRecentlyAccessed } from '../../../util/recently_accessed'; import { ml } from '../../../services/ml_api_service'; @@ -206,7 +205,7 @@ const AnnotationsTable = injectI18n(class AnnotationsTable extends Component { const url = `?_g=${_g}&_a=${_a}`; addItemToRecentlyAccessed('timeseriesexplorer', job.job_id, url); - window.open(`${chrome.getBasePath()}/app/ml#/timeseriesexplorer${url}`, '_self'); + window.open(`#/timeseriesexplorer${url}`, '_self'); } onMouseOverRow = (record) => { diff --git a/x-pack/legacy/plugins/ml/public/application/components/anomalies_table/links_menu.js b/x-pack/legacy/plugins/ml/public/application/components/anomalies_table/links_menu.js index 19cd77655f97c4d..f237bcc2efc53f8 100644 --- a/x-pack/legacy/plugins/ml/public/application/components/anomalies_table/links_menu.js +++ b/x-pack/legacy/plugins/ml/public/application/components/anomalies_table/links_menu.js @@ -205,7 +205,7 @@ export const LinksMenu = injectI18n(class LinksMenu extends Component { }); // Need to encode the _a parameter in case any entities contain unsafe characters such as '+'. - let path = `${chrome.getBasePath()}/app/ml#/timeseriesexplorer`; + let path = '#/timeseriesexplorer'; path += `?_g=${_g}&_a=${encodeURIComponent(_a)}`; window.open(path, '_blank'); } diff --git a/x-pack/legacy/plugins/ml/public/application/components/data_recognizer/data_recognizer.d.ts b/x-pack/legacy/plugins/ml/public/application/components/data_recognizer/data_recognizer.d.ts index e7d191a31e034e8..94a502e6eadde8f 100644 --- a/x-pack/legacy/plugins/ml/public/application/components/data_recognizer/data_recognizer.d.ts +++ b/x-pack/legacy/plugins/ml/public/application/components/data_recognizer/data_recognizer.d.ts @@ -7,11 +7,11 @@ import { FC } from 'react'; import { IndexPattern } from 'ui/index_patterns'; -import { SavedSearch } from 'src/legacy/core_plugins/kibana/public/discover/types'; +import { SavedSearchSavedObject } from '../../../../common/types/kibana'; declare const DataRecognizer: FC<{ indexPattern: IndexPattern; - savedSearch?: SavedSearch; + savedSearch?: SavedSearchSavedObject | null; results: { count: number; onChange?: Function; diff --git a/x-pack/legacy/plugins/ml/public/application/components/data_recognizer/recognized_result.js b/x-pack/legacy/plugins/ml/public/application/components/data_recognizer/recognized_result.js index 6f511abf89e310e..79b1b501c3829fe 100644 --- a/x-pack/legacy/plugins/ml/public/application/components/data_recognizer/recognized_result.js +++ b/x-pack/legacy/plugins/ml/public/application/components/data_recognizer/recognized_result.js @@ -20,7 +20,7 @@ export const RecognizedResult = ({ indexPattern, savedSearch }) => { - const id = (savedSearch === undefined || savedSearch.id === undefined) ? + const id = (savedSearch === null) ? `index=${indexPattern.id}` : `savedSearchId=${savedSearch.id}`; diff --git a/x-pack/legacy/plugins/ml/public/application/components/navigation_menu/main_tabs.tsx b/x-pack/legacy/plugins/ml/public/application/components/navigation_menu/main_tabs.tsx index cff174eb5627fe1..5735faa9c6f52cf 100644 --- a/x-pack/legacy/plugins/ml/public/application/components/navigation_menu/main_tabs.tsx +++ b/x-pack/legacy/plugins/ml/public/application/components/navigation_menu/main_tabs.tsx @@ -7,7 +7,6 @@ import React, { FC, useState } from 'react'; import { EuiTabs, EuiTab, EuiLink } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import chrome from 'ui/chrome'; import { TabId } from './navigation_menu'; export interface Tab { @@ -82,7 +81,7 @@ export const MainTabs: FC = ({ tabId, disableLinks }) => { return ( diff --git a/x-pack/legacy/plugins/ml/public/application/components/navigation_menu/tabs.tsx b/x-pack/legacy/plugins/ml/public/application/components/navigation_menu/tabs.tsx index 7014164ad97561d..20fa2cca41231ac 100644 --- a/x-pack/legacy/plugins/ml/public/application/components/navigation_menu/tabs.tsx +++ b/x-pack/legacy/plugins/ml/public/application/components/navigation_menu/tabs.tsx @@ -7,7 +7,6 @@ import React, { FC, useState } from 'react'; import { EuiTabs, EuiTab, EuiLink } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import chrome from 'ui/chrome'; import { Tab } from './main_tabs'; import { TabId } from './navigation_menu'; @@ -84,7 +83,7 @@ export const Tabs: FC = ({ tabId, mainTabId, disableLinks }) => { data-test-subj={ TAB_TEST_SUBJECT[id as TAB_TEST_SUBJECTS] + (id === selectedTabId ? ' selected' : '') } - href={`${chrome.getBasePath()}/app/ml#/${id}`} + href={`#/${id}`} key={`${id}-key`} color="text" > diff --git a/x-pack/legacy/plugins/ml/public/application/contexts/kibana/__mocks__/saved_search.ts b/x-pack/legacy/plugins/ml/public/application/contexts/kibana/__mocks__/saved_search.ts index 2bff760ed3711dd..cbbdaf410445e0f 100644 --- a/x-pack/legacy/plugins/ml/public/application/contexts/kibana/__mocks__/saved_search.ts +++ b/x-pack/legacy/plugins/ml/public/application/contexts/kibana/__mocks__/saved_search.ts @@ -4,14 +4,23 @@ * you may not use this file except in compliance with the Elastic License. */ -import { searchSourceMock } from '../../../../../../../../../src/legacy/ui/public/courier/search_source/mocks'; -import { SearchSourceContract } from '../../../../../../../../../src/legacy/ui/public/courier'; - -export const savedSearchMock = { +export const savedSearchMock: any = { id: 'the-saved-search-id', - title: 'the-saved-search-title', - searchSource: searchSourceMock as SearchSourceContract, - columns: [], - sort: [], - destroy: () => {}, + type: 'search', + attributes: { + title: 'the-saved-search-title', + kibanaSavedObjectMeta: { + searchSourceJSON: + '{"highlightAll":true,"version":true,"query":{"query":"foo : \\"bar\\" ","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + }, + }, + references: [ + { + name: 'kibanaSavedObjectMeta.searchSourceJSON.index', + type: 'index-pattern', + id: 'the-index-pattern-id', + }, + ], + migrationVersion: { search: '7.5.0' }, + error: undefined, }; diff --git a/x-pack/legacy/plugins/ml/public/application/contexts/kibana/kibana_context.ts b/x-pack/legacy/plugins/ml/public/application/contexts/kibana/kibana_context.ts index 00989245e20e7fd..9d0a3bc43e25821 100644 --- a/x-pack/legacy/plugins/ml/public/application/contexts/kibana/kibana_context.ts +++ b/x-pack/legacy/plugins/ml/public/application/contexts/kibana/kibana_context.ts @@ -7,12 +7,11 @@ import React from 'react'; import { KibanaConfig } from 'src/legacy/server/kbn_server'; -import { SavedSearch } from 'src/legacy/core_plugins/kibana/public/discover/types'; - import { IndexPattern, IndexPatternsContract, } from '../../../../../../../../src/plugins/data/public'; +import { SavedSearchSavedObject } from '../../../../common/types/kibana'; // set() method is missing in original d.ts export interface KibanaConfigTypeFix extends KibanaConfig { @@ -21,8 +20,8 @@ export interface KibanaConfigTypeFix extends KibanaConfig { export interface KibanaContextValue { combinedQuery: any; - currentIndexPattern: IndexPattern; - currentSavedSearch: SavedSearch; + currentIndexPattern: IndexPattern; // TODO this should be IndexPattern or null + currentSavedSearch: SavedSearchSavedObject | null; indexPatterns: IndexPatternsContract; kibanaConfig: KibanaConfigTypeFix; } diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/breadcrumbs.ts b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/breadcrumbs.ts deleted file mode 100644 index fde854b7f41c3fb..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/breadcrumbs.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; - -import { ML_BREADCRUMB } from '../../breadcrumbs'; - -export function getDataFrameAnalyticsBreadcrumbs() { - return [ - ML_BREADCRUMB, - { - text: i18n.translate('xpack.ml.dataFrameAnalyticsBreadcrumbs.dataFrameLabel', { - defaultMessage: 'Data Frame Analytics', - }), - href: '', - }, - ]; -} diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/directive.tsx b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/directive.tsx deleted file mode 100644 index 1d4ac85ae2e8722..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/directive.tsx +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; -import ReactDOM from 'react-dom'; - -// @ts-ignore -import { uiModules } from 'ui/modules'; -const module = uiModules.get('apps/ml', ['react']); - -import { I18nContext } from 'ui/i18n'; -import { IndexPatternsContract } from '../../../../../../../../../src/plugins/data/public'; - -import { InjectorService } from '../../../../../common/types/angular'; -import { createSearchItems } from '../../../jobs/new_job/utils/new_job_utils'; - -import { KibanaConfigTypeFix, KibanaContext } from '../../../contexts/kibana'; - -import { Page } from './page'; - -module.directive('mlDataFrameAnalyticsExploration', ($injector: InjectorService) => { - return { - scope: {}, - restrict: 'E', - link: (scope: ng.IScope, element: ng.IAugmentedJQuery) => { - const globalState = $injector.get('globalState'); - globalState.fetch(); - - const indexPatterns = $injector.get('indexPatterns'); - const kibanaConfig = $injector.get('config'); - const $route = $injector.get('$route'); - - const { indexPattern, savedSearch, combinedQuery } = createSearchItems( - kibanaConfig, - $route.current.locals.indexPattern, - $route.current.locals.savedSearch - ); - - const kibanaContext = { - combinedQuery, - currentIndexPattern: indexPattern, - currentSavedSearch: savedSearch, - indexPatterns, - kibanaConfig, - }; - - ReactDOM.render( - - - - - , - element[0] - ); - - element.on('$destroy', () => { - ReactDOM.unmountComponentAtNode(element[0]); - scope.$destroy(); - }); - }, - }; -}); diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/index.js b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/index.ts similarity index 88% rename from x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/index.js rename to x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/index.ts index 383901729132653..7e2d651439ae30b 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/index.js +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/index.ts @@ -4,5 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ - -import './directive'; +export { Page } from './page'; diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/route.ts b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/route.ts deleted file mode 100644 index b705c604c190ccd..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/route.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import uiRoutes from 'ui/routes'; - -import { checkFullLicense } from '../../../license/check_license'; -import { checkGetJobsPrivilege } from '../../../privilege/check_privilege'; -import { - loadCurrentIndexPattern, - loadCurrentSavedSearch, - loadIndexPatterns, -} from '../../../util/index_utils'; -import { getDataFrameAnalyticsBreadcrumbs } from '../../breadcrumbs'; - -const template = ``; - -uiRoutes.when('/data_frame_analytics/exploration?', { - template, - k7Breadcrumbs: getDataFrameAnalyticsBreadcrumbs, - resolve: { - CheckLicense: checkFullLicense, - privileges: checkGetJobsPrivilege, - indexPattern: loadCurrentIndexPattern, - indexPatterns: loadIndexPatterns, - savedSearch: loadCurrentSavedSearch, - }, -}); diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/directive.tsx b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/directive.tsx deleted file mode 100644 index 5d97ed6dfcd3d4b..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/directive.tsx +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; -import ReactDOM from 'react-dom'; - -// @ts-ignore -import { uiModules } from 'ui/modules'; -const module = uiModules.get('apps/ml', ['react']); - -import { I18nContext } from 'ui/i18n'; -import { InjectorService } from '../../../../../common/types/angular'; -import { createSearchItems } from '../../../jobs/new_job/utils/new_job_utils'; -import { IndexPatternsContract } from '../../../../../../../../../src/plugins/data/public'; - -import { KibanaConfigTypeFix, KibanaContext } from '../../../contexts/kibana'; - -import { Page } from './page'; - -module.directive('mlDataFrameAnalyticsManagement', ($injector: InjectorService) => { - return { - scope: {}, - restrict: 'E', - link: (scope: ng.IScope, element: ng.IAugmentedJQuery) => { - const indexPatterns = $injector.get('indexPatterns'); - const kibanaConfig = $injector.get('config'); - const $route = $injector.get('$route'); - - const { indexPattern, savedSearch, combinedQuery } = createSearchItems( - kibanaConfig, - $route.current.locals.indexPattern, - $route.current.locals.savedSearch - ); - - const kibanaContext = { - combinedQuery, - currentIndexPattern: indexPattern, - currentSavedSearch: savedSearch, - indexPatterns, - kibanaConfig, - }; - - ReactDOM.render( - - - - - , - element[0] - ); - - element.on('$destroy', () => { - ReactDOM.unmountComponentAtNode(element[0]); - scope.$destroy(); - }); - }, - }; -}); diff --git a/x-pack/legacy/plugins/ml/public/application/settings/calendars/index.js b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/index.ts similarity index 87% rename from x-pack/legacy/plugins/ml/public/application/settings/calendars/index.js rename to x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/index.ts index bcc62f4c5b10e2f..7e2d651439ae30b 100644 --- a/x-pack/legacy/plugins/ml/public/application/settings/calendars/index.js +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/index.ts @@ -4,7 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ - - -import './list'; -import './edit'; +export { Page } from './page'; diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/route.ts b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/route.ts deleted file mode 100644 index 89e02eb4206392a..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/route.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import uiRoutes from 'ui/routes'; - -import { checkFullLicense } from '../../../license/check_license'; -import { checkGetJobsPrivilege } from '../../../privilege/check_privilege'; -import { loadMlServerInfo } from '../../../services/ml_server_info'; -import { getMlNodeCount } from '../../../ml_nodes_check/check_ml_nodes'; -import { loadCurrentIndexPattern, loadCurrentSavedSearch } from '../../../util/index_utils'; -import { getDataFrameAnalyticsBreadcrumbs } from '../../breadcrumbs'; - -const template = ``; - -uiRoutes.when('/data_frame_analytics/?', { - template, - k7Breadcrumbs: getDataFrameAnalyticsBreadcrumbs, - resolve: { - CheckLicense: checkFullLicense, - privileges: checkGetJobsPrivilege, - indexPattern: loadCurrentIndexPattern, - savedSearch: loadCurrentSavedSearch, - mlNodeCount: getMlNodeCount, - loadMlServerInfo, - }, -}); diff --git a/x-pack/legacy/plugins/ml/public/application/datavisualizer/breadcrumbs.ts b/x-pack/legacy/plugins/ml/public/application/datavisualizer/breadcrumbs.ts deleted file mode 100644 index a4d1fd37bc33839..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/datavisualizer/breadcrumbs.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { ML_BREADCRUMB, DATA_VISUALIZER_BREADCRUMB } from '../../breadcrumbs'; - -export function getDataVisualizerBreadcrumbs() { - // Whilst top level nav menu with tabs remains, - // use root ML breadcrumb. - return [ML_BREADCRUMB, DATA_VISUALIZER_BREADCRUMB]; -} diff --git a/x-pack/legacy/plugins/ml/public/application/datavisualizer/datavisualizer_selector.tsx b/x-pack/legacy/plugins/ml/public/application/datavisualizer/datavisualizer_selector.tsx index c24061cb052b8ce..1727b1652c55d22 100644 --- a/x-pack/legacy/plugins/ml/public/application/datavisualizer/datavisualizer_selector.tsx +++ b/x-pack/legacy/plugins/ml/public/application/datavisualizer/datavisualizer_selector.tsx @@ -57,7 +57,7 @@ export const DatavisualizerSelector: FC = () => { return ( - + @@ -145,7 +145,7 @@ export const DatavisualizerSelector: FC = () => { footer={ - -`; - -uiRoutes.when('/datavisualizer', { - template, - k7Breadcrumbs: getDataVisualizerBreadcrumbs, - resolve: { - CheckLicense: checkBasicLicense, - privileges: checkFindFileStructurePrivilege, - }, -}); - -import { DatavisualizerSelector } from './datavisualizer_selector'; - -module.directive('datavisualizerSelector', function() { - return { - scope: {}, - restrict: 'E', - link: (scope: ng.IScope, element: ng.IAugmentedJQuery) => { - ReactDOM.render( - - - , - element[0] - ); - - element.on('$destroy', () => { - ReactDOM.unmountComponentAtNode(element[0]); - scope.$destroy(); - }); - }, - }; -}); diff --git a/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/breadcrumbs.ts b/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/breadcrumbs.ts deleted file mode 100644 index e8dd89f5db26473..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/breadcrumbs.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; -import { ML_BREADCRUMB, DATA_VISUALIZER_BREADCRUMB } from '../../../breadcrumbs'; - -export function getFileDataVisualizerBreadcrumbs() { - // Whilst top level nav menu with tabs remains, - // use root ML breadcrumb. - return [ - ML_BREADCRUMB, - DATA_VISUALIZER_BREADCRUMB, - { - text: i18n.translate('xpack.ml.dataVisualizer.fileBasedLabel', { - defaultMessage: 'File', - }), - href: '', - }, - ]; -} diff --git a/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/import_view/import_view.js b/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/import_view/import_view.js index c89f618aa835bc3..b50eef363847ecb 100644 --- a/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/import_view/import_view.js +++ b/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/import_view/import_view.js @@ -359,7 +359,7 @@ export class ImportView extends Component { } async loadIndexPatternNames() { - await loadIndexPatterns(); + await loadIndexPatterns(this.props.indexPatterns); const indexPatternNames = getIndexPatternNames(); this.setState({ indexPatternNames }); } diff --git a/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/results_links/results_links.js b/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/results_links/results_links.js index 30e91783fae2cf1..20b997582c3f9d2 100644 --- a/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/results_links/results_links.js +++ b/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/components/results_links/results_links.js @@ -121,7 +121,7 @@ export class ResultsLinks extends Component { /> } description="" - href={`${uiChrome.getBasePath()}/app/ml#/jobs/new_job/step/job_type?index=${indexPatternId}${_g}`} + href={`#/jobs/new_job/step/job_type?index=${indexPatternId}${_g}`} /> } @@ -137,7 +137,7 @@ export class ResultsLinks extends Component { /> } description="" - href={`${uiChrome.getBasePath()}/app/ml#/jobs/new_job/datavisualizer?index=${indexPatternId}${_g}`} + href={`#/jobs/new_job/datavisualizer?index=${indexPatternId}${_g}`} /> } diff --git a/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/file_datavisualizer.tsx b/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/file_datavisualizer.tsx index 99e61d5937c1d85..149e3d1818e642c 100644 --- a/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/file_datavisualizer.tsx +++ b/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/file_datavisualizer.tsx @@ -6,26 +6,22 @@ import React, { FC, Fragment } from 'react'; import { timefilter } from 'ui/timefilter'; -import { IndexPatternsContract } from '../../../../../../../../src/plugins/data/public'; import { KibanaConfigTypeFix } from '../../contexts/kibana'; import { NavigationMenu } from '../../components/navigation_menu'; +import { getIndexPatternsContract } from '../../util/index_utils'; // @ts-ignore import { FileDataVisualizerView } from './components/file_datavisualizer_view/index'; export interface FileDataVisualizerPageProps { - indexPatterns: IndexPatternsContract; kibanaConfig: KibanaConfigTypeFix; } -export const FileDataVisualizerPage: FC = ({ - indexPatterns, - kibanaConfig, -}) => { +export const FileDataVisualizerPage: FC = ({ kibanaConfig }) => { timefilter.disableTimeRangeSelector(); timefilter.disableAutoRefreshSelector(); - + const indexPatterns = getIndexPatternsContract(); return ( diff --git a/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/file_datavisualizer_directive.tsx b/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/file_datavisualizer_directive.tsx deleted file mode 100644 index 7ca2db041da295f..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/file_datavisualizer_directive.tsx +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; -import ReactDOM from 'react-dom'; -import { I18nContext } from 'ui/i18n'; - -// @ts-ignore -import { uiModules } from 'ui/modules'; - -const module = uiModules.get('apps/ml', ['react']); - -import uiRoutes from 'ui/routes'; -import { KibanaConfigTypeFix } from '../../contexts/kibana'; -import { getFileDataVisualizerBreadcrumbs } from './breadcrumbs'; -import { InjectorService } from '../../../../common/types/angular'; -import { checkBasicLicense } from '../../license/check_license'; -import { checkFindFileStructurePrivilege } from '../../privilege/check_privilege'; -import { getMlNodeCount } from '../../ml_nodes_check/check_ml_nodes'; -import { loadMlServerInfo } from '../../services/ml_server_info'; -import { loadIndexPatterns } from '../../util/index_utils'; -import { FileDataVisualizerPage, FileDataVisualizerPageProps } from './file_datavisualizer'; -import { IndexPatternsContract } from '../../../../../../../../src/plugins/data/public'; - -const template = ` -
- -`; - -uiRoutes.when('/filedatavisualizer/?', { - template, - k7Breadcrumbs: getFileDataVisualizerBreadcrumbs, - resolve: { - CheckLicense: checkBasicLicense, - privileges: checkFindFileStructurePrivilege, - indexPatterns: loadIndexPatterns, - mlNodeCount: getMlNodeCount, - loadMlServerInfo, - }, -}); - -module.directive('fileDatavisualizerPage', function($injector: InjectorService) { - return { - scope: {}, - restrict: 'E', - link: (scope: ng.IScope, element: ng.IAugmentedJQuery) => { - const indexPatterns = $injector.get('indexPatterns'); - const kibanaConfig = $injector.get('config'); - - const props: FileDataVisualizerPageProps = { - 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/application/datavisualizer/file_based/index.ts b/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/index.ts index 15796ea9ff0bdaa..683d5e940aa7cdb 100644 --- a/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/index.ts +++ b/x-pack/legacy/plugins/ml/public/application/datavisualizer/file_based/index.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -import './file_datavisualizer_directive'; +export { FileDataVisualizerPage } from './file_datavisualizer'; diff --git a/x-pack/legacy/plugins/ml/public/application/datavisualizer/index.ts b/x-pack/legacy/plugins/ml/public/application/datavisualizer/index.ts index dcda3ec9879aab9..770b48973b1543d 100644 --- a/x-pack/legacy/plugins/ml/public/application/datavisualizer/index.ts +++ b/x-pack/legacy/plugins/ml/public/application/datavisualizer/index.ts @@ -4,6 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -import './directive'; -import './file_based'; -import './index_based'; +export { DatavisualizerSelector } from './datavisualizer_selector'; diff --git a/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/breadcrumbs.ts b/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/breadcrumbs.ts deleted file mode 100644 index aba45e04c638fd0..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/breadcrumbs.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; -import { - ML_BREADCRUMB, - DATA_VISUALIZER_BREADCRUMB, - // @ts-ignore -} from '../../../breadcrumbs'; - -export function getDataVisualizerBreadcrumbs() { - // Whilst top level nav menu with tabs remains, - // use root ML breadcrumb. - return [ - ML_BREADCRUMB, - DATA_VISUALIZER_BREADCRUMB, - { - text: i18n.translate('xpack.ml.dataFrameAnalyticsBreadcrumbs.indexLabel', { - defaultMessage: 'Index', - }), - href: '', - }, - ]; -} diff --git a/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/components/actions_panel/actions_panel.tsx b/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/components/actions_panel/actions_panel.tsx index fca2508cb5d14a7..0b68f7e096d8572 100644 --- a/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/components/actions_panel/actions_panel.tsx +++ b/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/components/actions_panel/actions_panel.tsx @@ -13,7 +13,6 @@ import { IndexPattern } from 'ui/index_patterns'; import { EuiPanel, EuiSpacer, EuiText, EuiTitle, EuiFlexGroup } from '@elastic/eui'; -import { useUiChromeContext } from '../../../../contexts/ui/use_ui_chrome_context'; import { CreateJobLinkCard } from '../../../../components/create_job_link_card'; import { DataRecognizer } from '../../../../components/data_recognizer'; @@ -31,12 +30,10 @@ export const ActionsPanel: FC = ({ indexPattern }) => { }, }; - const basePath = useUiChromeContext().getBasePath(); - function openAdvancedJobWizard() { // TODO - pass the search string to the advanced job page as well as the index pattern // (add in with new advanced job wizard?) - window.open(`${basePath}/app/ml#/jobs/new_job/advanced?index=${indexPattern}`, '_self'); + window.open(`#/jobs/new_job/advanced?index=${indexPattern}`, '_self'); } // Note we use display:none for the DataRecognizer section as it needs to be @@ -87,7 +84,7 @@ export const ActionsPanel: FC = ({ indexPattern }) => { 'Use the full range of options to create a job for more advanced use cases', })} onClick={openAdvancedJobWizard} - href={`${basePath}/app/ml#/jobs/new_job/advanced?index=${indexPattern}`} + href={`#/jobs/new_job/advanced?index=${indexPattern}`} /> ); diff --git a/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/directive.tsx b/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/directive.tsx deleted file mode 100644 index 5de7cb6b71acb16..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/directive.tsx +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; -import ReactDOM from 'react-dom'; - -// @ts-ignore -import { uiModules } from 'ui/modules'; -const module = uiModules.get('apps/ml', ['react']); - -import { I18nContext } from 'ui/i18n'; -import { IndexPatternsContract } from '../../../../../../../../src/plugins/data/public'; -import { InjectorService } from '../../../../common/types/angular'; - -import { KibanaConfigTypeFix, KibanaContext } from '../../contexts/kibana/kibana_context'; -import { createSearchItems } from '../../jobs/new_job/utils/new_job_utils'; - -import { Page } from './page'; - -module.directive('mlDataVisualizer', ($injector: InjectorService) => { - return { - scope: {}, - restrict: 'E', - link: (scope: ng.IScope, element: ng.IAugmentedJQuery) => { - const indexPatterns = $injector.get('indexPatterns'); - const kibanaConfig = $injector.get('config'); - const $route = $injector.get('$route'); - - const { indexPattern, savedSearch, combinedQuery } = createSearchItems( - kibanaConfig, - $route.current.locals.indexPattern, - $route.current.locals.savedSearch - ); - - const kibanaContext = { - combinedQuery, - currentIndexPattern: indexPattern, - currentSavedSearch: savedSearch, - indexPatterns, - kibanaConfig, - }; - - ReactDOM.render( - - - - - , - element[0] - ); - - element.on('$destroy', () => { - ReactDOM.unmountComponentAtNode(element[0]); - scope.$destroy(); - }); - }, - }; -}); diff --git a/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/index.ts b/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/index.ts index 8ef2e327a898499..7e2d651439ae30b 100644 --- a/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/index.ts +++ b/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/index.ts @@ -4,5 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -import './directive'; -import './route'; +export { Page } from './page'; diff --git a/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/page.tsx b/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/page.tsx index 99e128e95410302..898c852fe50a533 100644 --- a/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/page.tsx +++ b/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/page.tsx @@ -31,7 +31,7 @@ import { FullTimeRangeSelector } from '../../components/full_time_range_selector import { mlTimefilterRefresh$ } from '../../services/timefilter_refresh_service'; import { useKibanaContext, SavedSearchQuery } from '../../contexts/kibana'; import { kbnTypeToMLJobType } from '../../util/field_types_utils'; -import { timeBasedIndexCheck } from '../../util/index_utils'; +import { timeBasedIndexCheck, getQueryFromSavedSearch } from '../../util/index_utils'; import { TimeBuckets } from '../../util/time_buckets'; import { FieldRequestConfig, FieldVisConfig } from './common'; import { ActionsPanel } from './components/actions_panel'; @@ -173,9 +173,8 @@ export const Page: FC = () => { useEffect(() => { // Check for a saved search being passed in. - const searchSource = currentSavedSearch.searchSource; - const query = searchSource.getField('query'); - if (query !== undefined) { + if (currentSavedSearch !== null) { + const { query } = getQueryFromSavedSearch(currentSavedSearch); const queryLanguage = query.language as SEARCH_QUERY_LANGUAGE; const qryString = query.query; let qry; diff --git a/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/route.ts b/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/route.ts deleted file mode 100644 index ab4df73e720ea32..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/datavisualizer/index_based/route.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -// @ts-ignore -import uiRoutes from 'ui/routes'; -import { checkBasicLicense } from '../../license/check_license'; -import { checkGetJobsPrivilege } from '../../privilege/check_privilege'; -import { loadCurrentIndexPattern, loadCurrentSavedSearch } from '../../util/index_utils'; - -import { checkMlNodesAvailable } from '../../ml_nodes_check'; -import { getDataVisualizerBreadcrumbs } from './breadcrumbs'; - -const template = ``; - -uiRoutes.when('/jobs/new_job/datavisualizer', { - template, - k7Breadcrumbs: getDataVisualizerBreadcrumbs, - resolve: { - CheckLicense: checkBasicLicense, - privileges: checkGetJobsPrivilege, - indexPattern: loadCurrentIndexPattern, - savedSearch: loadCurrentSavedSearch, - checkMlNodesAvailable, - }, -}); diff --git a/x-pack/legacy/plugins/ml/public/application/explorer/breadcrumbs.ts b/x-pack/legacy/plugins/ml/public/application/explorer/breadcrumbs.ts deleted file mode 100644 index c0dcd9e249b3bb9..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/explorer/breadcrumbs.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; -import { ML_BREADCRUMB, ANOMALY_DETECTION_BREADCRUMB } from '../../breadcrumbs'; - -export function getAnomalyExplorerBreadcrumbs() { - // Whilst top level nav menu with tabs remains, - // use root ML breadcrumb. - return [ - ML_BREADCRUMB, - ANOMALY_DETECTION_BREADCRUMB, - { - text: i18n.translate('xpack.ml.anomalyDetection.anomalyExplorerLabel', { - defaultMessage: 'Anomaly Explorer', - }), - href: '', - }, - ]; -} diff --git a/x-pack/legacy/plugins/ml/public/application/explorer/explorer.js b/x-pack/legacy/plugins/ml/public/application/explorer/explorer.js index 50a57f634fd1baf..d8a42064de4f2d0 100644 --- a/x-pack/legacy/plugins/ml/public/application/explorer/explorer.js +++ b/x-pack/legacy/plugins/ml/public/application/explorer/explorer.js @@ -93,7 +93,7 @@ function mapSwimlaneOptionsToEuiOptions(options) { } const ExplorerPage = ({ children, jobSelectorProps, resizeRef }) => ( -
+
{children} @@ -117,7 +117,6 @@ export const Explorer = injectI18n(injectObservablesAsProps( }; _unsubscribeAll = new Subject(); - // make sure dragSelect is only available if the mouse pointer is actually over a swimlane disableDragSelectOnMouseLeave = true; diff --git a/x-pack/legacy/plugins/ml/public/application/explorer/explorer_directive.tsx b/x-pack/legacy/plugins/ml/public/application/explorer/explorer_directive.tsx deleted file mode 100644 index b5d65fbf937e4d4..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/explorer/explorer_directive.tsx +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -/* - * AngularJS directive wrapper for rendering Anomaly Explorer's React component. - */ - -import React from 'react'; -import ReactDOM from 'react-dom'; - -import { Subscription } from 'rxjs'; - -import { IRootElementService, IRootScopeService, IScope } from 'angular'; - -// @ts-ignore -import { uiModules } from 'ui/modules'; -const module = uiModules.get('apps/ml'); - -import { I18nContext } from 'ui/i18n'; -import { State } from 'ui/state_management/state'; -import { AppState as IAppState, AppStateClass } from 'ui/state_management/app_state'; - -import { jobSelectServiceFactory } from '../components/job_selector/job_select_service_utils'; - -import { interval$ } from '../components/controls/select_interval'; -import { severity$ } from '../components/controls/select_severity'; -import { showCharts$ } from '../components/controls/checkbox_showcharts'; -import { subscribeAppStateToObservable } from '../util/app_state_utils'; - -import { Explorer } from './explorer'; -import { explorerService } from './explorer_dashboard_service'; -import { getExplorerDefaultAppState, ExplorerAppState } from './reducers'; - -interface ExplorerScope extends IScope { - appState: IAppState; -} - -module.directive('mlAnomalyExplorer', function( - globalState: State, - $rootScope: IRootScopeService, - AppState: AppStateClass -) { - function link($scope: ExplorerScope, element: IRootElementService) { - const subscriptions = new Subscription(); - - const { jobSelectService$, unsubscribeFromGlobalState } = jobSelectServiceFactory(globalState); - - ReactDOM.render( - - - , - element[0] - ); - - // Initialize the AppState in which to store swimlane and filter settings. - // AppState is used to store state in the URL. - $scope.appState = new AppState(getExplorerDefaultAppState()); - const { mlExplorerFilter, mlExplorerSwimlane } = $scope.appState; - - // Pass the current URL AppState on to anomaly explorer's reactive state. - // After this hand-off, the appState stored in explorerState$ is the single - // source of truth. - explorerService.setAppState({ mlExplorerSwimlane, mlExplorerFilter }); - - // Now that appState in explorerState$ is the single source of truth, - // subscribe to it and update the actual URL appState on changes. - subscriptions.add( - explorerService.appState$.subscribe((appState: ExplorerAppState) => { - $scope.appState.fetch(); - $scope.appState.mlExplorerFilter = appState.mlExplorerFilter; - $scope.appState.mlExplorerSwimlane = appState.mlExplorerSwimlane; - $scope.appState.save(); - $scope.$applyAsync(); - }) - ); - - subscriptions.add( - subscribeAppStateToObservable(AppState, 'mlShowCharts', showCharts$, () => - $rootScope.$applyAsync() - ) - ); - subscriptions.add( - subscribeAppStateToObservable(AppState, 'mlSelectInterval', interval$, () => - $rootScope.$applyAsync() - ) - ); - subscriptions.add( - subscribeAppStateToObservable(AppState, 'mlSelectSeverity', severity$, () => - $rootScope.$applyAsync() - ) - ); - - element.on('$destroy', () => { - ReactDOM.unmountComponentAtNode(element[0]); - $scope.$destroy(); - subscriptions.unsubscribe(); - unsubscribeFromGlobalState(); - }); - } - - return { link }; -}); diff --git a/x-pack/legacy/plugins/ml/public/application/explorer/explorer_route.ts b/x-pack/legacy/plugins/ml/public/application/explorer/explorer_route.ts deleted file mode 100644 index a061176a5ef5b14..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/explorer/explorer_route.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import uiRoutes from 'ui/routes'; - -import '../components/controls'; - -import { checkFullLicense } from '../license/check_license'; -import { checkGetJobsPrivilege } from '../privilege/check_privilege'; -import { mlJobService } from '../services/job_service'; -import { loadIndexPatterns } from '../util/index_utils'; - -import { getAnomalyExplorerBreadcrumbs } from './breadcrumbs'; - -uiRoutes.when('/explorer/?', { - template: ``, - k7Breadcrumbs: getAnomalyExplorerBreadcrumbs, - resolve: { - CheckLicense: checkFullLicense, - privileges: checkGetJobsPrivilege, - indexPatterns: loadIndexPatterns, - jobs: mlJobService.loadJobsWrapper, - }, -}); diff --git a/x-pack/legacy/plugins/ml/public/application/explorer/index.ts b/x-pack/legacy/plugins/ml/public/application/explorer/index.ts index edc25565daa9f5e..1dd9b76b8c20c30 100644 --- a/x-pack/legacy/plugins/ml/public/application/explorer/index.ts +++ b/x-pack/legacy/plugins/ml/public/application/explorer/index.ts @@ -4,9 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -import '../explorer/explorer_dashboard_service'; -import '../explorer/explorer_directive'; -import '../explorer/explorer_route'; -import '../explorer/explorer_charts'; -import '../explorer/select_limit'; -import '../components/job_selector'; +export { Explorer } from './explorer'; diff --git a/x-pack/legacy/plugins/ml/public/application/index.scss b/x-pack/legacy/plugins/ml/public/application/index.scss new file mode 100644 index 000000000000000..dbcdf288b6a8525 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/index.scss @@ -0,0 +1,45 @@ +// Should import both the EUI constants and any Kibana ones that are considered global +@import 'src/legacy/ui/public/styles/styling_constants'; + +// ML has it's own variables for coloring +@import 'variables'; + +// Kibana management page ML section +#kibanaManagementMLSection { + @import 'management/index'; +} + +// Protect the rest of Kibana from ML generic namespacing +// SASSTODO: Prefix ml selectors instead +#ml-app { + // App level + @import 'app'; + + // Sub applications + @import 'data_frame_analytics/index'; + @import 'datavisualizer/index'; + @import 'explorer/index'; // SASSTODO: This file needs to be rewritten + @import 'jobs/index'; // SASSTODO: This collection of sass files has multiple problems + @import 'overview/index'; + @import 'settings/index'; + @import 'timeseriesexplorer/index'; + + // Components + @import 'components/annotations/annotation_description_list/index'; // SASSTODO: This file overwrites EUI directly + @import 'components/anomalies_table/index'; // SASSTODO: This file overwrites EUI directly + @import 'components/chart_tooltip/index'; + @import 'components/controls/index'; + @import 'components/entity_cell/index'; + @import 'components/field_title_bar/index'; + @import 'components/field_type_icon/index'; + @import 'components/influencers_list/index'; + @import 'components/items_grid/index'; + @import 'components/job_selector/index'; + @import 'components/loading_indicator/index'; // SASSTODO: This component should be replaced with EuiLoadingSpinner + @import 'components/navigation_menu/index'; + @import 'components/rule_editor/index'; // SASSTODO: This file overwrites EUI directly + @import 'components/stats_bar/index'; + + // Hacks are last so they can overwrite anything above if needed + @import 'hacks'; +} diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/breadcrumbs.ts b/x-pack/legacy/plugins/ml/public/application/jobs/breadcrumbs.ts deleted file mode 100644 index f2954548ea5474f..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/jobs/breadcrumbs.ts +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; -import { Breadcrumb } from 'ui/chrome'; -import { - ANOMALY_DETECTION_BREADCRUMB, - DATA_VISUALIZER_BREADCRUMB, - ML_BREADCRUMB, -} from '../../breadcrumbs'; - -export function getJobManagementBreadcrumbs(): Breadcrumb[] { - // Whilst top level nav menu with tabs remains, - // use root ML breadcrumb. - return [ - ML_BREADCRUMB, - ANOMALY_DETECTION_BREADCRUMB, - { - text: i18n.translate('xpack.ml.anomalyDetection.jobManagementLabel', { - defaultMessage: 'Job Management', - }), - href: '', - }, - ]; -} - -export function getCreateJobBreadcrumbs(): Breadcrumb[] { - return [ - ML_BREADCRUMB, - ANOMALY_DETECTION_BREADCRUMB, - { - text: i18n.translate('xpack.ml.jobsBreadcrumbs.createJobLabel', { - defaultMessage: 'Create job', - }), - href: '#/jobs/new_job', - }, - ]; -} - -export function getCreateSingleMetricJobBreadcrumbs(): Breadcrumb[] { - return [ - ...getCreateJobBreadcrumbs(), - { - text: i18n.translate('xpack.ml.jobsBreadcrumbs.singleMetricLabel', { - defaultMessage: 'Single metric', - }), - href: '', - }, - ]; -} - -export function getCreateMultiMetricJobBreadcrumbs(): Breadcrumb[] { - return [ - ...getCreateJobBreadcrumbs(), - { - text: i18n.translate('xpack.ml.jobsBreadcrumbs.multiMetricLabel', { - defaultMessage: 'Multi metric', - }), - href: '', - }, - ]; -} - -export function getCreatePopulationJobBreadcrumbs(): Breadcrumb[] { - return [ - ...getCreateJobBreadcrumbs(), - { - text: i18n.translate('xpack.ml.jobsBreadcrumbs.populationLabel', { - defaultMessage: 'Population', - }), - href: '', - }, - ]; -} - -export function getAdvancedJobConfigurationBreadcrumbs(): Breadcrumb[] { - return [ - ...getCreateJobBreadcrumbs(), - { - text: i18n.translate('xpack.ml.jobsBreadcrumbs.advancedConfigurationLabel', { - defaultMessage: 'Advanced configuration', - }), - href: '', - }, - ]; -} - -export function getCreateRecognizerJobBreadcrumbs($routeParams: any): Breadcrumb[] { - return [ - ...getCreateJobBreadcrumbs(), - { - text: $routeParams.id, - href: '', - }, - ]; -} - -export function getDataVisualizerIndexOrSearchBreadcrumbs(): Breadcrumb[] { - return [ - ML_BREADCRUMB, - DATA_VISUALIZER_BREADCRUMB, - { - text: i18n.translate('xpack.ml.jobsBreadcrumbs.selectIndexOrSearchLabel', { - defaultMessage: 'Select index or search', - }), - href: '', - }, - ]; -} diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/index.ts b/x-pack/legacy/plugins/ml/public/application/jobs/index.ts similarity index 56% rename from x-pack/legacy/plugins/ml/public/application/data_frame_analytics/index.ts rename to x-pack/legacy/plugins/ml/public/application/jobs/index.ts index 7363c5a27f64b95..0bb30d4f76de7aa 100644 --- a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/index.ts +++ b/x-pack/legacy/plugins/ml/public/application/jobs/index.ts @@ -4,7 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -import './pages/analytics_exploration/directive'; -import './pages/analytics_exploration/route'; -import './pages/analytics_management/directive'; -import './pages/analytics_management/route'; +export { JobsPage } from './jobs_list'; +export {} from './new_job'; diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/components/job_actions/results.js b/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/components/job_actions/results.js index 5ec407f7f054e67..d78cb3710839114 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/components/job_actions/results.js +++ b/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/components/job_actions/results.js @@ -7,20 +7,20 @@ import PropTypes from 'prop-types'; import React from 'react'; +import chrome from 'ui/chrome'; import { EuiButtonIcon, EuiToolTip, } from '@elastic/eui'; -import chrome from 'ui/chrome'; import { mlJobService } from '../../../../services/job_service'; import { injectI18n } from '@kbn/i18n/react'; export function getLink(location, jobs) { const resultsPageUrl = mlJobService.createResultsUrlForJobs(jobs, location); - return `${chrome.getBasePath()}/app/${resultsPageUrl}`; + return `${chrome.getBasePath()}/app/ml${resultsPageUrl}`; } function ResultLinksUI({ jobs, intl }) { @@ -39,6 +39,7 @@ function ResultLinksUI({ jobs, intl }) { const singleMetricVisible = (jobs.length < 2); const singleMetricEnabled = (jobs.length === 1 && jobs[0].isSingleMetricViewerJob); const jobActionsDisabled = (jobs.length === 1 && jobs[0].deleting === true); + return ( {(singleMetricVisible) && diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/components/job_details/extract_job_details.js b/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/components/job_details/extract_job_details.js index 028e6a10d6abcfc..9b301200c76f281 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/components/job_details/extract_job_details.js +++ b/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/components/job_details/extract_job_details.js @@ -6,7 +6,6 @@ import React from 'react'; import { EuiLink } from '@elastic/eui'; -import chrome from 'ui/chrome'; import { detectorToString } from '../../../../util/string_utils'; import { formatValues, filterObjects } from './format_values'; import { i18n } from '@kbn/i18n'; @@ -62,7 +61,7 @@ export function extractJobDetails(job) { if (job.calendars) { calendars.items = job.calendars.map(c => [ '', - {c}, + {c}, ]); // remove the calendars list from the general section // so not to show it twice. diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/components/job_details/forecasts_table/forecasts_table.js b/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/components/job_details/forecasts_table/forecasts_table.js index 3df869174c146b4..8ae024e68460a09 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/components/job_details/forecasts_table/forecasts_table.js +++ b/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/components/job_details/forecasts_table/forecasts_table.js @@ -23,7 +23,6 @@ import { EuiLoadingSpinner } from '@elastic/eui'; import { formatDate, formatNumber } from '@elastic/eui/lib/services/format'; -import chrome from 'ui/chrome'; import { FORECAST_REQUEST_STATE } from '../../../../../../../common/constants/states'; import { addItemToRecentlyAccessed } from '../../../../../util/recently_accessed'; @@ -128,7 +127,7 @@ class ForecastsTableUI extends Component { const url = `?_g=${_g}&_a=${_a}`; addItemToRecentlyAccessed('timeseriesexplorer', this.props.job.job_id, url); - window.open(`${chrome.getBasePath()}/app/ml#/timeseriesexplorer${url}`, '_self'); + window.open(`#/timeseriesexplorer${url}`, '_self'); } render() { diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/components/jobs_list_view/jobs_list_view.js b/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/components/jobs_list_view/jobs_list_view.js index fc07d4d2a02940f..effc54c228130f1 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/components/jobs_list_view/jobs_list_view.js +++ b/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/components/jobs_list_view/jobs_list_view.js @@ -67,15 +67,6 @@ export class JobsListView extends Component { if (this.props.isManagementTable === true) { this.refreshJobSummaryList(true); } else { - // The advanced job wizard is still angularjs based and triggers - // broadcast events which it expects the jobs list to be subscribed to. - this.props.angularWrapperScope.$on('jobsUpdated', () => { - this.refreshJobSummaryList(true); - }); - this.props.angularWrapperScope.$on('openCreateWatchWindow', (e, job) => { - this.showCreateWatchFlyout(job.job_id); - }); - timefilter.disableTimeRangeSelector(); timefilter.enableAutoRefreshSelector(); diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/directive.js b/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/directive.js deleted file mode 100644 index f549ec3826cb575..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/directive.js +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - - -import ReactDOM from 'react-dom'; -import React from 'react'; - -import { uiModules } from 'ui/modules'; -const module = uiModules.get('apps/ml', ['react']); - -import { loadIndexPatterns } from '../../util/index_utils'; -import { checkFullLicense } from '../../license/check_license'; -import { checkGetJobsPrivilege } from '../../privilege/check_privilege'; -import { getMlNodeCount } from '../../ml_nodes_check/check_ml_nodes'; -import { getJobManagementBreadcrumbs } from '../../jobs/breadcrumbs'; -import { loadMlServerInfo } from '../../services/ml_server_info'; - -import uiRoutes from 'ui/routes'; - -const template = ``; - -uiRoutes - .when('/jobs/?', { - template, - k7Breadcrumbs: getJobManagementBreadcrumbs, - resolve: { - CheckLicense: checkFullLicense, - indexPatterns: loadIndexPatterns, - privileges: checkGetJobsPrivilege, - mlNodeCount: getMlNodeCount, - loadMlServerInfo, - } - }); - -import { JobsPage } from './jobs'; -import { I18nContext } from 'ui/i18n'; - -module.directive('jobsPage', function () { - return { - scope: {}, - restrict: 'E', - link: (scope, element) => { - ReactDOM.render( - - - , - element[0] - ); - - element.on('$destroy', () => { - ReactDOM.unmountComponentAtNode(element[0]); - scope.$destroy(); - }); - } - }; -}); diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/index.js b/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/index.ts similarity index 84% rename from x-pack/legacy/plugins/ml/public/application/jobs/index.js rename to x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/index.ts index 1ade8752d6721da..0b70e6b3c93525b 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/index.js +++ b/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/index.ts @@ -4,7 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ - - -import './jobs_list'; -import './new_job'; +export { JobsPage } from './jobs'; diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/jobs.js b/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/jobs.tsx similarity index 59% rename from x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/jobs.js rename to x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/jobs.tsx index 21c184cdcd298ea..f820372e20c09a5 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/jobs.js +++ b/x-pack/legacy/plugins/ml/public/application/jobs/jobs_list/jobs.tsx @@ -4,15 +4,18 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; +import React, { FC } from 'react'; import { NavigationMenu } from '../../components/navigation_menu'; +// @ts-ignore import { JobsListView } from './components/jobs_list_view'; -export const JobsPage = (props) => ( - <> - - - -); +export const JobsPage: FC<{ props?: any }> = props => { + return ( +
+ + +
+ ); +}; diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/advanced_job_creator.ts b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/advanced_job_creator.ts index 22aebc2b88a8864..d8917db7a33ffa5 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/advanced_job_creator.ts +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/advanced_job_creator.ts @@ -4,14 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SavedSearch } from 'src/legacy/core_plugins/kibana/public/discover/types'; import { IndexPattern } from 'ui/index_patterns'; +import { SavedSearchSavedObject } from '../../../../../../common/types/kibana'; import { JobCreator } from './job_creator'; import { Field, Aggregation, SplitField } from '../../../../../../common/types/fields'; import { Job, Datafeed, Detector, CustomRule } from './configs'; import { createBasicDetector } from './util/default_configs'; -import { JOB_TYPE } from './util/constants'; +import { JOB_TYPE } from '../../../../../../common/constants/new_job'; import { getRichDetectors } from './util/general'; import { isValidJson } from '../../../../../../common/util/validation_utils'; import { ml } from '../../../../services/ml_api_service'; @@ -32,7 +32,11 @@ export class AdvancedJobCreator extends JobCreator { private _richDetectors: RichDetector[] = []; private _queryString: string; - constructor(indexPattern: IndexPattern, savedSearch: SavedSearch, query: object) { + constructor( + indexPattern: IndexPattern, + savedSearch: SavedSearchSavedObject | null, + query: object + ) { super(indexPattern, savedSearch, query); this._queryString = JSON.stringify(this._datafeed_config.query); diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/configs/job.ts b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/configs/job.ts index 4960492eabeb33c..3246f8ae4b31ac4 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/configs/job.ts +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/configs/job.ts @@ -5,7 +5,7 @@ */ import { UrlConfig } from '../../../../../../../common/types/custom_urls'; -import { CREATED_BY_LABEL } from '../util/constants'; +import { CREATED_BY_LABEL } from '../../../../../../../common/constants/new_job'; export type JobId = string; export type BucketSpan = string; diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/job_creator.ts b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/job_creator.ts index e11cebe0383cd20..4707eff8d844ecc 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/job_creator.ts +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/job_creator.ts @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SavedSearch } from 'src/legacy/core_plugins/kibana/public/discover/types'; import { IndexPattern } from 'ui/index_patterns'; +import { SavedSearchSavedObject } from '../../../../../../common/types/kibana'; import { UrlConfig } from '../../../../../../common/types/custom_urls'; import { IndexPatternTitle } from '../../../../../../common/types/kibana'; import { ML_JOB_AGGREGATION } from '../../../../../../common/constants/aggregation_types'; @@ -15,7 +15,11 @@ import { Aggregation, Field } from '../../../../../../common/types/fields'; import { createEmptyJob, createEmptyDatafeed } from './util/default_configs'; import { mlJobService } from '../../../../services/job_service'; import { JobRunner, ProgressSubscriber } from '../job_runner'; -import { JOB_TYPE, CREATED_BY_LABEL, SHARED_RESULTS_INDEX_NAME } from './util/constants'; +import { + JOB_TYPE, + CREATED_BY_LABEL, + SHARED_RESULTS_INDEX_NAME, +} from '../../../../../../common/constants/new_job'; import { isSparseDataJob } from './util/general'; import { parseInterval } from '../../../../../../common/util/parse_interval'; import { Calendar } from '../../../../../../common/types/calendars'; @@ -24,7 +28,7 @@ import { mlCalendarService } from '../../../../services/calendar_service'; export class JobCreator { protected _type: JOB_TYPE = JOB_TYPE.SINGLE_METRIC; protected _indexPattern: IndexPattern; - protected _savedSearch: SavedSearch; + protected _savedSearch: SavedSearchSavedObject | null; protected _indexPatternTitle: IndexPatternTitle = ''; protected _job_config: Job; protected _calendars: Calendar[]; @@ -44,7 +48,11 @@ export class JobCreator { stop: boolean; } = { stop: false }; - constructor(indexPattern: IndexPattern, savedSearch: SavedSearch, query: object) { + constructor( + indexPattern: IndexPattern, + savedSearch: SavedSearchSavedObject | null, + query: object + ) { this._indexPattern = indexPattern; this._savedSearch = savedSearch; this._indexPatternTitle = indexPattern.title; diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/job_creator_factory.ts b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/job_creator_factory.ts index 375e112ed46faff..4ffcd1b06ca4796 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/job_creator_factory.ts +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/job_creator_factory.ts @@ -4,18 +4,18 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SavedSearch } from 'src/legacy/core_plugins/kibana/public/discover/types'; import { IndexPattern } from 'ui/index_patterns'; +import { SavedSearchSavedObject } from '../../../../../../common/types/kibana'; import { SingleMetricJobCreator } from './single_metric_job_creator'; import { MultiMetricJobCreator } from './multi_metric_job_creator'; import { PopulationJobCreator } from './population_job_creator'; import { AdvancedJobCreator } from './advanced_job_creator'; -import { JOB_TYPE } from './util/constants'; +import { JOB_TYPE } from '../../../../../../common/constants/new_job'; export const jobCreatorFactory = (jobType: JOB_TYPE) => ( indexPattern: IndexPattern, - savedSearch: SavedSearch, + savedSearch: SavedSearchSavedObject | null, query: object ) => { let jc; diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/multi_metric_job_creator.ts b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/multi_metric_job_creator.ts index fea328acb58b3cc..e86ee09d234f1d4 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/multi_metric_job_creator.ts +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/multi_metric_job_creator.ts @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SavedSearch } from 'src/legacy/core_plugins/kibana/public/discover/types'; import { IndexPattern } from 'ui/index_patterns'; +import { SavedSearchSavedObject } from '../../../../../../common/types/kibana'; import { JobCreator } from './job_creator'; import { Field, @@ -15,7 +15,11 @@ import { } from '../../../../../../common/types/fields'; import { Job, Datafeed, Detector } from './configs'; import { createBasicDetector } from './util/default_configs'; -import { JOB_TYPE, CREATED_BY_LABEL, DEFAULT_MODEL_MEMORY_LIMIT } from './util/constants'; +import { + JOB_TYPE, + CREATED_BY_LABEL, + DEFAULT_MODEL_MEMORY_LIMIT, +} from '../../../../../../common/constants/new_job'; import { ml } from '../../../../services/ml_api_service'; import { getRichDetectors } from './util/general'; @@ -26,7 +30,11 @@ export class MultiMetricJobCreator extends JobCreator { private _lastEstimatedModelMemoryLimit = DEFAULT_MODEL_MEMORY_LIMIT; protected _type: JOB_TYPE = JOB_TYPE.MULTI_METRIC; - constructor(indexPattern: IndexPattern, savedSearch: SavedSearch, query: object) { + constructor( + indexPattern: IndexPattern, + savedSearch: SavedSearchSavedObject | null, + query: object + ) { super(indexPattern, savedSearch, query); this.createdBy = CREATED_BY_LABEL.MULTI_METRIC; } diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/population_job_creator.ts b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/population_job_creator.ts index 9e9ccf8ab63e42d..8fcd03982424d93 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/population_job_creator.ts +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/population_job_creator.ts @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SavedSearch } from 'src/legacy/core_plugins/kibana/public/discover/types'; import { IndexPattern } from 'ui/index_patterns'; +import { SavedSearchSavedObject } from '../../../../../../common/types/kibana'; import { JobCreator } from './job_creator'; import { Field, @@ -15,7 +15,7 @@ import { } from '../../../../../../common/types/fields'; import { Job, Datafeed, Detector } from './configs'; import { createBasicDetector } from './util/default_configs'; -import { JOB_TYPE, CREATED_BY_LABEL } from './util/constants'; +import { JOB_TYPE, CREATED_BY_LABEL } from '../../../../../../common/constants/new_job'; import { getRichDetectors } from './util/general'; export class PopulationJobCreator extends JobCreator { @@ -25,7 +25,11 @@ export class PopulationJobCreator extends JobCreator { private _byFields: SplitField[] = []; protected _type: JOB_TYPE = JOB_TYPE.POPULATION; - constructor(indexPattern: IndexPattern, savedSearch: SavedSearch, query: object) { + constructor( + indexPattern: IndexPattern, + savedSearch: SavedSearchSavedObject | null, + query: object + ) { super(indexPattern, savedSearch, query); this.createdBy = CREATED_BY_LABEL.POPULATION; } diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/single_metric_job_creator.ts b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/single_metric_job_creator.ts index 5f3f6ff310d289d..cb8a46ade513cbd 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/single_metric_job_creator.ts +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/single_metric_job_creator.ts @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SavedSearch } from 'src/legacy/core_plugins/kibana/public/discover/types'; import { IndexPattern } from 'ui/index_patterns'; +import { SavedSearchSavedObject } from '../../../../../../common/types/kibana'; import { parseInterval } from '../../../../../../common/util/parse_interval'; import { JobCreator } from './job_creator'; import { Field, Aggregation, AggFieldPair } from '../../../../../../common/types/fields'; @@ -15,13 +15,17 @@ import { ML_JOB_AGGREGATION, ES_AGGREGATION, } from '../../../../../../common/constants/aggregation_types'; -import { JOB_TYPE, CREATED_BY_LABEL } from './util/constants'; +import { JOB_TYPE, CREATED_BY_LABEL } from '../../../../../../common/constants/new_job'; import { getRichDetectors } from './util/general'; export class SingleMetricJobCreator extends JobCreator { protected _type: JOB_TYPE = JOB_TYPE.SINGLE_METRIC; - constructor(indexPattern: IndexPattern, savedSearch: SavedSearch, query: object) { + constructor( + indexPattern: IndexPattern, + savedSearch: SavedSearchSavedObject | null, + query: object + ) { super(indexPattern, savedSearch, query); this.createdBy = CREATED_BY_LABEL.SINGLE_METRIC; } diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/type_guards.ts b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/type_guards.ts index 7162ec65767f9f8..9feb0416dd267f8 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/type_guards.ts +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/type_guards.ts @@ -8,7 +8,7 @@ import { SingleMetricJobCreator } from './single_metric_job_creator'; import { MultiMetricJobCreator } from './multi_metric_job_creator'; import { PopulationJobCreator } from './population_job_creator'; import { AdvancedJobCreator } from './advanced_job_creator'; -import { JOB_TYPE } from './util/constants'; +import { JOB_TYPE } from '../../../../../../common/constants/new_job'; export type JobCreatorType = | SingleMetricJobCreator diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/util/general.ts b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/util/general.ts index e7e5e8aa64f7bfe..760dbe447dc8942 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/util/general.ts +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/job_creator/util/general.ts @@ -19,7 +19,7 @@ import { } from '../../../../../../../common/types/fields'; import { mlJobService } from '../../../../../services/job_service'; import { JobCreatorType, isMultiMetricJobCreator, isPopulationJobCreator } from '../index'; -import { CREATED_BY_LABEL, JOB_TYPE } from './constants'; +import { CREATED_BY_LABEL, JOB_TYPE } from '../../../../../../../common/constants/new_job'; const getFieldByIdFactory = (scriptFields: Field[]) => (id: string) => { let field = newJobCapsService.getFieldById(id); diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/results_loader/results_loader.ts b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/results_loader/results_loader.ts index 82808ef3d37ee05..5048f44586a386d 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/results_loader/results_loader.ts +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/common/results_loader/results_loader.ts @@ -12,8 +12,8 @@ import { getSeverityType } from '../../../../../../common/util/anomaly_utils'; import { parseInterval } from '../../../../../../common/util/parse_interval'; import { ANOMALY_SEVERITY } from '../../../../../../common/constants/anomalies'; import { getScoresByRecord } from './searches'; -import { JOB_TYPE } from '../job_creator/util/constants'; import { ChartLoader } from '../chart_loader'; +import { JOB_TYPE } from '../../../../../../common/constants/new_job'; import { ES_AGGREGATION } from '../../../../../../common/constants/aggregation_types'; export interface Results { diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/index.ts b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/index.ts deleted file mode 100644 index 945d22967a65d68..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import './pages/new_job/route'; -import './pages/new_job/directive'; -import './pages/job_type/route'; -import './pages/job_type/directive'; -import './pages/index_or_search/route'; -import './pages/index_or_search/directive'; -import './recognize/route'; -import './recognize/directive'; diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/datafeed_step/components/query_delay/query_delay_input.tsx b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/datafeed_step/components/query_delay/query_delay_input.tsx index 097050fd829c982..0e6dd81fb91a986 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/datafeed_step/components/query_delay/query_delay_input.tsx +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/datafeed_step/components/query_delay/query_delay_input.tsx @@ -9,7 +9,7 @@ import { EuiFieldText } from '@elastic/eui'; import { JobCreatorContext } from '../../../job_creator_context'; import { Description } from './description'; import { useStringifiedValue } from '../hooks'; -import { DEFAULT_QUERY_DELAY } from '../../../../../common/job_creator/util/constants'; +import { DEFAULT_QUERY_DELAY } from '../../../../../../../../../common/constants/new_job'; export const QueryDelayInput: FC = () => { const { jobCreator, jobCreatorUpdate, jobValidator, jobValidatorUpdated } = useContext( diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/job_details_step/components/advanced_section/advanced_section.tsx b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/job_details_step/components/advanced_section/advanced_section.tsx index 87e133df225a0b5..5fbc7557a2fa794 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/job_details_step/components/advanced_section/advanced_section.tsx +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/job_details_step/components/advanced_section/advanced_section.tsx @@ -17,7 +17,7 @@ import { ModelPlotSwitch } from './components/model_plot'; import { DedicatedIndexSwitch } from './components/dedicated_index'; import { ModelMemoryLimitInput } from '../../../common/model_memory_limit'; import { JobCreatorContext } from '../../../job_creator_context'; -import { JOB_TYPE } from '../../../../../common/job_creator/util/constants'; +import { JOB_TYPE } from '../../../../../../../../../common/constants/new_job'; const ButtonContent = i18n.translate( 'xpack.ml.newJob.wizard.jobDetailsStep.advancedSectionButton', diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/multi_metric_view/chart_grid.tsx b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/multi_metric_view/chart_grid.tsx index b76fc120538f5d7..f11cdc62337172d 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/multi_metric_view/chart_grid.tsx +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/multi_metric_view/chart_grid.tsx @@ -11,7 +11,7 @@ import { AggFieldPair, SplitField } from '../../../../../../../../../common/type import { ChartSettings } from '../../../charts/common/settings'; import { LineChartData } from '../../../../../common/chart_loader'; import { ModelItem, Anomaly } from '../../../../../common/results_loader'; -import { JOB_TYPE } from '../../../../../common/job_creator/util/constants'; +import { JOB_TYPE } from '../../../../../../../../../common/constants/new_job'; import { SplitCards, useAnimateSplit } from '../split_cards'; import { DetectorTitle } from '../detector_title'; import { AnomalyChart, CHART_TYPE } from '../../../charts/anomaly_chart'; diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/population_view/chart_grid.tsx b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/population_view/chart_grid.tsx index 8cd533f8b2e2976..035e3c90f53ae2d 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/population_view/chart_grid.tsx +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/population_view/chart_grid.tsx @@ -11,7 +11,7 @@ import { AggFieldPair, SplitField } from '../../../../../../../../../common/type import { ChartSettings } from '../../../charts/common/settings'; import { LineChartData } from '../../../../../common/chart_loader'; import { ModelItem, Anomaly } from '../../../../../common/results_loader'; -import { JOB_TYPE } from '../../../../../common/job_creator/util/constants'; +import { JOB_TYPE } from '../../../../../../../../../common/constants/new_job'; import { SplitCards, useAnimateSplit } from '../split_cards'; import { DetectorTitle } from '../detector_title'; import { ByFieldSelector } from '../split_field'; diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/split_cards/split_cards.tsx b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/split_cards/split_cards.tsx index 918163572076ce3..118923aa203e17e 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/split_cards/split_cards.tsx +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/split_cards/split_cards.tsx @@ -9,7 +9,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiHorizontalRule, EuiSpacer } from '@elastic/eui'; import { SplitField } from '../../../../../../../../../common/types/fields'; -import { JOB_TYPE } from '../../../../../common/job_creator/util/constants'; +import { JOB_TYPE } from '../../../../../../../../../common/constants/new_job'; interface Props { fieldValues: string[]; diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/split_field/description.tsx b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/split_field/description.tsx index 2c6013073978003..6d4eeff2a547526 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/split_field/description.tsx +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/split_field/description.tsx @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiDescribedFormGroup, EuiFormRow } from '@elastic/eui'; -import { JOB_TYPE } from '../../../../../common/job_creator/util/constants'; +import { JOB_TYPE } from '../../../../../../../../../common/constants/new_job'; interface Props { jobType: JOB_TYPE; diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/pick_fields.tsx b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/pick_fields.tsx index bdb2076086fd56a..795dfc30f954a4b 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/pick_fields.tsx +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/pick_fields.tsx @@ -10,7 +10,7 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { JobCreatorContext } from '../job_creator_context'; import { WizardNav } from '../wizard_nav'; import { WIZARD_STEPS, StepProps } from '../step_types'; -import { JOB_TYPE } from '../../../common/job_creator/util/constants'; +import { JOB_TYPE } from '../../../../../../../common/constants/new_job'; import { SingleMetricView } from './components/single_metric_view'; import { MultiMetricView } from './components/multi_metric_view'; import { PopulationView } from './components/population_view'; diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/summary_step/components/datafeed_details/datafeed_details.tsx b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/summary_step/components/datafeed_details/datafeed_details.tsx index c624972aa07ea7a..d1900413d84c9d4 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/summary_step/components/datafeed_details/datafeed_details.tsx +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/summary_step/components/datafeed_details/datafeed_details.tsx @@ -10,7 +10,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiDescriptionList, EuiFormRow } from '@elas import { JobCreatorContext } from '../../../job_creator_context'; import { MLJobEditor } from '../../../../../../jobs_list/components/ml_job_editor'; import { calculateDatafeedFrequencyDefaultSeconds } from '../../../../../../../../../common/util/job_utils'; -import { DEFAULT_QUERY_DELAY } from '../../../../../common/job_creator/util/constants'; +import { DEFAULT_QUERY_DELAY } from '../../../../../../../../../common/constants/new_job'; import { getNewJobDefaults } from '../../../../../../../services/ml_server_info'; import { ListItems, defaultLabel, Italic } from '../common'; diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/summary_step/components/detector_chart/detector_chart.tsx b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/summary_step/components/detector_chart/detector_chart.tsx index bf60eda2e81c354..f72ff6cf985e568 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/summary_step/components/detector_chart/detector_chart.tsx +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/summary_step/components/detector_chart/detector_chart.tsx @@ -6,7 +6,7 @@ import React, { Fragment, FC, useContext } from 'react'; import { JobCreatorContext } from '../../../job_creator_context'; -import { JOB_TYPE } from '../../../../../common/job_creator/util/constants'; +import { JOB_TYPE } from '../../../../../../../../../common/constants/new_job'; import { SingleMetricView } from '../../../pick_fields_step/components/single_metric_view'; import { MultiMetricView } from '../../../pick_fields_step/components/multi_metric_view'; import { PopulationView } from '../../../pick_fields_step/components/population_view'; diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/summary_step/summary.tsx b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/summary_step/summary.tsx index 3f241f21a75e539..994847864d6bb65 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/summary_step/summary.tsx +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/summary_step/summary.tsx @@ -23,7 +23,7 @@ import { JobRunner } from '../../../common/job_runner'; import { mlJobService } from '../../../../../services/job_service'; import { JsonEditorFlyout, EDITOR_MODE } from '../common/json_editor_flyout'; import { DatafeedPreviewFlyout } from '../common/datafeed_preview_flyout'; -import { JOB_TYPE } from '../../../common/job_creator/util/constants'; +import { JOB_TYPE } from '../../../../../../../common/constants/new_job'; import { isSingleMetricJobCreator, isAdvancedJobCreator } from '../../../common/job_creator'; import { JobDetails } from './components/job_details'; import { DatafeedDetails } from './components/datafeed_details'; diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/time_range_step/time_range.tsx b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/time_range_step/time_range.tsx index 7410e10aa92cfd0..70a529b8e24d0fa 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/time_range_step/time_range.tsx +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/time_range_step/time_range.tsx @@ -5,6 +5,8 @@ */ import React, { FC, Fragment, useContext, useEffect, useState } from 'react'; +import { i18n } from '@kbn/i18n'; +import { toastNotifications } from 'ui/notify'; import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import { timefilter } from 'ui/timefilter'; @@ -16,7 +18,7 @@ import { useKibanaContext } from '../../../../../contexts/kibana'; import { FullTimeRangeSelector } from '../../../../../components/full_time_range_selector'; import { EventRateChart } from '../charts/event_rate_chart'; import { LineChartPoint } from '../../../common/chart_loader'; -import { JOB_TYPE } from '../../../common/job_creator/util/constants'; +import { JOB_TYPE } from '../../../../../../../common/constants/new_job'; import { GetTimeFieldRangeResponse } from '../../../../../services/ml_api_service'; import { TimeRangePicker, TimeRange } from '../../../common/components'; @@ -78,10 +80,18 @@ export const TimeRangeStep: FC = ({ setCurrentStep, isCurrentStep }) }, [jobCreatorUpdated]); function fullTimeRangeCallback(range: GetTimeFieldRangeResponse) { - setTimeRange({ - start: range.start.epoch, - end: range.end.epoch, - }); + if (range.start.epoch !== null && range.end.epoch !== null) { + setTimeRange({ + start: range.start.epoch, + end: range.end.epoch, + }); + } else { + toastNotifications.addDanger( + i18n.translate('xpack.ml.newJob.wizard.timeRangeStep.fullTimeRangeError', { + defaultMessage: 'An error occurred obtaining the time range for the index', + }) + ); + } } return ( diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/validation_step/validation.tsx b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/validation_step/validation.tsx index a543dbaaf3c5d1d..19b89ffec02ac99 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/validation_step/validation.tsx +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/validation_step/validation.tsx @@ -10,7 +10,7 @@ import { WIZARD_STEPS, StepProps } from '../step_types'; import { JobCreatorContext } from '../job_creator_context'; import { mlJobService } from '../../../../../services/job_service'; import { ValidateJob } from '../../../../../components/validate_job'; -import { JOB_TYPE } from '../../../common/job_creator/util/constants'; +import { JOB_TYPE } from '../../../../../../../common/constants/new_job'; const idFilterList = [ 'job_id_valid', diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/index_or_search/__test__/directive.js b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/index_or_search/__test__/directive.js deleted file mode 100644 index ffa16930e79f208..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/index_or_search/__test__/directive.js +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import ngMock from 'ng_mock'; -import expect from '@kbn/expect'; -import sinon from 'sinon'; - -// Import this way to be able to stub/mock functions later on in the tests using sinon. -import * as indexUtils from '../../../../../util/index_utils'; - -describe('ML - Index or Saved Search selection directive', () => { - let $scope; - let $compile; - let $element; - - beforeEach(ngMock.module('kibana')); - beforeEach(() => { - ngMock.inject(function ($injector) { - $compile = $injector.get('$compile'); - const $rootScope = $injector.get('$rootScope'); - $scope = $rootScope.$new(); - }); - }); - - afterEach(() => { - $scope.$destroy(); - }); - - it('Initialize Index or Saved Search selection directive', done => { - sinon.stub(indexUtils, 'timeBasedIndexCheck').callsFake(() => false); - ngMock.inject(function () { - expect(() => { - $element = $compile('')($scope); - }).to.not.throwError(); - - // directive has scope: false - const scope = $element.isolateScope(); - expect(scope).to.eql(undefined); - done(); - }); - }); -}); diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/index_or_search/directive.tsx b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/index_or_search/directive.tsx deleted file mode 100644 index 9bd653708d9c013..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/index_or_search/directive.tsx +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; -import ReactDOM from 'react-dom'; - -// @ts-ignore -import { uiModules } from 'ui/modules'; -const module = uiModules.get('apps/ml', ['react']); -import { timefilter } from 'ui/timefilter'; - -import { I18nContext } from 'ui/i18n'; -import { InjectorService } from '../../../../../../common/types/angular'; -import { Page } from './page'; - -module.directive('mlIndexOrSearch', ($injector: InjectorService) => { - return { - scope: {}, - restrict: 'E', - link: async (scope: ng.IScope, element: ng.IAugmentedJQuery) => { - // remove time picker from top of page - timefilter.disableTimeRangeSelector(); - timefilter.disableAutoRefreshSelector(); - - const $route = $injector.get('$route'); - const { nextStepPath } = $route.current.locals; - - ReactDOM.render( - {React.createElement(Page, { nextStepPath })}, - element[0] - ); - - element.on('$destroy', () => { - ReactDOM.unmountComponentAtNode(element[0]); - scope.$destroy(); - }); - }, - }; -}); diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/index_or_search/index.ts b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/index_or_search/index.ts new file mode 100644 index 000000000000000..31e0f67c0a0faa7 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/index_or_search/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { Page } from './page'; +export { preConfiguredJobRedirect } from './preconfigured_job_redirect'; diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/index_or_search/preconfigured_job_redirect.ts b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/index_or_search/preconfigured_job_redirect.ts index 0265129d9ccab6d..8500279e742b78e 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/index_or_search/preconfigured_job_redirect.ts +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/index_or_search/preconfigured_job_redirect.ts @@ -4,16 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ +import { IndexPatternsContract } from '../../../../../../../../../../src/plugins/data/public'; import { mlJobService } from '../../../../services/job_service'; import { loadIndexPatterns, getIndexPatternIdFromName } from '../../../../util/index_utils'; import { CombinedJob } from '../../common/job_creator/configs'; -import { CREATED_BY_LABEL, JOB_TYPE } from '../../common/job_creator/util/constants'; +import { CREATED_BY_LABEL, JOB_TYPE } from '../../../../../../common/constants/new_job'; -export async function preConfiguredJobRedirect() { +export async function preConfiguredJobRedirect(indexPatterns: IndexPatternsContract) { const { job } = mlJobService.tempJobCloningObjects; if (job) { try { - await loadIndexPatterns(); + await loadIndexPatterns(indexPatterns); const redirectUrl = getWizardUrlFromCloningJob(job); window.location.href = `#/${redirectUrl}`; return Promise.reject(); diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/index_or_search/route.ts b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/index_or_search/route.ts deleted file mode 100644 index 6dd5df177bd14ca..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/index_or_search/route.ts +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import uiRoutes from 'ui/routes'; -import { checkMlNodesAvailable } from '../../../../ml_nodes_check'; -import { preConfiguredJobRedirect } from './preconfigured_job_redirect'; -import { checkLicenseExpired, checkBasicLicense } from '../../../../license/check_license'; -import { loadIndexPatterns } from '../../../../util/index_utils'; -import { - checkCreateJobsPrivilege, - checkFindFileStructurePrivilege, -} from '../../../../privilege/check_privilege'; -import { - getCreateJobBreadcrumbs, - getDataVisualizerIndexOrSearchBreadcrumbs, -} from '../../../breadcrumbs'; - -uiRoutes.when('/jobs/new_job', { - redirectTo: '/jobs/new_job/step/index_or_search', -}); - -uiRoutes.when('/jobs/new_job/step/index_or_search', { - template: '', - k7Breadcrumbs: getCreateJobBreadcrumbs, - resolve: { - CheckLicense: checkLicenseExpired, - privileges: checkCreateJobsPrivilege, - indexPatterns: loadIndexPatterns, - preConfiguredJobRedirect, - checkMlNodesAvailable, - nextStepPath: () => '#/jobs/new_job/step/job_type', - }, -}); - -uiRoutes.when('/datavisualizer_index_select', { - template: '', - k7Breadcrumbs: getDataVisualizerIndexOrSearchBreadcrumbs, - resolve: { - CheckLicense: checkBasicLicense, - privileges: checkFindFileStructurePrivilege, - indexPatterns: loadIndexPatterns, - nextStepPath: () => '#jobs/new_job/datavisualizer', - }, -}); diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/job_type/__test__/directive.js b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/job_type/__test__/directive.js deleted file mode 100644 index bdf65e3bafe9627..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/job_type/__test__/directive.js +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import ngMock from 'ng_mock'; -import expect from '@kbn/expect'; -import sinon from 'sinon'; - -// Import this way to be able to stub/mock functions later on in the tests using sinon. -import * as indexUtils from '../../../../../util/index_utils'; - -describe('ML - Job Type Directive', () => { - let $scope; - let $compile; - let $element; - - beforeEach(ngMock.module('kibana')); - beforeEach(() => { - ngMock.inject(function ($injector) { - $compile = $injector.get('$compile'); - const $rootScope = $injector.get('$rootScope'); - $scope = $rootScope.$new(); - }); - }); - - afterEach(() => { - $scope.$destroy(); - }); - - it('Initialize Job Type Directive', done => { - sinon.stub(indexUtils, 'timeBasedIndexCheck').callsFake(() => false); - ngMock.inject(function () { - expect(() => { - $element = $compile('')($scope); - }).to.not.throwError(); - - // directive has scope: false - const scope = $element.isolateScope(); - expect(scope).to.eql(undefined); - done(); - }); - }); -}); diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/job_type/directive.tsx b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/job_type/directive.tsx deleted file mode 100644 index 3f2a7e553c7e0ac..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/job_type/directive.tsx +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; -import ReactDOM from 'react-dom'; - -// @ts-ignore -import { uiModules } from 'ui/modules'; -const module = uiModules.get('apps/ml', ['react']); -import { timefilter } from 'ui/timefilter'; - -import { I18nContext } from 'ui/i18n'; -import { InjectorService } from '../../../../../../common/types/angular'; -import { createSearchItems } from '../../utils/new_job_utils'; -import { Page } from './page'; - -import { KibanaContext, KibanaConfigTypeFix } from '../../../../contexts/kibana'; -import { IndexPatternsContract } from '../../../../../../../../../../src/plugins/data/public'; - -module.directive('mlJobTypePage', ($injector: InjectorService) => { - return { - scope: {}, - restrict: 'E', - link: async (scope: ng.IScope, element: ng.IAugmentedJQuery) => { - // remove time picker from top of page - timefilter.disableTimeRangeSelector(); - timefilter.disableAutoRefreshSelector(); - - const indexPatterns = $injector.get('indexPatterns'); - const kibanaConfig = $injector.get('config'); - const $route = $injector.get('$route'); - - const { indexPattern, savedSearch, combinedQuery } = createSearchItems( - kibanaConfig, - $route.current.locals.indexPattern, - $route.current.locals.savedSearch - ); - const kibanaContext = { - combinedQuery, - currentIndexPattern: indexPattern, - currentSavedSearch: savedSearch, - indexPatterns, - kibanaConfig, - }; - - ReactDOM.render( - - - {React.createElement(Page)} - - , - element[0] - ); - - element.on('$destroy', () => { - ReactDOM.unmountComponentAtNode(element[0]); - scope.$destroy(); - }); - }, - }; -}); diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/job_type/index.ts b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/job_type/index.ts new file mode 100644 index 000000000000000..7e2d651439ae30b --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/job_type/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { Page } from './page'; diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/job_type/page.tsx b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/job_type/page.tsx index 4991039ffa28868..dbae1948cbe0f61 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/job_type/page.tsx +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/job_type/page.tsx @@ -19,6 +19,7 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { useKibanaContext } from '../../../../contexts/kibana'; +import { isSavedSearchSavedObject } from '../../../../../../common/types/kibana'; import { DataRecognizer } from '../../../../components/data_recognizer'; import { addItemToRecentlyAccessed } from '../../../../util/recently_accessed'; import { timeBasedIndexCheck } from '../../../../util/index_utils'; @@ -32,33 +33,33 @@ export const Page: FC = () => { const isTimeBasedIndex = timeBasedIndexCheck(currentIndexPattern); const indexWarningTitle = - !isTimeBasedIndex && currentSavedSearch.id === undefined - ? i18n.translate('xpack.ml.newJob.wizard.jobType.indexPatternNotTimeBasedMessage', { - defaultMessage: 'Index pattern {indexPatternTitle} is not time based', - values: { indexPatternTitle: currentIndexPattern.title }, - }) - : i18n.translate( + !isTimeBasedIndex && isSavedSearchSavedObject(currentSavedSearch) + ? i18n.translate( 'xpack.ml.newJob.wizard.jobType.indexPatternFromSavedSearchNotTimeBasedMessage', { defaultMessage: '{savedSearchTitle} uses index pattern {indexPatternTitle} which is not time based', values: { - savedSearchTitle: currentSavedSearch.title, + savedSearchTitle: currentSavedSearch.attributes.title as string, indexPatternTitle: currentIndexPattern.title, }, } - ); - const pageTitleLabel = - currentSavedSearch.id !== undefined - ? i18n.translate('xpack.ml.newJob.wizard.jobType.savedSearchPageTitleLabel', { - defaultMessage: 'saved search {savedSearchTitle}', - values: { savedSearchTitle: currentSavedSearch.title }, - }) - : i18n.translate('xpack.ml.newJob.wizard.jobType.indexPatternPageTitleLabel', { - defaultMessage: 'index pattern {indexPatternTitle}', + ) + : i18n.translate('xpack.ml.newJob.wizard.jobType.indexPatternNotTimeBasedMessage', { + defaultMessage: 'Index pattern {indexPatternTitle} is not time based', values: { indexPatternTitle: currentIndexPattern.title }, }); + const pageTitleLabel = isSavedSearchSavedObject(currentSavedSearch) + ? i18n.translate('xpack.ml.newJob.wizard.jobType.savedSearchPageTitleLabel', { + defaultMessage: 'saved search {savedSearchTitle}', + values: { savedSearchTitle: currentSavedSearch.attributes.title as string }, + }) + : i18n.translate('xpack.ml.newJob.wizard.jobType.indexPatternPageTitleLabel', { + defaultMessage: 'index pattern {indexPatternTitle}', + values: { indexPatternTitle: currentIndexPattern.title }, + }); + const recognizerResults = { count: 0, onChange() { @@ -67,14 +68,15 @@ export const Page: FC = () => { }; const getUrl = (basePath: string) => { - return currentSavedSearch.id === undefined + return !isSavedSearchSavedObject(currentSavedSearch) ? `${basePath}?index=${currentIndexPattern.id}` : `${basePath}?savedSearchId=${currentSavedSearch.id}`; }; const addSelectionToRecentlyAccessed = () => { - const title = - currentSavedSearch.id === undefined ? currentIndexPattern.title : currentSavedSearch.title; + const title = !isSavedSearchSavedObject(currentSavedSearch) + ? currentIndexPattern.title + : (currentSavedSearch.attributes.title as string); const url = getUrl(''); addItemToRecentlyAccessed('jobs/new_job/datavisualizer', title, url); diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/job_type/route.ts b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/job_type/route.ts deleted file mode 100644 index ac2c838dbed311b..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/job_type/route.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import uiRoutes from 'ui/routes'; - -import { checkMlNodesAvailable } from '../../../../ml_nodes_check'; -import { checkLicenseExpired } from '../../../../license/check_license'; -import { checkCreateJobsPrivilege } from '../../../../privilege/check_privilege'; -import { loadCurrentIndexPattern, loadCurrentSavedSearch } from '../../../../util/index_utils'; -import { getCreateJobBreadcrumbs } from '../../../breadcrumbs'; - -uiRoutes.when('/jobs/new_job/step/job_type', { - template: '', - k7Breadcrumbs: getCreateJobBreadcrumbs, - resolve: { - CheckLicense: checkLicenseExpired, - privileges: checkCreateJobsPrivilege, - indexPattern: loadCurrentIndexPattern, - savedSearch: loadCurrentSavedSearch, - checkMlNodesAvailable, - }, -}); diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/directive.tsx b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/directive.tsx deleted file mode 100644 index d152dfc488ff860..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/directive.tsx +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; -import ReactDOM from 'react-dom'; - -// @ts-ignore -import { uiModules } from 'ui/modules'; -const module = uiModules.get('apps/ml', ['react']); -import { timefilter } from 'ui/timefilter'; -import { I18nContext } from 'ui/i18n'; -import { IndexPatternsContract } from '../../../../../../../../../../src/plugins/data/public'; - -import { InjectorService } from '../../../../../../common/types/angular'; -import { createSearchItems } from '../../utils/new_job_utils'; -import { Page, PageProps } from './page'; -import { JOB_TYPE } from '../../common/job_creator/util/constants'; - -import { KibanaContext, KibanaConfigTypeFix } from '../../../../contexts/kibana'; - -module.directive('mlNewJobPage', ($injector: InjectorService) => { - return { - scope: {}, - restrict: 'E', - link: async (scope: ng.IScope, element: ng.IAugmentedJQuery) => { - timefilter.disableTimeRangeSelector(); - timefilter.disableAutoRefreshSelector(); - - const indexPatterns = $injector.get('indexPatterns'); - const kibanaConfig = $injector.get('config'); - const $route = $injector.get('$route'); - const existingJobsAndGroups = $route.current.locals.existingJobsAndGroups; - - if ($route.current.locals.jobType === undefined) { - return; - } - const jobType: JOB_TYPE = $route.current.locals.jobType; - - const { indexPattern, savedSearch, combinedQuery } = createSearchItems( - kibanaConfig, - $route.current.locals.indexPattern, - $route.current.locals.savedSearch - ); - - const kibanaContext = { - combinedQuery, - currentIndexPattern: indexPattern, - currentSavedSearch: savedSearch, - indexPatterns, - kibanaConfig, - }; - - const props: PageProps = { - existingJobsAndGroups, - jobType, - }; - - ReactDOM.render( - - - {React.createElement(Page, props)} - - , - element[0] - ); - - element.on('$destroy', () => { - ReactDOM.unmountComponentAtNode(element[0]); - scope.$destroy(); - }); - }, - }; -}); diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/index.ts b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/index.ts new file mode 100644 index 000000000000000..7e2d651439ae30b --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { Page } from './page'; diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/page.tsx b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/page.tsx index e086b2b8aad7f0b..79f98c1170ff8d6 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/page.tsx +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/page.tsx @@ -16,7 +16,7 @@ import { JOB_TYPE, DEFAULT_MODEL_MEMORY_LIMIT, DEFAULT_BUCKET_SPAN, -} from '../../common/job_creator/util/constants'; +} from '../../../../../../common/constants/new_job'; import { ChartLoader } from '../../common/chart_loader'; import { ResultsLoader } from '../../common/results_loader'; import { JobValidator } from '../../common/job_validator'; @@ -104,7 +104,7 @@ export const Page: FC = ({ existingJobsAndGroups, jobType }) => { jobCreator.modelPlot = true; } - if (kibanaContext.currentSavedSearch.id !== undefined) { + if (kibanaContext.currentSavedSearch !== null) { // Jobs created from saved searches cannot be cloned in the wizard as the // ML job config holds no reference to the saved search ID. jobCreator.createdBy = null; diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/route.ts b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/route.ts deleted file mode 100644 index a527d92342d4ce6..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/route.ts +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import uiRoutes from 'ui/routes'; - -import { checkFullLicense } from '../../../../license/check_license'; -import { checkGetJobsPrivilege } from '../../../../privilege/check_privilege'; -import { loadCurrentIndexPattern, loadCurrentSavedSearch } from '../../../../util/index_utils'; - -import { - getCreateSingleMetricJobBreadcrumbs, - getCreateMultiMetricJobBreadcrumbs, - getCreatePopulationJobBreadcrumbs, - getAdvancedJobConfigurationBreadcrumbs, -} from '../../../breadcrumbs'; - -import { Route } from '../../../../../../common/types/kibana'; - -import { loadNewJobCapabilities } from '../../../../services/new_job_capabilities_service'; - -import { loadMlServerInfo } from '../../../../services/ml_server_info'; - -import { mlJobService } from '../../../../services/job_service'; -import { JOB_TYPE } from '../../common/job_creator/util/constants'; - -const template = ``; - -const routes: Route[] = [ - { - id: JOB_TYPE.SINGLE_METRIC, - k7Breadcrumbs: getCreateSingleMetricJobBreadcrumbs, - }, - { - id: JOB_TYPE.MULTI_METRIC, - k7Breadcrumbs: getCreateMultiMetricJobBreadcrumbs, - }, - { - id: JOB_TYPE.POPULATION, - k7Breadcrumbs: getCreatePopulationJobBreadcrumbs, - }, - { - id: JOB_TYPE.ADVANCED, - k7Breadcrumbs: getAdvancedJobConfigurationBreadcrumbs, - }, -]; - -routes.forEach((route: Route) => { - uiRoutes.when(`/jobs/new_job/${route.id}`, { - template, - k7Breadcrumbs: route.k7Breadcrumbs, - resolve: { - CheckLicense: checkFullLicense, - privileges: checkGetJobsPrivilege, - indexPattern: loadCurrentIndexPattern, - savedSearch: loadCurrentSavedSearch, - loadNewJobCapabilities, - loadMlServerInfo, - existingJobsAndGroups: mlJobService.getJobAndGroupIds, - jobType: () => route.id, - }, - }); -}); diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/wizard.tsx b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/wizard.tsx index 50b8650f99bb89f..b63ada4bb535c39 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/wizard.tsx +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/wizard.tsx @@ -20,7 +20,7 @@ import { JobValidator } from '../../common/job_validator'; import { newJobCapsService } from '../../../../services/new_job_capabilities_service'; import { WizardSteps } from './wizard_steps'; import { WizardHorizontalSteps } from './wizard_horizontal_steps'; -import { JOB_TYPE } from '../../common/job_creator/util/constants'; +import { JOB_TYPE } from '../../../../../../common/constants/new_job'; interface Props { jobCreator: JobCreatorType; diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/wizard_horizontal_steps.tsx b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/wizard_horizontal_steps.tsx index b5369402230b722..18b199ca8983fcc 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/wizard_horizontal_steps.tsx +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/wizard_horizontal_steps.tsx @@ -10,7 +10,7 @@ import { i18n } from '@kbn/i18n'; import { EuiStepsHorizontal } from '@elastic/eui'; import { WIZARD_STEPS } from '../components/step_types'; -import { JOB_TYPE } from '../../common/job_creator/util/constants'; +import { JOB_TYPE } from '../../../../../../common/constants/new_job'; interface Props { currentStep: WIZARD_STEPS; diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/wizard_steps.tsx b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/wizard_steps.tsx index 0f4eae230acfd81..8e81c05092c98b3 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/wizard_steps.tsx +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/new_job/wizard_steps.tsx @@ -34,10 +34,10 @@ export const WizardSteps: FC = ({ currentStep, setCurrentStep }) => { const [additionalExpanded, setAdditionalExpanded] = useState(false); function getSummaryStepTitle() { - if (kibanaContext.currentSavedSearch.id !== undefined) { + if (kibanaContext.currentSavedSearch !== null) { return i18n.translate('xpack.ml.newJob.wizard.stepComponentWrapper.summaryTitleSavedSearch', { defaultMessage: 'New job from saved search {title}', - values: { title: kibanaContext.currentSavedSearch.title }, + values: { title: kibanaContext.currentSavedSearch.attributes.title as string }, }); } else if (kibanaContext.currentIndexPattern.id !== undefined) { return i18n.translate( diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/__test__/directive.js b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/__test__/directive.js deleted file mode 100644 index d5d5ee4438e3295..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/__test__/directive.js +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import ngMock from 'ng_mock'; -import expect from '@kbn/expect'; -import sinon from 'sinon'; - -// Import this way to be able to stub/mock functions later on in the tests using sinon. -import * as indexUtils from '../../../../util/index_utils'; - -describe('ML - Recognize job directive', () => { - let $scope; - let $compile; - let $element; - - beforeEach(ngMock.module('kibana')); - beforeEach(() => { - ngMock.inject(function ($injector) { - $compile = $injector.get('$compile'); - const $rootScope = $injector.get('$rootScope'); - $scope = $rootScope.$new(); - }); - }); - - afterEach(() => { - $scope.$destroy(); - }); - - it('Initialize Recognize job directive', done => { - sinon.stub(indexUtils, 'timeBasedIndexCheck').callsFake(() => false); - ngMock.inject(function () { - expect(() => { - $element = $compile('')($scope); - }).to.not.throwError(); - - // directive has scope: false - const scope = $element.isolateScope(); - expect(scope).to.eql(undefined); - done(); - }); - }); -}); diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/directive.tsx b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/directive.tsx deleted file mode 100644 index 4ed12dfff4c2079..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/directive.tsx +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; -import ReactDOM from 'react-dom'; - -// @ts-ignore -import { uiModules } from 'ui/modules'; -const module = uiModules.get('apps/ml', ['react']); -import { timefilter } from 'ui/timefilter'; - -import { I18nContext } from 'ui/i18n'; -import { InjectorService } from '../../../../../common/types/angular'; - -import { createSearchItems } from '../utils/new_job_utils'; -import { Page } from './page'; - -import { KibanaContext, KibanaConfigTypeFix } from '../../../contexts/kibana'; -import { IndexPatternsContract } from '../../../../../../../../../src/plugins/data/public'; - -module.directive('mlRecognizePage', ($injector: InjectorService) => { - return { - scope: {}, - restrict: 'E', - link: async (scope: ng.IScope, element: ng.IAugmentedJQuery) => { - // remove time picker from top of page - timefilter.disableTimeRangeSelector(); - timefilter.disableAutoRefreshSelector(); - - const indexPatterns = $injector.get('indexPatterns'); - const kibanaConfig = $injector.get('config'); - const $route = $injector.get('$route'); - - const moduleId = $route.current.params.id; - const existingGroupIds: string[] = $route.current.locals.existingJobsAndGroups.groupIds; - - const { indexPattern, savedSearch, combinedQuery } = createSearchItems( - kibanaConfig, - $route.current.locals.indexPattern, - $route.current.locals.savedSearch - ); - const kibanaContext = { - combinedQuery, - currentIndexPattern: indexPattern, - currentSavedSearch: savedSearch, - indexPatterns, - kibanaConfig, - }; - - ReactDOM.render( - - - {React.createElement(Page, { moduleId, existingGroupIds })} - - , - element[0] - ); - - element.on('$destroy', () => { - ReactDOM.unmountComponentAtNode(element[0]); - scope.$destroy(); - }); - }, - }; -}); diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/index.ts b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/index.ts new file mode 100644 index 000000000000000..7e2d651439ae30b --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { Page } from './page'; diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/page.tsx b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/page.tsx index 11b2a8f01342dbf..141ed5d1bbb8ff4 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/page.tsx +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/page.tsx @@ -85,17 +85,17 @@ export const Page: FC = ({ moduleId, existingGroupIds }) => { combinedQuery, } = useKibanaContext(); const pageTitle = - savedSearch.id !== undefined + savedSearch !== null ? i18n.translate('xpack.ml.newJob.recognize.savedSearchPageTitle', { defaultMessage: 'saved search {savedSearchTitle}', - values: { savedSearchTitle: savedSearch.title }, + values: { savedSearchTitle: savedSearch.attributes.title as string }, }) : i18n.translate('xpack.ml.newJob.recognize.indexPatternPageTitle', { defaultMessage: 'index pattern {indexPatternTitle}', values: { indexPatternTitle: indexPattern.title }, }); - const displayQueryWarning = savedSearch.id !== undefined; - const tempQuery = savedSearch.id === undefined ? undefined : combinedQuery; + const displayQueryWarning = savedSearch !== null; + const tempQuery = savedSearch === null ? undefined : combinedQuery; /** * Loads recognizer module configuration. diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/resolvers.ts b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/resolvers.ts index d2ca22972c20192..cb44210b970e7e1 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/resolvers.ts +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/resolvers.ts @@ -16,25 +16,20 @@ 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($route: any) { +export function checkViewOrCreateJobs(moduleId: string, indexPatternId: string): Promise { return new Promise((resolve, reject) => { - const moduleId = $route.current.params.id; - const indexPatternId = $route.current.params.index; - // Load the module, and check if the job(s) in the module have been created. // If so, load the jobs in the Anomaly Explorer. // Otherwise open the data recognizer wizard for the module. // Always want to call reject() so as not to load original page. ml.dataRecognizerModuleJobsExist({ moduleId }) .then((resp: any) => { - const basePath = `${chrome.getBasePath()}/app/`; - if (resp.jobsExist === true) { const resultsPageUrl = mlJobService.createResultsUrlForJobs(resp.jobs, 'explorer'); - window.location.href = `${basePath}${resultsPageUrl}`; + window.location.href = resultsPageUrl; reject(); } else { - window.location.href = `${basePath}ml#/jobs/new_job/recognize?id=${moduleId}&index=${indexPatternId}`; + window.location.href = `#/jobs/new_job/recognize?id=${moduleId}&index=${indexPatternId}`; reject(); } }) diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/route.ts b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/route.ts deleted file mode 100644 index 7b1d71540c163c8..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/recognize/route.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import uiRoutes from 'ui/routes'; -import { checkMlNodesAvailable } from '../../..//ml_nodes_check/check_ml_nodes'; -import { checkLicenseExpired } from '../../..//license/check_license'; -import { getCreateRecognizerJobBreadcrumbs } from '../../breadcrumbs'; -import { checkCreateJobsPrivilege } from '../../../privilege/check_privilege'; -import { loadCurrentIndexPattern, loadCurrentSavedSearch } from '../../../util/index_utils'; -import { mlJobService } from '../../../services/job_service'; -import { checkViewOrCreateJobs } from './resolvers'; - -uiRoutes.when('/jobs/new_job/recognize', { - template: '', - k7Breadcrumbs: getCreateRecognizerJobBreadcrumbs, - resolve: { - CheckLicense: checkLicenseExpired, - privileges: checkCreateJobsPrivilege, - indexPattern: loadCurrentIndexPattern, - savedSearch: loadCurrentSavedSearch, - checkMlNodesAvailable, - existingJobsAndGroups: mlJobService.getJobAndGroupIds, - }, -}); - -uiRoutes.when('/modules/check_view_or_create', { - template: '', - resolve: { - checkViewOrCreateJobs, - }, -}); diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/utils/new_job_utils.ts b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/utils/new_job_utils.ts index 455fac9b532d61e..050387e6de263c9 100644 --- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/utils/new_job_utils.ts +++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/utils/new_job_utils.ts @@ -5,24 +5,18 @@ */ import { IndexPattern } from 'ui/index_patterns'; -import { SavedSearch } from 'src/legacy/core_plugins/kibana/public/discover/types'; +import { esQuery, Query, esKuery } from '../../../../../../../../../src/plugins/data/public'; import { KibanaConfigTypeFix } from '../../../contexts/kibana'; -import { esQuery, Query, IIndexPattern } from '../../../../../../../../../src/plugins/data/public'; - -export interface SearchItems { - indexPattern: IIndexPattern; - savedSearch: SavedSearch; - query: any; - combinedQuery: any; -} +import { SEARCH_QUERY_LANGUAGE } from '../../../../../common/constants/search'; +import { SavedSearchSavedObject } from '../../../../../common/types/kibana'; +import { getQueryFromSavedSearch } from '../../../util/index_utils'; // 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 createSearchItems( kibanaConfig: KibanaConfigTypeFix, indexPattern: IndexPattern, - savedSearch: SavedSearch + savedSearch: SavedSearchSavedObject | null ) { // query is only used by the data visualizer as it needs // a lucene query_string. @@ -43,22 +37,36 @@ export function createSearchItems( }, }; - if (indexPattern.id === undefined && savedSearch.id !== undefined) { - const searchSource = savedSearch.searchSource; - indexPattern = searchSource.getField('index')!; + if (savedSearch !== null) { + const data = getQueryFromSavedSearch(savedSearch); - query = searchSource.getField('query')!; - const fs = searchSource.getField('filter'); + query = data.query; + const filter = data.filter; - const filters = Array.isArray(fs) ? fs : []; + const filters = Array.isArray(filter) ? filter : []; - const esQueryConfigs = esQuery.getEsQueryConfig(kibanaConfig); - combinedQuery = esQuery.buildEsQuery(indexPattern, [query], filters, esQueryConfigs); + if (query.language === SEARCH_QUERY_LANGUAGE.KUERY) { + const ast = esKuery.fromKueryExpression(query.query); + if (query.query !== '') { + combinedQuery = esKuery.toElasticsearchQuery(ast, indexPattern); + } + const filterQuery = esQuery.buildQueryFromFilters(filters, indexPattern); + + if (combinedQuery.bool.filter === undefined) { + combinedQuery.bool.filter = []; + } + if (combinedQuery.bool.must_not === undefined) { + combinedQuery.bool.must_not = []; + } + combinedQuery.bool.filter = [...combinedQuery.bool.filter, ...filterQuery.filter]; + combinedQuery.bool.must_not = [...combinedQuery.bool.must_not, ...filterQuery.must_not]; + } else { + const esQueryConfigs = esQuery.getEsQueryConfig(kibanaConfig); + combinedQuery = esQuery.buildEsQuery(indexPattern, [query], filters, esQueryConfigs); + } } return { - indexPattern, - savedSearch, query, combinedQuery, }; diff --git a/x-pack/legacy/plugins/ml/public/application/overview/breadcrumbs.ts b/x-pack/legacy/plugins/ml/public/application/overview/breadcrumbs.ts deleted file mode 100644 index 9df503b462b6c0a..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/overview/breadcrumbs.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; -// @ts-ignore -import { ML_BREADCRUMB } from '../../breadcrumbs'; - -export function getOverviewBreadcrumbs() { - // Whilst top level nav menu with tabs remains, - // use root ML breadcrumb. - return [ - ML_BREADCRUMB, - { - text: i18n.translate('xpack.ml.overviewBreadcrumbs.overviewLabel', { - defaultMessage: 'Overview', - }), - href: '', - }, - ]; -} diff --git a/x-pack/legacy/plugins/ml/public/application/overview/directive.tsx b/x-pack/legacy/plugins/ml/public/application/overview/directive.tsx deleted file mode 100644 index bd3b653ccbb64af..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/overview/directive.tsx +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import ReactDOM from 'react-dom'; -import React from 'react'; -import { I18nContext } from 'ui/i18n'; -import { timefilter } from 'ui/timefilter'; -// @ts-ignore -import { uiModules } from 'ui/modules'; -const module = uiModules.get('apps/ml', ['react']); - -import { OverviewPage } from './overview_page'; - -module.directive('mlOverview', function() { - return { - scope: {}, - restrict: 'E', - link: async (scope: ng.IScope, element: ng.IAugmentedJQuery) => { - timefilter.disableTimeRangeSelector(); - timefilter.disableAutoRefreshSelector(); - - ReactDOM.render( - - - , - element[0] - ); - - element.on('$destroy', () => { - ReactDOM.unmountComponentAtNode(element[0]); - scope.$destroy(); - }); - }, - }; -}); diff --git a/x-pack/legacy/plugins/ml/public/application/overview/index.ts b/x-pack/legacy/plugins/ml/public/application/overview/index.ts index ac00eab1f2cdb03..7d99bb109401543 100644 --- a/x-pack/legacy/plugins/ml/public/application/overview/index.ts +++ b/x-pack/legacy/plugins/ml/public/application/overview/index.ts @@ -4,5 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -import './route'; -import './directive'; +export { OverviewPage } from './overview_page'; diff --git a/x-pack/legacy/plugins/ml/public/breadcrumbs.ts b/x-pack/legacy/plugins/ml/public/application/routing/breadcrumbs.ts similarity index 64% rename from x-pack/legacy/plugins/ml/public/breadcrumbs.ts rename to x-pack/legacy/plugins/ml/public/application/routing/breadcrumbs.ts index ba4703d4818ff5b..6d8138d4bcd2c6f 100644 --- a/x-pack/legacy/plugins/ml/public/breadcrumbs.ts +++ b/x-pack/legacy/plugins/ml/public/application/routing/breadcrumbs.ts @@ -5,31 +5,32 @@ */ import { i18n } from '@kbn/i18n'; +import { ChromeBreadcrumb } from '../../../../../../../src/core/public'; -export const ML_BREADCRUMB = Object.freeze({ +export const ML_BREADCRUMB: ChromeBreadcrumb = Object.freeze({ text: i18n.translate('xpack.ml.machineLearningBreadcrumbLabel', { defaultMessage: 'Machine Learning', }), href: '#/', }); -export const SETTINGS = Object.freeze({ +export const SETTINGS: ChromeBreadcrumb = Object.freeze({ text: i18n.translate('xpack.ml.settingsBreadcrumbLabel', { defaultMessage: 'Settings', }), - href: '#/settings?', + href: '#/settings', }); -export const ANOMALY_DETECTION_BREADCRUMB = Object.freeze({ +export const ANOMALY_DETECTION_BREADCRUMB: ChromeBreadcrumb = Object.freeze({ text: i18n.translate('xpack.ml.anomalyDetectionBreadcrumbLabel', { defaultMessage: 'Anomaly Detection', }), - href: '#/jobs?', + href: '#/jobs', }); -export const DATA_VISUALIZER_BREADCRUMB = Object.freeze({ +export const DATA_VISUALIZER_BREADCRUMB: ChromeBreadcrumb = Object.freeze({ text: i18n.translate('xpack.ml.datavisualizerBreadcrumbLabel', { defaultMessage: 'Data Visualizer', }), - href: '#/datavisualizer?', + href: '#/datavisualizer', }); diff --git a/x-pack/legacy/plugins/ml/public/application/routing/index.ts b/x-pack/legacy/plugins/ml/public/application/routing/index.ts new file mode 100644 index 000000000000000..3ec5361568526dc --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { MlRouter, MlRoute } from './router'; diff --git a/x-pack/legacy/plugins/ml/public/application/overview/route.ts b/x-pack/legacy/plugins/ml/public/application/routing/resolvers.ts similarity index 50% rename from x-pack/legacy/plugins/ml/public/application/overview/route.ts rename to x-pack/legacy/plugins/ml/public/application/routing/resolvers.ts index e737961e184fcee..30c5fbc497afe68 100644 --- a/x-pack/legacy/plugins/ml/public/application/overview/route.ts +++ b/x-pack/legacy/plugins/ml/public/application/routing/resolvers.ts @@ -4,23 +4,24 @@ * you may not use this file except in compliance with the Elastic License. */ -import uiRoutes from 'ui/routes'; -import { getMlNodeCount } from '../ml_nodes_check/check_ml_nodes'; +import { loadIndexPatterns, loadSavedSearches } from '../util/index_utils'; import { checkFullLicense } from '../license/check_license'; import { checkGetJobsPrivilege } from '../privilege/check_privilege'; +import { getMlNodeCount } from '../ml_nodes_check/check_ml_nodes'; import { loadMlServerInfo } from '../services/ml_server_info'; -import { getOverviewBreadcrumbs } from './breadcrumbs'; -import './directive'; - -const template = ``; +import { PageDependencies } from './router'; -uiRoutes.when('/overview/?', { - template, - k7Breadcrumbs: getOverviewBreadcrumbs, - resolve: { - CheckLicense: checkFullLicense, - privileges: checkGetJobsPrivilege, - mlNodeCount: getMlNodeCount, - loadMlServerInfo, - }, +export interface Resolvers { + [name: string]: () => Promise; +} +export interface ResolverResults { + [name: string]: any; +} +export const basicResolvers = (deps: PageDependencies): Resolvers => ({ + checkFullLicense, + getMlNodeCount, + loadMlServerInfo, + loadIndexPatterns: () => loadIndexPatterns(deps.indexPatterns), + checkGetJobsPrivilege, + loadSavedSearches, }); diff --git a/x-pack/legacy/plugins/ml/public/application/routing/router.tsx b/x-pack/legacy/plugins/ml/public/application/routing/router.tsx new file mode 100644 index 000000000000000..174c1ef1d4fe8d8 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/router.tsx @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC } from 'react'; +import { HashRouter, Route, RouteProps } from 'react-router-dom'; +import { Location } from 'history'; +import { I18nContext } from 'ui/i18n'; + +import { IndexPatternsContract } from '../../../../../../../src/plugins/data/public'; +import { KibanaContext, KibanaConfigTypeFix, KibanaContextValue } from '../contexts/kibana'; +import { ChromeBreadcrumb } from '../../../../../../../src/core/public'; + +import * as routes from './routes'; + +// custom RouteProps making location non-optional +interface MlRouteProps extends RouteProps { + location: Location; +} + +export interface MlRoute { + path: string; + render(props: MlRouteProps, config: KibanaConfigTypeFix, deps: PageDependencies): JSX.Element; + breadcrumbs: ChromeBreadcrumb[]; +} + +export interface PageProps { + location: Location; + config: KibanaConfigTypeFix; + deps: PageDependencies; +} + +export interface PageDependencies { + indexPatterns: IndexPatternsContract; +} + +export const PageLoader: FC<{ context: KibanaContextValue }> = ({ context, children }) => { + return context === null ? null : ( + + {children} + + ); +}; + +export const MlRouter: FC<{ + config: KibanaConfigTypeFix; + setBreadcrumbs: (breadcrumbs: ChromeBreadcrumb[]) => void; + indexPatterns: IndexPatternsContract; +}> = ({ config, setBreadcrumbs, indexPatterns }) => { + return ( + +
+ {Object.entries(routes).map(([name, route]) => ( + { + window.setTimeout(() => { + setBreadcrumbs(route.breadcrumbs); + }); + return route.render(props, config, { indexPatterns }); + }} + /> + ))} +
+
+ ); +}; diff --git a/x-pack/legacy/plugins/ml/public/application/routing/routes/access_denied.tsx b/x-pack/legacy/plugins/ml/public/application/routing/routes/access_denied.tsx new file mode 100644 index 000000000000000..3a2f445ac6b82ce --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/routes/access_denied.tsx @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC } from 'react'; +import { i18n } from '@kbn/i18n'; +import { MlRoute, PageLoader, PageProps } from '../router'; +import { useResolver } from '../use_resolver'; +import { Page } from '../../access_denied'; + +const breadcrumbs = [ + { + text: i18n.translate('xpack.ml.accessDeniedLabel', { + defaultMessage: 'Access denied', + }), + href: '', + }, +]; + +export const accessDeniedRoute: MlRoute = { + path: '/access-denied', + render: (props, config, deps) => , + breadcrumbs, +}; + +const PageWrapper: FC = ({ config }) => { + const { context } = useResolver(undefined, undefined, config, {}); + + return ( + + + + ); +}; diff --git a/x-pack/legacy/plugins/ml/public/application/routing/routes/data_frame_analytics/analytics_job_exploration.tsx b/x-pack/legacy/plugins/ml/public/application/routing/routes/data_frame_analytics/analytics_job_exploration.tsx new file mode 100644 index 000000000000000..41c286c54836c2b --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/routes/data_frame_analytics/analytics_job_exploration.tsx @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC } from 'react'; +import { i18n } from '@kbn/i18n'; +import { decode } from 'rison-node'; + +// @ts-ignore +import queryString from 'query-string'; +import { MlRoute, PageLoader, PageProps } from '../../router'; +import { useResolver } from '../../use_resolver'; +import { basicResolvers } from '../../resolvers'; +import { Page } from '../../../data_frame_analytics/pages/analytics_exploration'; +import { ANALYSIS_CONFIG_TYPE } from '../../../data_frame_analytics/common/analytics'; +import { DATA_FRAME_TASK_STATE } from '../../../data_frame_analytics/pages/analytics_management/components/analytics_list/common'; +import { ML_BREADCRUMB } from '../../breadcrumbs'; + +const breadcrumbs = [ + ML_BREADCRUMB, + { + text: i18n.translate('xpack.ml.dataFrameAnalyticsBreadcrumbs.dataFrameExplorationLabel', { + defaultMessage: 'Data Frame Analytics', + }), + href: '', + }, +]; + +export const analyticsJobExplorationRoute: MlRoute = { + path: '/data_frame_analytics/exploration', + render: (props, config, deps) => , + breadcrumbs, +}; + +const PageWrapper: FC = ({ location, config, deps }) => { + const { context } = useResolver('', undefined, config, basicResolvers(deps)); + const { _g } = queryString.parse(location.search); + let globalState: any = null; + try { + globalState = decode(_g); + } catch (error) { + // eslint-disable-next-line no-console + console.error('Could not parse global state'); + window.location.href = '#data_frame_analytics'; + } + const jobId: string = globalState.ml.jobId; + const analysisType: ANALYSIS_CONFIG_TYPE = globalState.ml.analysisType; + const jobStatus: DATA_FRAME_TASK_STATE = globalState.ml.jobStatus; + + return ( + + + + ); +}; diff --git a/x-pack/legacy/plugins/ml/public/application/routing/routes/data_frame_analytics/analytics_jobs_list.tsx b/x-pack/legacy/plugins/ml/public/application/routing/routes/data_frame_analytics/analytics_jobs_list.tsx new file mode 100644 index 000000000000000..31bd10f2138ad17 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/routes/data_frame_analytics/analytics_jobs_list.tsx @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC } from 'react'; +import { i18n } from '@kbn/i18n'; + +import { MlRoute, PageLoader, PageProps } from '../../router'; +import { useResolver } from '../../use_resolver'; +import { basicResolvers } from '../../resolvers'; +import { Page } from '../../../data_frame_analytics/pages/analytics_management'; +import { ML_BREADCRUMB } from '../../breadcrumbs'; + +const breadcrumbs = [ + ML_BREADCRUMB, + { + text: i18n.translate('xpack.ml.dataFrameAnalyticsBreadcrumbs.dataFrameListLabel', { + defaultMessage: 'Data Frame Analytics', + }), + href: '', + }, +]; + +export const analyticsJobsListRoute: MlRoute = { + path: '/data_frame_analytics', + render: (props, config, deps) => , + breadcrumbs, +}; + +const PageWrapper: FC = ({ location, config, deps }) => { + const { context } = useResolver('', undefined, config, basicResolvers(deps)); + return ( + + + + ); +}; diff --git a/x-pack/legacy/plugins/ml/public/application/routing/routes/data_frame_analytics/index.ts b/x-pack/legacy/plugins/ml/public/application/routing/routes/data_frame_analytics/index.ts new file mode 100644 index 000000000000000..552c15a408b65bd --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/routes/data_frame_analytics/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export * from './analytics_jobs_list'; +export * from './analytics_job_exploration'; diff --git a/x-pack/legacy/plugins/ml/public/application/routing/routes/datavisualizer/datavisualizer.tsx b/x-pack/legacy/plugins/ml/public/application/routing/routes/datavisualizer/datavisualizer.tsx new file mode 100644 index 000000000000000..3faca285319d5fe --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/routes/datavisualizer/datavisualizer.tsx @@ -0,0 +1,40 @@ +/* + * 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. + */ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC } from 'react'; + +import { MlRoute, PageLoader, PageProps } from '../../router'; +import { useResolver } from '../../use_resolver'; +import { DatavisualizerSelector } from '../../../datavisualizer'; + +import { checkBasicLicense } from '../../../license/check_license'; +import { checkFindFileStructurePrivilege } from '../../../privilege/check_privilege'; +import { DATA_VISUALIZER_BREADCRUMB, ML_BREADCRUMB } from '../../breadcrumbs'; + +const breadcrumbs = [ML_BREADCRUMB, DATA_VISUALIZER_BREADCRUMB]; + +export const selectorRoute: MlRoute = { + path: '/datavisualizer', + render: (props, config, deps) => , + breadcrumbs, +}; + +const PageWrapper: FC = ({ location, config }) => { + const { context } = useResolver(undefined, undefined, config, { + checkBasicLicense, + checkFindFileStructurePrivilege, + }); + return ( + + + + ); +}; diff --git a/x-pack/legacy/plugins/ml/public/application/routing/routes/datavisualizer/file_based.tsx b/x-pack/legacy/plugins/ml/public/application/routing/routes/datavisualizer/file_based.tsx new file mode 100644 index 000000000000000..11e6b85f939d3f6 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/routes/datavisualizer/file_based.tsx @@ -0,0 +1,55 @@ +/* + * 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. + */ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC } from 'react'; +import { i18n } from '@kbn/i18n'; + +import { MlRoute, PageLoader, PageProps } from '../../router'; +import { useResolver } from '../../use_resolver'; +import { FileDataVisualizerPage } from '../../../datavisualizer/file_based'; + +import { checkBasicLicense } from '../../../license/check_license'; +import { checkFindFileStructurePrivilege } from '../../../privilege/check_privilege'; +import { loadIndexPatterns } from '../../../util/index_utils'; + +import { getMlNodeCount } from '../../../ml_nodes_check'; +import { DATA_VISUALIZER_BREADCRUMB, ML_BREADCRUMB } from '../../breadcrumbs'; + +const breadcrumbs = [ + ML_BREADCRUMB, + DATA_VISUALIZER_BREADCRUMB, + { + text: i18n.translate('xpack.ml.dataVisualizer.fileBasedLabel', { + defaultMessage: 'File', + }), + href: '', + }, +]; + +export const fileBasedRoute: MlRoute = { + path: '/filedatavisualizer', + render: (props, config, deps) => , + breadcrumbs, +}; + +const PageWrapper: FC = ({ location, config, deps }) => { + const { context } = useResolver('', undefined, config, { + checkBasicLicense, + loadIndexPatterns: () => loadIndexPatterns(deps.indexPatterns), + checkFindFileStructurePrivilege, + getMlNodeCount, + }); + return ( + + + + ); +}; diff --git a/x-pack/legacy/plugins/ml/public/application/routing/routes/datavisualizer/index.ts b/x-pack/legacy/plugins/ml/public/application/routing/routes/datavisualizer/index.ts new file mode 100644 index 000000000000000..7f61317ef34021b --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/routes/datavisualizer/index.ts @@ -0,0 +1,9 @@ +/* + * 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 * from './datavisualizer'; +export * from './index_based'; +export * from './file_based'; diff --git a/x-pack/legacy/plugins/ml/public/application/routing/routes/datavisualizer/index_based.tsx b/x-pack/legacy/plugins/ml/public/application/routing/routes/datavisualizer/index_based.tsx new file mode 100644 index 000000000000000..ab359238695d42f --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/routes/datavisualizer/index_based.tsx @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC } from 'react'; +import { i18n } from '@kbn/i18n'; + +// @ts-ignore +import queryString from 'query-string'; +import { MlRoute, PageLoader, PageProps } from '../../router'; +import { useResolver } from '../../use_resolver'; +import { Page } from '../../../datavisualizer/index_based'; + +import { checkBasicLicense } from '../../../license/check_license'; +import { checkGetJobsPrivilege } from '../../../privilege/check_privilege'; +import { loadIndexPatterns } from '../../../util/index_utils'; +import { checkMlNodesAvailable } from '../../../ml_nodes_check'; +import { DATA_VISUALIZER_BREADCRUMB, ML_BREADCRUMB } from '../../breadcrumbs'; + +const breadcrumbs = [ + ML_BREADCRUMB, + DATA_VISUALIZER_BREADCRUMB, + { + text: i18n.translate('xpack.ml.dataFrameAnalyticsBreadcrumbs.indexLabel', { + defaultMessage: 'Index', + }), + href: '', + }, +]; + +export const indexBasedRoute: MlRoute = { + path: '/jobs/new_job/datavisualizer', + render: (props, config, deps) => , + breadcrumbs, +}; + +const PageWrapper: FC = ({ location, config, deps }) => { + const { index, savedSearchId } = queryString.parse(location.search); + const { context } = useResolver(index, savedSearchId, config, { + checkBasicLicense, + loadIndexPatterns: () => loadIndexPatterns(deps.indexPatterns), + checkGetJobsPrivilege, + checkMlNodesAvailable, + }); + + return ( + + + + ); +}; diff --git a/x-pack/legacy/plugins/ml/public/application/routing/routes/explorer.tsx b/x-pack/legacy/plugins/ml/public/application/routing/routes/explorer.tsx new file mode 100644 index 000000000000000..1b6b91026d6a5a3 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/routes/explorer.tsx @@ -0,0 +1,156 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC, useEffect } from 'react'; +import { i18n } from '@kbn/i18n'; +import { decode } from 'rison-node'; +import { Subscription } from 'rxjs'; + +// @ts-ignore +import queryString from 'query-string'; +import { timefilter } from 'ui/timefilter'; +import { MlRoute, PageLoader, PageProps } from '../router'; +import { useResolver } from '../use_resolver'; +import { basicResolvers } from '../resolvers'; +import { Explorer } from '../../explorer'; +import { mlJobService } from '../../services/job_service'; +import { getExplorerDefaultAppState, ExplorerAppState } from '../../explorer/reducers'; +import { explorerService } from '../../explorer/explorer_dashboard_service'; +import { jobSelectServiceFactory } from '../../components/job_selector/job_select_service_utils'; +import { subscribeAppStateToObservable } from '../../util/app_state_utils'; + +import { interval$ } from '../../components/controls/select_interval'; +import { severity$ } from '../../components/controls/select_severity'; +import { showCharts$ } from '../../components/controls/checkbox_showcharts'; +import { ANOMALY_DETECTION_BREADCRUMB, ML_BREADCRUMB } from '../breadcrumbs'; + +const breadcrumbs = [ + ML_BREADCRUMB, + ANOMALY_DETECTION_BREADCRUMB, + { + text: i18n.translate('xpack.ml.anomalyDetection.anomalyExplorerLabel', { + defaultMessage: 'Anomaly Explorer', + }), + href: '', + }, +]; + +export const explorerRoute: MlRoute = { + path: '/explorer', + render: (props, config, deps) => , + breadcrumbs, +}; + +const PageWrapper: FC = ({ location, config, deps }) => { + const { index } = queryString.parse(location.search); + const { context } = useResolver(index, undefined, config, { + ...basicResolvers(deps), + jobs: mlJobService.loadJobsWrapper, + }); + const { _a, _g } = queryString.parse(location.search); + let appState: any = {}; + let globalState: any = {}; + try { + appState = decode(_a); + globalState = decode(_g); + } catch (error) { + // eslint-disable-next-line no-console + console.error('Could not parse global or app state'); + } + + if (appState.mlExplorerSwimlane === undefined) { + appState.mlExplorerSwimlane = {}; + } + + if (appState.mlExplorerFilter === undefined) { + appState.mlExplorerFilter = {}; + } + + appState.fetch = () => {}; + appState.on = () => {}; + appState.off = () => {}; + appState.save = () => {}; + globalState.fetch = () => {}; + globalState.on = () => {}; + globalState.off = () => {}; + globalState.save = () => {}; + + return ( + + + + ); +}; + +class AppState { + fetch() {} + on() {} + off() {} + save() {} +} + +const ExplorerWrapper: FC<{ globalState: any; appState: any }> = ({ globalState, appState }) => { + const subscriptions = new Subscription(); + + const { jobSelectService$, unsubscribeFromGlobalState } = jobSelectServiceFactory(globalState); + appState = getExplorerDefaultAppState(); + const { mlExplorerFilter, mlExplorerSwimlane } = appState; + window.setTimeout(() => { + // Pass the current URL AppState on to anomaly explorer's reactive state. + // After this hand-off, the appState stored in explorerState$ is the single + // source of truth. + explorerService.setAppState({ mlExplorerSwimlane, mlExplorerFilter }); + + // Now that appState in explorerState$ is the single source of truth, + // subscribe to it and update the actual URL appState on changes. + subscriptions.add( + explorerService.appState$.subscribe((appStateIn: ExplorerAppState) => { + // appState.fetch(); + appState.mlExplorerFilter = appStateIn.mlExplorerFilter; + appState.mlExplorerSwimlane = appStateIn.mlExplorerSwimlane; + // appState.save(); + }) + ); + }); + + subscriptions.add(subscribeAppStateToObservable(AppState, 'mlShowCharts', showCharts$, () => {})); + subscriptions.add( + subscribeAppStateToObservable(AppState, 'mlSelectInterval', interval$, () => {}) + ); + subscriptions.add( + subscribeAppStateToObservable(AppState, 'mlSelectSeverity', severity$, () => {}) + ); + + if (globalState.time) { + timefilter.setTime({ + from: globalState.time.from, + to: globalState.time.to, + }); + } + + useEffect(() => { + return () => { + subscriptions.unsubscribe(); + unsubscribeFromGlobalState(); + }; + }); + + return ( +
+ +
+ ); +}; diff --git a/x-pack/legacy/plugins/ml/public/application/routing/routes/index.ts b/x-pack/legacy/plugins/ml/public/application/routing/routes/index.ts new file mode 100644 index 000000000000000..89ed35d5588f2d5 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/routes/index.ts @@ -0,0 +1,15 @@ +/* + * 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 * from './overview'; +export * from './jobs_list'; +export * from './new_job'; +export * from './datavisualizer'; +export * from './settings'; +export * from './data_frame_analytics'; +export * from './timeseriesexplorer'; +export * from './explorer'; +export * from './access_denied'; diff --git a/x-pack/legacy/plugins/ml/public/application/routing/routes/jobs_list.tsx b/x-pack/legacy/plugins/ml/public/application/routing/routes/jobs_list.tsx new file mode 100644 index 000000000000000..e61c24426bde994 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/routes/jobs_list.tsx @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC } from 'react'; +import { i18n } from '@kbn/i18n'; +import { MlRoute, PageLoader, PageProps } from '../router'; +import { useResolver } from '../use_resolver'; +import { basicResolvers } from '../resolvers'; +import { JobsPage } from '../../jobs/jobs_list'; +import { ANOMALY_DETECTION_BREADCRUMB, ML_BREADCRUMB } from '../breadcrumbs'; + +const breadcrumbs = [ + ML_BREADCRUMB, + ANOMALY_DETECTION_BREADCRUMB, + { + text: i18n.translate('xpack.ml.anomalyDetection.jobManagementLabel', { + defaultMessage: 'Job Management', + }), + href: '', + }, +]; + +export const jobListRoute: MlRoute = { + path: '/jobs', + render: (props, config, deps) => , + breadcrumbs, +}; + +const PageWrapper: FC = ({ config, deps }) => { + const { context } = useResolver(undefined, undefined, config, basicResolvers(deps)); + + return ( + + + + ); +}; diff --git a/x-pack/legacy/plugins/ml/public/application/routing/routes/new_job/index.ts b/x-pack/legacy/plugins/ml/public/application/routing/routes/new_job/index.ts new file mode 100644 index 000000000000000..b226b75743ca61c --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/routes/new_job/index.ts @@ -0,0 +1,11 @@ +/* + * 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 * from './index_or_search'; +export * from './job_type'; +export * from './new_job'; +export * from './wizard'; +export * from './recognize'; diff --git a/x-pack/legacy/plugins/ml/public/application/routing/routes/new_job/index_or_search.tsx b/x-pack/legacy/plugins/ml/public/application/routing/routes/new_job/index_or_search.tsx new file mode 100644 index 000000000000000..b81058a9c89af39 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/routes/new_job/index_or_search.tsx @@ -0,0 +1,90 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC } from 'react'; +import { i18n } from '@kbn/i18n'; +import { MlRoute, PageLoader, PageDependencies } from '../../router'; +import { useResolver } from '../../use_resolver'; +import { basicResolvers } from '../../resolvers'; +import { Page, preConfiguredJobRedirect } from '../../../jobs/new_job/pages/index_or_search'; +import { ANOMALY_DETECTION_BREADCRUMB, ML_BREADCRUMB } from '../../breadcrumbs'; +import { KibanaConfigTypeFix } from '../../../contexts/kibana'; +import { checkBasicLicense } from '../../../license/check_license'; +import { loadIndexPatterns } from '../../../util/index_utils'; +import { checkGetJobsPrivilege } from '../../../privilege/check_privilege'; +import { checkMlNodesAvailable } from '../../../ml_nodes_check'; + +enum MODE { + NEW_JOB, + DATAVISUALIZER, +} + +const breadcrumbs = [ + ML_BREADCRUMB, + ANOMALY_DETECTION_BREADCRUMB, + { + text: i18n.translate('xpack.ml.jobsBreadcrumbs.selectIndexOrSearchLabel', { + defaultMessage: 'Create job', + }), + href: '', + }, +]; + +export const indexOrSearchRoute: MlRoute = { + path: '/jobs/new_job/step/index_or_search', + render: (props, config, deps) => ( + + ), + breadcrumbs, +}; + +export const dataVizIndexOrSearchRoute: MlRoute = { + path: '/datavisualizer_index_select', + render: (props, config, deps) => ( + + ), + breadcrumbs, +}; + +const PageWrapper: FC<{ + config: KibanaConfigTypeFix; + nextStepPath: string; + deps: PageDependencies; + mode: MODE; +}> = ({ config, nextStepPath, deps, mode }) => { + const newJobResolvers = { + ...basicResolvers(deps), + preConfiguredJobRedirect: () => preConfiguredJobRedirect(deps.indexPatterns), + }; + const dataVizResolvers = { + checkBasicLicense, + loadIndexPatterns: () => loadIndexPatterns(deps.indexPatterns), + checkGetJobsPrivilege, + checkMlNodesAvailable, + }; + + const { context } = useResolver( + undefined, + undefined, + config, + mode === MODE.NEW_JOB ? newJobResolvers : dataVizResolvers + ); + return ( + + + + ); +}; diff --git a/x-pack/legacy/plugins/ml/public/application/routing/routes/new_job/job_type.tsx b/x-pack/legacy/plugins/ml/public/application/routing/routes/new_job/job_type.tsx new file mode 100644 index 000000000000000..e537a186ec784fb --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/routes/new_job/job_type.tsx @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC } from 'react'; +import { i18n } from '@kbn/i18n'; + +// @ts-ignore +import queryString from 'query-string'; +import { MlRoute, PageLoader, PageProps } from '../../router'; +import { useResolver } from '../../use_resolver'; +import { basicResolvers } from '../../resolvers'; +import { Page } from '../../../jobs/new_job/pages/job_type'; +import { ANOMALY_DETECTION_BREADCRUMB, ML_BREADCRUMB } from '../../breadcrumbs'; + +const breadcrumbs = [ + ML_BREADCRUMB, + ANOMALY_DETECTION_BREADCRUMB, + { + text: i18n.translate('xpack.ml.jobsBreadcrumbs.selectJobType', { + defaultMessage: 'Create job', + }), + href: '', + }, +]; + +export const jobTypeRoute: MlRoute = { + path: '/jobs/new_job/step/job_type', + render: (props, config, deps) => , + breadcrumbs, +}; + +const PageWrapper: FC = ({ location, config, deps }) => { + const { index, savedSearchId } = queryString.parse(location.search); + const { context } = useResolver(index, savedSearchId, config, basicResolvers(deps)); + return ( + + + + ); +}; diff --git a/x-pack/legacy/plugins/ml/public/application/routing/routes/new_job/new_job.tsx b/x-pack/legacy/plugins/ml/public/application/routing/routes/new_job/new_job.tsx new file mode 100644 index 000000000000000..b110434f6f0a8ea --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/routes/new_job/new_job.tsx @@ -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 React, { FC } from 'react'; +import { i18n } from '@kbn/i18n'; +import { Redirect } from 'react-router-dom'; + +import { MlRoute } from '../../router'; +import { ANOMALY_DETECTION_BREADCRUMB, ML_BREADCRUMB } from '../../breadcrumbs'; + +const breadcrumbs = [ + ML_BREADCRUMB, + ANOMALY_DETECTION_BREADCRUMB, + { + text: i18n.translate('xpack.ml.jobsBreadcrumbs.jobWizardLabel', { + defaultMessage: 'Create job', + }), + href: '#/jobs/new_job', + }, +]; + +export const newJobRoute: MlRoute = { + path: '/jobs/new_job', + render: () => , + breadcrumbs, +}; + +const Page: FC = () => { + return ; +}; diff --git a/x-pack/legacy/plugins/ml/public/application/routing/routes/new_job/recognize.tsx b/x-pack/legacy/plugins/ml/public/application/routing/routes/new_job/recognize.tsx new file mode 100644 index 000000000000000..4f5085facfb2980 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/routes/new_job/recognize.tsx @@ -0,0 +1,66 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC } from 'react'; +import { i18n } from '@kbn/i18n'; +// @ts-ignore +import queryString from 'query-string'; + +import { MlRoute, PageLoader, PageProps } from '../../router'; +import { useResolver } from '../../use_resolver'; +import { basicResolvers } from '../../resolvers'; +import { Page } from '../../../jobs/new_job/recognize'; +import { checkViewOrCreateJobs } from '../../../jobs/new_job/recognize/resolvers'; +import { mlJobService } from '../../../services/job_service'; +import { ANOMALY_DETECTION_BREADCRUMB, ML_BREADCRUMB } from '../../breadcrumbs'; + +const breadcrumbs = [ + ML_BREADCRUMB, + ANOMALY_DETECTION_BREADCRUMB, + { + text: i18n.translate('xpack.ml.jobsBreadcrumbs.selectIndexOrSearchLabelRecognize', { + defaultMessage: 'Select index or search', + }), + href: '', + }, +]; + +export const recognizeRoute: MlRoute = { + path: '/jobs/new_job/recognize', + render: (props, config, deps) => , + breadcrumbs, +}; + +export const checkViewOrCreateRoute: MlRoute = { + path: '/modules/check_view_or_create', + render: (props, config, deps) => ( + + ), + breadcrumbs: [], +}; + +const PageWrapper: FC = ({ location, config, deps }) => { + const { id, index, savedSearchId } = queryString.parse(location.search); + const { context, results } = useResolver(index, savedSearchId, config, { + ...basicResolvers(deps), + existingJobsAndGroups: mlJobService.getJobAndGroupIds, + }); + + return ( + + + + ); +}; + +const CheckViewOrCreateWrapper: FC = ({ location, config, deps }) => { + const { id: moduleId, index: indexPatternId } = queryString.parse(location.search); + // the single resolver checkViewOrCreateJobs redirects only. so will always reject + useResolver(undefined, undefined, config, { + checkViewOrCreateJobs: () => checkViewOrCreateJobs(moduleId, indexPatternId), + }); + return null; +}; diff --git a/x-pack/legacy/plugins/ml/public/application/routing/routes/new_job/wizard.tsx b/x-pack/legacy/plugins/ml/public/application/routing/routes/new_job/wizard.tsx new file mode 100644 index 000000000000000..ea1baefdce0d1be --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/routes/new_job/wizard.tsx @@ -0,0 +1,121 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC } from 'react'; +import { i18n } from '@kbn/i18n'; +// @ts-ignore +import queryString from 'query-string'; + +import { basicResolvers } from '../../resolvers'; +import { MlRoute, PageLoader, PageProps } from '../../router'; +import { useResolver } from '../../use_resolver'; +import { Page } from '../../../jobs/new_job/pages/new_job'; +import { JOB_TYPE } from '../../../../../common/constants/new_job'; +import { mlJobService } from '../../../services/job_service'; +import { loadNewJobCapabilities } from '../../../services/new_job_capabilities_service'; +import { checkCreateJobsPrivilege } from '../../../privilege/check_privilege'; +import { ANOMALY_DETECTION_BREADCRUMB, ML_BREADCRUMB } from '../../breadcrumbs'; + +interface WizardPageProps extends PageProps { + jobType: JOB_TYPE; +} + +const createJobBreadcrumbs = { + text: i18n.translate('xpack.ml.jobsBreadcrumbs.createJobLabel', { + defaultMessage: 'Create job', + }), + href: '#/jobs/new_job', +}; + +const baseBreadcrumbs = [ML_BREADCRUMB, ANOMALY_DETECTION_BREADCRUMB, createJobBreadcrumbs]; + +const singleMetricBreadcrumbs = [ + ...baseBreadcrumbs, + { + text: i18n.translate('xpack.ml.jobsBreadcrumbs.singleMetricLabel', { + defaultMessage: 'Single metric', + }), + href: '', + }, +]; + +const multiMetricBreadcrumbs = [ + ...baseBreadcrumbs, + { + text: i18n.translate('xpack.ml.jobsBreadcrumbs.multiMetricLabel', { + defaultMessage: 'Multi metric', + }), + href: '', + }, +]; + +const populationBreadcrumbs = [ + ...baseBreadcrumbs, + { + text: i18n.translate('xpack.ml.jobsBreadcrumbs.populationLabel', { + defaultMessage: 'Population', + }), + href: '', + }, +]; + +const advancedBreadcrumbs = [ + ...baseBreadcrumbs, + { + text: i18n.translate('xpack.ml.jobsBreadcrumbs.advancedConfigurationLabel', { + defaultMessage: 'Advanced configuration', + }), + href: '', + }, +]; + +export const singleMetricRoute: MlRoute = { + path: '/jobs/new_job/single_metric', + render: (props, config, deps) => ( + + ), + breadcrumbs: singleMetricBreadcrumbs, +}; + +export const multiMetricRoute: MlRoute = { + path: '/jobs/new_job/multi_metric', + render: (props, config, deps) => ( + + ), + breadcrumbs: multiMetricBreadcrumbs, +}; + +export const populationRoute: MlRoute = { + path: '/jobs/new_job/population', + render: (props, config, deps) => ( + + ), + breadcrumbs: populationBreadcrumbs, +}; + +export const advancedRoute: MlRoute = { + path: '/jobs/new_job/advanced', + render: (props, config, deps) => ( + + ), + breadcrumbs: advancedBreadcrumbs, +}; + +const PageWrapper: FC = ({ location, config, jobType, deps }) => { + const { index, savedSearchId } = queryString.parse(location.search); + const { context, results } = useResolver(index, savedSearchId, config, { + ...basicResolvers(deps), + privileges: checkCreateJobsPrivilege, + jobCaps: () => loadNewJobCapabilities(index, savedSearchId, deps.indexPatterns), + existingJobsAndGroups: mlJobService.getJobAndGroupIds, + }); + + return ( + + + + ); +}; diff --git a/x-pack/legacy/plugins/ml/public/application/routing/routes/overview.tsx b/x-pack/legacy/plugins/ml/public/application/routing/routes/overview.tsx new file mode 100644 index 000000000000000..fe9f4336148f3c8 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/routes/overview.tsx @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC } from 'react'; +import { i18n } from '@kbn/i18n'; + +import { Redirect } from 'react-router-dom'; +import { MlRoute, PageLoader, PageProps } from '../router'; +import { useResolver } from '../use_resolver'; +import { OverviewPage } from '../../overview'; + +import { checkFullLicense } from '../../license/check_license'; +import { checkGetJobsPrivilege } from '../../privilege/check_privilege'; +import { getMlNodeCount } from '../../ml_nodes_check'; +import { loadMlServerInfo } from '../../services/ml_server_info'; +import { ML_BREADCRUMB } from '../breadcrumbs'; + +const breadcrumbs = [ + ML_BREADCRUMB, + { + text: i18n.translate('xpack.ml.overview.overviewLabel', { + defaultMessage: 'Overview', + }), + href: '#/overview', + }, +]; + +export const overviewRoute: MlRoute = { + path: '/overview', + render: (props, config, deps) => , + breadcrumbs, +}; + +const PageWrapper: FC = ({ config }) => { + const { context } = useResolver(undefined, undefined, config, { + checkFullLicense, + checkGetJobsPrivilege, + getMlNodeCount, + loadMlServerInfo, + }); + + return ( + + + + ); +}; + +export const appRootRoute: MlRoute = { + path: '/', + render: () => , + breadcrumbs: [], +}; + +const Page: FC = () => { + return ; +}; diff --git a/x-pack/legacy/plugins/ml/public/application/routing/routes/settings/calendar_list.tsx b/x-pack/legacy/plugins/ml/public/application/routing/routes/settings/calendar_list.tsx new file mode 100644 index 000000000000000..56ff57f6610b270 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/routes/settings/calendar_list.tsx @@ -0,0 +1,56 @@ +/* + * 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. + */ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC } from 'react'; +import { i18n } from '@kbn/i18n'; + +import { MlRoute, PageLoader, PageProps } from '../../router'; +import { useResolver } from '../../use_resolver'; + +import { checkFullLicense } from '../../../license/check_license'; +import { checkGetJobsPrivilege, checkPermission } from '../../../privilege/check_privilege'; +import { getMlNodeCount } from '../../../ml_nodes_check/check_ml_nodes'; +import { CalendarsList } from '../../../settings/calendars'; +import { SETTINGS, ML_BREADCRUMB } from '../../breadcrumbs'; + +const breadcrumbs = [ + ML_BREADCRUMB, + SETTINGS, + { + text: i18n.translate('xpack.ml.settings.breadcrumbs.calendarManagementLabel', { + defaultMessage: 'Calendar management', + }), + href: '#/settings/calendars_list', + }, +]; + +export const calendarListRoute: MlRoute = { + path: '/settings/calendars_list', + render: (props, config, deps) => , + breadcrumbs, +}; + +const PageWrapper: FC = ({ config }) => { + const { context } = useResolver(undefined, undefined, config, { + checkFullLicense, + checkGetJobsPrivilege, + getMlNodeCount, + }); + + const canCreateCalendar = checkPermission('canCreateCalendar'); + const canDeleteCalendar = checkPermission('canDeleteCalendar'); + + return ( + + + + ); +}; diff --git a/x-pack/legacy/plugins/ml/public/application/routing/routes/settings/calendar_new_edit.tsx b/x-pack/legacy/plugins/ml/public/application/routing/routes/settings/calendar_new_edit.tsx new file mode 100644 index 000000000000000..fb68f103e1b77bb --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/routes/settings/calendar_new_edit.tsx @@ -0,0 +1,92 @@ +/* + * 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. + */ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC } from 'react'; +import { i18n } from '@kbn/i18n'; + +import { MlRoute, PageLoader, PageProps } from '../../router'; +import { useResolver } from '../../use_resolver'; + +import { checkFullLicense } from '../../../license/check_license'; +import { checkGetJobsPrivilege, checkPermission } from '../../../privilege/check_privilege'; +import { checkMlNodesAvailable } from '../../../ml_nodes_check/check_ml_nodes'; +import { NewCalendar } from '../../../settings/calendars'; +import { SETTINGS, ML_BREADCRUMB } from '../../breadcrumbs'; + +enum MODE { + NEW, + EDIT, +} + +interface NewCalendarPageProps extends PageProps { + mode: MODE; +} + +const newBreadcrumbs = [ + ML_BREADCRUMB, + SETTINGS, + { + text: i18n.translate('xpack.ml.settings.breadcrumbs.calendarManagement.createLabel', { + defaultMessage: 'Create', + }), + href: '#/settings/calendars_list/new_calendar', + }, +]; + +const editBreadcrumbs = [ + ML_BREADCRUMB, + SETTINGS, + { + text: i18n.translate('xpack.ml.settings.breadcrumbs.calendarManagement.editLabel', { + defaultMessage: 'Edit', + }), + href: '#/settings/calendars_list/edit_calendar', + }, +]; + +export const newCalendarRoute: MlRoute = { + path: '/settings/calendars_list/new_calendar', + render: (props, config, deps) => ( + + ), + breadcrumbs: newBreadcrumbs, +}; + +export const editCalendarRoute: MlRoute = { + path: '/settings/calendars_list/edit_calendar/:calendarId', + render: (props, config, deps) => ( + + ), + breadcrumbs: editBreadcrumbs, +}; + +const PageWrapper: FC = ({ location, config, mode }) => { + let calendarId: string | undefined; + if (mode === MODE.EDIT) { + const pathMatch: string[] | null = location.pathname.match(/.+\/(.+)$/); + calendarId = pathMatch && pathMatch.length > 1 ? pathMatch[1] : undefined; + } + + const { context } = useResolver(undefined, undefined, config, { + checkFullLicense, + checkGetJobsPrivilege, + checkMlNodesAvailable, + }); + + const canCreateCalendar = checkPermission('canCreateCalendar'); + const canDeleteCalendar = checkPermission('canDeleteCalendar'); + + return ( + + + + ); +}; diff --git a/x-pack/legacy/plugins/ml/public/application/routing/routes/settings/filter_list.tsx b/x-pack/legacy/plugins/ml/public/application/routing/routes/settings/filter_list.tsx new file mode 100644 index 000000000000000..cb19883e962c1d7 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/routes/settings/filter_list.tsx @@ -0,0 +1,57 @@ +/* + * 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. + */ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC } from 'react'; +import { i18n } from '@kbn/i18n'; + +import { MlRoute, PageLoader, PageProps } from '../../router'; +import { useResolver } from '../../use_resolver'; + +import { checkFullLicense } from '../../../license/check_license'; +import { checkGetJobsPrivilege, checkPermission } from '../../../privilege/check_privilege'; +import { getMlNodeCount } from '../../../ml_nodes_check/check_ml_nodes'; +import { FilterLists } from '../../../settings/filter_lists'; + +import { SETTINGS, ML_BREADCRUMB } from '../../breadcrumbs'; + +const breadcrumbs = [ + ML_BREADCRUMB, + SETTINGS, + { + text: i18n.translate('xpack.ml.settings.breadcrumbs.filterListsLabel', { + defaultMessage: 'Filter lists', + }), + href: '#/settings/filter_lists', + }, +]; + +export const filterListRoute: MlRoute = { + path: '/settings/filter_lists', + render: (props, config, deps) => , + breadcrumbs, +}; + +const PageWrapper: FC = ({ config }) => { + const { context } = useResolver(undefined, undefined, config, { + checkFullLicense, + checkGetJobsPrivilege, + getMlNodeCount, + }); + + const canCreateFilter = checkPermission('canCreateFilter'); + const canDeleteFilter = checkPermission('canDeleteFilter'); + + return ( + + + + ); +}; diff --git a/x-pack/legacy/plugins/ml/public/application/routing/routes/settings/filter_list_new_edit.tsx b/x-pack/legacy/plugins/ml/public/application/routing/routes/settings/filter_list_new_edit.tsx new file mode 100644 index 000000000000000..7a596a488ddb6c4 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/routes/settings/filter_list_new_edit.tsx @@ -0,0 +1,98 @@ +/* + * 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. + */ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC } from 'react'; +import { i18n } from '@kbn/i18n'; + +import { MlRoute, PageLoader, PageProps } from '../../router'; +import { useResolver } from '../../use_resolver'; + +import { checkFullLicense } from '../../../license/check_license'; +import { checkGetJobsPrivilege, checkPermission } from '../../../privilege/check_privilege'; +import { checkMlNodesAvailable } from '../../../ml_nodes_check/check_ml_nodes'; +import { EditFilterList } from '../../../settings/filter_lists'; +import { SETTINGS, ML_BREADCRUMB } from '../../breadcrumbs'; + +enum MODE { + NEW, + EDIT, +} + +interface NewFilterPageProps extends PageProps { + mode: MODE; +} + +const newBreadcrumbs = [ + ML_BREADCRUMB, + SETTINGS, + { + text: i18n.translate('xpack.ml.settings.breadcrumbs.filterLists.createLabel', { + defaultMessage: 'Create', + }), + href: '#/settings/filter_lists/new', + }, +]; + +const editBreadcrumbs = [ + ML_BREADCRUMB, + SETTINGS, + { + text: i18n.translate('xpack.ml.settings.breadcrumbs.filterLists.editLabel', { + defaultMessage: 'Edit', + }), + href: '#/settings/filter_lists/edit', + }, +]; + +export const newFilterListRoute: MlRoute = { + path: '/settings/filter_lists/new_filter_list', + render: (props, config, deps) => ( + + ), + breadcrumbs: newBreadcrumbs, +}; + +export const editFilterListRoute: MlRoute = { + path: '/settings/filter_lists/edit_filter_list/:filterId', + render: (props, config, deps) => ( + + ), + breadcrumbs: editBreadcrumbs, +}; + +const PageWrapper: FC = ({ location, config, mode }) => { + let filterId: string | undefined; + if (mode === MODE.EDIT) { + const pathMatch: string[] | null = location.pathname.match(/.+\/(.+)$/); + filterId = pathMatch && pathMatch.length > 1 ? pathMatch[1] : undefined; + } + + const { context } = useResolver(undefined, undefined, config, { + checkFullLicense, + checkGetJobsPrivilege, + checkMlNodesAvailable, + }); + + const canCreateFilter = checkPermission('canCreateFilter'); + const canDeleteFilter = checkPermission('canDeleteFilter'); + + return ( + + + + ); +}; diff --git a/x-pack/legacy/plugins/ml/public/application/routing/routes/settings/index.ts b/x-pack/legacy/plugins/ml/public/application/routing/routes/settings/index.ts new file mode 100644 index 000000000000000..f638b78e05fb1a4 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/routes/settings/index.ts @@ -0,0 +1,11 @@ +/* + * 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 * from './settings'; +export * from './calendar_list'; +export * from './calendar_new_edit'; +export * from './filter_list'; +export * from './filter_list_new_edit'; diff --git a/x-pack/legacy/plugins/ml/public/application/routing/routes/settings/settings.tsx b/x-pack/legacy/plugins/ml/public/application/routing/routes/settings/settings.tsx new file mode 100644 index 000000000000000..b62ecc0539e7235 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/routes/settings/settings.tsx @@ -0,0 +1,46 @@ +/* + * 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. + */ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC } from 'react'; + +import { MlRoute, PageLoader, PageProps } from '../../router'; +import { useResolver } from '../../use_resolver'; + +import { checkFullLicense } from '../../../license/check_license'; +import { checkGetJobsPrivilege, checkPermission } from '../../../privilege/check_privilege'; +import { getMlNodeCount } from '../../../ml_nodes_check/check_ml_nodes'; +import { Settings } from '../../../settings'; +import { ML_BREADCRUMB, SETTINGS } from '../../breadcrumbs'; + +const breadcrumbs = [ML_BREADCRUMB, SETTINGS]; + +export const settingsRoute: MlRoute = { + path: '/settings', + render: (props, config, deps) => , + breadcrumbs, +}; + +const PageWrapper: FC = ({ config }) => { + const { context } = useResolver(undefined, undefined, config, { + checkFullLicense, + checkGetJobsPrivilege, + getMlNodeCount, + }); + + const canGetFilters = checkPermission('canGetFilters'); + const canGetCalendars = checkPermission('canGetCalendars'); + + return ( + + + + ); +}; diff --git a/x-pack/legacy/plugins/ml/public/application/routing/routes/timeseriesexplorer.tsx b/x-pack/legacy/plugins/ml/public/application/routing/routes/timeseriesexplorer.tsx new file mode 100644 index 000000000000000..a40bbfa214b2810 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/routes/timeseriesexplorer.tsx @@ -0,0 +1,155 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC, useEffect } from 'react'; +import { i18n } from '@kbn/i18n'; +import { decode } from 'rison-node'; +import moment from 'moment'; +import { Subscription } from 'rxjs'; + +// @ts-ignore +import queryString from 'query-string'; +import { timefilter } from 'ui/timefilter'; +import { MlRoute, PageLoader, PageProps } from '../router'; +import { useResolver } from '../use_resolver'; +import { basicResolvers } from '../resolvers'; +import { TimeSeriesExplorer } from '../../timeseriesexplorer'; +import { mlJobService } from '../../services/job_service'; +import { APP_STATE_ACTION } from '../../timeseriesexplorer/timeseriesexplorer_constants'; +import { subscribeAppStateToObservable } from '../../util/app_state_utils'; +import { interval$ } from '../../components/controls/select_interval'; +import { severity$ } from '../../components/controls/select_severity'; +import { ANOMALY_DETECTION_BREADCRUMB, ML_BREADCRUMB } from '../breadcrumbs'; + +export const timeSeriesExplorerRoute: MlRoute = { + path: '/timeseriesexplorer', + render: (props, config, deps) => , + breadcrumbs: [ + ML_BREADCRUMB, + ANOMALY_DETECTION_BREADCRUMB, + { + text: i18n.translate('xpack.ml.anomalyDetection.singleMetricViewerLabel', { + defaultMessage: 'Single Metric Viewer', + }), + href: '', + }, + ], +}; + +const PageWrapper: FC = ({ location, config, deps }) => { + const { context } = useResolver('', undefined, config, { + ...basicResolvers(deps), + jobs: mlJobService.loadJobsWrapper, + }); + const { _a, _g } = queryString.parse(location.search); + let appState: any = {}; + let globalState: any = {}; + try { + appState = decode(_a); + globalState = decode(_g); + } catch (error) { + // eslint-disable-next-line no-console + console.error('Could not parse global or app state'); + } + if (appState.mlTimeSeriesExplorer === undefined) { + appState.mlTimeSeriesExplorer = {}; + } + globalState.fetch = () => {}; + globalState.on = () => {}; + globalState.off = () => {}; + globalState.save = () => {}; + + return ( + + + + ); +}; + +class AppState { + fetch() {} + on() {} + off() {} + save() {} +} + +const TimeSeriesExplorerWrapper: FC<{ globalState: any; appState: any; config: any }> = ({ + globalState, + appState, + config, +}) => { + if (globalState.time) { + timefilter.setTime({ + from: globalState.time.from, + to: globalState.time.to, + }); + } + + const subscriptions = new Subscription(); + subscriptions.add( + subscribeAppStateToObservable(AppState, 'mlSelectInterval', interval$, () => {}) + ); + subscriptions.add( + subscribeAppStateToObservable(AppState, 'mlSelectSeverity', severity$, () => {}) + ); + + const appStateHandler = (action: string, payload: any) => { + switch (action) { + case APP_STATE_ACTION.CLEAR: + delete appState.mlTimeSeriesExplorer.detectorIndex; + delete appState.mlTimeSeriesExplorer.entities; + delete appState.mlTimeSeriesExplorer.forecastId; + break; + + case APP_STATE_ACTION.GET_DETECTOR_INDEX: + return appState.mlTimeSeriesExplorer.detectorIndex; + case APP_STATE_ACTION.SET_DETECTOR_INDEX: + appState.mlTimeSeriesExplorer.detectorIndex = payload; + break; + + case APP_STATE_ACTION.GET_ENTITIES: + return appState.mlTimeSeriesExplorer.entities; + case APP_STATE_ACTION.SET_ENTITIES: + appState.mlTimeSeriesExplorer.entities = payload; + break; + + case APP_STATE_ACTION.GET_FORECAST_ID: + return appState.mlTimeSeriesExplorer.forecastId; + case APP_STATE_ACTION.SET_FORECAST_ID: + appState.mlTimeSeriesExplorer.forecastId = payload; + break; + + case APP_STATE_ACTION.GET_ZOOM: + return appState.mlTimeSeriesExplorer.zoom; + case APP_STATE_ACTION.SET_ZOOM: + appState.mlTimeSeriesExplorer.zoom = payload; + break; + case APP_STATE_ACTION.UNSET_ZOOM: + delete appState.mlTimeSeriesExplorer.zoom; + break; + } + }; + + useEffect(() => { + return () => { + subscriptions.unsubscribe(); + }; + }); + + const tzConfig = config.get('dateFormat:tz'); + const dateFormatTz = tzConfig !== 'Browser' ? tzConfig : moment.tz.guess(); + + return ( + + ); +}; diff --git a/x-pack/legacy/plugins/ml/public/application/routing/use_resolver.ts b/x-pack/legacy/plugins/ml/public/application/routing/use_resolver.ts new file mode 100644 index 000000000000000..f74260c06567e0e --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/routing/use_resolver.ts @@ -0,0 +1,70 @@ +/* + * 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 { useEffect, useState } from 'react'; +import { + getIndexPatternById, + getIndexPatternsContract, + getIndexPatternAndSavedSearch, +} from '../util/index_utils'; +import { createSearchItems } from '../jobs/new_job/utils/new_job_utils'; +import { ResolverResults, Resolvers } from './resolvers'; +import { KibanaConfigTypeFix, KibanaContextValue } from '../contexts/kibana'; + +export const useResolver = ( + indexPatternId: string | undefined, + savedSearchId: string | undefined, + config: KibanaConfigTypeFix, + resolvers: Resolvers +): { context: KibanaContextValue; results: ResolverResults } => { + const funcNames = Object.keys(resolvers); // Object.entries gets this wrong?! + const funcs = Object.values(resolvers); // Object.entries gets this wrong?! + const tempResults = funcNames.reduce((p, c) => { + p[c] = {}; + return p; + }, {} as ResolverResults); + + const [context, setContext] = useState(null); + const [results, setResults] = useState(tempResults); + + useEffect(() => { + (async () => { + try { + const res = await Promise.all(funcs.map(r => r())); + res.forEach((r, i) => (tempResults[funcNames[i]] = r)); + setResults(tempResults); + + if (indexPatternId !== undefined || savedSearchId !== undefined) { + // note, currently we're using our own kibana context that requires a current index pattern to be set + // this means, if the page uses this context, useResolver must be passed a string for the index pattern id + // and loadIndexPatterns must be part of the resolvers. + const { indexPattern, savedSearch } = + savedSearchId !== undefined + ? await getIndexPatternAndSavedSearch(savedSearchId) + : { savedSearch: null, indexPattern: await getIndexPatternById(indexPatternId!) }; + + const { combinedQuery } = createSearchItems(config, indexPattern!, savedSearch); + + setContext({ + combinedQuery, + currentIndexPattern: indexPattern, + currentSavedSearch: savedSearch, + indexPatterns: getIndexPatternsContract()!, + kibanaConfig: config, + }); + } else { + setContext({}); + } + } catch (error) { + // quietly fail. Let the resolvers handle the redirection if any fail to resolve + // eslint-disable-next-line no-console + console.error('ML page loading resolver', error); + } + })(); + }, []); + + return { context, results }; +}; diff --git a/x-pack/legacy/plugins/ml/public/application/services/job_service.d.ts b/x-pack/legacy/plugins/ml/public/application/services/job_service.d.ts index a3096a942a7c719..b9ed83eeffba163 100644 --- a/x-pack/legacy/plugins/ml/public/application/services/job_service.d.ts +++ b/x-pack/legacy/plugins/ml/public/application/services/job_service.d.ts @@ -35,10 +35,10 @@ declare interface JobService { end: number | undefined ): Promise; createResultsUrl(jobId: string[], start: number, end: number, location: string): string; - getJobAndGroupIds(): ExistingJobsAndGroups; + getJobAndGroupIds(): Promise; searchPreview(job: CombinedJob): Promise>; getJob(jobId: string): CombinedJob; - loadJobsWrapper(): Promise; + loadJobsWrapper(): Promise; } export const mlJobService: JobService; diff --git a/x-pack/legacy/plugins/ml/public/application/services/job_service.js b/x-pack/legacy/plugins/ml/public/application/services/job_service.js index 90aa5d8d66faacd..dbe81df0f047193 100644 --- a/x-pack/legacy/plugins/ml/public/application/services/job_service.js +++ b/x-pack/legacy/plugins/ml/public/application/services/job_service.js @@ -912,7 +912,7 @@ function createResultsUrl(jobIds, start, end, resultsPage) { let path = ''; if (resultsPage !== undefined) { - path += 'ml#/'; + path += '#/'; path += resultsPage; } diff --git a/x-pack/legacy/plugins/ml/public/application/services/new_job_capabilities_service.ts b/x-pack/legacy/plugins/ml/public/application/services/new_job_capabilities_service.ts index f79515c80556a37..9d5c33d6cfc5c06 100644 --- a/x-pack/legacy/plugins/ml/public/application/services/new_job_capabilities_service.ts +++ b/x-pack/legacy/plugins/ml/public/application/services/new_job_capabilities_service.ts @@ -4,8 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SavedSearchLoader } from 'src/legacy/core_plugins/kibana/public/discover/types'; - import { Field, Aggregation, @@ -20,18 +18,16 @@ import { IndexPatternsContract, } from '../../../../../../../src/plugins/data/public'; import { ml } from './ml_api_service'; +import { getIndexPatternAndSavedSearch } from '../util/index_utils'; // called in the angular routing resolve block to initialize the // newJobCapsService with the currently selected index pattern export function loadNewJobCapabilities( - indexPatterns: IndexPatternsContract, - savedSearches: SavedSearchLoader, - $route: Record + indexPatternId: string, + savedSearchId: string, + indexPatterns: IndexPatternsContract ) { return new Promise(async (resolve, reject) => { - // get the index pattern id or saved search id from the url params - const { index: indexPatternId, savedSearchId } = $route.current.params; - if (indexPatternId !== undefined) { // index pattern is being used const indexPattern: IndexPattern = await indexPatterns.get(indexPatternId); @@ -40,8 +36,13 @@ export function loadNewJobCapabilities( } else if (savedSearchId !== undefined) { // saved search is being used // load the index pattern from the saved search - const savedSearch = await savedSearches.get(savedSearchId); - const indexPattern = savedSearch.searchSource.getField('index')!; + const { indexPattern } = await getIndexPatternAndSavedSearch(savedSearchId); + if (indexPattern === null) { + // eslint-disable-next-line no-console + console.error('Cannot retrieve index pattern from saved search'); + reject(); + return; + } await newJobCapsService.initializeFromIndexPattern(indexPattern); resolve(newJobCapsService.newJobCaps); } else { diff --git a/x-pack/legacy/plugins/ml/public/application/settings/breadcrumbs.ts b/x-pack/legacy/plugins/ml/public/application/settings/breadcrumbs.ts deleted file mode 100644 index bd04003c9eca4ec..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/settings/breadcrumbs.ts +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; -import { ML_BREADCRUMB, ANOMALY_DETECTION_BREADCRUMB, 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]; -} - -export function getCalendarManagementBreadcrumbs() { - return [ - ...getSettingsBreadcrumbs(), - { - text: i18n.translate('xpack.ml.settings.breadcrumbs.calendarManagementLabel', { - defaultMessage: 'Calendar management', - }), - href: '#/settings/calendars_list', - }, - ]; -} - -export function getCreateCalendarBreadcrumbs() { - return [ - ...getCalendarManagementBreadcrumbs(), - { - text: i18n.translate('xpack.ml.settings.breadcrumbs.calendarManagement.createLabel', { - defaultMessage: 'Create', - }), - href: '#/settings/calendars_list/new_calendar', - }, - ]; -} - -export function getEditCalendarBreadcrumbs() { - return [ - ...getCalendarManagementBreadcrumbs(), - { - text: i18n.translate('xpack.ml.settings.breadcrumbs.calendarManagement.editLabel', { - defaultMessage: 'Edit', - }), - href: '#/settings/calendars_list/edit_calendar', - }, - ]; -} - -export function getFilterListsBreadcrumbs() { - return [ - ...getSettingsBreadcrumbs(), - { - text: i18n.translate('xpack.ml.settings.breadcrumbs.filterListsLabel', { - defaultMessage: 'Filter lists', - }), - href: '#/settings/filter_lists', - }, - ]; -} - -export function getCreateFilterListBreadcrumbs() { - return [ - ...getFilterListsBreadcrumbs(), - { - text: i18n.translate('xpack.ml.settings.breadcrumbs.filterLists.createLabel', { - defaultMessage: 'Create', - }), - href: '#/settings/filter_lists/new', - }, - ]; -} - -export function getEditFilterListBreadcrumbs() { - return [ - ...getFilterListsBreadcrumbs(), - { - text: i18n.translate('xpack.ml.settings.breadcrumbs.filterLists.editLabel', { - defaultMessage: 'Edit', - }), - href: '#/settings/filter_lists/edit', - }, - ]; -} diff --git a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/calendar_form/__snapshots__/calendar_form.test.js.snap b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/calendar_form/__snapshots__/calendar_form.test.js.snap index 408042fb70cbac1..267fb3930121bbf 100644 --- a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/calendar_form/__snapshots__/calendar_form.test.js.snap +++ b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/calendar_form/__snapshots__/calendar_form.test.js.snap @@ -181,7 +181,7 @@ exports[`CalendarForm Renders calendar form 1`] = ` grow={false} > - -`; - -uiRoutes - .when('/settings/calendars_list/new_calendar', { - template, - k7Breadcrumbs: getCreateCalendarBreadcrumbs, - resolve: { - CheckLicense: checkFullLicense, - privileges: checkGetJobsPrivilege, - checkMlNodesAvailable, - }, - }) - .when('/settings/calendars_list/edit_calendar/:calendarId', { - template, - k7Breadcrumbs: getEditCalendarBreadcrumbs, - resolve: { - CheckLicense: checkFullLicense, - privileges: checkGetJobsPrivilege, - checkMlNodesAvailable, - }, - }); - -module.directive('mlNewCalendar', function($route: any) { - return { - restrict: 'E', - replace: false, - scope: {}, - link(scope: ng.IScope, element: ng.IAugmentedJQuery) { - const props = { - calendarId: $route.current.params.calendarId, - canCreateCalendar: checkPermission('canCreateCalendar'), - canDeleteCalendar: checkPermission('canDeleteCalendar'), - }; - - ReactDOM.render( - - - , - element[0] - ); - }, - }; -}); diff --git a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/index.ts b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/index.ts index aa8b2ec2c29c970..5e008e4796d1cb4 100644 --- a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/index.ts +++ b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/index.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -import './directive'; +export { NewCalendar } from './new_calendar'; diff --git a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/new_calendar.d.ts b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/new_calendar.d.ts index d6de538d6388a8a..002a88ec03f0d15 100644 --- a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/new_calendar.d.ts +++ b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/new_calendar.d.ts @@ -7,7 +7,7 @@ import { FC } from 'react'; declare const NewCalendar: FC<{ - calendarId: string; + calendarId?: string; canCreateCalendar: boolean; canDeleteCalendar: boolean; }>; diff --git a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/new_calendar.js b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/new_calendar.js index feabd60d8d3a0a5..c9fe2503b0c5b45 100644 --- a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/new_calendar.js +++ b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/new_calendar.js @@ -18,7 +18,6 @@ import { EuiOverlayMask, } from '@elastic/eui'; -import chrome from 'ui/chrome'; import { toastNotifications } from 'ui/notify'; import { NavigationMenu } from '../../../components/navigation_menu'; @@ -153,7 +152,7 @@ export const NewCalendar = injectI18n(class NewCalendar extends Component { try { await ml.addCalendar(calendar); - window.location = `${chrome.getBasePath()}/app/ml#/settings/calendars_list`; + window.location = '#/settings/calendars_list'; } catch (error) { console.log('Error saving calendar', error); this.setState({ saving: false }); @@ -176,7 +175,7 @@ export const NewCalendar = injectI18n(class NewCalendar extends Component { try { await ml.updateCalendar(calendar); - window.location = `${chrome.getBasePath()}/app/ml#/settings/calendars_list`; + window.location = '#/settings/calendars_list'; } catch (error) { console.log('Error saving calendar', error); this.setState({ saving: false }); diff --git a/x-pack/legacy/plugins/ml/public/application/settings/calendars/index.ts b/x-pack/legacy/plugins/ml/public/application/settings/calendars/index.ts new file mode 100644 index 000000000000000..88aa20ea063208b --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/settings/calendars/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { NewCalendar } from './edit'; +export { CalendarsList } from './list'; diff --git a/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/directive.tsx b/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/directive.tsx deleted file mode 100644 index 1b90a27c07ada01..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/directive.tsx +++ /dev/null @@ -1,58 +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 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 { CalendarsList } from './calendars_list'; - -const template = ` -
- -`; - -uiRoutes.when('/settings/calendars_list', { - template, - k7Breadcrumbs: getCalendarManagementBreadcrumbs, - resolve: { - CheckLicense: checkFullLicense, - privileges: checkGetJobsPrivilege, - mlNodeCount: getMlNodeCount, - }, -}); - -module.directive('mlCalendarsList', function() { - return { - restrict: 'E', - replace: false, - scope: {}, - link(scope: ng.IScope, element: ng.IAugmentedJQuery) { - const props = { - canCreateCalendar: checkPermission('canCreateCalendar'), - canDeleteCalendar: checkPermission('canDeleteCalendar'), - }; - - ReactDOM.render( - - - , - element[0] - ); - }, - }; -}); diff --git a/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/index.ts b/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/index.ts index aa8b2ec2c29c970..dcf8ade3301b393 100644 --- a/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/index.ts +++ b/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/index.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -import './directive'; +export { CalendarsList } from './calendars_list'; diff --git a/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/table/__snapshots__/table.test.js.snap b/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/table/__snapshots__/table.test.js.snap index 1932ff3d83efa74..7958546f3a0cff3 100644 --- a/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/table/__snapshots__/table.test.js.snap +++ b/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/table/__snapshots__/table.test.js.snap @@ -70,7 +70,7 @@ exports[`CalendarsListTable renders the table with all calendars 1`] = ` "toolsRight": Array [ diff --git a/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/table/table.js b/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/table/table.js index 3a5c8eec31c0670..285f9423cd4c10b 100644 --- a/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/table/table.js +++ b/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/table/table.js @@ -15,8 +15,6 @@ import { EuiInMemoryTable, } from '@elastic/eui'; -import chrome from 'ui/chrome'; - import { FormattedMessage, injectI18n } from '@kbn/i18n/react'; @@ -55,7 +53,7 @@ export const CalendarsListTable = injectI18n(function CalendarsListTable({ truncateText: true, render: (id) => ( {id} @@ -98,7 +96,7 @@ export const CalendarsListTable = injectI18n(function CalendarsListTable({ size="s" data-test-subj="mlCalendarButtonCreate" key="new_calendar_button" - href={`${chrome.getBasePath()}/app/ml#/settings/calendars_list/new_calendar`} + href="#/settings/calendars_list/new_calendar" isDisabled={(canCreateCalendar === false || mlNodesAvailable === false)} > - -`; - -uiRoutes - .when('/settings/filter_lists/new_filter_list', { - template, - k7Breadcrumbs: getCreateFilterListBreadcrumbs, - resolve: { - CheckLicense: checkFullLicense, - privileges: checkGetJobsPrivilege, - mlNodeCount: getMlNodeCount, - }, - }) - .when('/settings/filter_lists/edit_filter_list/:filterId', { - template, - k7Breadcrumbs: getEditFilterListBreadcrumbs, - resolve: { - CheckLicense: checkFullLicense, - privileges: checkGetJobsPrivilege, - mlNodeCount: getMlNodeCount, - }, - }); - -module.directive('mlEditFilterList', function($route: any) { - return { - restrict: 'E', - replace: false, - scope: {}, - link(scope: ng.IScope, element: ng.IAugmentedJQuery) { - const props = { - filterId: $route.current.params.filterId, - canCreateFilter: checkPermission('canCreateFilter'), - canDeleteFilter: checkPermission('canDeleteFilter'), - }; - - ReactDOM.render( - - - , - element[0] - ); - }, - }; -}); diff --git a/x-pack/legacy/plugins/ml/public/application/settings/filter_lists/edit/edit_filter_list.d.ts b/x-pack/legacy/plugins/ml/public/application/settings/filter_lists/edit/edit_filter_list.d.ts index 71d82d7694cf051..56ef8745cb28bdb 100644 --- a/x-pack/legacy/plugins/ml/public/application/settings/filter_lists/edit/edit_filter_list.d.ts +++ b/x-pack/legacy/plugins/ml/public/application/settings/filter_lists/edit/edit_filter_list.d.ts @@ -7,7 +7,7 @@ import { FC } from 'react'; declare const EditFilterList: FC<{ - filterId: string; + filterId?: string; canCreateFilter: boolean; canDeleteFilter: boolean; }>; diff --git a/x-pack/legacy/plugins/ml/public/application/settings/filter_lists/edit/index.ts b/x-pack/legacy/plugins/ml/public/application/settings/filter_lists/edit/index.ts index aa8b2ec2c29c970..52b35f361777f41 100644 --- a/x-pack/legacy/plugins/ml/public/application/settings/filter_lists/edit/index.ts +++ b/x-pack/legacy/plugins/ml/public/application/settings/filter_lists/edit/index.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -import './directive'; +export { EditFilterList } from './edit_filter_list'; diff --git a/x-pack/legacy/plugins/ml/public/application/settings/filter_lists/index.ts b/x-pack/legacy/plugins/ml/public/application/settings/filter_lists/index.ts index 6a942d5c251df98..52dcda9b3f7c0f9 100644 --- a/x-pack/legacy/plugins/ml/public/application/settings/filter_lists/index.ts +++ b/x-pack/legacy/plugins/ml/public/application/settings/filter_lists/index.ts @@ -4,5 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -import './edit'; -import './list'; +export { EditFilterList } from './edit'; +export { FilterLists } from './list'; diff --git a/x-pack/legacy/plugins/ml/public/application/settings/filter_lists/list/directive.tsx b/x-pack/legacy/plugins/ml/public/application/settings/filter_lists/list/directive.tsx deleted file mode 100644 index 7b572344c603b50..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/settings/filter_lists/list/directive.tsx +++ /dev/null @@ -1,58 +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 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 { 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() { - return { - restrict: 'E', - replace: false, - scope: {}, - link(scope: ng.IScope, element: ng.IAugmentedJQuery) { - const props = { - canCreateFilter: checkPermission('canCreateFilter'), - canDeleteFilter: checkPermission('canDeleteFilter'), - }; - - ReactDOM.render( - - - , - element[0] - ); - }, - }; -}); diff --git a/x-pack/legacy/plugins/ml/public/application/settings/filter_lists/list/index.ts b/x-pack/legacy/plugins/ml/public/application/settings/filter_lists/list/index.ts index aa8b2ec2c29c970..2e5cc371e317d7f 100644 --- a/x-pack/legacy/plugins/ml/public/application/settings/filter_lists/list/index.ts +++ b/x-pack/legacy/plugins/ml/public/application/settings/filter_lists/list/index.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -import './directive'; +export { FilterLists } from './filter_lists'; diff --git a/x-pack/legacy/plugins/ml/public/application/settings/filter_lists/list/table.js b/x-pack/legacy/plugins/ml/public/application/settings/filter_lists/list/table.js index a5cc1ed761b5673..85bba8e4fe7443e 100644 --- a/x-pack/legacy/plugins/ml/public/application/settings/filter_lists/list/table.js +++ b/x-pack/legacy/plugins/ml/public/application/settings/filter_lists/list/table.js @@ -26,7 +26,6 @@ import { import { FormattedMessage, injectI18n } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -import chrome from 'ui/chrome'; import { DeleteFilterListModal } from '../components/delete_filter_list_modal'; @@ -68,7 +67,7 @@ function NewFilterButton({ canCreateFilter }) { return ( @@ -89,7 +88,7 @@ function getColumns() { defaultMessage: 'ID', }), render: (id) => ( - + {id} ), diff --git a/x-pack/legacy/plugins/ml/public/application/settings/index.ts b/x-pack/legacy/plugins/ml/public/application/settings/index.ts index d9fc996ae4a301e..db74dcb1a1846e8 100644 --- a/x-pack/legacy/plugins/ml/public/application/settings/index.ts +++ b/x-pack/legacy/plugins/ml/public/application/settings/index.ts @@ -4,6 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -import './settings_directive'; -import './calendars'; -import './filter_lists'; +export { Settings } from './settings'; diff --git a/x-pack/legacy/plugins/ml/public/application/settings/settings.tsx b/x-pack/legacy/plugins/ml/public/application/settings/settings.tsx index 3c1ae2973721a9a..225f39fc6f419a5 100644 --- a/x-pack/legacy/plugins/ml/public/application/settings/settings.tsx +++ b/x-pack/legacy/plugins/ml/public/application/settings/settings.tsx @@ -19,7 +19,6 @@ import { import { FormattedMessage } from '@kbn/i18n/react'; -import { useUiChromeContext } from '../contexts/ui/use_ui_chrome_context'; import { NavigationMenu } from '../components/navigation_menu'; interface Props { @@ -28,8 +27,6 @@ interface Props { } export const Settings: FC = ({ canGetFilters, canGetCalendars }) => { - const basePath = useUiChromeContext().getBasePath(); - return ( @@ -53,7 +50,7 @@ export const Settings: FC = ({ canGetFilters, canGetCalendars }) => { data-test-subj="ml_calendar_mng_button" size="l" color="primary" - href={`${basePath}/app/ml#/settings/calendars_list`} + href="#/settings/calendars_list" isDisabled={canGetCalendars === false} > = ({ canGetFilters, canGetCalendars }) => { data-test-subj="ml_filter_lists_button" size="l" color="primary" - href={`${basePath}/app/ml#/settings/filter_lists`} + href="#/settings/filter_lists" isDisabled={canGetFilters === false} > - -`; - -uiRoutes.when('/settings', { - template, - k7Breadcrumbs: getSettingsBreadcrumbs, - resolve: { - CheckLicense: checkFullLicense, - privileges: checkGetJobsPrivilege, - mlNodeCount: getMlNodeCount, - }, -}); - -import { Settings } from './settings'; - -module.directive('mlSettings', function() { - const canGetFilters = checkPermission('canGetFilters'); - const canGetCalendars = checkPermission('canGetCalendars'); - - return { - restrict: 'E', - replace: false, - scope: {}, - link(scope: ng.IScope, element: ng.IAugmentedJQuery) { - timefilter.disableTimeRangeSelector(); - timefilter.disableAutoRefreshSelector(); - - ReactDOM.render( - - - , - element[0] - ); - }, - }; -}); diff --git a/x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/breadcrumbs.js b/x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/breadcrumbs.js deleted file mode 100644 index 2aa4c845b125d7b..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/breadcrumbs.js +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - - -import { ML_BREADCRUMB, ANOMALY_DETECTION_BREADCRUMB } from '../../breadcrumbs'; -import { i18n } from '@kbn/i18n'; - - -export function getSingleMetricViewerBreadcrumbs() { - // Whilst top level nav menu with tabs remains, - // use root ML breadcrumb. - return [ - ML_BREADCRUMB, - ANOMALY_DETECTION_BREADCRUMB, - { - text: i18n.translate('xpack.ml.anomalyDetection.singleMetricViewerLabel', { - defaultMessage: 'Single Metric Viewer' - }), - href: '' - } - - ]; -} - diff --git a/x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/index.js b/x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/index.js deleted file mode 100644 index 5aa6cfe8835ad56..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/index.js +++ /dev/null @@ -1,11 +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 './timeseriesexplorer_directive'; -import './timeseriesexplorer_route'; -import './timeseries_search_service'; -import '../components/job_selector'; -import '../components/chart_tooltip'; diff --git a/x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/index.ts b/x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/index.ts new file mode 100644 index 000000000000000..6877e8ef754fdbe --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { TimeSeriesExplorer } from './timeseriesexplorer'; diff --git a/x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.d.ts b/x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.d.ts new file mode 100644 index 000000000000000..ac4bc6186e5b47e --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.d.ts @@ -0,0 +1,15 @@ +/* + * 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 { Timefilter } from 'ui/timefilter'; +import { FC } from 'react'; + +declare const TimeSeriesExplorer: FC<{ + appStateHandler: (action: string, payload: any) => void; + dateFormatTz: string; + globalState: any; + timefilter: Timefilter; +}>; diff --git a/x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js b/x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js index a70e1d38784e98c..99eb4beb977da1e 100644 --- a/x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js +++ b/x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js @@ -142,7 +142,7 @@ const TimeSeriesExplorerPage = ({ children, jobSelectorProps, loading, resizeRef If we'd just show no progress bar when not loading it would result in a flickering height effect. */} {!loading && ()} -
+
{children}
diff --git a/x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_directive.js b/x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_directive.js deleted file mode 100644 index 048a8dbc4a6db82..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_directive.js +++ /dev/null @@ -1,111 +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 { get } from 'lodash'; -import moment from 'moment-timezone'; -import { Subscription } from 'rxjs'; - -import React from 'react'; -import ReactDOM from 'react-dom'; - -import { uiModules } from 'ui/modules'; -const module = uiModules.get('apps/ml'); - -import { timefilter } from 'ui/timefilter'; -import { I18nContext } from 'ui/i18n'; - -import '../components/controls'; - -import { severity$ } from '../components/controls/select_severity/select_severity'; -import { interval$ } from '../components/controls/select_interval/select_interval'; -import { subscribeAppStateToObservable } from '../util/app_state_utils'; - -import { TimeSeriesExplorer } from './timeseriesexplorer'; -import { APP_STATE_ACTION } from './timeseriesexplorer_constants'; - -module.directive('mlTimeSeriesExplorer', function ($injector) { - function link($scope, $element) { - const globalState = $injector.get('globalState'); - const AppState = $injector.get('AppState'); - const config = $injector.get('config'); - - const subscriptions = new Subscription(); - subscriptions.add(subscribeAppStateToObservable(AppState, 'mlSelectInterval', interval$)); - subscriptions.add(subscribeAppStateToObservable(AppState, 'mlSelectSeverity', severity$)); - - $scope.appState = new AppState({ mlTimeSeriesExplorer: {} }); - - const appStateHandler = (action, payload) => { - $scope.appState.fetch(); - switch (action) { - case APP_STATE_ACTION.CLEAR: - delete $scope.appState.mlTimeSeriesExplorer.detectorIndex; - delete $scope.appState.mlTimeSeriesExplorer.entities; - delete $scope.appState.mlTimeSeriesExplorer.forecastId; - break; - - case APP_STATE_ACTION.GET_DETECTOR_INDEX: - return get($scope, 'appState.mlTimeSeriesExplorer.detectorIndex'); - case APP_STATE_ACTION.SET_DETECTOR_INDEX: - $scope.appState.mlTimeSeriesExplorer.detectorIndex = payload; - break; - - case APP_STATE_ACTION.GET_ENTITIES: - return get($scope, 'appState.mlTimeSeriesExplorer.entities', {}); - case APP_STATE_ACTION.SET_ENTITIES: - $scope.appState.mlTimeSeriesExplorer.entities = payload; - break; - - case APP_STATE_ACTION.GET_FORECAST_ID: - return get($scope, 'appState.mlTimeSeriesExplorer.forecastId'); - case APP_STATE_ACTION.SET_FORECAST_ID: - $scope.appState.mlTimeSeriesExplorer.forecastId = payload; - break; - - case APP_STATE_ACTION.GET_ZOOM: - return get($scope, 'appState.mlTimeSeriesExplorer.zoom'); - case APP_STATE_ACTION.SET_ZOOM: - $scope.appState.mlTimeSeriesExplorer.zoom = payload; - break; - case APP_STATE_ACTION.UNSET_ZOOM: - delete $scope.appState.mlTimeSeriesExplorer.zoom; - break; - } - $scope.appState.save(); - $scope.$applyAsync(); - }; - - function updateComponent() { - // Pass the timezone to the server for use when aggregating anomalies (by day / hour) for the table. - const tzConfig = config.get('dateFormat:tz'); - const dateFormatTz = (tzConfig !== 'Browser') ? tzConfig : moment.tz.guess(); - - ReactDOM.render( - - - , - $element[0] - ); - } - - $element.on('$destroy', () => { - ReactDOM.unmountComponentAtNode($element[0]); - subscriptions.unsubscribe(); - }); - - updateComponent(); - } - - return { - link, - }; -}); diff --git a/x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_route.js b/x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_route.js deleted file mode 100644 index 63b9b819be315a0..000000000000000 --- a/x-pack/legacy/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_route.js +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import uiRoutes from 'ui/routes'; - -import '../components/controls'; - -import { checkFullLicense } from '../license/check_license'; -import { getMlNodeCount } from '../ml_nodes_check/check_ml_nodes'; -import { checkGetJobsPrivilege } from '../privilege/check_privilege'; -import { mlJobService } from '../services/job_service'; -import { loadIndexPatterns } from '../util/index_utils'; - -import { getSingleMetricViewerBreadcrumbs } from './breadcrumbs'; - -uiRoutes - .when('/timeseriesexplorer/?', { - template: '', - k7Breadcrumbs: getSingleMetricViewerBreadcrumbs, - resolve: { - CheckLicense: checkFullLicense, - privileges: checkGetJobsPrivilege, - indexPatterns: loadIndexPatterns, - mlNodeCount: getMlNodeCount, - jobs: mlJobService.loadJobsWrapper - } - }); diff --git a/x-pack/legacy/plugins/ml/public/application/util/chart_utils.js b/x-pack/legacy/plugins/ml/public/application/util/chart_utils.js index 8aa933eb5e53fec..110795c2d0290cd 100644 --- a/x-pack/legacy/plugins/ml/public/application/util/chart_utils.js +++ b/x-pack/legacy/plugins/ml/public/application/util/chart_utils.js @@ -12,7 +12,6 @@ import { MULTI_BUCKET_IMPACT } from '../../../common/constants/multi_bucket_impa import moment from 'moment'; import rison from 'rison-node'; -import chrome from 'ui/chrome'; import { timefilter } from 'ui/timefilter'; import { CHART_TYPE } from '../explorer/explorer_constants'; @@ -229,7 +228,7 @@ export function getExploreSeriesLink(series) { } }); - return `${chrome.getBasePath()}/app/ml#/timeseriesexplorer?_g=${_g}&_a=${encodeURIComponent(_a)}`; + return `#/timeseriesexplorer?_g=${_g}&_a=${encodeURIComponent(_a)}`; } export function showMultiBucketAnomalyMarker(point) { diff --git a/x-pack/legacy/plugins/ml/public/application/util/chart_utils.test.js b/x-pack/legacy/plugins/ml/public/application/util/chart_utils.test.js index a229113826a2e94..5ef6b592ae27158 100644 --- a/x-pack/legacy/plugins/ml/public/application/util/chart_utils.test.js +++ b/x-pack/legacy/plugins/ml/public/application/util/chart_utils.test.js @@ -58,7 +58,7 @@ timefilter.setTime({ describe('getExploreSeriesLink', () => { test('get timeseriesexplorer link', () => { const link = getExploreSeriesLink(seriesConfig); - const expectedLink = `/app/ml#/timeseriesexplorer?_g=(ml:(jobIds:!(population-03)),` + + const expectedLink = `#/timeseriesexplorer?_g=(ml:(jobIds:!(population-03)),` + `refreshInterval:(display:Off,pause:!f,value:0),time:(from:'2017-02-23T00:00:00.000Z',mode:absolute,` + `to:'2017-02-23T23:59:59.999Z'))&_a=(mlTimeSeriesExplorer%3A(detectorIndex%3A0%2Centities%3A` + `(nginx.access.remote_ip%3A'72.57.0.53')%2Czoom%3A(from%3A'2017-02-19T20%3A00%3A00.000Z'%2Cto%3A'2017-02-27T04%3A00%3A00.000Z'))` + diff --git a/x-pack/legacy/plugins/ml/public/application/util/index_utils.ts b/x-pack/legacy/plugins/ml/public/application/util/index_utils.ts index 99882b0243be8fd..2b8838c04cf696f 100644 --- a/x-pack/legacy/plugins/ml/public/application/util/index_utils.ts +++ b/x-pack/legacy/plugins/ml/public/application/util/index_utils.ts @@ -6,19 +6,17 @@ import { toastNotifications } from 'ui/notify'; import { i18n } from '@kbn/i18n'; -import { SavedObjectAttributes, SimpleSavedObject } from 'kibana/public'; import chrome from 'ui/chrome'; -import { npStart } from 'ui/new_platform'; -import { SavedSearchLoader } from '../../../../../../../src/legacy/core_plugins/kibana/public/discover/types'; +import { Query } from 'src/plugins/data/public'; import { IndexPattern, IndexPatternsContract } from '../../../../../../../src/plugins/data/public'; - -type IndexPatternSavedObject = SimpleSavedObject; +import { IndexPatternSavedObject, SavedSearchSavedObject } from '../../../common/types/kibana'; let indexPatternCache: IndexPatternSavedObject[] = []; -let fullIndexPatterns: IndexPatternsContract | null = null; +let savedSearchesCache: SavedSearchSavedObject[] = []; +let indexPatternsContract: IndexPatternsContract | null = null; -export function loadIndexPatterns() { - fullIndexPatterns = npStart.plugins.data.indexPatterns; +export function loadIndexPatterns(indexPatterns: IndexPatternsContract) { + indexPatternsContract = indexPatterns; const savedObjectsClient = chrome.getSavedObjectsClient(); return savedObjectsClient .find({ @@ -32,10 +30,33 @@ export function loadIndexPatterns() { }); } +export function loadSavedSearches() { + const savedObjectsClient = chrome.getSavedObjectsClient(); + return savedObjectsClient + .find({ + type: 'search', + perPage: 10000, + }) + .then(response => { + savedSearchesCache = response.savedObjects; + return savedSearchesCache; + }); +} + +export async function loadSavedSearchById(id: string) { + const savedObjectsClient = chrome.getSavedObjectsClient(); + const ss = await savedObjectsClient.get('search', id); + return ss.error === undefined ? ss : null; +} + export function getIndexPatterns() { return indexPatternCache; } +export function getIndexPatternsContract() { + return indexPatternsContract; +} + export function getIndexPatternNames() { return indexPatternCache.map(i => i.attributes && i.attributes.title); } @@ -49,27 +70,44 @@ export function getIndexPatternIdFromName(name: string) { return null; } -export function loadCurrentIndexPattern( - indexPatterns: IndexPatternsContract, - $route: Record -) { - fullIndexPatterns = indexPatterns; - return fullIndexPatterns.get($route.current.params.index); +export async function getIndexPatternAndSavedSearch(savedSearchId: string) { + const resp: { savedSearch: SavedSearchSavedObject | null; indexPattern: IndexPattern | null } = { + savedSearch: null, + indexPattern: null, + }; + + if (savedSearchId === undefined) { + return resp; + } + + const ss = await loadSavedSearchById(savedSearchId); + if (ss === null) { + return resp; + } + const indexPatternId = ss.references.find(r => r.type === 'index-pattern')?.id; + resp.indexPattern = await getIndexPatternById(indexPatternId!); + resp.savedSearch = ss; + return resp; +} + +export function getQueryFromSavedSearch(savedSearch: SavedSearchSavedObject) { + const search = savedSearch.attributes.kibanaSavedObjectMeta as { searchSourceJSON: string }; + return JSON.parse(search.searchSourceJSON) as { + query: Query; + filter: any[]; + }; } export function getIndexPatternById(id: string): Promise { - if (fullIndexPatterns !== null) { - return fullIndexPatterns.get(id); + if (indexPatternsContract !== null) { + return indexPatternsContract.get(id); } else { throw new Error('Index patterns are not initialized!'); } } -export function loadCurrentSavedSearch( - savedSearches: SavedSearchLoader, - $route: Record -) { - return savedSearches.get($route.current.params.savedSearchId); +export function getSavedSearchById(id: string): SavedSearchSavedObject | undefined { + return savedSearchesCache.find(s => s.id === id); } /** diff --git a/x-pack/legacy/plugins/ml/public/index.scss b/x-pack/legacy/plugins/ml/public/index.scss deleted file mode 100644 index ac3f3fef97c702e..000000000000000 --- a/x-pack/legacy/plugins/ml/public/index.scss +++ /dev/null @@ -1,45 +0,0 @@ -// Should import both the EUI constants and any Kibana ones that are considered global -@import 'src/legacy/ui/public/styles/styling_constants'; - -// ML has it's own variables for coloring -@import 'application/variables'; - -// Kibana management page ML section -#kibanaManagementMLSection { - @import 'application/management/index'; -} - -// Protect the rest of Kibana from ML generic namespacing -// SASSTODO: Prefix ml selectors instead -#ml-app { - // App level - @import 'application/app'; - - // Sub applications - @import 'application/data_frame_analytics/index'; - @import 'application/datavisualizer/index'; - @import 'application/explorer/index'; // SASSTODO: This file needs to be rewritten - @import 'application/jobs/index'; // SASSTODO: This collection of sass files has multiple problems - @import 'application/overview/index'; - @import 'application/settings/index'; - @import 'application/timeseriesexplorer/index'; - - // Components - @import 'application/components/annotations/annotation_description_list/index'; // SASSTODO: This file overwrites EUI directly - @import 'application/components/anomalies_table/index'; // SASSTODO: This file overwrites EUI directly - @import 'application/components/chart_tooltip/index'; - @import 'application/components/controls/index'; - @import 'application/components/entity_cell/index'; - @import 'application/components/field_title_bar/index'; - @import 'application/components/field_type_icon/index'; - @import 'application/components/influencers_list/index'; - @import 'application/components/items_grid/index'; - @import 'application/components/job_selector/index'; - @import 'application/components/loading_indicator/index'; // SASSTODO: This component should be replaced with EuiLoadingSpinner - @import 'application/components/navigation_menu/index'; - @import 'application/components/rule_editor/index'; // SASSTODO: This file overwrites EUI directly - @import 'application/components/stats_bar/index'; - - // Hacks are last so they can overwrite anything above if needed - @import 'application/hacks'; -} diff --git a/x-pack/legacy/plugins/ml/public/index.ts b/x-pack/legacy/plugins/ml/public/index.ts new file mode 100755 index 000000000000000..0057983104cc099 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/index.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 { PluginInitializer } from '../../../../../src/core/public'; +import { MlPlugin, MlPluginSetup, MlPluginStart } from './plugin'; + +export const plugin: PluginInitializer = () => new MlPlugin(); + +export { MlPluginSetup, MlPluginStart }; diff --git a/x-pack/legacy/plugins/ml/public/legacy.ts b/x-pack/legacy/plugins/ml/public/legacy.ts new file mode 100644 index 000000000000000..3e007a18f4c5acc --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/legacy.ts @@ -0,0 +1,17 @@ +/* + * 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 { npSetup, npStart } from 'ui/new_platform'; + +import { PluginInitializerContext } from '../../../../../src/core/public'; +import { plugin } from '.'; + +const pluginInstance = plugin({} as PluginInitializerContext); + +export const setup = pluginInstance.setup(npSetup.core, { + npData: npStart.plugins.data, +}); +export const start = pluginInstance.start(npStart.core, npStart.plugins); diff --git a/x-pack/legacy/plugins/ml/public/plugin.ts b/x-pack/legacy/plugins/ml/public/plugin.ts new file mode 100644 index 000000000000000..2a80b1844604684 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/plugin.ts @@ -0,0 +1,46 @@ +/* + * 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 { Plugin as DataPlugin } from 'src/plugins/data/public'; +import { Plugin, CoreStart, CoreSetup } from '../../../../../src/core/public'; + +export interface MlSetupDependencies { + npData: ReturnType; +} + +export interface MlStartDependencies { + __LEGACY: { + Storage: any; + xpackInfo: any; + }; +} + +export class MlPlugin implements Plugin { + setup(core: CoreSetup, { npData }: MlSetupDependencies) { + core.application.register({ + id: 'ml', + title: 'Machine learning', + async mount(context, params) { + const { renderApp } = await import('./application/app'); + return renderApp(context, { + ...params, + indexPatterns: npData.indexPatterns, + npData, + }); + }, + }); + + return {}; + } + + start(core: CoreStart, deps: {}) { + return {}; + } + public stop() {} +} + +export type MlPluginSetup = ReturnType; +export type MlPluginStart = ReturnType; diff --git a/x-pack/legacy/plugins/ml/server/models/job_service/new_job/line_chart.ts b/x-pack/legacy/plugins/ml/server/models/job_service/new_job/line_chart.ts index eb2f50b8e92509e..5bb0f3998214669 100644 --- a/x-pack/legacy/plugins/ml/server/models/job_service/new_job/line_chart.ts +++ b/x-pack/legacy/plugins/ml/server/models/job_service/new_job/line_chart.ts @@ -128,6 +128,14 @@ function getSearchJsonFromConfig( }, }; + if (query.bool === undefined) { + query.bool = { + must: [], + }; + } else if (query.bool.must === undefined) { + query.bool.must = []; + } + query.bool.must.push({ range: { [timeField]: { diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 054382ed0fa8135..2e7d4233dd7ff7d 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -7118,7 +7118,6 @@ "xpack.ml.itemsGrid.noItemsAddedTitle": "項目が追加されていません", "xpack.ml.itemsGrid.noMatchingItemsTitle": "一致する項目が見つかりません。", "xpack.ml.jobsBreadcrumbs.advancedConfigurationLabel": "高度な構成", - "xpack.ml.jobsBreadcrumbs.createJobLabel": "ジョブを作成", "xpack.ml.jobsBreadcrumbs.multiMetricLabel": "マルチメトリック", "xpack.ml.jobsBreadcrumbs.populationLabel": "集団", "xpack.ml.jobsBreadcrumbs.selectIndexOrSearchLabel": "インデックスまたは検索を選択", @@ -7693,7 +7692,6 @@ "xpack.ml.validateJob.modal.linkToJobTipsText.mlJobTipsLinkText": "機械学習ジョブのヒント", "xpack.ml.validateJob.modal.validateJobTitle": "ジョブ {title} の検証", "xpack.ml.validateJob.validateJobButtonLabel": "ジョブを検証", - "xpack.ml.dataFrameAnalyticsBreadcrumbs.dataFrameLabel": "分析", "xpack.ml.datavisualizer.actionsPanel.advancedDescription": "より高度なユースケースでは、ジョブの作成にすべてのオプションを使用します", "xpack.ml.datavisualizer.actionsPanel.advancedTitle": "高度な設定", "xpack.ml.datavisualizer.actionsPanel.createJobDescription": "高度なジョブウィザードでジョブを作成し、このデータの異常を検出します:", @@ -8045,7 +8043,6 @@ "xpack.ml.overview.statsBar.runningAnalyticsLabel": "実行中", "xpack.ml.overview.statsBar.stoppedAnalyticsLabel": "停止中", "xpack.ml.overview.statsBar.totalAnalyticsLabel": "分析ジョブ合計", - "xpack.ml.overviewBreadcrumbs.overviewLabel": "概要", "xpack.ml.overviewJobsList.statsBar.activeMLNodesLabel": "アクティブな ML ノード", "xpack.ml.overviewJobsList.statsBar.closedJobsLabel": "ジョブを作成", "xpack.ml.overviewJobsList.statsBar.failedJobsLabel": "失敗したジョブ", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 1977da8ac9100e9..fd5573901fb00b2 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -7120,7 +7120,6 @@ "xpack.ml.itemsGrid.noItemsAddedTitle": "没有添加任何项", "xpack.ml.itemsGrid.noMatchingItemsTitle": "没有匹配的项", "xpack.ml.jobsBreadcrumbs.advancedConfigurationLabel": "高级配置", - "xpack.ml.jobsBreadcrumbs.createJobLabel": "创建作业", "xpack.ml.jobsBreadcrumbs.multiMetricLabel": "多指标", "xpack.ml.jobsBreadcrumbs.populationLabel": "填充", "xpack.ml.jobsBreadcrumbs.selectIndexOrSearchLabel": "选择索引或搜索", @@ -7786,7 +7785,6 @@ "xpack.ml.dataframe.analyticsList.type": "类型", "xpack.ml.dataframe.analyticsList.viewActionName": "查看", "xpack.ml.dataframe.analyticsList.viewAriaLabel": "查看", - "xpack.ml.dataFrameAnalyticsBreadcrumbs.dataFrameLabel": "分析", "xpack.ml.datavisualizer.actionsPanel.advancedDescription": "使用全部选项为更高级的用例创建作业", "xpack.ml.datavisualizer.actionsPanel.advancedTitle": "高级", "xpack.ml.datavisualizer.actionsPanel.createJobDescription": "使用“高级作业”向导创建作业,以查找此数据中的异常:", @@ -8138,7 +8136,6 @@ "xpack.ml.overview.statsBar.runningAnalyticsLabel": "正在运行", "xpack.ml.overview.statsBar.stoppedAnalyticsLabel": "已停止", "xpack.ml.overview.statsBar.totalAnalyticsLabel": "分析作业总数", - "xpack.ml.overviewBreadcrumbs.overviewLabel": "概览", "xpack.ml.overviewJobsList.statsBar.activeMLNodesLabel": "活动 ML 节点", "xpack.ml.overviewJobsList.statsBar.closedJobsLabel": "已关闭的作业", "xpack.ml.overviewJobsList.statsBar.failedJobsLabel": "失败的作业",