From 3130759c47ca108a2e86c61007dcd2554cbc66c2 Mon Sep 17 00:00:00 2001 From: Robert Oskamp Date: Wed, 11 Dec 2019 16:25:48 +0100 Subject: [PATCH 01/79] [ML] Functional tests - export service types (#52612) With this PR the types of the ML services that are used in other services are exported from the service file to allow a cleaner re-use. --- x-pack/test/functional/services/machine_learning/api.ts | 3 +++ .../test/functional/services/machine_learning/common.ts | 3 +++ .../functional/services/machine_learning/custom_urls.ts | 3 +++ .../services/machine_learning/data_frame_analytics.ts | 5 ++--- .../services/machine_learning/job_management.ts | 5 ++--- .../services/machine_learning/job_wizard_advanced.ts | 5 ++--- .../services/machine_learning/job_wizard_common.ts | 9 ++++----- 7 files changed, 19 insertions(+), 14 deletions(-) diff --git a/x-pack/test/functional/services/machine_learning/api.ts b/x-pack/test/functional/services/machine_learning/api.ts index 1995f37782948..1f3711ff5e506 100644 --- a/x-pack/test/functional/services/machine_learning/api.ts +++ b/x-pack/test/functional/services/machine_learning/api.ts @@ -4,12 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ import expect from '@kbn/expect'; +import { ProvidedType } from '@kbn/test/types/ftr'; import { FtrProviderContext } from '../../ftr_provider_context'; import { JOB_STATE, DATAFEED_STATE } from '../../../../legacy/plugins/ml/common/constants/states'; import { DATA_FRAME_TASK_STATE } from '../../../../legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/common'; +export type MlApi = ProvidedType; + export function MachineLearningAPIProvider({ getService }: FtrProviderContext) { const es = getService('legacyEs'); const log = getService('log'); diff --git a/x-pack/test/functional/services/machine_learning/common.ts b/x-pack/test/functional/services/machine_learning/common.ts index 12b9e8a1cfb29..35ee32fa5d94e 100644 --- a/x-pack/test/functional/services/machine_learning/common.ts +++ b/x-pack/test/functional/services/machine_learning/common.ts @@ -3,6 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import { ProvidedType } from '@kbn/test/types/ftr'; import { FtrProviderContext } from '../../ftr_provider_context'; @@ -11,6 +12,8 @@ interface SetValueOptions { typeCharByChar?: boolean; } +export type MlCommon = ProvidedType; + export function MachineLearningCommonProvider({ getService }: FtrProviderContext) { const log = getService('log'); const retry = getService('retry'); diff --git a/x-pack/test/functional/services/machine_learning/custom_urls.ts b/x-pack/test/functional/services/machine_learning/custom_urls.ts index dc6e4a2fccb10..6842908462018 100644 --- a/x-pack/test/functional/services/machine_learning/custom_urls.ts +++ b/x-pack/test/functional/services/machine_learning/custom_urls.ts @@ -4,9 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ import expect from '@kbn/expect'; +import { ProvidedType } from '@kbn/test/types/ftr'; import { FtrProviderContext } from '../../ftr_provider_context'; +export type MlCustomUrls = ProvidedType; + export function MachineLearningCustomUrlsProvider({ getService }: FtrProviderContext) { const testSubjects = getService('testSubjects'); diff --git a/x-pack/test/functional/services/machine_learning/data_frame_analytics.ts b/x-pack/test/functional/services/machine_learning/data_frame_analytics.ts index 163c3c60ffdab..8c8b5db1d2c52 100644 --- a/x-pack/test/functional/services/machine_learning/data_frame_analytics.ts +++ b/x-pack/test/functional/services/machine_learning/data_frame_analytics.ts @@ -3,16 +3,15 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { ProvidedType } from '@kbn/test/types/ftr'; import { FtrProviderContext } from '../../ftr_provider_context'; -import { MachineLearningAPIProvider } from './api'; +import { MlApi } from './api'; import { DATA_FRAME_TASK_STATE } from '../../../../legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/common'; export function MachineLearningDataFrameAnalyticsProvider( { getService }: FtrProviderContext, - mlApi: ProvidedType + mlApi: MlApi ) { const testSubjects = getService('testSubjects'); diff --git a/x-pack/test/functional/services/machine_learning/job_management.ts b/x-pack/test/functional/services/machine_learning/job_management.ts index 5ffb235a828d6..1fa1f62a9ae11 100644 --- a/x-pack/test/functional/services/machine_learning/job_management.ts +++ b/x-pack/test/functional/services/machine_learning/job_management.ts @@ -3,16 +3,15 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { ProvidedType } from '@kbn/test/types/ftr'; import { FtrProviderContext } from '../../ftr_provider_context'; -import { MachineLearningAPIProvider } from './api'; +import { MlApi } from './api'; import { JOB_STATE, DATAFEED_STATE } from '../../../../legacy/plugins/ml/common/constants/states'; export function MachineLearningJobManagementProvider( { getService }: FtrProviderContext, - mlApi: ProvidedType + mlApi: MlApi ) { const testSubjects = getService('testSubjects'); diff --git a/x-pack/test/functional/services/machine_learning/job_wizard_advanced.ts b/x-pack/test/functional/services/machine_learning/job_wizard_advanced.ts index ab53b0412ca35..755091ca10f3b 100644 --- a/x-pack/test/functional/services/machine_learning/job_wizard_advanced.ts +++ b/x-pack/test/functional/services/machine_learning/job_wizard_advanced.ts @@ -4,14 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ import expect from '@kbn/expect'; -import { ProvidedType } from '@kbn/test/types/ftr'; import { FtrProviderContext } from '../../ftr_provider_context'; -import { MachineLearningCommonProvider } from './common'; +import { MlCommon } from './common'; export function MachineLearningJobWizardAdvancedProvider( { getService }: FtrProviderContext, - mlCommon: ProvidedType + mlCommon: MlCommon ) { const comboBox = getService('comboBox'); const testSubjects = getService('testSubjects'); diff --git a/x-pack/test/functional/services/machine_learning/job_wizard_common.ts b/x-pack/test/functional/services/machine_learning/job_wizard_common.ts index b9e6822c8f41a..c2f408276d9e4 100644 --- a/x-pack/test/functional/services/machine_learning/job_wizard_common.ts +++ b/x-pack/test/functional/services/machine_learning/job_wizard_common.ts @@ -4,16 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ import expect from '@kbn/expect'; -import { ProvidedType } from '@kbn/test/types/ftr'; import { FtrProviderContext } from '../../ftr_provider_context'; -import { MachineLearningCommonProvider } from './common'; -import { MachineLearningCustomUrlsProvider } from './custom_urls'; +import { MlCommon } from './common'; +import { MlCustomUrls } from './custom_urls'; export function MachineLearningJobWizardCommonProvider( { getService }: FtrProviderContext, - mlCommon: ProvidedType, - customUrls: ProvidedType + mlCommon: MlCommon, + customUrls: MlCustomUrls ) { const comboBox = getService('comboBox'); const retry = getService('retry'); From 8c19b5e017dd1d2d3adaca641937e361a16c9294 Mon Sep 17 00:00:00 2001 From: Chris Roberson Date: Wed, 11 Dec 2019 10:35:34 -0500 Subject: [PATCH 02/79] Skip all logstash pipeline tests (#52743) --- .../apis/monitoring/logstash/multicluster_pipelines.js | 2 +- .../test/api_integration/apis/monitoring/logstash/pipelines.js | 2 +- x-pack/test/functional/apps/monitoring/logstash/pipelines.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/test/api_integration/apis/monitoring/logstash/multicluster_pipelines.js b/x-pack/test/api_integration/apis/monitoring/logstash/multicluster_pipelines.js index bea09562bdb11..fa26a0dcac794 100644 --- a/x-pack/test/api_integration/apis/monitoring/logstash/multicluster_pipelines.js +++ b/x-pack/test/api_integration/apis/monitoring/logstash/multicluster_pipelines.js @@ -11,7 +11,7 @@ export default function ({ getService }) { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); - describe('pipelines listing multicluster', () => { + describe.skip('pipelines listing multicluster', () => { const archive = 'monitoring/logstash_pipelines_multicluster'; const timeRange = { min: '2019-11-11T15:13:45.266Z', diff --git a/x-pack/test/api_integration/apis/monitoring/logstash/pipelines.js b/x-pack/test/api_integration/apis/monitoring/logstash/pipelines.js index 0852b8293886e..9e2160a69c726 100644 --- a/x-pack/test/api_integration/apis/monitoring/logstash/pipelines.js +++ b/x-pack/test/api_integration/apis/monitoring/logstash/pipelines.js @@ -11,7 +11,7 @@ export default function ({ getService }) { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); - describe('pipelines', () => { + describe.skip('pipelines', () => { const archive = 'monitoring/logstash/changing_pipelines'; const timeRange = { min: '2019-11-04T15:40:44.855Z', diff --git a/x-pack/test/functional/apps/monitoring/logstash/pipelines.js b/x-pack/test/functional/apps/monitoring/logstash/pipelines.js index f4d2a5a4a20a5..3aacd9e66dd4a 100644 --- a/x-pack/test/functional/apps/monitoring/logstash/pipelines.js +++ b/x-pack/test/functional/apps/monitoring/logstash/pipelines.js @@ -14,7 +14,7 @@ export default function ({ getService, getPageObjects }) { const pipelinesList = getService('monitoringLogstashPipelines'); const lsClusterSummaryStatus = getService('monitoringLogstashSummaryStatus'); - describe('Logstash pipelines', () => { + describe.skip('Logstash pipelines', () => { const { setup, tearDown } = getLifecycleMethods(getService, getPageObjects); before(async () => { From 6f79046ff2ef21978277d4775eda296c8adb549b Mon Sep 17 00:00:00 2001 From: Ben Skelker <54019610+benskelker@users.noreply.github.com> Date: Wed, 11 Dec 2019 17:41:24 +0200 Subject: [PATCH 03/79] [SIEM] Improves map configuration text on Network page (#52469) * updates SIEM network page maps conf message * corrects link atts * updated message * updated message again * finally * updates after feedback --- .../index_patterns_missing_prompt.test.tsx.snap | 11 +++++++++-- .../embeddables/index_patterns_missing_prompt.tsx | 13 +++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/x-pack/legacy/plugins/siem/public/components/embeddables/__snapshots__/index_patterns_missing_prompt.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/embeddables/__snapshots__/index_patterns_missing_prompt.test.tsx.snap index fb896059460b9..6794aab205703 100644 --- a/x-pack/legacy/plugins/siem/public/components/embeddables/__snapshots__/index_patterns_missing_prompt.test.tsx.snap +++ b/x-pack/legacy/plugins/siem/public/components/embeddables/__snapshots__/index_patterns_missing_prompt.test.tsx.snap @@ -16,7 +16,7 @@ exports[`IndexPatternsMissingPrompt renders correctly against snapshot 1`] = `

beats , + "defaultIndex": + siem:defaultIndex + , "example": ./packetbeat setup , @@ -39,7 +46,7 @@ exports[`IndexPatternsMissingPrompt renders correctly against snapshot 1`] = `

diff --git a/x-pack/legacy/plugins/siem/public/components/embeddables/index_patterns_missing_prompt.tsx b/x-pack/legacy/plugins/siem/public/components/embeddables/index_patterns_missing_prompt.tsx index 1e29676415d79..6533be49c3430 100644 --- a/x-pack/legacy/plugins/siem/public/components/embeddables/index_patterns_missing_prompt.tsx +++ b/x-pack/legacy/plugins/siem/public/components/embeddables/index_patterns_missing_prompt.tsx @@ -21,9 +21,18 @@ export const IndexPatternsMissingPromptComponent = () => ( <>

+ {'siem:defaultIndex'} + + ), beats: ( (

From c962009df6c73e9335cfcb7889729a989638b6c0 Mon Sep 17 00:00:00 2001 From: Pete Harverson Date: Wed, 11 Dec 2019 15:54:05 +0000 Subject: [PATCH 04/79] [ML] Adds Enterprise license to Start trial text on data viz page (#52749) --- .../datavisualizer/datavisualizer_selector.tsx | 8 ++++---- x-pack/plugins/translations/translations/ja-JP.json | 8 +++----- x-pack/plugins/translations/translations/zh-CN.json | 10 ++++------ 3 files changed, 11 insertions(+), 15 deletions(-) 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 e6f6d4581c706..c24061cb052b8 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 @@ -32,13 +32,13 @@ function startTrialDescription() { ), diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 55147c7863d1f..054382ed0fa81 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -463,9 +463,6 @@ "common.ui.management.breadcrumb": "管理", "common.ui.management.connectDataDisplayName": "データに接続", "common.ui.management.displayName": "管理", - "management.editIndexPattern.createIndex.defaultButtonDescription": "すべてのデータに完全集約を実行", - "management.editIndexPattern.createIndex.defaultButtonText": "標準インデックスパターン", - "management.editIndexPattern.createIndex.defaultTypeName": "インデックスパターン", "common.ui.management.nav.menu": "管理メニュー", "common.ui.modals.cancelButtonLabel": "キャンセル", "common.ui.notify.fatalError.errorStatusMessage": "エラー {errStatus} {errStatusText}: {errMessage}", @@ -566,6 +563,9 @@ "common.ui.aggTypes.scaleMetricsLabel": "メトリック値のスケーリング (廃止)", "common.ui.aggTypes.scaleMetricsTooltip": "これを有効にすると、手動最低間隔を選択し、広い間隔が使用された場合、カウントと合計メトリックが手動で選択された間隔にスケーリングされます。", "common.ui.aggTypes.buckets.ranges.rangesFormatMessage": "{gte} {from} と {lt} {to}", + "management.editIndexPattern.createIndex.defaultButtonDescription": "すべてのデータに完全集約を実行", + "management.editIndexPattern.createIndex.defaultButtonText": "標準インデックスパターン", + "management.editIndexPattern.createIndex.defaultTypeName": "インデックスパターン", "core.ui.overlays.banner.attentionTitle": "注意", "core.ui.overlays.banner.closeButtonLabel": "閉じる", "core.ui.chrome.headerGlobalNav.goHomePageIconAriaLabel": "ホームページに移動", @@ -6900,8 +6900,6 @@ "xpack.ml.datavisualizer.selector.startTrialButtonLabel": "トライアルを開始", "xpack.ml.datavisualizer.selector.startTrialTitle": "トライアルを開始", "xpack.ml.datavisualizer.selector.uploadFileButtonLabel": "ファイルをアップロード", - "xpack.ml.datavisualizer.startTrial.fullMLFeaturesDescription": "{platinumSubscriptionLink} が提供するすべての機械学習機能を体験するには、30 日間のトライアルを開始してください。", - "xpack.ml.datavisualizer.startTrial.platinumSubscriptionTitle": "プラチナサブスクリプション", "xpack.ml.dataVisualizerPageLabel": "データビジュアライザー", "xpack.ml.explorer.annotationsTitle": "注釈", "xpack.ml.explorer.anomaliesTitle": "異常", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 974467a8d20d0..1977da8ac9100 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -463,9 +463,6 @@ "common.ui.management.breadcrumb": "管理", "common.ui.management.connectDataDisplayName": "连接数据", "common.ui.management.displayName": "管理", - "management.editIndexPattern.createIndex.defaultButtonDescription": "对任何数据执行完全聚合", - "management.editIndexPattern.createIndex.defaultButtonText": "标准索引模式", - "management.editIndexPattern.createIndex.defaultTypeName": "索引模式", "common.ui.management.nav.menu": "管理菜单", "common.ui.modals.cancelButtonLabel": "取消", "common.ui.notify.fatalError.errorStatusMessage": "错误 {errStatus} {errStatusText}:{errMessage}", @@ -567,6 +564,9 @@ "common.ui.aggTypes.scaleMetricsLabel": "缩放指标值(已弃用)", "common.ui.aggTypes.scaleMetricsTooltip": "如果选择手动最小时间间隔并将使用较大的时间间隔,则启用此设置将使计数和求和指标缩放到手动选择的时间间隔。", "common.ui.aggTypes.buckets.ranges.rangesFormatMessage": "{gte} {from} 且 {lt} {to}", + "management.editIndexPattern.createIndex.defaultButtonDescription": "对任何数据执行完全聚合", + "management.editIndexPattern.createIndex.defaultButtonText": "标准索引模式", + "management.editIndexPattern.createIndex.defaultTypeName": "索引模式", "core.ui.overlays.banner.attentionTitle": "注意", "core.ui.overlays.banner.closeButtonLabel": "关闭", "core.ui.chrome.headerGlobalNav.goHomePageIconAriaLabel": "前往主页", @@ -6902,8 +6902,6 @@ "xpack.ml.datavisualizer.selector.startTrialButtonLabel": "开始试用", "xpack.ml.datavisualizer.selector.startTrialTitle": "开始试用", "xpack.ml.datavisualizer.selector.uploadFileButtonLabel": "上传文件", - "xpack.ml.datavisualizer.startTrial.fullMLFeaturesDescription": "要体验 {platinumSubscriptionLink} 提供的完整 Machine Learning 功能,可以安装为期 30 天的试用版。", - "xpack.ml.datavisualizer.startTrial.platinumSubscriptionTitle": "白金级订阅", "xpack.ml.dataVisualizerPageLabel": "数据可视化工具", "xpack.ml.explorer.annotationsTitle": "注释", "xpack.ml.explorer.anomaliesTitle": "异常", @@ -12825,4 +12823,4 @@ "xpack.licensing.welcomeBanner.licenseIsExpiredDescription.updateYourLicenseLinkText": "更新您的许可", "xpack.licensing.welcomeBanner.licenseIsExpiredTitle": "您的{licenseType}许可已过期" } -} +} \ No newline at end of file From 16447626c964ece49ebbdc90768b5c7e1b1f4a39 Mon Sep 17 00:00:00 2001 From: Victor Martinez Date: Wed, 11 Dec 2019 15:56:41 +0000 Subject: [PATCH 05/79] ci(jenkins): simplify the kibana setup for the e2e tests (#52729) --- .../plugins/apm/cypress/ci/kibana.dev.yml | 53 ------------------- 1 file changed, 53 deletions(-) diff --git a/x-pack/legacy/plugins/apm/cypress/ci/kibana.dev.yml b/x-pack/legacy/plugins/apm/cypress/ci/kibana.dev.yml index 900fb8d47cecf..3082391f23a15 100644 --- a/x-pack/legacy/plugins/apm/cypress/ci/kibana.dev.yml +++ b/x-pack/legacy/plugins/apm/cypress/ci/kibana.dev.yml @@ -1,57 +1,4 @@ ## # Disabled plugins ######################## -# data.enabled: false -# interpreter.enabled: false -# visualizations.enabled: false -# xpack.apm.enabled: false -# console.enabled: false -console_extensions.enabled: false -dashboard_embeddable_container.enabled: false -dashboard_mode.enabled: false -embeddable_api.enabled: false -file_upload.enabled: false -# input_control_vis.enabled: false -inspector_views.enabled: false -kibana_react.enabled: false -markdown_vis.enabled: false -metric_vis.enabled: false -metrics.enabled: false -region_map.enabled: false -table_vis.enabled: false -tagcloud.enabled: false -tile_map.enabled: false -timelion.enabled: false -ui_metric.enabled: false -vega.enabled: false -xpack.actions.enabled: false -xpack.alerting.enabled: false -xpack.beats.enabled: false -xpack.canvas.enabled: false -xpack.cloud.enabled: false -xpack.code.enabled: false -xpack.encryptedSavedObjects.enabled: false -xpack.graph.enabled: false -xpack.grokdebugger.enabled: false -xpack.index_management.enabled: false -xpack.infra.enabled: false -# xpack.license_management.enabled: false -xpack.lens.enabled: false -xpack.logstash.enabled: false -xpack.maps.enabled: false -xpack.ml.enabled: false -xpack.monitoring.enabled: false -xpack.oss_telemetry.enabled: false -xpack.remote_clusters.enabled: false -xpack.rollup.enabled: false -xpack.searchprofiler.enabled: false -# xpack.security.enabled: false -xpack.siem.enabled: false -xpack.snapshot_restore.enabled: false -xpack.spaces.enabled: false -xpack.task_manager.enabled: false -xpack.tilemap.enabled: false -xpack.upgrade_assistant.enabled: false -xpack.uptime.enabled: false -xpack.watcher.enabled: false logging.verbose: true From 4f2a6f8362a810719e091a25008e44f958aaac06 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Wed, 11 Dec 2019 15:58:11 +0000 Subject: [PATCH 06/79] [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 0000000000000..140a709b0c42b --- /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 96a46c92cb602..48e88e79f9674 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 86db2ce59d7e7..d647bd882162b 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 999eb44b372bc..cef3475a9654f 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 9b42998c814fd..3078a0c812ff1 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 0000000000000..f36b484818690 --- /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 883754896487e..7e2d651439ae3 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 1c908e114cbeb..32b2ade5dc9dc 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 722e2c8d05e9b..0000000000000 --- 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 0000000000000..c790f10725716 --- /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 909abfd4abc23..640ae8f962eed 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 19cd77655f97c..f237bcc2efc53 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 e7d191a31e034..94a502e6eadde 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 6f511abf89e31..79b1b501c3829 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 cff174eb5627f..5735faa9c6f52 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 7014164ad9756..20fa2cca41231 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 2bff760ed3711..cbbdaf410445e 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 00989245e20e7..9d0a3bc43e258 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 fde854b7f41c3..0000000000000 --- 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 1d4ac85ae2e87..0000000000000 --- 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 3839017291326..7e2d651439ae3 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 b705c604c190c..0000000000000 --- 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 5d97ed6dfcd3d..0000000000000 --- 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 bcc62f4c5b10e..7e2d651439ae3 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 89e02eb420639..0000000000000 --- 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 a4d1fd37bc338..0000000000000 --- 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 c24061cb052b8..1727b1652c55d 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 e8dd89f5db264..0000000000000 --- 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 c89f618aa835b..b50eef363847e 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 30e91783fae2c..20b997582c3f9 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 99e61d5937c1d..149e3d1818e64 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 7ca2db041da29..0000000000000 --- 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 15796ea9ff0bd..683d5e940aa7c 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 dcda3ec9879aa..770b48973b154 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 aba45e04c638f..0000000000000 --- 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 fca2508cb5d14..0b68f7e096d85 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 5de7cb6b71acb..0000000000000 --- 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 8ef2e327a8984..7e2d651439ae3 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 99e128e954103..898c852fe50a5 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 ab4df73e720ea..0000000000000 --- 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 c0dcd9e249b3b..0000000000000 --- 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 50a57f634fd1b..d8a42064de4f2 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 b5d65fbf937e4..0000000000000 --- 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 a061176a5ef5b..0000000000000 --- 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 edc25565daa9f..1dd9b76b8c20c 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 0000000000000..dbcdf288b6a85 --- /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 f2954548ea547..0000000000000 --- 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 7363c5a27f64b..0bb30d4f76de7 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 5ec407f7f054e..d78cb37108391 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 028e6a10d6abc..9b301200c76f2 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 3df869174c146..8ae024e68460a 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 fc07d4d2a0294..effc54c228130 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 f549ec3826cb5..0000000000000 --- 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 1ade8752d6721..0b70e6b3c9352 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 21c184cdcd298..f820372e20c09 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 22aebc2b88a88..d8917db7a33ff 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 4960492eabeb3..3246f8ae4b31a 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 e11cebe0383cd..4707eff8d844e 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 375e112ed46fa..4ffcd1b06ca47 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 fea328acb58b3..e86ee09d234f1 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 9e9ccf8ab63e4..8fcd03982424d 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 5f3f6ff310d28..cb8a46ade513c 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 7162ec65767f9..9feb0416dd267 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 e7e5e8aa64f7b..760dbe447dc89 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 82808ef3d37ee..5048f44586a38 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 945d22967a65d..0000000000000 --- 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 097050fd829c9..0e6dd81fb91a9 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 87e133df225a0..5fbc7557a2fa7 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 b76fc120538f5..f11cdc6233717 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 8cd533f8b2e29..035e3c90f53ae 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 918163572076c..118923aa203e1 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 2c60130739780..6d4eeff2a5475 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 bdb2076086fd5..795dfc30f954a 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 c624972aa07ea..d1900413d84c9 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 bf60eda2e81c3..f72ff6cf985e5 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 3f241f21a75e5..994847864d6bb 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 7410e10aa92cf..70a529b8e24d0 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 a543dbaaf3c5d..19b89ffec02ac 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 ffa16930e79f2..0000000000000 --- 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 9bd653708d9c0..0000000000000 --- 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 0000000000000..31e0f67c0a0fa --- /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 0265129d9ccab..8500279e742b7 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 6dd5df177bd14..0000000000000 --- 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 bdf65e3bafe96..0000000000000 --- 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 3f2a7e553c7e0..0000000000000 --- 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 0000000000000..7e2d651439ae3 --- /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 4991039ffa288..dbae1948cbe0f 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 ac2c838dbed31..0000000000000 --- 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 d152dfc488ff8..0000000000000 --- 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 0000000000000..7e2d651439ae3 --- /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 e086b2b8aad7f..79f98c1170ff8 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 a527d92342d4c..0000000000000 --- 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 50b8650f99bb8..b63ada4bb535c 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 b5369402230b7..18b199ca8983f 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 0f4eae230acfd..8e81c05092c98 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 d5d5ee4438e32..0000000000000 --- 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 4ed12dfff4c20..0000000000000 --- 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 0000000000000..7e2d651439ae3 --- /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 11b2a8f01342d..141ed5d1bbb8f 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 d2ca22972c201..cb44210b970e7 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 7b1d71540c163..0000000000000 --- 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 455fac9b532d6..050387e6de263 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 9df503b462b6c..0000000000000 --- 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 bd3b653ccbb64..0000000000000 --- 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 ac00eab1f2cdb..7d99bb1094015 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 ba4703d4818ff..6d8138d4bcd2c 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 0000000000000..3ec5361568526 --- /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 e737961e184fc..30c5fbc497afe 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 0000000000000..174c1ef1d4fe8 --- /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 0000000000000..3a2f445ac6b82 --- /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 0000000000000..41c286c54836c --- /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 0000000000000..31bd10f2138ad --- /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 0000000000000..552c15a408b65 --- /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 0000000000000..3faca285319d5 --- /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 0000000000000..11e6b85f939d3 --- /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 0000000000000..7f61317ef3402 --- /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 0000000000000..ab359238695d4 --- /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 0000000000000..1b6b91026d6a5 --- /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 0000000000000..89ed35d5588f2 --- /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 0000000000000..e61c24426bde9 --- /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 0000000000000..b226b75743ca6 --- /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 0000000000000..b81058a9c89af --- /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 0000000000000..e537a186ec784 --- /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 0000000000000..b110434f6f0a8 --- /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 0000000000000..4f5085facfb29 --- /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 0000000000000..ea1baefdce0d1 --- /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 0000000000000..fe9f4336148f3 --- /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 0000000000000..56ff57f6610b2 --- /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 0000000000000..fb68f103e1b77 --- /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 0000000000000..cb19883e962c1 --- /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 0000000000000..7a596a488ddb6 --- /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 0000000000000..f638b78e05fb1 --- /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 0000000000000..b62ecc0539e72 --- /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 0000000000000..a40bbfa214b28 --- /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 0000000000000..f74260c06567e --- /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 a3096a942a7c7..b9ed83eeffba1 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 90aa5d8d66faa..dbe81df0f0471 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 f79515c80556a..9d5c33d6cfc5c 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 bd04003c9eca4..0000000000000 --- 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 408042fb70cba..267fb3930121b 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 aa8b2ec2c29c9..5e008e4796d1c 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 d6de538d6388a..002a88ec03f0d 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 feabd60d8d3a0..c9fe2503b0c5b 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 0000000000000..88aa20ea06320 --- /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 1b90a27c07ada..0000000000000 --- 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 aa8b2ec2c29c9..dcf8ade3301b3 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 1932ff3d83efa..7958546f3a0cf 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 3a5c8eec31c06..285f9423cd4c1 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 71d82d7694cf0..56ef8745cb28b 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 aa8b2ec2c29c9..52b35f361777f 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 6a942d5c251df..52dcda9b3f7c0 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 7b572344c603b..0000000000000 --- 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 aa8b2ec2c29c9..2e5cc371e317d 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 a5cc1ed761b56..85bba8e4fe744 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 d9fc996ae4a30..db74dcb1a1846 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 3c1ae2973721a..225f39fc6f419 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 2aa4c845b125d..0000000000000 --- 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 5aa6cfe8835ad..0000000000000 --- 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 0000000000000..6877e8ef754fd --- /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 0000000000000..ac4bc6186e5b4 --- /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 a70e1d38784e9..99eb4beb977da 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 048a8dbc4a6db..0000000000000 --- 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 63b9b819be315..0000000000000 --- 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 8aa933eb5e53f..110795c2d0290 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 a229113826a2e..5ef6b592ae271 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 99882b0243be8..2b8838c04cf69 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 ac3f3fef97c70..0000000000000 --- 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 0000000000000..0057983104cc0 --- /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 0000000000000..3e007a18f4c5a --- /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 0000000000000..2a80b18446046 --- /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 eb2f50b8e9250..5bb0f39982146 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 054382ed0fa81..2e7d4233dd7ff 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 1977da8ac9100..fd5573901fb00 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": "失败的作业", From a12d8551a1c89fc674653c315e2947ff8d4492e5 Mon Sep 17 00:00:00 2001 From: "Devin W. Hurley" Date: Wed, 11 Dec 2019 11:09:36 -0500 Subject: [PATCH 07/79] [SIEM] [Detection Engine] Search signals index (#52661) * adds route for querying signals index, also updates signal status type names * first pass at happy path tests * fixes stuff after rebase with master * utilizes removes search_query from payload and replaces it with just query, adds aggs to signals search api, updates route and validation tests * removes _headers parameter from route handler and updates comment for aggs script --- .../legacy/plugins/siem/common/constants.ts | 1 + .../plugins/siem/server/kibana.index.ts | 2 + .../routes/__mocks__/request_responses.ts | 29 +++- .../query_signals_index_schema.test.ts | 39 ++++++ .../schemas/query_signals_index_schema.ts | 12 ++ .../schemas/set_signal_status_schema.test.ts | 14 +- .../signals/open_close_signals_route.ts | 4 +- .../signals/query_signals_route.test.ts | 129 ++++++++++++++++++ .../routes/signals/query_signals_route.ts | 47 +++++++ .../scripts/signals/aggs_signals.sh | 19 +++ .../scripts/signals/query_signals.sh | 19 +++ .../lib/detection_engine/signals/types.ts | 25 +++- 12 files changed, 323 insertions(+), 17 deletions(-) create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/query_signals_index_schema.test.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/query_signals_index_schema.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/query_signals_route.test.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/query_signals_route.ts create mode 100755 x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/signals/aggs_signals.sh create mode 100755 x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/signals/query_signals.sh diff --git a/x-pack/legacy/plugins/siem/common/constants.ts b/x-pack/legacy/plugins/siem/common/constants.ts index 0924b6c6eb5e6..c3494c0969900 100644 --- a/x-pack/legacy/plugins/siem/common/constants.ts +++ b/x-pack/legacy/plugins/siem/common/constants.ts @@ -53,3 +53,4 @@ export const DETECTION_ENGINE_INDEX_URL = `${DETECTION_ENGINE_URL}/index`; export const SIGNALS_INDEX_KEY = 'signalsIndex'; export const DETECTION_ENGINE_SIGNALS_URL = `${DETECTION_ENGINE_URL}/signals`; export const DETECTION_ENGINE_SIGNALS_STATUS_URL = `${DETECTION_ENGINE_SIGNALS_URL}/status`; +export const DETECTION_ENGINE_QUERY_SIGNALS_URL = `${DETECTION_ENGINE_SIGNALS_URL}/search`; diff --git a/x-pack/legacy/plugins/siem/server/kibana.index.ts b/x-pack/legacy/plugins/siem/server/kibana.index.ts index f56e6b3c3f550..65b673e1c72a5 100644 --- a/x-pack/legacy/plugins/siem/server/kibana.index.ts +++ b/x-pack/legacy/plugins/siem/server/kibana.index.ts @@ -15,6 +15,7 @@ import { findRulesRoute } from './lib/detection_engine/routes/rules/find_rules_r import { deleteRulesRoute } from './lib/detection_engine/routes/rules/delete_rules_route'; import { updateRulesRoute } from './lib/detection_engine/routes/rules/update_rules_route'; import { setSignalsStatusRoute } from './lib/detection_engine/routes/signals/open_close_signals_route'; +import { querySignalsRoute } from './lib/detection_engine/routes/signals/query_signals_route'; import { ServerFacade } from './types'; import { deleteIndexRoute } from './lib/detection_engine/routes/index/delete_index_route'; import { isAlertExecutor } from './lib/detection_engine/signals/types'; @@ -44,6 +45,7 @@ export const initServerWithKibana = (context: PluginInitializerContext, __legacy // POST /api/detection_engine/signals/status // Example usage can be found in siem/server/lib/detection_engine/scripts/signals setSignalsStatusRoute(__legacy); + querySignalsRoute(__legacy); // Detection Engine index routes that have the REST endpoints of /api/detection_engine/index // All REST index creation, policy management for spaces diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts index 978434859ef95..86726187c4fbd 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -6,10 +6,11 @@ import { ServerInjectOptions } from 'hapi'; import { ActionResult } from '../../../../../../actions/server/types'; -import { SignalsRestParams } from '../../signals/types'; +import { SignalsStatusRestParams, SignalsQueryRestParams } from '../../signals/types'; import { DETECTION_ENGINE_RULES_URL, DETECTION_ENGINE_SIGNALS_STATUS_URL, + DETECTION_ENGINE_QUERY_SIGNALS_URL, } from '../../../../../common/constants'; import { RuleAlertType } from '../../rules/types'; import { RuleAlertParamsRest } from '../../types'; @@ -40,17 +41,25 @@ export const typicalPayload = (): Partial> = ], }); -export const typicalSetStatusSignalByIdsPayload = (): Partial => ({ +export const typicalSetStatusSignalByIdsPayload = (): Partial => ({ signal_ids: ['somefakeid1', 'somefakeid2'], status: 'closed', }); -export const typicalSetStatusSignalByQueryPayload = (): Partial => ({ +export const typicalSetStatusSignalByQueryPayload = (): Partial => ({ query: { range: { '@timestamp': { gte: 'now-2M', lte: 'now/M' } } }, status: 'closed', }); -export const setStatusSignalMissingIdsAndQueryPayload = (): Partial => ({ +export const typicalSignalsQuery = (): Partial => ({ + query: { match_all: {} }, +}); + +export const typicalSignalsQueryAggs = (): Partial => ({ + aggs: { statuses: { terms: { field: 'signal.status', size: 10 } } }, +}); + +export const setStatusSignalMissingIdsAndQueryPayload = (): Partial => ({ status: 'closed', }); @@ -134,6 +143,18 @@ export const getSetSignalStatusByQueryRequest = (): ServerInjectOptions => ({ }, }); +export const getSignalsQueryRequest = (): ServerInjectOptions => ({ + method: 'POST', + url: DETECTION_ENGINE_QUERY_SIGNALS_URL, + payload: { ...typicalSignalsQuery() }, +}); + +export const getSignalsAggsQueryRequest = (): ServerInjectOptions => ({ + method: 'POST', + url: DETECTION_ENGINE_QUERY_SIGNALS_URL, + payload: { ...typicalSignalsQueryAggs() }, +}); + export const createActionResult = (): ActionResult => ({ id: 'result-1', actionTypeId: 'action-id-1', diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/query_signals_index_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/query_signals_index_schema.test.ts new file mode 100644 index 0000000000000..4f0dbf10f4559 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/query_signals_index_schema.test.ts @@ -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 { querySignalsSchema } from './query_signals_index_schema'; +import { SignalsQueryRestParams } from '../../signals/types'; + +describe('query and aggs on signals index', () => { + test('query and aggs simultaneously', () => { + expect( + querySignalsSchema.validate>({ + query: {}, + aggs: {}, + }).error + ).toBeFalsy(); + }); + + test('query only', () => { + expect( + querySignalsSchema.validate>({ + query: {}, + }).error + ).toBeFalsy(); + }); + + test('aggs only', () => { + expect( + querySignalsSchema.validate>({ + aggs: {}, + }).error + ).toBeFalsy(); + }); + + test('missing query and aggs is invalid', () => { + expect(querySignalsSchema.validate>({}).error).toBeTruthy(); + }); +}); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/query_signals_index_schema.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/query_signals_index_schema.ts new file mode 100644 index 0000000000000..53ce50692e84a --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/query_signals_index_schema.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 Joi from 'joi'; + +export const querySignalsSchema = Joi.object({ + query: Joi.object(), + aggs: Joi.object(), +}).min(1); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/set_signal_status_schema.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/set_signal_status_schema.test.ts index b586b4666bfee..792c7afad05b1 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/set_signal_status_schema.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/schemas/set_signal_status_schema.test.ts @@ -5,12 +5,12 @@ */ import { setSignalsStatusSchema } from './set_signal_status_schema'; -import { SignalsRestParams } from '../../signals/types'; +import { SignalsStatusRestParams } from '../../signals/types'; describe('set signal status schema', () => { test('signal_ids and status is valid', () => { expect( - setSignalsStatusSchema.validate>({ + setSignalsStatusSchema.validate>({ signal_ids: ['somefakeid'], status: 'open', }).error @@ -19,7 +19,7 @@ describe('set signal status schema', () => { test('query and status is valid', () => { expect( - setSignalsStatusSchema.validate>({ + setSignalsStatusSchema.validate>({ query: {}, status: 'open', }).error @@ -28,7 +28,7 @@ describe('set signal status schema', () => { test('signal_ids and missing status is invalid', () => { expect( - setSignalsStatusSchema.validate>({ + setSignalsStatusSchema.validate>({ signal_ids: ['somefakeid'], }).error ).toBeTruthy(); @@ -36,7 +36,7 @@ describe('set signal status schema', () => { test('query and missing status is invalid', () => { expect( - setSignalsStatusSchema.validate>({ + setSignalsStatusSchema.validate>({ query: {}, }).error ).toBeTruthy(); @@ -44,7 +44,7 @@ describe('set signal status schema', () => { test('status is present but query or signal_ids is missing is invalid', () => { expect( - setSignalsStatusSchema.validate>({ + setSignalsStatusSchema.validate>({ status: 'closed', }).error ).toBeTruthy(); @@ -54,7 +54,7 @@ describe('set signal status schema', () => { expect( setSignalsStatusSchema.validate< Partial< - Omit & { + Omit & { status: string; } > diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/open_close_signals_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/open_close_signals_route.ts index b342cc5cd14ef..7c49a1942ee91 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/open_close_signals_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/open_close_signals_route.ts @@ -6,7 +6,7 @@ import Hapi from 'hapi'; import { DETECTION_ENGINE_SIGNALS_STATUS_URL } from '../../../../../common/constants'; -import { SignalsRequest } from '../../signals/types'; +import { SignalsStatusRequest } from '../../signals/types'; import { setSignalsStatusSchema } from '../schemas/set_signal_status_schema'; import { ServerFacade } from '../../../../types'; import { transformError, getIndex } from '../utils'; @@ -24,7 +24,7 @@ export const setSignalsStatusRouteDef = (server: ServerFacade): Hapi.ServerRoute payload: setSignalsStatusSchema, }, }, - async handler(request: SignalsRequest, headers) { + async handler(request: SignalsStatusRequest) { const { signal_ids: signalIds, query, status } = request.payload; const index = getIndex(request, server); const { callWithRequest } = server.plugins.elasticsearch.getCluster('data'); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/query_signals_route.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/query_signals_route.test.ts new file mode 100644 index 0000000000000..1b990e8c1ff57 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/query_signals_route.test.ts @@ -0,0 +1,129 @@ +/* + * 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 { createMockServer } from '../__mocks__/_mock_server'; +import { querySignalsRoute } from './query_signals_route'; +import * as myUtils from '../utils'; +import { ServerInjectOptions } from 'hapi'; +import { + getSignalsQueryRequest, + getSignalsAggsQueryRequest, + typicalSignalsQuery, + typicalSignalsQueryAggs, +} from '../__mocks__/request_responses'; +import { DETECTION_ENGINE_QUERY_SIGNALS_URL } from '../../../../../common/constants'; + +describe('query for signal', () => { + let { server, elasticsearch } = createMockServer(); + + beforeEach(() => { + jest.resetAllMocks(); + jest.spyOn(myUtils, 'getIndex').mockReturnValue('fakeindex'); + ({ server, elasticsearch } = createMockServer()); + elasticsearch.getCluster = jest.fn(() => ({ + callWithRequest: jest.fn(() => true), + })); + querySignalsRoute(server); + }); + + describe('query and agg on signals index', () => { + test('returns 200 when using single query', async () => { + elasticsearch.getCluster = jest.fn(() => ({ + callWithRequest: jest.fn( + (_req, _type: string, queryBody: { index: string; body: object }) => { + expect(queryBody.body).toMatchObject({ ...typicalSignalsQueryAggs() }); + return true; + } + ), + })); + const { statusCode } = await server.inject(getSignalsAggsQueryRequest()); + expect(statusCode).toBe(200); + expect(myUtils.getIndex).toHaveReturnedWith('fakeindex'); + }); + + test('returns 200 when using single agg', async () => { + elasticsearch.getCluster = jest.fn(() => ({ + callWithRequest: jest.fn( + (_req, _type: string, queryBody: { index: string; body: object }) => { + expect(queryBody.body).toMatchObject({ ...typicalSignalsQueryAggs() }); + return true; + } + ), + })); + const { statusCode } = await server.inject(getSignalsAggsQueryRequest()); + expect(statusCode).toBe(200); + expect(myUtils.getIndex).toHaveReturnedWith('fakeindex'); + }); + + test('returns 200 when using aggs and query together', async () => { + const allTogether = getSignalsQueryRequest(); + allTogether.payload = { ...typicalSignalsQueryAggs(), ...typicalSignalsQuery() }; + elasticsearch.getCluster = jest.fn(() => ({ + callWithRequest: jest.fn( + (_req, _type: string, queryBody: { index: string; body: object }) => { + expect(queryBody.body).toMatchObject({ + ...typicalSignalsQueryAggs(), + ...typicalSignalsQuery(), + }); + return true; + } + ), + })); + const { statusCode } = await server.inject(allTogether); + expect(statusCode).toBe(200); + expect(myUtils.getIndex).toHaveReturnedWith('fakeindex'); + }); + + test('returns 400 when missing aggs and query', async () => { + const allTogether = getSignalsQueryRequest(); + allTogether.payload = {}; + const { statusCode } = await server.inject(allTogether); + expect(statusCode).toBe(400); + }); + }); + + describe('validation', () => { + test('returns 200 if query present', async () => { + const request: ServerInjectOptions = { + method: 'POST', + url: DETECTION_ENGINE_QUERY_SIGNALS_URL, + payload: typicalSignalsQuery(), + }; + const { statusCode } = await server.inject(request); + expect(statusCode).toBe(200); + }); + + test('returns 200 if aggs is present', async () => { + const request: ServerInjectOptions = { + method: 'POST', + url: DETECTION_ENGINE_QUERY_SIGNALS_URL, + payload: typicalSignalsQueryAggs(), + }; + const { statusCode } = await server.inject(request); + expect(statusCode).toBe(200); + }); + + test('returns 200 if aggs and query are present', async () => { + const request: ServerInjectOptions = { + method: 'POST', + url: DETECTION_ENGINE_QUERY_SIGNALS_URL, + payload: { ...typicalSignalsQueryAggs(), ...typicalSignalsQuery() }, + }; + const { statusCode } = await server.inject(request); + expect(statusCode).toBe(200); + }); + + test('returns 400 if aggs and query are NOT present', async () => { + const request: ServerInjectOptions = { + method: 'POST', + url: DETECTION_ENGINE_QUERY_SIGNALS_URL, + payload: {}, + }; + const { statusCode } = await server.inject(request); + expect(statusCode).toBe(400); + }); + }); +}); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/query_signals_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/query_signals_route.ts new file mode 100644 index 0000000000000..89ffed259cf77 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/signals/query_signals_route.ts @@ -0,0 +1,47 @@ +/* + * 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 Hapi from 'hapi'; +import { DETECTION_ENGINE_QUERY_SIGNALS_URL } from '../../../../../common/constants'; +import { SignalsQueryRequest } from '../../signals/types'; +import { querySignalsSchema } from '../schemas/query_signals_index_schema'; +import { ServerFacade } from '../../../../types'; +import { transformError, getIndex } from '../utils'; + +export const querySignalsRouteDef = (server: ServerFacade): Hapi.ServerRoute => { + return { + method: 'POST', + path: DETECTION_ENGINE_QUERY_SIGNALS_URL, + options: { + tags: ['access:siem'], + validate: { + options: { + abortEarly: false, + }, + payload: querySignalsSchema, + }, + }, + async handler(request: SignalsQueryRequest) { + const { query, aggs } = request.payload; + const body = { query, aggs }; + const index = getIndex(request, server); + const { callWithRequest } = server.plugins.elasticsearch.getCluster('data'); + try { + return callWithRequest(request, 'search', { + index, + body, + }); + } catch (exc) { + // error while getting or updating signal with id: id in signal index .siem-signals + return transformError(exc); + } + }, + }; +}; + +export const querySignalsRoute = (server: ServerFacade) => { + server.route(querySignalsRouteDef(server)); +}; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/signals/aggs_signals.sh b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/signals/aggs_signals.sh new file mode 100755 index 0000000000000..27186a14af902 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/signals/aggs_signals.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +# +# 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. +# + +set -e +./check_env_variables.sh + +# Example: ./signals/aggs_signal.sh + curl -s -k \ + -H 'Content-Type: application/json' \ + -H 'kbn-xsrf: 123' \ + -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ + -X POST ${KIBANA_URL}${SPACE_URL}/api/detection_engine/signals/search \ + -d '{"aggs": {"statuses": {"terms": {"field": "signal.status", "size": 10 }}}}' \ + | jq . diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/signals/query_signals.sh b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/signals/query_signals.sh new file mode 100755 index 0000000000000..2fc76406ec0f6 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/signals/query_signals.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +# +# 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. +# + +set -e +./check_env_variables.sh + +# Example: ./signals/query_signals.sh + curl -s -k \ + -H 'Content-Type: application/json' \ + -H 'kbn-xsrf: 123' \ + -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ + -X POST ${KIBANA_URL}${SPACE_URL}/api/detection_engine/signals/search \ + -d '{ "query": { "match_all": {} } } ' \ + | jq . diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/types.ts index 213ceb29a6e25..a30182c537884 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/types.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/signals/types.ts @@ -15,12 +15,29 @@ export interface SignalsParams { status: 'open' | 'closed'; } -export type SignalsRestParams = Omit & { - signal_ids: SignalsParams['signalIds']; +export interface SignalsStatusParams { + signalIds: string[] | undefined | null; + query: object | undefined | null; + status: 'open' | 'closed'; +} + +export interface SignalQueryParams { + query: object | undefined | null; + aggs: object | undefined | null; +} + +export type SignalsStatusRestParams = Omit & { + signal_ids: SignalsStatusParams['signalIds']; }; -export interface SignalsRequest extends RequestFacade { - payload: SignalsRestParams; +export type SignalsQueryRestParams = SignalQueryParams; + +export interface SignalsStatusRequest extends RequestFacade { + payload: SignalsStatusRestParams; +} + +export interface SignalsQueryRequest extends RequestFacade { + payload: SignalsQueryRestParams; } export type SearchTypes = From 73938f0cf463b640661c88fe1fed2d777d3341b5 Mon Sep 17 00:00:00 2001 From: Mariana Dima Date: Wed, 11 Dec 2019 17:34:46 +0100 Subject: [PATCH 08/79] add azure data (#52669) --- .../azure_metrics/screenshot.png | Bin 0 -> 1259487 bytes .../home/tutorial_resources/logos/azure.svg | 17 +++++ .../server/tutorials/azure_metrics/index.js | 61 ++++++++++++++++++ .../kibana/server/tutorials/register.js | 2 + 4 files changed, 80 insertions(+) create mode 100644 src/legacy/core_plugins/kibana/public/home/tutorial_resources/azure_metrics/screenshot.png create mode 100644 src/legacy/core_plugins/kibana/public/home/tutorial_resources/logos/azure.svg create mode 100644 src/legacy/core_plugins/kibana/server/tutorials/azure_metrics/index.js diff --git a/src/legacy/core_plugins/kibana/public/home/tutorial_resources/azure_metrics/screenshot.png b/src/legacy/core_plugins/kibana/public/home/tutorial_resources/azure_metrics/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..22136049b494ad9627683b0b3fff29cd83f0361a GIT binary patch literal 1259487 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≺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ƻgG#8PFd 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 z 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

{nHiKwL|Q~NpZV==ZS7)d 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 z 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 z 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

01>= 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

<@Mg5Pw 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 Ub?1Ls1U?Qpx$Y(HK6T}P0bI7e%m4rY literal 0 HcmV?d00001 diff --git a/src/legacy/core_plugins/kibana/public/home/tutorial_resources/logos/azure.svg b/src/legacy/core_plugins/kibana/public/home/tutorial_resources/logos/azure.svg new file mode 100644 index 0000000000000..f8df12ba05c50 --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/home/tutorial_resources/logos/azure.svg @@ -0,0 +1,17 @@ + + + + + + + + + diff --git a/src/legacy/core_plugins/kibana/server/tutorials/azure_metrics/index.js b/src/legacy/core_plugins/kibana/server/tutorials/azure_metrics/index.js new file mode 100644 index 0000000000000..8bd0d17b143cf --- /dev/null +++ b/src/legacy/core_plugins/kibana/server/tutorials/azure_metrics/index.js @@ -0,0 +1,61 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category'; +import { onPremInstructions, cloudInstructions, onPremCloudInstructions } from '../../../common/tutorials/metricbeat_instructions'; + +export function azureMetricsSpecProvider(context) { + const moduleName = 'azure'; + return { + id: 'azureMetrics', + name: i18n.translate('kbn.server.tutorials.azureMetrics.nameTitle', { + defaultMessage: 'Azure metrics', + }), + isBeta: true, + category: TUTORIAL_CATEGORY.METRICS, + shortDescription: i18n.translate('kbn.server.tutorials.azureMetrics.shortDescription', { + defaultMessage: 'Fetch Azure Monitor metrics.', + }), + longDescription: i18n.translate('kbn.server.tutorials.azureMetrics.longDescription', { + defaultMessage: 'The `azure` Metricbeat module fetches Azure Monitor metrics. \ +[Learn more]({learnMoreLink}).', + values: { + learnMoreLink: '{config.docs.beats.metricbeat}/metricbeat-module-azure.html', + }, + }), + euiIconType: 'logoAzure', + artifacts: { + application: { + label: i18n.translate('kbn.server.tutorials.azureMetrics.artifacts.application.label', { + defaultMessage: 'Discover', + }), + path: '/app/kibana#/discover' + }, + dashboards: [], + exportedFields: { + documentationUrl: '{config.docs.beats.metricbeat}/exported-fields-azure.html' + } + }, + completionTimeMinutes: 10, + onPrem: onPremInstructions(moduleName, null, null, null, context), + elasticCloud: cloudInstructions(moduleName), + onPremElasticCloud: onPremCloudInstructions(moduleName) + }; +} diff --git a/src/legacy/core_plugins/kibana/server/tutorials/register.js b/src/legacy/core_plugins/kibana/server/tutorials/register.js index 75f29a9f10e53..ec6ffe7e6a7ba 100644 --- a/src/legacy/core_plugins/kibana/server/tutorials/register.js +++ b/src/legacy/core_plugins/kibana/server/tutorials/register.js @@ -82,6 +82,7 @@ import { traefikMetricsSpecProvider } from './traefik_metrics'; import { awsLogsSpecProvider } from './aws_logs'; import { activemqLogsSpecProvider } from './activemq_logs'; import { activemqMetricsSpecProvider } from './activemq_metrics'; +import { azureMetricsSpecProvider } from './azure_metrics'; export function registerTutorials(server) { server.newPlatform.setup.plugins.home.tutorials.registerTutorial(systemLogsSpecProvider); @@ -150,4 +151,5 @@ export function registerTutorials(server) { server.newPlatform.setup.plugins.home.tutorials.registerTutorial(awsLogsSpecProvider); server.newPlatform.setup.plugins.home.tutorials.registerTutorial(activemqLogsSpecProvider); server.newPlatform.setup.plugins.home.tutorials.registerTutorial(activemqMetricsSpecProvider); + server.newPlatform.setup.plugins.home.tutorials.registerTutorial(azureMetricsSpecProvider); } From a25bf49eb8d6238013293ee4579e036139967d24 Mon Sep 17 00:00:00 2001 From: Spencer Date: Wed, 11 Dec 2019 09:42:43 -0700 Subject: [PATCH 09/79] Add failure screenshot links to JUnit failures (#52449) --- .../add_messages_to_report.test.ts | 49 ++++---- .../add_messages_to_report.ts | 14 +-- .../failed_tests_reporter/report_metadata.ts | 53 ++++++++ .../run_failed_tests_reporter_cli.ts | 46 +++---- .../src/failed_tests_reporter/test_report.ts | 26 ++-- .../functional_test_runner.ts | 3 + .../lib/failure_metadata.test.ts | 71 +++++++++++ .../lib/failure_metadata.ts | 104 +++++++++++++++ .../src/functional_test_runner/lib/index.ts | 1 + .../lib/lifecycle_event.ts | 68 ++++++++++ .../lib/mocha/reporter/reporter.js | 2 + .../__tests__/junit_report_generation.js | 4 + .../src/mocha/junit_report_generation.js | 2 + packages/kbn-test/types/ftr.d.ts | 7 +- test/functional/services/screenshots.ts | 10 +- vars/kibanaPipeline.groovy | 119 +++++++++--------- 16 files changed, 450 insertions(+), 129 deletions(-) create mode 100644 packages/kbn-test/src/failed_tests_reporter/report_metadata.ts create mode 100644 packages/kbn-test/src/functional_test_runner/lib/failure_metadata.test.ts create mode 100644 packages/kbn-test/src/functional_test_runner/lib/failure_metadata.ts create mode 100644 packages/kbn-test/src/functional_test_runner/lib/lifecycle_event.ts diff --git a/packages/kbn-test/src/failed_tests_reporter/add_messages_to_report.test.ts b/packages/kbn-test/src/failed_tests_reporter/add_messages_to_report.test.ts index 9e800e88bc9ba..5a7939f87130b 100644 --- a/packages/kbn-test/src/failed_tests_reporter/add_messages_to_report.test.ts +++ b/packages/kbn-test/src/failed_tests_reporter/add_messages_to_report.test.ts @@ -73,12 +73,17 @@ it('rewrites ftr reports with minimal changes', async () => { =================================================================== --- ftr.xml [object Object] +++ ftr.xml - @@ -2,52 +2,56 @@ + @@ -1,53 +1,56 @@ + ‹?xml version="1.0" encoding="utf-8"?› ‹testsuites› ‹testsuite timestamp="2019-06-05T23:37:10" time="903.670" tests="129" failures="5" skipped="71"› ‹testcase name="maps app maps loaded from sample data ecommerce "before all" hook" classname="Chrome X-Pack UI Functional Tests.x-pack/test/functional/apps/maps/sample_data·js" time="154.378"› - ‹system-out› + - ‹system-out› - ‹![CDATA[[00:00:00] │ + + ‹system-out›Failed Tests Reporter: + + - foo bar + + + + + [00:00:00] │ [00:07:04] └-: maps app ... @@ -94,13 +99,8 @@ it('rewrites ftr reports with minimal changes', async () => { at process._tickCallback (internal/process/next_tick.js:68:7) at lastError (/var/lib/jenkins/workspace/elastic+kibana+master/JOB/x-pack-ciGroup7/node/immutable/kibana/test/common/services/retry/retry_for_success.ts:28:9) - at onFailure (/var/lib/jenkins/workspace/elastic+kibana+master/JOB/x-pack-ciGroup7/node/immutable/kibana/test/common/services/retry/retry_for_success.ts:68:13)]]› - - ‹/failure› + at onFailure (/var/lib/jenkins/workspace/elastic+kibana+master/JOB/x-pack-ciGroup7/node/immutable/kibana/test/common/services/retry/retry_for_success.ts:68:13) - + - + - +Failed Tests Reporter: - + - foo bar - +‹/failure› + ‹/failure› ‹/testcase› ‹testcase name="maps app "after all" hook" classname="Chrome X-Pack UI Functional Tests.x-pack/test/functional/apps/maps" time="0.179"› ‹system-out› @@ -181,11 +181,11 @@ it('rewrites jest reports with minimal changes', async () => { + ‹failure›‹![CDATA[ + TypeError: Cannot read property '0' of undefined + at Object.‹anonymous›.test (/var/lib/jenkins/workspace/elastic+kibana+master/JOB/x-pack-intake/node/immutable/kibana/x-pack/legacy/plugins/code/server/lsp/abstract_launcher.test.ts:166:10) - + - + - +Failed Tests Reporter: + + ]]›‹/failure› + + ‹system-out›Failed Tests Reporter: + - foo bar - +]]›‹/failure› + + + +‹/system-out› ‹/testcase› ‹testcase classname="X-Pack Jest Tests.x-pack/legacy/plugins/code/server/lsp" name="passive launcher can start and end a process" time="0.435"/› ‹testcase classname="X-Pack Jest Tests.x-pack/legacy/plugins/code/server/lsp" name="passive launcher should restart a process if a process died before connected" time="1.502"/› @@ -216,12 +216,17 @@ it('rewrites mocha reports with minimal changes', async () => { =================================================================== --- mocha.xml [object Object] +++ mocha.xml - @@ -2,12 +2,12 @@ + @@ -1,13 +1,16 @@ + ‹?xml version="1.0" encoding="utf-8"?› ‹testsuites› ‹testsuite timestamp="2019-06-13T23:29:36" time="30.739" tests="1444" failures="2" skipped="3"› ‹testcase name="code in multiple nodes "before all" hook" classname="X-Pack Mocha Tests.x-pack/legacy/plugins/code/server/__tests__/multi_node·ts" time="0.121"› - ‹system-out› + - ‹system-out› - ‹![CDATA[]]› + + ‹system-out›Failed Tests Reporter: + + - foo bar + + + + + ‹/system-out› - ‹failure› @@ -232,7 +237,7 @@ it('rewrites mocha reports with minimal changes', async () => { ‹head›‹title›503 Service Temporarily Unavailable‹/title›‹/head› ‹body bgcolor="white"› ‹center›‹h1›503 Service Temporarily Unavailable‹/h1›‹/center› - @@ -15,24 +15,28 @@ + @@ -15,24 +18,24 @@ ‹/body› ‹/html› @@ -240,11 +245,7 @@ it('rewrites mocha reports with minimal changes', async () => { - at process._tickCallback (internal/process/next_tick.js:68:7)]]› - ‹/failure› + at process._tickCallback (internal/process/next_tick.js:68:7) - + - + - +Failed Tests Reporter: - + - foo bar - +]]›‹/failure› + + ]]›‹/failure› ‹/testcase› ‹testcase name="code in multiple nodes "after all" hook" classname="X-Pack Mocha Tests.x-pack/legacy/plugins/code/server/__tests__/multi_node·ts" time="0.003"› ‹system-out› @@ -324,11 +325,11 @@ it('rewrites karma reports with minimal changes', async () => { + at Generator.prototype.‹computed› [as next] (webpack://%5Bname%5D/./node_modules/regenerator-runtime/runtime.js?:114:21) + at asyncGeneratorStep (http://localhost:5610/bundles/tests.bundle.js?shards=4&shard_num=1:158772:103) + at _next (http://localhost:5610/bundles/tests.bundle.js?shards=4&shard_num=1:158774:194) - + - + - +Failed Tests Reporter: - + - foo bar +]]›‹/failure› + + ‹system-out›Failed Tests Reporter: + + - foo bar + + + +‹/system-out› ‹/testcase› ‹testcase name="CoordinateMapsVisualizationTest CoordinateMapsVisualization - basics should toggle to Heatmap OK" time="0.055" classname="Browser Unit Tests.CoordinateMapsVisualizationTest"/› ‹testcase name="VegaParser._parseSchema should warn on vega-lite version too new to be supported" time="0.001" classname="Browser Unit Tests.VegaParser·_parseSchema"/› diff --git a/packages/kbn-test/src/failed_tests_reporter/add_messages_to_report.ts b/packages/kbn-test/src/failed_tests_reporter/add_messages_to_report.ts index f82e1ef1fc19a..32ea5fa0f9033 100644 --- a/packages/kbn-test/src/failed_tests_reporter/add_messages_to_report.ts +++ b/packages/kbn-test/src/failed_tests_reporter/add_messages_to_report.ts @@ -57,16 +57,14 @@ export async function addMessagesToReport(options: { } log.info(`${classname} - ${name}:${messageList}`); - const append = `\n\nFailed Tests Reporter:${messageList}\n`; + const output = `Failed Tests Reporter:${messageList}\n\n`; - if ( - testCase.failure[0] && - typeof testCase.failure[0] === 'object' && - typeof testCase.failure[0]._ === 'string' - ) { - testCase.failure[0]._ += append; + if (!testCase['system-out']) { + testCase['system-out'] = [output]; + } else if (typeof testCase['system-out'][0] === 'string') { + testCase['system-out'][0] = output + String(testCase['system-out'][0]); } else { - testCase.failure[0] = String(testCase.failure[0]) + append; + testCase['system-out'][0]._ = output + testCase['system-out'][0]._; } } diff --git a/packages/kbn-test/src/failed_tests_reporter/report_metadata.ts b/packages/kbn-test/src/failed_tests_reporter/report_metadata.ts new file mode 100644 index 0000000000000..aad4c5d3c30c0 --- /dev/null +++ b/packages/kbn-test/src/failed_tests_reporter/report_metadata.ts @@ -0,0 +1,53 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { TestReport, makeTestCaseIter } from './test_report'; +import { Message } from './add_messages_to_report'; + +export function* getMetadataIter(report: TestReport) { + for (const testCase of makeTestCaseIter(report)) { + if (!testCase.$['metadata-json']) { + yield [{}, testCase]; + } else { + yield [{}, JSON.parse(testCase.$['metadata-json'])]; + } + } +} + +export function getReportMessages(report: TestReport) { + const messages: Message[] = []; + for (const [metadata, testCase] of getMetadataIter(report)) { + for (const message of metadata.messages || []) { + messages.push({ + classname: testCase.$.classname, + name: testCase.$.name, + message, + }); + } + + for (const screenshot of metadata.screenshots || []) { + messages.push({ + classname: testCase.$.classname, + name: testCase.$.name, + message: `Screenshot: ${screenshot.name} ${screenshot.url}`, + }); + } + } + return messages; +} diff --git a/packages/kbn-test/src/failed_tests_reporter/run_failed_tests_reporter_cli.ts b/packages/kbn-test/src/failed_tests_reporter/run_failed_tests_reporter_cli.ts index b3c2a8dc338da..fd7976d6e87e1 100644 --- a/packages/kbn-test/src/failed_tests_reporter/run_failed_tests_reporter_cli.ts +++ b/packages/kbn-test/src/failed_tests_reporter/run_failed_tests_reporter_cli.ts @@ -25,7 +25,8 @@ import { GithubApi } from './github_api'; import { updateFailureIssue, createFailureIssue } from './report_failure'; import { getIssueMetadata } from './issue_metadata'; import { readTestReport } from './test_report'; -import { addMessagesToReport, Message } from './add_messages_to_report'; +import { addMessagesToReport } from './add_messages_to_report'; +import { getReportMessages } from './report_metadata'; export function runFailedTestsReporterCli() { run( @@ -74,17 +75,22 @@ export function runFailedTestsReporterCli() { for (const reportPath of reportPaths) { const report = await readTestReport(reportPath); - const messages: Message[] = []; + const messages = getReportMessages(report); for (const failure of await getFailures(report)) { - if (failure.likelyIrrelevant) { + const pushMessage = (msg: string) => { messages.push({ classname: failure.classname, name: failure.name, - message: - 'Failure is likely irrelevant' + - (updateGithub ? ', so an issue was not created or updated' : ''), + message: msg, }); + }; + + if (failure.likelyIrrelevant) { + pushMessage( + 'Failure is likely irrelevant' + + (updateGithub ? ', so an issue was not created or updated' : '') + ); continue; } @@ -97,30 +103,18 @@ export function runFailedTestsReporterCli() { if (existingIssue) { const newFailureCount = await updateFailureIssue(buildUrl, existingIssue, githubApi); const url = existingIssue.html_url; - const message = - `Test has failed ${newFailureCount - 1} times on tracked branches: ${url}` + - (updateGithub - ? `. Updated existing issue: ${url} (fail count: ${newFailureCount})` - : ''); - - messages.push({ - classname: failure.classname, - name: failure.name, - message, - }); + pushMessage(`Test has failed ${newFailureCount - 1} times on tracked branches: ${url}`); + if (updateGithub) { + pushMessage(`Updated existing issue: ${url} (fail count: ${newFailureCount})`); + } continue; } const newIssueUrl = await createFailureIssue(buildUrl, failure, githubApi); - const message = - `Test has not failed recently on tracked branches` + - (updateGithub ? `Created new issue: ${newIssueUrl}` : ''); - - messages.push({ - classname: failure.classname, - name: failure.name, - message, - }); + pushMessage('Test has not failed recently on tracked branches'); + if (updateGithub) { + pushMessage(`Created new issue: ${newIssueUrl}`); + } } // mutates report to include messages and writes updated report to disk diff --git a/packages/kbn-test/src/failed_tests_reporter/test_report.ts b/packages/kbn-test/src/failed_tests_reporter/test_report.ts index 644a4cc9fd5a7..6b759ef1d4c62 100644 --- a/packages/kbn-test/src/failed_tests_reporter/test_report.ts +++ b/packages/kbn-test/src/failed_tests_reporter/test_report.ts @@ -58,13 +58,15 @@ export interface TestCase { classname: string; /* number of seconds this test took */ time: string; + /* optional JSON encoded metadata */ + 'metadata-json'?: string; }; /* contents of system-out elements */ - 'system-out'?: string[]; + 'system-out'?: Array; /* contents of failure elements */ failure?: Array; /* contents of skipped elements */ - skipped?: string[]; + skipped?: Array; } export interface FailedTestCase extends TestCase { @@ -82,19 +84,23 @@ export async function readTestReport(testReportPath: string) { return await parseTestReport(await readAsync(testReportPath, 'utf8')); } -export function* makeFailedTestCaseIter(report: TestReport) { - // Grab the failures. Reporters may report multiple testsuites in a single file. +export function* makeTestCaseIter(report: TestReport) { + // Reporters may report multiple testsuites in a single file. const testSuites = 'testsuites' in report ? report.testsuites.testsuite : [report.testsuite]; for (const testSuite of testSuites) { for (const testCase of testSuite.testcase) { - const { failure } = testCase; - - if (!failure) { - continue; - } + yield testCase; + } + } +} - yield testCase as FailedTestCase; +export function* makeFailedTestCaseIter(report: TestReport) { + for (const testCase of makeTestCaseIter(report)) { + if (!testCase.failure) { + continue; } + + yield testCase as FailedTestCase; } } diff --git a/packages/kbn-test/src/functional_test_runner/functional_test_runner.ts b/packages/kbn-test/src/functional_test_runner/functional_test_runner.ts index fcba9691b1772..e566a9a4af262 100644 --- a/packages/kbn-test/src/functional_test_runner/functional_test_runner.ts +++ b/packages/kbn-test/src/functional_test_runner/functional_test_runner.ts @@ -23,6 +23,7 @@ import { Suite, Test } from './fake_mocha_types'; import { Lifecycle, LifecyclePhase, + FailureMetadata, readConfigFile, ProviderCollection, readProviderSpec, @@ -33,6 +34,7 @@ import { export class FunctionalTestRunner { public readonly lifecycle = new Lifecycle(); + public readonly failureMetadata = new FailureMetadata(this.lifecycle); private closed = false; constructor( @@ -114,6 +116,7 @@ export class FunctionalTestRunner { const coreProviders = readProviderSpec('Service', { lifecycle: () => this.lifecycle, log: () => this.log, + failureMetadata: () => this.failureMetadata, config: () => config, }); diff --git a/packages/kbn-test/src/functional_test_runner/lib/failure_metadata.test.ts b/packages/kbn-test/src/functional_test_runner/lib/failure_metadata.test.ts new file mode 100644 index 0000000000000..7ae46ef6fac1e --- /dev/null +++ b/packages/kbn-test/src/functional_test_runner/lib/failure_metadata.test.ts @@ -0,0 +1,71 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Lifecycle } from './lifecycle'; +import { FailureMetadata } from './failure_metadata'; + +it('collects metadata for the current test', async () => { + const lifecycle = new Lifecycle(); + const failureMetadata = new FailureMetadata(lifecycle); + + const test1 = {}; + await lifecycle.beforeEachTest.trigger(test1); + failureMetadata.add({ foo: 'bar' }); + + expect(failureMetadata.get(test1)).toMatchInlineSnapshot(` + Object { + "foo": "bar", + } + `); + + const test2 = {}; + await lifecycle.beforeEachTest.trigger(test2); + failureMetadata.add({ test: 2 }); + + expect(failureMetadata.get(test1)).toMatchInlineSnapshot(` + Object { + "foo": "bar", + } + `); + expect(failureMetadata.get(test2)).toMatchInlineSnapshot(` + Object { + "test": 2, + } + `); +}); + +it('adds messages to the messages state', () => { + const lifecycle = new Lifecycle(); + const failureMetadata = new FailureMetadata(lifecycle); + + const test1 = {}; + lifecycle.beforeEachTest.trigger(test1); + failureMetadata.addMessages(['foo', 'bar']); + failureMetadata.addMessages(['baz']); + + expect(failureMetadata.get(test1)).toMatchInlineSnapshot(` + Object { + "messages": Array [ + "foo", + "bar", + "baz", + ], + } + `); +}); diff --git a/packages/kbn-test/src/functional_test_runner/lib/failure_metadata.ts b/packages/kbn-test/src/functional_test_runner/lib/failure_metadata.ts new file mode 100644 index 0000000000000..9dc58d5b0b21f --- /dev/null +++ b/packages/kbn-test/src/functional_test_runner/lib/failure_metadata.ts @@ -0,0 +1,104 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import Path from 'path'; + +import { REPO_ROOT } from '@kbn/dev-utils'; + +import { Lifecycle } from './lifecycle'; + +interface Metadata { + [key: string]: unknown; +} + +export class FailureMetadata { + // mocha's global types mean we can't import Mocha or it will override the global jest types.............. + private currentTest?: any; + private readonly allMetadata = new Map(); + + constructor(lifecycle: Lifecycle) { + if (!process.env.GCS_UPLOAD_PREFIX && process.env.CI) { + throw new Error( + 'GCS_UPLOAD_PREFIX environment variable is not set and must always be set on CI' + ); + } + + lifecycle.beforeEachTest.add(test => { + this.currentTest = test; + }); + } + + add(metadata: Metadata | ((current: Metadata) => Metadata)) { + if (!this.currentTest) { + throw new Error('no current test to associate metadata with'); + } + + const current = this.allMetadata.get(this.currentTest); + this.allMetadata.set(this.currentTest, { + ...current, + ...(typeof metadata === 'function' ? metadata(current || {}) : metadata), + }); + } + + addMessages(messages: string[]) { + this.add(current => ({ + messages: [...(Array.isArray(current.messages) ? current.messages : []), ...messages], + })); + } + + /** + * @param name Name to label the URL with + * @param repoPath absolute path, within the repo, that will be uploaded + */ + addScreenshot(name: string, repoPath: string) { + const prefix = process.env.GCS_UPLOAD_PREFIX; + + if (!prefix) { + return; + } + + const slash = prefix.endsWith('/') ? '' : '/'; + const urlPath = Path.relative(REPO_ROOT, repoPath) + .split(Path.sep) + .map(c => encodeURIComponent(c)) + .join('/'); + + if (urlPath.startsWith('..')) { + throw new Error( + `Only call addUploadLink() with paths that are within the repo root, received ${repoPath} and repo root is ${REPO_ROOT}` + ); + } + + const url = `https://storage.googleapis.com/${prefix}${slash}${urlPath}`; + const screenshot = { + name, + url, + }; + + this.add(current => ({ + screenshots: [...(Array.isArray(current.screenshots) ? current.screenshots : []), screenshot], + })); + + return screenshot; + } + + get(test: any) { + return this.allMetadata.get(test); + } +} diff --git a/packages/kbn-test/src/functional_test_runner/lib/index.ts b/packages/kbn-test/src/functional_test_runner/lib/index.ts index 2d354938d7648..8940eccad503a 100644 --- a/packages/kbn-test/src/functional_test_runner/lib/index.ts +++ b/packages/kbn-test/src/functional_test_runner/lib/index.ts @@ -22,3 +22,4 @@ export { LifecyclePhase } from './lifecycle_phase'; export { readConfigFile, Config } from './config'; export { readProviderSpec, ProviderCollection, Provider } from './providers'; export { runTests, setupMocha } from './mocha'; +export { FailureMetadata } from './failure_metadata'; diff --git a/packages/kbn-test/src/functional_test_runner/lib/lifecycle_event.ts b/packages/kbn-test/src/functional_test_runner/lib/lifecycle_event.ts new file mode 100644 index 0000000000000..22b7363454361 --- /dev/null +++ b/packages/kbn-test/src/functional_test_runner/lib/lifecycle_event.ts @@ -0,0 +1,68 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import * as Rx from 'rxjs'; + +export type GetArgsType> = T extends LifecycleEvent + ? X + : never; + +export class LifecycleEvent { + private readonly handlers: Array<(...args: Args) => Promise | void> = []; + + private readonly beforeSubj = this.options.singular + ? new Rx.BehaviorSubject(undefined) + : new Rx.Subject(); + public readonly before$ = this.beforeSubj.asObservable(); + + private readonly afterSubj = this.options.singular + ? new Rx.BehaviorSubject(undefined) + : new Rx.Subject(); + public readonly after$ = this.afterSubj.asObservable(); + + constructor( + private readonly options: { + singular?: boolean; + } = {} + ) {} + + public add(fn: (...args: Args) => Promise | void) { + this.handlers.push(fn); + } + + public async trigger(...args: Args) { + if (this.beforeSubj.isStopped) { + throw new Error(`singular lifecycle event can only be triggered once`); + } + + this.beforeSubj.next(undefined); + if (this.options.singular) { + this.beforeSubj.complete(); + } + + try { + await Promise.all(this.handlers.map(async fn => await fn(...args))); + } finally { + this.afterSubj.next(undefined); + if (this.options.singular) { + this.afterSubj.complete(); + } + } + } +} diff --git a/packages/kbn-test/src/functional_test_runner/lib/mocha/reporter/reporter.js b/packages/kbn-test/src/functional_test_runner/lib/mocha/reporter/reporter.js index ea697b096ce99..0e8c1bc121e15 100644 --- a/packages/kbn-test/src/functional_test_runner/lib/mocha/reporter/reporter.js +++ b/packages/kbn-test/src/functional_test_runner/lib/mocha/reporter/reporter.js @@ -32,6 +32,7 @@ import { writeEpilogue } from './write_epilogue'; export function MochaReporterProvider({ getService }) { const log = getService('log'); const config = getService('config'); + const failureMetadata = getService('failureMetadata'); let originalLogWriters; let reporterCaptureStartTime; @@ -53,6 +54,7 @@ export function MochaReporterProvider({ getService }) { if (config.get('junit.enabled') && config.get('junit.reportName')) { setupJUnitReportGeneration(runner, { reportName: config.get('junit.reportName'), + getTestMetadata: t => failureMetadata.get(t), }); } } diff --git a/packages/kbn-test/src/mocha/__tests__/junit_report_generation.js b/packages/kbn-test/src/mocha/__tests__/junit_report_generation.js index 1cb53ea0ca1c5..b27f2fcf47a5a 100644 --- a/packages/kbn-test/src/mocha/__tests__/junit_report_generation.js +++ b/packages/kbn-test/src/mocha/__tests__/junit_report_generation.js @@ -98,6 +98,7 @@ describe('dev/mocha/junit report generation', () => { classname: sharedClassname, name: 'SUITE works', time: testPass.$.time, + 'metadata-json': '{}', }, 'system-out': testPass['system-out'], }); @@ -109,6 +110,7 @@ describe('dev/mocha/junit report generation', () => { classname: sharedClassname, name: 'SUITE fails', time: testFail.$.time, + 'metadata-json': '{}', }, 'system-out': testFail['system-out'], failure: [testFail.failure[0]], @@ -124,6 +126,7 @@ describe('dev/mocha/junit report generation', () => { classname: sharedClassname, name: 'SUITE SUB_SUITE "before each" hook: fail hook for "never runs"', time: beforeEachFail.$.time, + 'metadata-json': '{}', }, 'system-out': testFail['system-out'], failure: [beforeEachFail.failure[0]], @@ -133,6 +136,7 @@ describe('dev/mocha/junit report generation', () => { $: { classname: sharedClassname, name: 'SUITE SUB_SUITE never runs', + 'metadata-json': '{}', }, 'system-out': testFail['system-out'], skipped: [''], diff --git a/packages/kbn-test/src/mocha/junit_report_generation.js b/packages/kbn-test/src/mocha/junit_report_generation.js index 51601fab12e53..80f63b2dc6595 100644 --- a/packages/kbn-test/src/mocha/junit_report_generation.js +++ b/packages/kbn-test/src/mocha/junit_report_generation.js @@ -32,6 +32,7 @@ export function setupJUnitReportGeneration(runner, options = {}) { const { reportName = 'Unnamed Mocha Tests', rootDirectory = dirname(require.resolve('../../../../package.json')), + getTestMetadata = () => ({}), } = options; const stats = {}; @@ -118,6 +119,7 @@ export function setupJUnitReportGeneration(runner, options = {}) { name: getFullTitle(node), classname: `${reportName}.${getPath(node).replace(/\./g, '·')}`, time: getDuration(node), + 'metadata-json': JSON.stringify(getTestMetadata(node) || {}), }); } diff --git a/packages/kbn-test/types/ftr.d.ts b/packages/kbn-test/types/ftr.d.ts index e917ed63ca5d3..8beecab88878d 100644 --- a/packages/kbn-test/types/ftr.d.ts +++ b/packages/kbn-test/types/ftr.d.ts @@ -18,9 +18,9 @@ */ import { ToolingLog } from '@kbn/dev-utils'; -import { Config, Lifecycle } from '../src/functional_test_runner/lib'; +import { Config, Lifecycle, FailureMetadata } from '../src/functional_test_runner/lib'; -export { Lifecycle, Config }; +export { Lifecycle, Config, FailureMetadata }; interface AsyncInstance { /** @@ -61,7 +61,7 @@ export interface GenericFtrProviderContext< * Determine if a service is avaliable * @param serviceName */ - hasService(serviceName: 'config' | 'log' | 'lifecycle'): true; + hasService(serviceName: 'config' | 'log' | 'lifecycle' | 'failureMetadata'): true; hasService(serviceName: K): serviceName is K; hasService(serviceName: string): serviceName is Extract; @@ -73,6 +73,7 @@ export interface GenericFtrProviderContext< getService(serviceName: 'config'): Config; getService(serviceName: 'log'): ToolingLog; getService(serviceName: 'lifecycle'): Lifecycle; + getService(serviceName: 'failureMetadata'): FailureMetadata; getService(serviceName: T): ServiceMap[T]; /** diff --git a/test/functional/services/screenshots.ts b/test/functional/services/screenshots.ts index ddafa211ece7f..9e673fe919a74 100644 --- a/test/functional/services/screenshots.ts +++ b/test/functional/services/screenshots.ts @@ -22,6 +22,7 @@ import { writeFile, readFileSync, mkdir } from 'fs'; import { promisify } from 'util'; import del from 'del'; + import { comparePngs } from './lib/compare_pngs'; import { FtrProviderContext } from '../ftr_provider_context'; import { WebElementWrapper } from './lib/web_element_wrapper'; @@ -32,6 +33,7 @@ const writeFileAsync = promisify(writeFile); export async function ScreenshotsProvider({ getService }: FtrProviderContext) { const log = getService('log'); const config = getService('config'); + const failureMetadata = getService('failureMetadata'); const browser = getService('browser'); const SESSION_DIRECTORY = resolve(config.get('screenshots.directory'), 'session'); @@ -68,11 +70,15 @@ export async function ScreenshotsProvider({ getService }: FtrProviderContext) { } async take(name: string, el?: WebElementWrapper) { - return await this._take(resolve(SESSION_DIRECTORY, `${name}.png`), el); + const path = resolve(SESSION_DIRECTORY, `${name}.png`); + await this._take(path, el); + failureMetadata.addScreenshot(name, path); } async takeForFailure(name: string, el?: WebElementWrapper) { - await this._take(resolve(FAILURE_DIRECTORY, `${name}.png`), el); + const path = resolve(FAILURE_DIRECTORY, `${name}.png`); + await this._take(path, el); + failureMetadata.addScreenshot(`failure[${name}]`, path); } async _take(path: string, el?: WebElementWrapper) { diff --git a/vars/kibanaPipeline.groovy b/vars/kibanaPipeline.groovy index 77907a07addd1..dbb33f2766dac 100644 --- a/vars/kibanaPipeline.groovy +++ b/vars/kibanaPipeline.groovy @@ -1,47 +1,45 @@ -def withWorkers(name, preWorkerClosure = {}, workerClosures = [:]) { +def withWorkers(machineName, preWorkerClosure = {}, workerClosures = [:]) { return { jobRunner('tests-xl', true) { - try { - doSetup() - preWorkerClosure() - - def nextWorker = 1 - def worker = { workerClosure -> - def workerNumber = nextWorker - nextWorker++ - - return { - // This delay helps smooth out CPU load caused by ES/Kibana instances starting up at the same time - def delay = (workerNumber-1)*20 - sleep(delay) - - workerClosure(workerNumber) + withGcsArtifactUpload(machineName, { + try { + doSetup() + preWorkerClosure() + + def nextWorker = 1 + def worker = { workerClosure -> + def workerNumber = nextWorker + nextWorker++ + + return { + // This delay helps smooth out CPU load caused by ES/Kibana instances starting up at the same time + def delay = (workerNumber-1)*20 + sleep(delay) + + workerClosure(workerNumber) + } } - } - def workers = [:] - workerClosures.each { workerName, workerClosure -> - workers[workerName] = worker(workerClosure) - } - - parallel(workers) - } finally { - catchError { - uploadAllGcsArtifacts(name) - } + def workers = [:] + workerClosures.each { workerName, workerClosure -> + workers[workerName] = worker(workerClosure) + } - catchError { - runErrorReporter() - } + parallel(workers) + } finally { + catchError { + runErrorReporter() + } - catchError { - runbld.junit() - } + catchError { + runbld.junit() + } - catchError { - publishJunit() + catchError { + publishJunit() + } } - } + }) } } } @@ -96,19 +94,19 @@ def legacyJobRunner(name) { "JOB=${name}", ]) { jobRunner('linux && immutable', false) { - try { - runbld('.ci/run.sh', "Execute ${name}", true) - } finally { - catchError { - uploadAllGcsArtifacts(name) - } - catchError { - runErrorReporter() + withGcsArtifactUpload(name, { + try { + runbld('.ci/run.sh', "Execute ${name}", true) + } finally { + catchError { + runErrorReporter() + } + + catchError { + publishJunit() + } } - catchError { - publishJunit() - } - } + }) } } } @@ -171,19 +169,18 @@ def jobRunner(label, useRamDisk, closure) { // TODO what should happen if GCS, Junit, or email publishing fails? Unstable build? Failed build? -def uploadGcsArtifact(workerName, pattern) { - def storageLocation = "gs://kibana-ci-artifacts/jobs/${env.JOB_NAME}/${BUILD_NUMBER}/${workerName}" // TODO - +def uploadGcsArtifact(uploadPrefix, pattern) { googleStorageUpload( credentialsId: 'kibana-ci-gcs-plugin', - bucket: storageLocation, + bucket: "gs://${uploadPrefix}", pattern: pattern, sharedPublicly: true, showInline: true, ) } -def uploadAllGcsArtifacts(workerName) { +def withGcsArtifactUpload(workerName, closure) { + def uploadPrefix = "kibana-ci-artifacts/jobs/${env.JOB_NAME}/${BUILD_NUMBER}/${workerName}" def ARTIFACT_PATTERNS = [ 'target/kibana-*', 'target/junit/**/*', @@ -194,9 +191,19 @@ def uploadAllGcsArtifacts(workerName) { 'x-pack/test/functional/apps/reporting/reports/session/*.pdf', ] - ARTIFACT_PATTERNS.each { pattern -> - uploadGcsArtifact(workerName, pattern) - } + withEnv([ + "GCS_UPLOAD_PREFIX=${uploadPrefix}" + ], { + try { + closure() + } finally { + catchError { + ARTIFACT_PATTERNS.each { pattern -> + uploadGcsArtifact(uploadPrefix, pattern) + } + } + } + }) } def publishJunit() { From ab1fe3f14e791957c865c7d6b5dff3d2ebf4a8dc Mon Sep 17 00:00:00 2001 From: Spencer Date: Wed, 11 Dec 2019 09:50:03 -0700 Subject: [PATCH 10/79] [kbnClient] Retry uiSettings.replace() calls up to 5 times (#52601) * [kbn/dev-utils] target ES2019 to transpile ?? * Retry uiSettings.replace() calls up to 5 times * share logic for selecting junit report name to ensure they are unique * convert to junit report path helper --- .../src/kbn_client/kbn_client_requester.ts | 70 ++++++++++--------- .../src/kbn_client/kbn_client_ui_settings.ts | 30 ++++---- packages/kbn-dev-utils/tsconfig.json | 1 + packages/kbn-test/src/index.ts | 2 + packages/kbn-test/src/junit_report_path.ts | 32 +++++++++ .../__tests__/junit_report_generation.js | 13 +--- .../src/mocha/junit_report_generation.js | 11 +-- .../integration_tests/junit_reporter.test.js | 3 +- src/dev/jest/junit_reporter.js | 10 +-- tasks/config/karma.js | 5 +- 10 files changed, 99 insertions(+), 78 deletions(-) create mode 100644 packages/kbn-test/src/junit_report_path.ts diff --git a/packages/kbn-dev-utils/src/kbn_client/kbn_client_requester.ts b/packages/kbn-dev-utils/src/kbn_client/kbn_client_requester.ts index 25962c91a896d..4244006f4a3a3 100644 --- a/packages/kbn-dev-utils/src/kbn_client/kbn_client_requester.ts +++ b/packages/kbn-dev-utils/src/kbn_client/kbn_client_requester.ts @@ -62,8 +62,7 @@ export interface ReqOptions { query?: Record; method: 'GET' | 'POST' | 'PUT' | 'DELETE'; body?: any; - attempt?: number; - maxAttempts?: number; + retries?: number; } const delay = (ms: number) => @@ -87,44 +86,47 @@ export class KbnClientRequester { async request(options: ReqOptions): Promise { const url = Url.resolve(this.pickUrl(), options.path); const description = options.description || `${options.method} ${url}`; - const attempt = options.attempt === undefined ? 1 : options.attempt; - const maxAttempts = - options.maxAttempts === undefined ? DEFAULT_MAX_ATTEMPTS : options.maxAttempts; - - try { - const response = await Axios.request({ - method: options.method, - url, - data: options.body, - params: options.query, - headers: { - 'kbn-xsrf': 'kbn-client', - }, - }); - - return response.data; - } catch (error) { - let retryErrorMsg: string | undefined; - if (isAxiosRequestError(error)) { - retryErrorMsg = `[${description}] request failed (attempt=${attempt})`; - } else if (isConcliftOnGetError(error)) { - retryErrorMsg = `Conflict on GET (path=${options.path}, attempt=${attempt})`; - } + let attempt = 0; + const maxAttempts = options.retries ?? DEFAULT_MAX_ATTEMPTS; + + while (true) { + attempt += 1; + + try { + const response = await Axios.request({ + method: options.method, + url, + data: options.body, + params: options.query, + headers: { + 'kbn-xsrf': 'kbn-client', + }, + }); + + return response.data; + } catch (error) { + const conflictOnGet = isConcliftOnGetError(error); + const requestedRetries = options.retries !== undefined; + const failedToGetResponse = isAxiosRequestError(error); + + let errorMessage; + if (conflictOnGet) { + errorMessage = `Conflict on GET (path=${options.path}, attempt=${attempt}/${maxAttempts})`; + this.log.error(errorMessage); + } else if (requestedRetries || failedToGetResponse) { + errorMessage = `[${description}] request failed (attempt=${attempt}/${maxAttempts})`; + this.log.error(errorMessage); + } else { + throw error; + } - if (retryErrorMsg) { if (attempt < maxAttempts) { - this.log.error(retryErrorMsg); await delay(1000 * attempt); - return await this.request({ - ...options, - attempt: attempt + 1, - }); + continue; } - throw new Error(retryErrorMsg + ' and ran out of retries'); + throw new Error(`${errorMessage} -- and ran out of retries`); } - - throw error; } } } diff --git a/packages/kbn-dev-utils/src/kbn_client/kbn_client_ui_settings.ts b/packages/kbn-dev-utils/src/kbn_client/kbn_client_ui_settings.ts index 03033bc5c2ccc..ad01dea624c3c 100644 --- a/packages/kbn-dev-utils/src/kbn_client/kbn_client_ui_settings.ts +++ b/packages/kbn-dev-utils/src/kbn_client/kbn_client_ui_settings.ts @@ -40,7 +40,7 @@ export class KbnClientUiSettings { async get(setting: string) { const all = await this.getAll(); - const value = all.settings[setting] ? all.settings[setting].userValue : undefined; + const value = all[setting]?.userValue; this.log.verbose('uiSettings.value: %j', value); return value; @@ -68,24 +68,24 @@ export class KbnClientUiSettings { * with some defaults */ async replace(doc: UiSettingValues) { - const all = await this.getAll(); - for (const [name, { isOverridden }] of Object.entries(all.settings)) { - if (!isOverridden) { - await this.unset(name); + this.log.debug('replacing kibana config doc: %j', doc); + + const changes: Record = { + ...this.defaults, + ...doc, + }; + + for (const [name, { isOverridden }] of Object.entries(await this.getAll())) { + if (!isOverridden && !changes.hasOwnProperty(name)) { + changes[name] = null; } } - this.log.debug('replacing kibana config doc: %j', doc); - await this.requester.request({ method: 'POST', path: '/api/kibana/settings', - body: { - changes: { - ...this.defaults, - ...doc, - }, - }, + body: { changes }, + retries: 5, }); } @@ -105,9 +105,11 @@ export class KbnClientUiSettings { } private async getAll() { - return await this.requester.request({ + const resp = await this.requester.request({ path: '/api/kibana/settings', method: 'GET', }); + + return resp.settings; } } diff --git a/packages/kbn-dev-utils/tsconfig.json b/packages/kbn-dev-utils/tsconfig.json index 40a3bd475f1c1..4c519a609d86f 100644 --- a/packages/kbn-dev-utils/tsconfig.json +++ b/packages/kbn-dev-utils/tsconfig.json @@ -2,6 +2,7 @@ "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "target", + "target": "ES2019", "declaration": true }, "include": [ diff --git a/packages/kbn-test/src/index.ts b/packages/kbn-test/src/index.ts index 62739fd37030f..06a83cdd8b1dc 100644 --- a/packages/kbn-test/src/index.ts +++ b/packages/kbn-test/src/index.ts @@ -49,3 +49,5 @@ export { } from './mocha'; export { runFailedTestsReporterCli } from './failed_tests_reporter'; + +export { makeJunitReportPath } from './junit_report_path'; diff --git a/packages/kbn-test/src/junit_report_path.ts b/packages/kbn-test/src/junit_report_path.ts new file mode 100644 index 0000000000000..11eaf3d2b14a5 --- /dev/null +++ b/packages/kbn-test/src/junit_report_path.ts @@ -0,0 +1,32 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { resolve } from 'path'; + +const job = process.env.JOB ? `job-${process.env.JOB}-` : ''; +const num = process.env.CI_WORKER_NUMBER ? `worker-${process.env.CI_WORKER_NUMBER}-` : ''; + +export function makeJunitReportPath(rootDirectory: string, reportName: string) { + return resolve( + rootDirectory, + 'target/junit', + process.env.JOB || '.', + `TEST-${job}${num}${reportName}.xml` + ); +} diff --git a/packages/kbn-test/src/mocha/__tests__/junit_report_generation.js b/packages/kbn-test/src/mocha/__tests__/junit_report_generation.js index b27f2fcf47a5a..7472e271bd1e9 100644 --- a/packages/kbn-test/src/mocha/__tests__/junit_report_generation.js +++ b/packages/kbn-test/src/mocha/__tests__/junit_report_generation.js @@ -25,6 +25,7 @@ import { parseString } from 'xml2js'; import del from 'del'; import Mocha from 'mocha'; import expect from '@kbn/expect'; +import { makeJunitReportPath } from '@kbn/test'; import { setupJUnitReportGeneration } from '../junit_report_generation'; @@ -50,17 +51,7 @@ describe('dev/mocha/junit report generation', () => { mocha.addFile(resolve(PROJECT_DIR, 'test.js')); await new Promise(resolve => mocha.run(resolve)); const report = await fcb(cb => - parseString( - readFileSync( - resolve( - PROJECT_DIR, - 'target/junit', - process.env.JOB || '.', - `TEST-${process.env.JOB ? process.env.JOB + '-' : ''}test.xml` - ) - ), - cb - ) + parseString(readFileSync(makeJunitReportPath(PROJECT_DIR, 'test')), cb) ); // test case results are wrapped in diff --git a/packages/kbn-test/src/mocha/junit_report_generation.js b/packages/kbn-test/src/mocha/junit_report_generation.js index 80f63b2dc6595..95e84117106a4 100644 --- a/packages/kbn-test/src/mocha/junit_report_generation.js +++ b/packages/kbn-test/src/mocha/junit_report_generation.js @@ -17,11 +17,12 @@ * under the License. */ -import { resolve, dirname, relative } from 'path'; +import { dirname, relative } from 'path'; import { writeFileSync, mkdirSync } from 'fs'; import { inspect } from 'util'; import xmlBuilder from 'xmlbuilder'; +import { makeJunitReportPath } from '@kbn/test'; import { getSnapshotOfRunnableLogs } from './log_cache'; import { escapeCdata } from '../'; @@ -137,13 +138,7 @@ export function setupJUnitReportGeneration(runner, options = {}) { } }); - const reportPath = resolve( - rootDirectory, - 'target/junit', - process.env.JOB || '.', - `TEST-${process.env.JOB ? process.env.JOB + '-' : ''}${reportName}.xml` - ); - + const reportPath = makeJunitReportPath(rootDirectory, reportName); const reportXML = builder.end(); mkdirSync(dirname(reportPath), { recursive: true }); writeFileSync(reportPath, reportXML, 'utf8'); diff --git a/src/dev/jest/integration_tests/junit_reporter.test.js b/src/dev/jest/integration_tests/junit_reporter.test.js index ed5d73cd87c40..2abfa5648dcca 100644 --- a/src/dev/jest/integration_tests/junit_reporter.test.js +++ b/src/dev/jest/integration_tests/junit_reporter.test.js @@ -24,12 +24,13 @@ import { readFileSync } from 'fs'; import del from 'del'; import execa from 'execa'; import xml2js from 'xml2js'; +import { makeJunitReportPath } from '@kbn/test'; const MINUTE = 1000 * 60; const ROOT_DIR = resolve(__dirname, '../../../../'); const FIXTURE_DIR = resolve(__dirname, '__fixtures__'); const TARGET_DIR = resolve(FIXTURE_DIR, 'target'); -const XML_PATH = resolve(TARGET_DIR, 'junit', process.env.JOB || '.', `TEST-${process.env.JOB ? process.env.JOB + '-' : ''}Jest Tests.xml`); +const XML_PATH = makeJunitReportPath(FIXTURE_DIR, 'Jest Tests'); afterAll(async () => { await del(TARGET_DIR); diff --git a/src/dev/jest/junit_reporter.js b/src/dev/jest/junit_reporter.js index 7f51326ee46bb..0f8003f4ed6a1 100644 --- a/src/dev/jest/junit_reporter.js +++ b/src/dev/jest/junit_reporter.js @@ -22,7 +22,7 @@ import { writeFileSync, mkdirSync } from 'fs'; import xmlBuilder from 'xmlbuilder'; -import { escapeCdata } from '@kbn/test'; +import { escapeCdata, makeJunitReportPath } from '@kbn/test'; const ROOT_DIR = dirname(require.resolve('../../../package.json')); @@ -102,13 +102,7 @@ export default class JestJUnitReporter { }); }); - const reportPath = resolve( - rootDirectory, - 'target/junit', - process.env.JOB || '.', - `TEST-${process.env.JOB ? process.env.JOB + '-' : ''}${reportName}.xml` - ); - + const reportPath = makeJunitReportPath(rootDirectory, reportName); const reportXML = root.end(); mkdirSync(dirname(reportPath), { recursive: true }); writeFileSync(reportPath, reportXML, 'utf8'); diff --git a/tasks/config/karma.js b/tasks/config/karma.js index 25723677390bd..23371e52dd9e1 100644 --- a/tasks/config/karma.js +++ b/tasks/config/karma.js @@ -17,8 +17,9 @@ * under the License. */ -import { resolve, dirname } from 'path'; +import { dirname } from 'path'; import { times } from 'lodash'; +import { makeJunitReportPath } from '@kbn/test'; const TOTAL_CI_SHARDS = 4; const ROOT = dirname(require.resolve('../../package.json')); @@ -79,7 +80,7 @@ module.exports = function (grunt) { reporters: pickReporters(), junitReporter: { - outputFile: resolve(ROOT, 'target/junit', process.env.JOB || '.', `TEST-${process.env.JOB ? process.env.JOB + '-' : ''}karma.xml`), + outputFile: makeJunitReportPath(ROOT, 'karma'), useBrowserName: false, nameFormatter: (_, result) => [...result.suite, result.description].join(' '), classNameFormatter: (_, result) => { From a91e53f18f692ad1f89f35cf289749da80f71773 Mon Sep 17 00:00:00 2001 From: Josh Dover Date: Wed, 11 Dec 2019 10:53:17 -0600 Subject: [PATCH 11/79] Add asResponse option to HttpService methods (#52434) --- .../public/kibana-plugin-public.httpbody.md | 12 - .../kibana-plugin-public.httperrorresponse.md | 2 +- ...ugin-public.httpfetchoptions.asresponse.md | 13 + .../kibana-plugin-public.httpfetchoptions.md | 1 + .../kibana-plugin-public.httphandler.md | 6 +- ...-plugin-public.httpinterceptor.response.md | 6 +- ...in-public.httpinterceptor.responseerror.md | 4 +- .../kibana-plugin-public.httpresponse.md | 19 -- ...bana-plugin-public.httpresponse.request.md | 11 - ...kibana-plugin-public.ihttpresponse.body.md | 13 + .../kibana-plugin-public.ihttpresponse.md | 21 ++ ...ana-plugin-public.ihttpresponse.request.md | 13 + ...na-plugin-public.ihttpresponse.response.md | 13 + ....ihttpresponseinterceptoroverrides.body.md | 13 + ...ublic.ihttpresponseinterceptoroverrides.md | 21 ++ ...tpresponseinterceptoroverrides.response.md | 13 + ...gin-public.interceptedhttpresponse.body.md | 11 - ...a-plugin-public.interceptedhttpresponse.md | 20 -- ...public.interceptedhttpresponse.response.md | 11 - .../core/public/kibana-plugin-public.md | 7 +- .../capabilities/capabilities_service.tsx | 2 +- src/core/public/http/fetch.ts | 155 ++++++++++++ src/core/public/http/http_service.test.ts | 30 ++- src/core/public/http/http_setup.ts | 232 +----------------- src/core/public/http/intercept.ts | 134 ++++++++++ src/core/public/http/response.ts | 40 +++ src/core/public/http/types.ts | 52 ++-- src/core/public/index.ts | 5 +- src/core/public/public.api.md | 40 +-- .../components/share_context_menu.test.tsx | 2 +- .../components/url_panel_content.test.tsx | 2 +- .../public/services/fetch_top_nodes.test.ts | 4 +- .../indexpattern_plugin/datapanel.test.tsx | 12 +- .../public/indexpattern_plugin/loader.test.ts | 3 +- .../session_timeout_http_interceptor.ts | 9 +- 35 files changed, 570 insertions(+), 382 deletions(-) delete mode 100644 docs/development/core/public/kibana-plugin-public.httpbody.md create mode 100644 docs/development/core/public/kibana-plugin-public.httpfetchoptions.asresponse.md delete mode 100644 docs/development/core/public/kibana-plugin-public.httpresponse.md delete mode 100644 docs/development/core/public/kibana-plugin-public.httpresponse.request.md create mode 100644 docs/development/core/public/kibana-plugin-public.ihttpresponse.body.md create mode 100644 docs/development/core/public/kibana-plugin-public.ihttpresponse.md create mode 100644 docs/development/core/public/kibana-plugin-public.ihttpresponse.request.md create mode 100644 docs/development/core/public/kibana-plugin-public.ihttpresponse.response.md create mode 100644 docs/development/core/public/kibana-plugin-public.ihttpresponseinterceptoroverrides.body.md create mode 100644 docs/development/core/public/kibana-plugin-public.ihttpresponseinterceptoroverrides.md create mode 100644 docs/development/core/public/kibana-plugin-public.ihttpresponseinterceptoroverrides.response.md delete mode 100644 docs/development/core/public/kibana-plugin-public.interceptedhttpresponse.body.md delete mode 100644 docs/development/core/public/kibana-plugin-public.interceptedhttpresponse.md delete mode 100644 docs/development/core/public/kibana-plugin-public.interceptedhttpresponse.response.md create mode 100644 src/core/public/http/fetch.ts create mode 100644 src/core/public/http/intercept.ts create mode 100644 src/core/public/http/response.ts diff --git a/docs/development/core/public/kibana-plugin-public.httpbody.md b/docs/development/core/public/kibana-plugin-public.httpbody.md deleted file mode 100644 index ab31f28b8dc38..0000000000000 --- a/docs/development/core/public/kibana-plugin-public.httpbody.md +++ /dev/null @@ -1,12 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpBody](./kibana-plugin-public.httpbody.md) - -## HttpBody type - - -Signature: - -```typescript -export declare type HttpBody = BodyInit | null | any; -``` diff --git a/docs/development/core/public/kibana-plugin-public.httperrorresponse.md b/docs/development/core/public/kibana-plugin-public.httperrorresponse.md index aa669df796a09..5b1ee898a444d 100644 --- a/docs/development/core/public/kibana-plugin-public.httperrorresponse.md +++ b/docs/development/core/public/kibana-plugin-public.httperrorresponse.md @@ -8,7 +8,7 @@ Signature: ```typescript -export interface HttpErrorResponse extends HttpResponse +export interface HttpErrorResponse extends IHttpResponse ``` ## Properties diff --git a/docs/development/core/public/kibana-plugin-public.httpfetchoptions.asresponse.md b/docs/development/core/public/kibana-plugin-public.httpfetchoptions.asresponse.md new file mode 100644 index 0000000000000..250cf83309b3c --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.httpfetchoptions.asresponse.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpFetchOptions](./kibana-plugin-public.httpfetchoptions.md) > [asResponse](./kibana-plugin-public.httpfetchoptions.asresponse.md) + +## HttpFetchOptions.asResponse property + +When `true` the return type of [HttpHandler](./kibana-plugin-public.httphandler.md) will be an [IHttpResponse](./kibana-plugin-public.ihttpresponse.md) with detailed request and response information. When `false`, the return type will just be the parsed response body. Defaults to `false`. + +Signature: + +```typescript +asResponse?: boolean; +``` diff --git a/docs/development/core/public/kibana-plugin-public.httpfetchoptions.md b/docs/development/core/public/kibana-plugin-public.httpfetchoptions.md index eca29b37425e9..6a0c4a8a7f137 100644 --- a/docs/development/core/public/kibana-plugin-public.httpfetchoptions.md +++ b/docs/development/core/public/kibana-plugin-public.httpfetchoptions.md @@ -16,6 +16,7 @@ export interface HttpFetchOptions extends HttpRequestInit | Property | Type | Description | | --- | --- | --- | +| [asResponse](./kibana-plugin-public.httpfetchoptions.asresponse.md) | boolean | When true the return type of [HttpHandler](./kibana-plugin-public.httphandler.md) will be an [IHttpResponse](./kibana-plugin-public.ihttpresponse.md) with detailed request and response information. When false, the return type will just be the parsed response body. Defaults to false. | | [headers](./kibana-plugin-public.httpfetchoptions.headers.md) | HttpHeadersInit | Headers to send with the request. See [HttpHeadersInit](./kibana-plugin-public.httpheadersinit.md). | | [prependBasePath](./kibana-plugin-public.httpfetchoptions.prependbasepath.md) | boolean | Whether or not the request should automatically prepend the basePath. Defaults to true. | | [query](./kibana-plugin-public.httpfetchoptions.query.md) | HttpFetchQuery | The query string for an HTTP request. See [HttpFetchQuery](./kibana-plugin-public.httpfetchquery.md). | diff --git a/docs/development/core/public/kibana-plugin-public.httphandler.md b/docs/development/core/public/kibana-plugin-public.httphandler.md index 80fd1ea2e5761..89458c4743cd6 100644 --- a/docs/development/core/public/kibana-plugin-public.httphandler.md +++ b/docs/development/core/public/kibana-plugin-public.httphandler.md @@ -2,12 +2,12 @@ [Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpHandler](./kibana-plugin-public.httphandler.md) -## HttpHandler type +## HttpHandler interface -A function for making an HTTP requests to Kibana's backend. See [HttpFetchOptions](./kibana-plugin-public.httpfetchoptions.md) for options and [HttpBody](./kibana-plugin-public.httpbody.md) for the response. +A function for making an HTTP requests to Kibana's backend. See [HttpFetchOptions](./kibana-plugin-public.httpfetchoptions.md) for options and [IHttpResponse](./kibana-plugin-public.ihttpresponse.md) for the response. Signature: ```typescript -export declare type HttpHandler = (path: string, options?: HttpFetchOptions) => Promise; +export interface HttpHandler ``` diff --git a/docs/development/core/public/kibana-plugin-public.httpinterceptor.response.md b/docs/development/core/public/kibana-plugin-public.httpinterceptor.response.md index ca43ea31f0e2e..3a67dcbad3119 100644 --- a/docs/development/core/public/kibana-plugin-public.httpinterceptor.response.md +++ b/docs/development/core/public/kibana-plugin-public.httpinterceptor.response.md @@ -9,17 +9,17 @@ Define an interceptor to be executed after a response is received. Signature: ```typescript -response?(httpResponse: HttpResponse, controller: IHttpInterceptController): Promise | InterceptedHttpResponse | void; +response?(httpResponse: IHttpResponse, controller: IHttpInterceptController): Promise | IHttpResponseInterceptorOverrides | void; ``` ## Parameters | Parameter | Type | Description | | --- | --- | --- | -| httpResponse | HttpResponse | | +| httpResponse | IHttpResponse | | | controller | IHttpInterceptController | | Returns: -`Promise | InterceptedHttpResponse | void` +`Promise | IHttpResponseInterceptorOverrides | void` diff --git a/docs/development/core/public/kibana-plugin-public.httpinterceptor.responseerror.md b/docs/development/core/public/kibana-plugin-public.httpinterceptor.responseerror.md index b8abd50e45461..476ceba649d40 100644 --- a/docs/development/core/public/kibana-plugin-public.httpinterceptor.responseerror.md +++ b/docs/development/core/public/kibana-plugin-public.httpinterceptor.responseerror.md @@ -9,7 +9,7 @@ Define an interceptor to be executed if a response interceptor throws an error o Signature: ```typescript -responseError?(httpErrorResponse: HttpErrorResponse, controller: IHttpInterceptController): Promise | InterceptedHttpResponse | void; +responseError?(httpErrorResponse: HttpErrorResponse, controller: IHttpInterceptController): Promise | IHttpResponseInterceptorOverrides | void; ``` ## Parameters @@ -21,5 +21,5 @@ responseError?(httpErrorResponse: HttpErrorResponse, controller: IHttpInterceptC Returns: -`Promise | InterceptedHttpResponse | void` +`Promise | IHttpResponseInterceptorOverrides | void` diff --git a/docs/development/core/public/kibana-plugin-public.httpresponse.md b/docs/development/core/public/kibana-plugin-public.httpresponse.md deleted file mode 100644 index e44515cc8a1e0..0000000000000 --- a/docs/development/core/public/kibana-plugin-public.httpresponse.md +++ /dev/null @@ -1,19 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpResponse](./kibana-plugin-public.httpresponse.md) - -## HttpResponse interface - - -Signature: - -```typescript -export interface HttpResponse extends InterceptedHttpResponse -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [request](./kibana-plugin-public.httpresponse.request.md) | Readonly<Request> | | - diff --git a/docs/development/core/public/kibana-plugin-public.httpresponse.request.md b/docs/development/core/public/kibana-plugin-public.httpresponse.request.md deleted file mode 100644 index 84ab1bc7af853..0000000000000 --- a/docs/development/core/public/kibana-plugin-public.httpresponse.request.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [HttpResponse](./kibana-plugin-public.httpresponse.md) > [request](./kibana-plugin-public.httpresponse.request.md) - -## HttpResponse.request property - -Signature: - -```typescript -request: Readonly; -``` diff --git a/docs/development/core/public/kibana-plugin-public.ihttpresponse.body.md b/docs/development/core/public/kibana-plugin-public.ihttpresponse.body.md new file mode 100644 index 0000000000000..2f8710ccdc60e --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.ihttpresponse.body.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IHttpResponse](./kibana-plugin-public.ihttpresponse.md) > [body](./kibana-plugin-public.ihttpresponse.body.md) + +## IHttpResponse.body property + +Parsed body received, may be undefined if there was an error. + +Signature: + +```typescript +readonly body?: TResponseBody; +``` diff --git a/docs/development/core/public/kibana-plugin-public.ihttpresponse.md b/docs/development/core/public/kibana-plugin-public.ihttpresponse.md new file mode 100644 index 0000000000000..5ddce0ba2d0f1 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.ihttpresponse.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IHttpResponse](./kibana-plugin-public.ihttpresponse.md) + +## IHttpResponse interface + + +Signature: + +```typescript +export interface IHttpResponse +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [body](./kibana-plugin-public.ihttpresponse.body.md) | TResponseBody | Parsed body received, may be undefined if there was an error. | +| [request](./kibana-plugin-public.ihttpresponse.request.md) | Readonly<Request> | Raw request sent to Kibana server. | +| [response](./kibana-plugin-public.ihttpresponse.response.md) | Readonly<Response> | Raw response received, may be undefined if there was an error. | + diff --git a/docs/development/core/public/kibana-plugin-public.ihttpresponse.request.md b/docs/development/core/public/kibana-plugin-public.ihttpresponse.request.md new file mode 100644 index 0000000000000..12e5405eb5ed4 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.ihttpresponse.request.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IHttpResponse](./kibana-plugin-public.ihttpresponse.md) > [request](./kibana-plugin-public.ihttpresponse.request.md) + +## IHttpResponse.request property + +Raw request sent to Kibana server. + +Signature: + +```typescript +readonly request: Readonly; +``` diff --git a/docs/development/core/public/kibana-plugin-public.ihttpresponse.response.md b/docs/development/core/public/kibana-plugin-public.ihttpresponse.response.md new file mode 100644 index 0000000000000..9d0b4b59a638d --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.ihttpresponse.response.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IHttpResponse](./kibana-plugin-public.ihttpresponse.md) > [response](./kibana-plugin-public.ihttpresponse.response.md) + +## IHttpResponse.response property + +Raw response received, may be undefined if there was an error. + +Signature: + +```typescript +readonly response?: Readonly; +``` diff --git a/docs/development/core/public/kibana-plugin-public.ihttpresponseinterceptoroverrides.body.md b/docs/development/core/public/kibana-plugin-public.ihttpresponseinterceptoroverrides.body.md new file mode 100644 index 0000000000000..36fcfb390617c --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.ihttpresponseinterceptoroverrides.body.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IHttpResponseInterceptorOverrides](./kibana-plugin-public.ihttpresponseinterceptoroverrides.md) > [body](./kibana-plugin-public.ihttpresponseinterceptoroverrides.body.md) + +## IHttpResponseInterceptorOverrides.body property + +Parsed body received, may be undefined if there was an error. + +Signature: + +```typescript +readonly body?: TResponseBody; +``` diff --git a/docs/development/core/public/kibana-plugin-public.ihttpresponseinterceptoroverrides.md b/docs/development/core/public/kibana-plugin-public.ihttpresponseinterceptoroverrides.md new file mode 100644 index 0000000000000..44f067c429e98 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.ihttpresponseinterceptoroverrides.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IHttpResponseInterceptorOverrides](./kibana-plugin-public.ihttpresponseinterceptoroverrides.md) + +## IHttpResponseInterceptorOverrides interface + +Properties that can be returned by HttpInterceptor.request to override the response. + +Signature: + +```typescript +export interface IHttpResponseInterceptorOverrides +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [body](./kibana-plugin-public.ihttpresponseinterceptoroverrides.body.md) | TResponseBody | Parsed body received, may be undefined if there was an error. | +| [response](./kibana-plugin-public.ihttpresponseinterceptoroverrides.response.md) | Readonly<Response> | Raw response received, may be undefined if there was an error. | + diff --git a/docs/development/core/public/kibana-plugin-public.ihttpresponseinterceptoroverrides.response.md b/docs/development/core/public/kibana-plugin-public.ihttpresponseinterceptoroverrides.response.md new file mode 100644 index 0000000000000..bcba996645ba6 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.ihttpresponseinterceptoroverrides.response.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [IHttpResponseInterceptorOverrides](./kibana-plugin-public.ihttpresponseinterceptoroverrides.md) > [response](./kibana-plugin-public.ihttpresponseinterceptoroverrides.response.md) + +## IHttpResponseInterceptorOverrides.response property + +Raw response received, may be undefined if there was an error. + +Signature: + +```typescript +readonly response?: Readonly; +``` diff --git a/docs/development/core/public/kibana-plugin-public.interceptedhttpresponse.body.md b/docs/development/core/public/kibana-plugin-public.interceptedhttpresponse.body.md deleted file mode 100644 index fc6d34c0b74f2..0000000000000 --- a/docs/development/core/public/kibana-plugin-public.interceptedhttpresponse.body.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [InterceptedHttpResponse](./kibana-plugin-public.interceptedhttpresponse.md) > [body](./kibana-plugin-public.interceptedhttpresponse.body.md) - -## InterceptedHttpResponse.body property - -Signature: - -```typescript -body?: HttpBody; -``` diff --git a/docs/development/core/public/kibana-plugin-public.interceptedhttpresponse.md b/docs/development/core/public/kibana-plugin-public.interceptedhttpresponse.md deleted file mode 100644 index c4a7f4d6b2afa..0000000000000 --- a/docs/development/core/public/kibana-plugin-public.interceptedhttpresponse.md +++ /dev/null @@ -1,20 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [InterceptedHttpResponse](./kibana-plugin-public.interceptedhttpresponse.md) - -## InterceptedHttpResponse interface - - -Signature: - -```typescript -export interface InterceptedHttpResponse -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [body](./kibana-plugin-public.interceptedhttpresponse.body.md) | HttpBody | | -| [response](./kibana-plugin-public.interceptedhttpresponse.response.md) | Response | | - diff --git a/docs/development/core/public/kibana-plugin-public.interceptedhttpresponse.response.md b/docs/development/core/public/kibana-plugin-public.interceptedhttpresponse.response.md deleted file mode 100644 index dceb55113ee78..0000000000000 --- a/docs/development/core/public/kibana-plugin-public.interceptedhttpresponse.response.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [InterceptedHttpResponse](./kibana-plugin-public.interceptedhttpresponse.md) > [response](./kibana-plugin-public.interceptedhttpresponse.response.md) - -## InterceptedHttpResponse.response property - -Signature: - -```typescript -response?: Response; -``` diff --git a/docs/development/core/public/kibana-plugin-public.md b/docs/development/core/public/kibana-plugin-public.md index f527c92d070de..22b6f7faf2daa 100644 --- a/docs/development/core/public/kibana-plugin-public.md +++ b/docs/development/core/public/kibana-plugin-public.md @@ -52,10 +52,10 @@ The plugin integrates with the core system via lifecycle events: `setup` | [HttpErrorResponse](./kibana-plugin-public.httperrorresponse.md) | | | [HttpFetchOptions](./kibana-plugin-public.httpfetchoptions.md) | All options that may be used with a [HttpHandler](./kibana-plugin-public.httphandler.md). | | [HttpFetchQuery](./kibana-plugin-public.httpfetchquery.md) | | +| [HttpHandler](./kibana-plugin-public.httphandler.md) | A function for making an HTTP requests to Kibana's backend. See [HttpFetchOptions](./kibana-plugin-public.httpfetchoptions.md) for options and [IHttpResponse](./kibana-plugin-public.ihttpresponse.md) for the response. | | [HttpHeadersInit](./kibana-plugin-public.httpheadersinit.md) | | | [HttpInterceptor](./kibana-plugin-public.httpinterceptor.md) | An object that may define global interceptor functions for different parts of the request and response lifecycle. See [IHttpInterceptController](./kibana-plugin-public.ihttpinterceptcontroller.md). | | [HttpRequestInit](./kibana-plugin-public.httprequestinit.md) | Fetch API options available to [HttpHandler](./kibana-plugin-public.httphandler.md)s. | -| [HttpResponse](./kibana-plugin-public.httpresponse.md) | | | [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) | | | [I18nStart](./kibana-plugin-public.i18nstart.md) | I18nStart.Context is required by any localizable React component from @kbn/i18n and @elastic/eui packages and is supposed to be used as the topmost component for any i18n-compatible React tree. | | [IAnonymousPaths](./kibana-plugin-public.ianonymouspaths.md) | APIs for denoting paths as not requiring authentication | @@ -63,7 +63,8 @@ The plugin integrates with the core system via lifecycle events: `setup` | [IContextContainer](./kibana-plugin-public.icontextcontainer.md) | An object that handles registration of context providers and configuring handlers with context. | | [IHttpFetchError](./kibana-plugin-public.ihttpfetcherror.md) | | | [IHttpInterceptController](./kibana-plugin-public.ihttpinterceptcontroller.md) | Used to halt a request Promise chain in a [HttpInterceptor](./kibana-plugin-public.httpinterceptor.md). | -| [InterceptedHttpResponse](./kibana-plugin-public.interceptedhttpresponse.md) | | +| [IHttpResponse](./kibana-plugin-public.ihttpresponse.md) | | +| [IHttpResponseInterceptorOverrides](./kibana-plugin-public.ihttpresponseinterceptoroverrides.md) | Properties that can be returned by HttpInterceptor.request to override the response. | | [IUiSettingsClient](./kibana-plugin-public.iuisettingsclient.md) | Client-side client that provides access to the advanced settings stored in elasticsearch. The settings provide control over the behavior of the Kibana application. For example, a user can specify how to display numeric or date fields. Users can adjust the settings via Management UI. [IUiSettingsClient](./kibana-plugin-public.iuisettingsclient.md) | | [LegacyCoreSetup](./kibana-plugin-public.legacycoresetup.md) | Setup interface exposed to the legacy platform via the ui/new_platform module. | | [LegacyCoreStart](./kibana-plugin-public.legacycorestart.md) | Start interface exposed to the legacy platform via the ui/new_platform module. | @@ -108,8 +109,6 @@ The plugin integrates with the core system via lifecycle events: `setup` | [HandlerContextType](./kibana-plugin-public.handlercontexttype.md) | Extracts the type of the first argument of a [HandlerFunction](./kibana-plugin-public.handlerfunction.md) to represent the type of the context. | | [HandlerFunction](./kibana-plugin-public.handlerfunction.md) | A function that accepts a context object and an optional number of additional arguments. Used for the generic types in [IContextContainer](./kibana-plugin-public.icontextcontainer.md) | | [HandlerParameters](./kibana-plugin-public.handlerparameters.md) | Extracts the types of the additional arguments of a [HandlerFunction](./kibana-plugin-public.handlerfunction.md), excluding the [HandlerContextType](./kibana-plugin-public.handlercontexttype.md). | -| [HttpBody](./kibana-plugin-public.httpbody.md) | | -| [HttpHandler](./kibana-plugin-public.httphandler.md) | A function for making an HTTP requests to Kibana's backend. See [HttpFetchOptions](./kibana-plugin-public.httpfetchoptions.md) for options and [HttpBody](./kibana-plugin-public.httpbody.md) for the response. | | [HttpSetup](./kibana-plugin-public.httpsetup.md) | See [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) | | [HttpStart](./kibana-plugin-public.httpstart.md) | See [HttpServiceBase](./kibana-plugin-public.httpservicebase.md) | | [IContextProvider](./kibana-plugin-public.icontextprovider.md) | A function that returns a context value for a specific key of given context type. | diff --git a/src/core/public/application/capabilities/capabilities_service.tsx b/src/core/public/application/capabilities/capabilities_service.tsx index e330a4b0326ae..24d9765953c44 100644 --- a/src/core/public/application/capabilities/capabilities_service.tsx +++ b/src/core/public/application/capabilities/capabilities_service.tsx @@ -74,7 +74,7 @@ export class CapabilitiesService { const url = http.anonymousPaths.isAnonymous(window.location.pathname) ? '/api/core/capabilities/defaults' : '/api/core/capabilities'; - const capabilities = await http.post(url, { + const capabilities = await http.post(url, { body: payload, }); return deepFreeze(capabilities); diff --git a/src/core/public/http/fetch.ts b/src/core/public/http/fetch.ts new file mode 100644 index 0000000000000..472b617cacd7f --- /dev/null +++ b/src/core/public/http/fetch.ts @@ -0,0 +1,155 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { merge } from 'lodash'; +import { format } from 'url'; + +import { IBasePath, HttpInterceptor, HttpHandler, HttpFetchOptions, IHttpResponse } from './types'; +import { HttpFetchError } from './http_fetch_error'; +import { HttpInterceptController } from './http_intercept_controller'; +import { HttpResponse } from './response'; +import { interceptRequest, interceptResponse } from './intercept'; +import { HttpInterceptHaltError } from './http_intercept_halt_error'; + +interface Params { + basePath: IBasePath; + kibanaVersion: string; +} + +const JSON_CONTENT = /^(application\/(json|x-javascript)|text\/(x-)?javascript|x-json)(;.*)?$/; +const NDJSON_CONTENT = /^(application\/ndjson)(;.*)?$/; + +export class FetchService { + private readonly interceptors = new Set(); + + constructor(private readonly params: Params) {} + + public intercept(interceptor: HttpInterceptor) { + this.interceptors.add(interceptor); + return () => this.interceptors.delete(interceptor); + } + + public removeAllInterceptors() { + this.interceptors.clear(); + } + + public fetch: HttpHandler = async ( + path: string, + options: HttpFetchOptions = {} + ) => { + const initialRequest = this.createRequest(path, options); + const controller = new HttpInterceptController(); + + // We wrap the interception in a separate promise to ensure that when + // a halt is called we do not resolve or reject, halting handling of the promise. + return new Promise>(async (resolve, reject) => { + try { + const interceptedRequest = await interceptRequest( + initialRequest, + this.interceptors, + controller + ); + const initialResponse = this.fetchResponse(interceptedRequest); + const interceptedResponse = await interceptResponse( + initialResponse, + this.interceptors, + controller + ); + + if (options.asResponse) { + resolve(interceptedResponse); + } else { + resolve(interceptedResponse.body); + } + } catch (error) { + if (!(error instanceof HttpInterceptHaltError)) { + reject(error); + } + } + }); + }; + + private createRequest(path: string, options?: HttpFetchOptions): Request { + // Merge and destructure options out that are not applicable to the Fetch API. + const { query, prependBasePath: shouldPrependBasePath, asResponse, ...fetchOptions } = merge( + { + method: 'GET', + credentials: 'same-origin', + prependBasePath: true, + headers: { + 'kbn-version': this.params.kibanaVersion, + 'Content-Type': 'application/json', + }, + }, + options || {} + ); + const url = format({ + pathname: shouldPrependBasePath ? this.params.basePath.prepend(path) : path, + query, + }); + + if ( + options && + options.headers && + 'Content-Type' in options.headers && + options.headers['Content-Type'] === undefined + ) { + delete fetchOptions.headers['Content-Type']; + } + + return new Request(url, fetchOptions); + } + + private async fetchResponse(request: Request) { + let response: Response; + let body = null; + + try { + response = await window.fetch(request); + } catch (err) { + throw new HttpFetchError(err.message, request); + } + + const contentType = response.headers.get('Content-Type') || ''; + + try { + if (NDJSON_CONTENT.test(contentType)) { + body = await response.blob(); + } else if (JSON_CONTENT.test(contentType)) { + body = await response.json(); + } else { + const text = await response.text(); + + try { + body = JSON.parse(text); + } catch (err) { + body = text; + } + } + } catch (err) { + throw new HttpFetchError(err.message, request, response, body); + } + + if (!response.ok) { + throw new HttpFetchError(response.statusText, request, response, body); + } + + return new HttpResponse({ request, response, body }); + } +} diff --git a/src/core/public/http/http_service.test.ts b/src/core/public/http/http_service.test.ts index 13906b91ed8df..09f3cca419e4d 100644 --- a/src/core/public/http/http_service.test.ts +++ b/src/core/public/http/http_service.test.ts @@ -24,7 +24,7 @@ import fetchMock from 'fetch-mock/es5/client'; import { readFileSync } from 'fs'; import { join } from 'path'; import { setup, SetupTap } from '../../../test_utils/public/http_test_setup'; -import { HttpResponse } from './types'; +import { IHttpResponse } from './types'; function delay(duration: number) { return new Promise(r => setTimeout(r, duration)); @@ -101,32 +101,32 @@ describe('http requests', () => { it('should return response', async () => { const { http } = setup(); - fetchMock.get('*', { foo: 'bar' }); - const json = await http.fetch('/my/path'); - expect(json).toEqual({ foo: 'bar' }); }); it('should prepend url with basepath by default', async () => { const { http } = setup(); - fetchMock.get('*', {}); await http.fetch('/my/path'); - expect(fetchMock.lastUrl()).toBe('http://localhost/myBase/my/path'); }); it('should not prepend url with basepath when disabled', async () => { const { http } = setup(); - fetchMock.get('*', {}); await http.fetch('my/path', { prependBasePath: false }); - expect(fetchMock.lastUrl()).toBe('/my/path'); }); + it('should not include undefined query params', async () => { + const { http } = setup(); + fetchMock.get('*', {}); + await http.fetch('/my/path', { query: { a: undefined } }); + expect(fetchMock.lastUrl()).toBe('http://localhost/myBase/my/path'); + }); + it('should make request with defaults', async () => { const { http } = setup(); @@ -145,6 +145,18 @@ describe('http requests', () => { }); }); + it('should expose detailed response object when asResponse = true', async () => { + const { http } = setup(); + + fetchMock.get('*', { foo: 'bar' }); + + const response = await http.fetch('/my/path', { asResponse: true }); + + expect(response.request).toBeInstanceOf(Request); + expect(response.response).toBeInstanceOf(Response); + expect(response.body).toEqual({ foo: 'bar' }); + }); + it('should reject on network error', async () => { const { http } = setup(); @@ -496,7 +508,7 @@ describe('interception', () => { it('should accumulate response information', async () => { const bodies = ['alpha', 'beta', 'gamma']; - const createResponse = jest.fn((httpResponse: HttpResponse) => ({ + const createResponse = jest.fn((httpResponse: IHttpResponse) => ({ body: bodies.shift(), })); diff --git a/src/core/public/http/http_setup.ts b/src/core/public/http/http_setup.ts index 602382e3a5a60..c63750849f13a 100644 --- a/src/core/public/http/http_setup.ts +++ b/src/core/public/http/http_setup.ts @@ -27,21 +27,16 @@ import { takeUntil, tap, } from 'rxjs/operators'; -import { merge } from 'lodash'; -import { format } from 'url'; import { InjectedMetadataSetup } from '../injected_metadata'; import { FatalErrorsSetup } from '../fatal_errors'; -import { HttpFetchOptions, HttpServiceBase, HttpInterceptor, HttpResponse } from './types'; +import { HttpFetchOptions, HttpServiceBase } from './types'; import { HttpInterceptController } from './http_intercept_controller'; -import { HttpFetchError } from './http_fetch_error'; import { HttpInterceptHaltError } from './http_intercept_halt_error'; import { BasePath } from './base_path_service'; import { AnonymousPaths } from './anonymous_paths'; +import { FetchService } from './fetch'; -const JSON_CONTENT = /^(application\/(json|x-javascript)|text\/(x-)?javascript|x-json)(;.*)?$/; -const NDJSON_CONTENT = /^(application\/ndjson)(;.*)?$/; - -function checkHalt(controller: HttpInterceptController, error?: Error) { +export function checkHalt(controller: HttpInterceptController, error?: Error) { if (error instanceof HttpInterceptHaltError) { throw error; } else if (controller.halted) { @@ -55,224 +50,15 @@ export const setup = ( ): HttpServiceBase => { const loadingCount$ = new BehaviorSubject(0); const stop$ = new Subject(); - const interceptors = new Set(); const kibanaVersion = injectedMetadata.getKibanaVersion(); const basePath = new BasePath(injectedMetadata.getBasePath()); const anonymousPaths = new AnonymousPaths(basePath); - function intercept(interceptor: HttpInterceptor) { - interceptors.add(interceptor); - - return () => interceptors.delete(interceptor); - } - - function removeAllInterceptors() { - interceptors.clear(); - } - - function createRequest(path: string, options?: HttpFetchOptions) { - const { query, prependBasePath: shouldPrependBasePath, ...fetchOptions } = merge( - { - method: 'GET', - credentials: 'same-origin', - prependBasePath: true, - headers: { - 'kbn-version': kibanaVersion, - 'Content-Type': 'application/json', - }, - }, - options || {} - ); - const url = format({ - pathname: shouldPrependBasePath ? basePath.prepend(path) : path, - query, - }); - - if ( - options && - options.headers && - 'Content-Type' in options.headers && - options.headers['Content-Type'] === undefined - ) { - delete fetchOptions.headers['Content-Type']; - } - - return new Request(url, fetchOptions); - } - - // Request/response interceptors are called in opposite orders. - // Request hooks start from the newest interceptor and end with the oldest. - function interceptRequest( - request: Request, - controller: HttpInterceptController - ): Promise { - let next = request; - - return [...interceptors].reduceRight( - (promise, interceptor) => - promise.then( - async (current: Request) => { - next = current; - checkHalt(controller); - - if (!interceptor.request) { - return current; - } - - return (await interceptor.request(current, controller)) || current; - }, - async error => { - checkHalt(controller, error); - - if (!interceptor.requestError) { - throw error; - } - - const nextRequest = await interceptor.requestError( - { error, request: next }, - controller - ); - - if (!nextRequest) { - throw error; - } - - next = nextRequest; - return next; - } - ), - Promise.resolve(request) - ); - } - - // Response hooks start from the oldest interceptor and end with the newest. - async function interceptResponse( - responsePromise: Promise, - controller: HttpInterceptController - ) { - let current: HttpResponse | undefined; - - const finalHttpResponse = await [...interceptors].reduce( - (promise, interceptor) => - promise.then( - async httpResponse => { - current = httpResponse; - checkHalt(controller); - - if (!interceptor.response) { - return httpResponse; - } - - return { - ...httpResponse, - ...((await interceptor.response(httpResponse, controller)) || {}), - }; - }, - async error => { - const request = error.request || (current && current.request); - - checkHalt(controller, error); - - if (!interceptor.responseError) { - throw error; - } - - try { - const next = await interceptor.responseError( - { - error, - request, - response: error.response || (current && current.response), - body: error.body || (current && current.body), - }, - controller - ); - - checkHalt(controller, error); - - if (!next) { - throw error; - } - - return { ...next, request }; - } catch (err) { - checkHalt(controller, err); - throw err; - } - } - ), - responsePromise - ); - - return finalHttpResponse.body; - } - - async function fetcher(request: Request): Promise { - let response; - let body = null; - - try { - response = await window.fetch(request); - } catch (err) { - throw new HttpFetchError(err.message, request); - } - - const contentType = response.headers.get('Content-Type') || ''; - - try { - if (NDJSON_CONTENT.test(contentType)) { - body = await response.blob(); - } else if (JSON_CONTENT.test(contentType)) { - body = await response.json(); - } else { - const text = await response.text(); - - try { - body = JSON.parse(text); - } catch (err) { - body = text; - } - } - } catch (err) { - throw new HttpFetchError(err.message, request, response, body); - } - - if (!response.ok) { - throw new HttpFetchError(response.statusText, request, response, body); - } - - return { response, body, request }; - } - - async function fetch(path: string, options: HttpFetchOptions = {}) { - const controller = new HttpInterceptController(); - const initialRequest = createRequest(path, options); - - // We wrap the interception in a separate promise to ensure that when - // a halt is called we do not resolve or reject, halting handling of the promise. - return new Promise(async (resolve, reject) => { - function rejectIfNotHalted(err: any) { - if (!(err instanceof HttpInterceptHaltError)) { - reject(err); - } - } - - try { - const request = await interceptRequest(initialRequest, controller); - - try { - resolve(await interceptResponse(fetcher(request), controller)); - } catch (err) { - rejectIfNotHalted(err); - } - } catch (err) { - rejectIfNotHalted(err); - } - }); - } + const fetchService = new FetchService({ basePath, kibanaVersion }); function shorthand(method: string) { - return (path: string, options: HttpFetchOptions = {}) => fetch(path, { ...options, method }); + return (path: string, options: HttpFetchOptions = {}) => + fetchService.fetch(path, { ...options, method }); } function stop() { @@ -321,9 +107,9 @@ export const setup = ( stop, basePath, anonymousPaths, - intercept, - removeAllInterceptors, - fetch, + intercept: fetchService.intercept.bind(fetchService), + removeAllInterceptors: fetchService.removeAllInterceptors.bind(fetchService), + fetch: fetchService.fetch.bind(fetchService), delete: shorthand('DELETE'), get: shorthand('GET'), head: shorthand('HEAD'), diff --git a/src/core/public/http/intercept.ts b/src/core/public/http/intercept.ts new file mode 100644 index 0000000000000..e2a16565c61c4 --- /dev/null +++ b/src/core/public/http/intercept.ts @@ -0,0 +1,134 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { HttpInterceptController } from './http_intercept_controller'; +import { HttpInterceptHaltError } from './http_intercept_halt_error'; +import { HttpInterceptor, IHttpResponse } from './types'; +import { HttpResponse } from './response'; + +export async function interceptRequest( + request: Request, + interceptors: ReadonlySet, + controller: HttpInterceptController +): Promise { + let next = request; + + return [...interceptors].reduceRight( + (promise, interceptor) => + promise.then( + async (current: Request) => { + next = current; + checkHalt(controller); + + if (!interceptor.request) { + return current; + } + + return (await interceptor.request(current, controller)) || current; + }, + async error => { + checkHalt(controller, error); + + if (!interceptor.requestError) { + throw error; + } + + const nextRequest = await interceptor.requestError({ error, request: next }, controller); + + if (!nextRequest) { + throw error; + } + + next = nextRequest; + return next; + } + ), + Promise.resolve(request) + ); +} + +export async function interceptResponse( + responsePromise: Promise, + interceptors: ReadonlySet, + controller: HttpInterceptController +): Promise { + let current: IHttpResponse; + + return await [...interceptors].reduce( + (promise, interceptor) => + promise.then( + async httpResponse => { + current = httpResponse; + checkHalt(controller); + + if (!interceptor.response) { + return httpResponse; + } + + const interceptorOverrides = (await interceptor.response(httpResponse, controller)) || {}; + + return new HttpResponse({ + ...httpResponse, + ...interceptorOverrides, + }); + }, + async error => { + const request = error.request || (current && current.request); + + checkHalt(controller, error); + + if (!interceptor.responseError) { + throw error; + } + + try { + const next = await interceptor.responseError( + { + error, + request, + response: error.response || (current && current.response), + body: error.body || (current && current.body), + }, + controller + ); + + checkHalt(controller, error); + + if (!next) { + throw error; + } + + return new HttpResponse({ ...next, request }); + } catch (err) { + checkHalt(controller, err); + throw err; + } + } + ), + responsePromise + ); +} + +function checkHalt(controller: HttpInterceptController, error?: Error) { + if (error instanceof HttpInterceptHaltError) { + throw error; + } else if (controller.halted) { + throw new HttpInterceptHaltError(); + } +} diff --git a/src/core/public/http/response.ts b/src/core/public/http/response.ts new file mode 100644 index 0000000000000..706e7caaca976 --- /dev/null +++ b/src/core/public/http/response.ts @@ -0,0 +1,40 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { IHttpResponse } from './types'; + +export class HttpResponse implements IHttpResponse { + public readonly request: Request; + public readonly response?: Response; + public readonly body?: TResponseBody; + + constructor({ + request, + response, + body, + }: { + request: Request; + response?: Response; + body?: TResponseBody; + }) { + this.request = request; + this.response = response; + this.body = body; + } +} diff --git a/src/core/public/http/types.ts b/src/core/public/http/types.ts index 870d4af8f9e86..48385a72325db 100644 --- a/src/core/public/http/types.ts +++ b/src/core/public/http/types.ts @@ -229,31 +229,49 @@ export interface HttpFetchOptions extends HttpRequestInit { * Headers to send with the request. See {@link HttpHeadersInit}. */ headers?: HttpHeadersInit; + + /** + * When `true` the return type of {@link HttpHandler} will be an {@link IHttpResponse} with detailed request and + * response information. When `false`, the return type will just be the parsed response body. Defaults to `false`. + */ + asResponse?: boolean; } /** * A function for making an HTTP requests to Kibana's backend. See {@link HttpFetchOptions} for options and - * {@link HttpBody} for the response. + * {@link IHttpResponse} for the response. * * @param path the path on the Kibana server to send the request to. Should not include the basePath. * @param options {@link HttpFetchOptions} - * @returns a Promise that resolves to a {@link HttpBody} + * @returns a Promise that resolves to a {@link IHttpResponse} * @public */ -export type HttpHandler = (path: string, options?: HttpFetchOptions) => Promise; - -/** @public */ -export type HttpBody = BodyInit | null | any; +export interface HttpHandler { + (path: string, options: HttpFetchOptions & { asResponse: true }): Promise< + IHttpResponse + >; + (path: string, options?: HttpFetchOptions): Promise; +} /** @public */ -export interface InterceptedHttpResponse { - response?: Response; - body?: HttpBody; +export interface IHttpResponse { + /** Raw request sent to Kibana server. */ + readonly request: Readonly; + /** Raw response received, may be undefined if there was an error. */ + readonly response?: Readonly; + /** Parsed body received, may be undefined if there was an error. */ + readonly body?: TResponseBody; } -/** @public */ -export interface HttpResponse extends InterceptedHttpResponse { - request: Readonly; +/** + * Properties that can be returned by HttpInterceptor.request to override the response. + * @public + */ +export interface IHttpResponseInterceptorOverrides { + /** Raw response received, may be undefined if there was an error. */ + readonly response?: Readonly; + /** Parsed body received, may be undefined if there was an error. */ + readonly body?: TResponseBody; } /** @public */ @@ -272,7 +290,7 @@ export interface IHttpFetchError extends Error { } /** @public */ -export interface HttpErrorResponse extends HttpResponse { +export interface HttpErrorResponse extends IHttpResponse { error: Error | IHttpFetchError; } /** @public */ @@ -310,13 +328,13 @@ export interface HttpInterceptor { /** * Define an interceptor to be executed after a response is received. - * @param httpResponse {@link HttpResponse} + * @param httpResponse {@link IHttpResponse} * @param controller {@link IHttpInterceptController} */ response?( - httpResponse: HttpResponse, + httpResponse: IHttpResponse, controller: IHttpInterceptController - ): Promise | InterceptedHttpResponse | void; + ): Promise | IHttpResponseInterceptorOverrides | void; /** * Define an interceptor to be executed if a response interceptor throws an error or returns a rejected Promise. @@ -326,7 +344,7 @@ export interface HttpInterceptor { responseError?( httpErrorResponse: HttpErrorResponse, controller: IHttpInterceptController - ): Promise | InterceptedHttpResponse | void; + ): Promise | IHttpResponseInterceptorOverrides | void; } /** diff --git a/src/core/public/index.ts b/src/core/public/index.ts index cfec03427f3e7..035cbcca86ac7 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -112,14 +112,13 @@ export { HttpErrorResponse, HttpErrorRequest, HttpInterceptor, - HttpResponse, + IHttpResponse, HttpHandler, - HttpBody, IBasePath, IAnonymousPaths, IHttpInterceptController, IHttpFetchError, - InterceptedHttpResponse, + IHttpResponseInterceptorOverrides, } from './http'; export { OverlayStart, OverlayBannersStart, OverlayRef } from './overlays'; diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index 6fbc7324ce393..157f0bab466b0 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -464,9 +464,6 @@ export type HandlerFunction = (context: T, ...args: any[]) => // @public export type HandlerParameters> = T extends (context: any, ...args: infer U) => any ? U : never; -// @public (undocumented) -export type HttpBody = BodyInit | null | any; - // @public (undocumented) export interface HttpErrorRequest { // (undocumented) @@ -476,13 +473,14 @@ export interface HttpErrorRequest { } // @public (undocumented) -export interface HttpErrorResponse extends HttpResponse { +export interface HttpErrorResponse extends IHttpResponse { // (undocumented) error: Error | IHttpFetchError; } // @public export interface HttpFetchOptions extends HttpRequestInit { + asResponse?: boolean; headers?: HttpHeadersInit; prependBasePath?: boolean; query?: HttpFetchQuery; @@ -495,7 +493,14 @@ export interface HttpFetchQuery { } // @public -export type HttpHandler = (path: string, options?: HttpFetchOptions) => Promise; +export interface HttpHandler { + // (undocumented) + (path: string, options: HttpFetchOptions & { + asResponse: true; + }): Promise>; + // (undocumented) + (path: string, options?: HttpFetchOptions): Promise; +} // @public (undocumented) export interface HttpHeadersInit { @@ -507,8 +512,8 @@ export interface HttpHeadersInit { export interface HttpInterceptor { request?(request: Request, controller: IHttpInterceptController): Promise | Request | void; requestError?(httpErrorRequest: HttpErrorRequest, controller: IHttpInterceptController): Promise | Request | void; - response?(httpResponse: HttpResponse, controller: IHttpInterceptController): Promise | InterceptedHttpResponse | void; - responseError?(httpErrorResponse: HttpErrorResponse, controller: IHttpInterceptController): Promise | InterceptedHttpResponse | void; + response?(httpResponse: IHttpResponse, controller: IHttpInterceptController): Promise | IHttpResponseInterceptorOverrides | void; + responseError?(httpErrorResponse: HttpErrorResponse, controller: IHttpInterceptController): Promise | IHttpResponseInterceptorOverrides | void; } // @public @@ -529,12 +534,6 @@ export interface HttpRequestInit { window?: null; } -// @public (undocumented) -export interface HttpResponse extends InterceptedHttpResponse { - // (undocumented) - request: Readonly; -} - // @public (undocumented) export interface HttpServiceBase { addLoadingCount(countSource$: Observable): void; @@ -613,11 +612,16 @@ export interface IHttpInterceptController { } // @public (undocumented) -export interface InterceptedHttpResponse { - // (undocumented) - body?: HttpBody; - // (undocumented) - response?: Response; +export interface IHttpResponse { + readonly body?: TResponseBody; + readonly request: Readonly; + readonly response?: Readonly; +} + +// @public +export interface IHttpResponseInterceptorOverrides { + readonly body?: TResponseBody; + readonly response?: Readonly; } // @public diff --git a/src/plugins/share/public/components/share_context_menu.test.tsx b/src/plugins/share/public/components/share_context_menu.test.tsx index 7fb0449ead502..1f2242ae4c515 100644 --- a/src/plugins/share/public/components/share_context_menu.test.tsx +++ b/src/plugins/share/public/components/share_context_menu.test.tsx @@ -34,7 +34,7 @@ const defaultProps = { isDirty: false, onClose: () => {}, basePath: '', - post: () => Promise.resolve(), + post: () => Promise.resolve({} as any), objectType: 'dashboard', }; diff --git a/src/plugins/share/public/components/url_panel_content.test.tsx b/src/plugins/share/public/components/url_panel_content.test.tsx index 9da1a23641ab8..9db8d1ccf2efa 100644 --- a/src/plugins/share/public/components/url_panel_content.test.tsx +++ b/src/plugins/share/public/components/url_panel_content.test.tsx @@ -28,7 +28,7 @@ const defaultProps = { allowShortUrl: true, objectType: 'dashboard', basePath: '', - post: () => Promise.resolve(), + post: () => Promise.resolve({} as any), }; test('render', () => { diff --git a/x-pack/legacy/plugins/graph/public/services/fetch_top_nodes.test.ts b/x-pack/legacy/plugins/graph/public/services/fetch_top_nodes.test.ts index 0a0fc8cae5d26..3bfc868fcb06e 100644 --- a/x-pack/legacy/plugins/graph/public/services/fetch_top_nodes.test.ts +++ b/x-pack/legacy/plugins/graph/public/services/fetch_top_nodes.test.ts @@ -12,7 +12,7 @@ const icon = getSuitableIcon(''); describe('fetch_top_nodes', () => { it('should build terms agg', async () => { const postMock = jest.fn(() => Promise.resolve({ resp: {} })); - await fetchTopNodes(postMock, 'test', [ + await fetchTopNodes(postMock as any, 'test', [ { color: '', hopSize: 5, icon, name: 'field1', selected: false, type: 'string' }, { color: '', hopSize: 5, icon, name: 'field2', selected: false, type: 'string' }, ]); @@ -64,7 +64,7 @@ describe('fetch_top_nodes', () => { }, }) ); - const result = await fetchTopNodes(postMock, 'test', [ + const result = await fetchTopNodes(postMock as any, 'test', [ { color: 'red', hopSize: 5, icon, name: 'field1', selected: false, type: 'string' }, { color: 'blue', hopSize: 5, icon, name: 'field2', selected: false, type: 'string' }, ]); diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/datapanel.test.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/datapanel.test.tsx index dc23df250ebd4..52f00a7cd4e9d 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/datapanel.test.tsx +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/datapanel.test.tsx @@ -278,7 +278,7 @@ describe('IndexPattern Data Panel', () => { function testProps() { const setState = jest.fn(); - core.http.get = jest.fn(async (url: string) => { + core.http.get.mockImplementation(async (url: string) => { const parts = url.split('/'); const indexPatternTitle = parts[parts.length - 1]; return { @@ -484,7 +484,7 @@ describe('IndexPattern Data Panel', () => { let overlapCount = 0; const props = testProps(); - core.http.get = jest.fn((url: string) => { + core.http.get.mockImplementation((url: string) => { if (queryCount) { ++overlapCount; } @@ -533,11 +533,9 @@ describe('IndexPattern Data Panel', () => { it('shows all fields if empty state button is clicked', async () => { const props = testProps(); - core.http.get = jest.fn((url: string) => { - return Promise.resolve({ - indexPatternTitle: props.currentIndexPatternId, - existingFieldNames: [], - }); + core.http.get.mockResolvedValue({ + indexPatternTitle: props.currentIndexPatternId, + existingFieldNames: [], }); const inst = mountWithIntl(); diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/loader.test.ts b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/loader.test.ts index 72cbd1b861a05..2fb678aed5a54 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/loader.test.ts +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/loader.test.ts @@ -528,7 +528,8 @@ describe('loader', () => { await syncExistingFields({ dateRange: { fromDate: '1900-01-01', toDate: '2000-01-01' }, - fetchJson, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + fetchJson: fetchJson as any, indexPatterns: [{ title: 'a' }, { title: 'b' }, { title: 'c' }], setState, }); diff --git a/x-pack/plugins/security/public/session/session_timeout_http_interceptor.ts b/x-pack/plugins/security/public/session/session_timeout_http_interceptor.ts index 81625e1753b27..8a2251f3f7f7c 100644 --- a/x-pack/plugins/security/public/session/session_timeout_http_interceptor.ts +++ b/x-pack/plugins/security/public/session/session_timeout_http_interceptor.ts @@ -4,7 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import { HttpInterceptor, HttpErrorResponse, HttpResponse, IAnonymousPaths } from 'src/core/public'; +import { + HttpInterceptor, + HttpErrorResponse, + IHttpResponse, + IAnonymousPaths, +} from 'src/core/public'; import { ISessionTimeout } from './session_timeout'; @@ -15,7 +20,7 @@ const isSystemAPIRequest = (request: Request) => { export class SessionTimeoutHttpInterceptor implements HttpInterceptor { constructor(private sessionTimeout: ISessionTimeout, private anonymousPaths: IAnonymousPaths) {} - response(httpResponse: HttpResponse) { + response(httpResponse: IHttpResponse) { if (this.anonymousPaths.isAnonymous(window.location.pathname)) { return; } From 2ec82d3dd918b58695cb5df4b90a420749832b16 Mon Sep 17 00:00:00 2001 From: Aleh Zasypkin Date: Wed, 11 Dec 2019 18:35:49 +0100 Subject: [PATCH 12/79] Migrate the rest of the API endpoints to the New Platform plugin (#50695) --- .../security/authentication/index.asciidoc | 2 +- test/common/services/security/user.ts | 4 +- .../setup-custom-kibana-user-role.ts | 6 +- .../common/{model/index.ts => model.ts} | 5 +- x-pack/legacy/plugins/security/index.js | 10 +- .../public/hacks/on_unauthorized_response.js | 4 +- .../legacy/plugins/security/public/lib/api.ts | 4 +- .../security/public/lib/api_keys_api.ts | 5 +- .../security/public/objects/lib/get_fields.ts | 2 +- .../public/services/shield_indices.js | 2 +- .../security/public/services/shield_user.js | 4 +- .../basic_login_form/basic_login_form.tsx | 2 +- .../security/public/views/logout/logout.js | 2 +- .../components/api_keys_grid_page.tsx | 2 +- .../invalidate_provider.tsx | 2 +- .../lib/__tests__/__fixtures__/request.ts | 39 -- .../lib/__tests__/__fixtures__/server.ts | 56 -- .../server/lib/route_pre_check_license.js | 18 - .../security/server/lib/user_schema.js | 17 - .../routes/api/v1/__tests__/authenticate.js | 260 -------- .../server/routes/api/v1/__tests__/users.js | 214 ------- .../server/routes/api/v1/api_keys/get.js | 45 -- .../server/routes/api/v1/api_keys/get.test.js | 166 ----- .../server/routes/api/v1/api_keys/index.js | 20 - .../routes/api/v1/api_keys/invalidate.js | 70 --- .../routes/api/v1/api_keys/invalidate.test.js | 200 ------ .../routes/api/v1/api_keys/privileges.js | 75 --- .../routes/api/v1/api_keys/privileges.test.js | 254 -------- .../server/routes/api/v1/authenticate.js | 227 ------- .../security/server/routes/api/v1/indices.js | 36 -- .../security/server/routes/api/v1/users.js | 142 ----- .../cypress/integration/lib/login/helpers.ts | 6 +- .../legacy/server/lib/esjs_shield_plugin.js | 579 ------------------ x-pack/legacy/server/lib/get_client_shield.ts | 14 - .../plugins/security/common/model/api_key.ts | 0 x-pack/plugins/security/common/model/index.ts | 1 + .../authentication/providers/oidc.test.ts | 15 +- .../server/elasticsearch_client_plugin.ts | 576 +++++++++++++++++ x-pack/plugins/security/server/errors.ts | 14 + x-pack/plugins/security/server/index.ts | 14 +- x-pack/plugins/security/server/plugin.test.ts | 9 +- x-pack/plugins/security/server/plugin.ts | 7 +- .../server/routes/api_keys/get.test.ts | 160 +++++ .../security/server/routes/api_keys/get.ts | 43 ++ .../security/server/routes/api_keys/index.ts | 16 + .../server/routes/api_keys/invalidate.test.ts | 220 +++++++ .../server/routes/api_keys/invalidate.ts | 69 +++ .../server/routes/api_keys/privileges.test.ts | 187 ++++++ .../server/routes/api_keys/privileges.ts | 49 ++ .../routes/authentication/basic.test.ts | 172 ++++++ .../server/routes/authentication/basic.ts | 48 ++ .../routes/authentication/common.test.ts | 202 ++++++ .../server/routes/authentication/common.ts | 78 +++ .../server/routes/authentication/index.ts | 28 + .../server/routes/authentication/oidc.ts | 274 +++++++++ .../server/routes/authentication/saml.ts | 19 +- .../authorization/privileges/get.test.ts | 2 +- .../routes/authorization/roles/delete.test.ts | 8 +- .../routes/authorization/roles/delete.ts | 8 +- .../routes/authorization/roles/get.test.ts | 8 +- .../server/routes/authorization/roles/get.ts | 8 +- .../authorization/roles/get_all.test.ts | 8 +- .../routes/authorization/roles/get_all.ts | 8 +- .../routes/authorization/roles/put.test.ts | 2 +- .../server/routes/authorization/roles/put.ts | 8 +- .../plugins/security/server/routes/index.ts | 6 + .../server/routes/indices/get_fields.ts | 47 ++ .../security/server/routes/indices/index.ts} | 7 +- .../routes/users/change_password.test.ts | 207 +++++++ .../server/routes/users/change_password.ts | 80 +++ .../server/routes/users/create_or_update.ts | 47 ++ .../security/server/routes/users/delete.ts | 32 + .../security/server/routes/users/get.ts | 37 ++ .../security/server/routes/users/get_all.ts | 27 + .../security/server/routes/users/index.ts | 20 + .../apis/security/basic_login.js | 36 +- .../apis/security/change_password.ts | 20 +- .../apis/security/index_fields.ts | 4 +- .../api_integration/apis/security/session.ts | 2 +- .../api_integration/services/legacy_es.js | 4 +- .../apis/security/kerberos_login.ts | 44 +- .../apis/authorization_code_flow/oidc_auth.js | 53 +- .../apis/implicit_flow/oidc_auth.ts | 20 +- x-pack/test/oidc_api_integration/config.ts | 4 +- .../apis/security/pki_auth.ts | 38 +- .../apis/security/saml_login.ts | 50 +- .../common/services/legacy_es.js | 4 +- .../common/services/legacy_es.js | 4 +- .../test/token_api_integration/auth/header.js | 10 +- .../test/token_api_integration/auth/login.js | 14 +- .../test/token_api_integration/auth/logout.js | 10 +- .../token_api_integration/auth/session.js | 16 +- 92 files changed, 2885 insertions(+), 2713 deletions(-) rename x-pack/legacy/plugins/security/common/{model/index.ts => model.ts} (84%) delete mode 100644 x-pack/legacy/plugins/security/server/lib/__tests__/__fixtures__/request.ts delete mode 100644 x-pack/legacy/plugins/security/server/lib/__tests__/__fixtures__/server.ts delete mode 100644 x-pack/legacy/plugins/security/server/lib/route_pre_check_license.js delete mode 100644 x-pack/legacy/plugins/security/server/lib/user_schema.js delete mode 100644 x-pack/legacy/plugins/security/server/routes/api/v1/__tests__/authenticate.js delete mode 100644 x-pack/legacy/plugins/security/server/routes/api/v1/__tests__/users.js delete mode 100644 x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/get.js delete mode 100644 x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/get.test.js delete mode 100644 x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/index.js delete mode 100644 x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/invalidate.js delete mode 100644 x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/invalidate.test.js delete mode 100644 x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/privileges.js delete mode 100644 x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/privileges.test.js delete mode 100644 x-pack/legacy/plugins/security/server/routes/api/v1/authenticate.js delete mode 100644 x-pack/legacy/plugins/security/server/routes/api/v1/indices.js delete mode 100644 x-pack/legacy/plugins/security/server/routes/api/v1/users.js delete mode 100644 x-pack/legacy/server/lib/esjs_shield_plugin.js delete mode 100644 x-pack/legacy/server/lib/get_client_shield.ts rename x-pack/{legacy => }/plugins/security/common/model/api_key.ts (100%) create mode 100644 x-pack/plugins/security/server/elasticsearch_client_plugin.ts create mode 100644 x-pack/plugins/security/server/routes/api_keys/get.test.ts create mode 100644 x-pack/plugins/security/server/routes/api_keys/get.ts create mode 100644 x-pack/plugins/security/server/routes/api_keys/index.ts create mode 100644 x-pack/plugins/security/server/routes/api_keys/invalidate.test.ts create mode 100644 x-pack/plugins/security/server/routes/api_keys/invalidate.ts create mode 100644 x-pack/plugins/security/server/routes/api_keys/privileges.test.ts create mode 100644 x-pack/plugins/security/server/routes/api_keys/privileges.ts create mode 100644 x-pack/plugins/security/server/routes/authentication/basic.test.ts create mode 100644 x-pack/plugins/security/server/routes/authentication/basic.ts create mode 100644 x-pack/plugins/security/server/routes/authentication/common.test.ts create mode 100644 x-pack/plugins/security/server/routes/authentication/common.ts create mode 100644 x-pack/plugins/security/server/routes/authentication/oidc.ts create mode 100644 x-pack/plugins/security/server/routes/indices/get_fields.ts rename x-pack/{legacy/plugins/security/common/constants.ts => plugins/security/server/routes/indices/index.ts} (54%) create mode 100644 x-pack/plugins/security/server/routes/users/change_password.test.ts create mode 100644 x-pack/plugins/security/server/routes/users/change_password.ts create mode 100644 x-pack/plugins/security/server/routes/users/create_or_update.ts create mode 100644 x-pack/plugins/security/server/routes/users/delete.ts create mode 100644 x-pack/plugins/security/server/routes/users/get.ts create mode 100644 x-pack/plugins/security/server/routes/users/get_all.ts create mode 100644 x-pack/plugins/security/server/routes/users/index.ts diff --git a/docs/user/security/authentication/index.asciidoc b/docs/user/security/authentication/index.asciidoc index 32f341a9c1b7c..2e2aaf688e8b6 100644 --- a/docs/user/security/authentication/index.asciidoc +++ b/docs/user/security/authentication/index.asciidoc @@ -163,7 +163,7 @@ required by {kib}. If you want to use Third Party initiated SSO , then you must + [source,yaml] -------------------------------------------------------------------------------- -server.xsrf.whitelist: [/api/security/v1/oidc] +server.xsrf.whitelist: [/api/security/oidc/initiate_login] -------------------------------------------------------------------------------- [float] diff --git a/test/common/services/security/user.ts b/test/common/services/security/user.ts index e1c9b3fb998ad..ae02127043234 100644 --- a/test/common/services/security/user.ts +++ b/test/common/services/security/user.ts @@ -38,7 +38,7 @@ export class User { public async create(username: string, user: any) { this.log.debug(`creating user ${username}`); const { data, status, statusText } = await this.axios.post( - `/api/security/v1/users/${username}`, + `/internal/security/users/${username}`, { username, ...user, @@ -55,7 +55,7 @@ export class User { public async delete(username: string) { this.log.debug(`deleting user ${username}`); const { data, status, statusText } = await this.axios.delete( - `/api/security/v1/users/${username}` + `/internal/security/users/${username}` ); if (status !== 204) { throw new Error( diff --git a/x-pack/legacy/plugins/apm/scripts/kibana-security/setup-custom-kibana-user-role.ts b/x-pack/legacy/plugins/apm/scripts/kibana-security/setup-custom-kibana-user-role.ts index 9591dfdecbfef..66f2a8d1ac79f 100644 --- a/x-pack/legacy/plugins/apm/scripts/kibana-security/setup-custom-kibana-user-role.ts +++ b/x-pack/legacy/plugins/apm/scripts/kibana-security/setup-custom-kibana-user-role.ts @@ -183,7 +183,7 @@ async function createOrUpdateUser(newUser: User) { async function createUser(newUser: User) { const user = await callKibana({ method: 'POST', - url: `/api/security/v1/users/${newUser.username}`, + url: `/internal/security/users/${newUser.username}`, data: { ...newUser, enabled: true, @@ -209,7 +209,7 @@ async function updateUser(existingUser: User, newUser: User) { // assign role to user await callKibana({ method: 'POST', - url: `/api/security/v1/users/${username}`, + url: `/internal/security/users/${username}`, data: { ...existingUser, roles: allRoles } }); @@ -219,7 +219,7 @@ async function updateUser(existingUser: User, newUser: User) { async function getUser(username: string) { try { return await callKibana({ - url: `/api/security/v1/users/${username}` + url: `/internal/security/users/${username}` }); } catch (e) { const err = e as AxiosError; diff --git a/x-pack/legacy/plugins/security/common/model/index.ts b/x-pack/legacy/plugins/security/common/model.ts similarity index 84% rename from x-pack/legacy/plugins/security/common/model/index.ts rename to x-pack/legacy/plugins/security/common/model.ts index 6c2976815559b..90e6a5403dfe8 100644 --- a/x-pack/legacy/plugins/security/common/model/index.ts +++ b/x-pack/legacy/plugins/security/common/model.ts @@ -4,8 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -export { ApiKey } from './api_key'; export { + ApiKey, + ApiKeyToInvalidate, AuthenticatedUser, BuiltinESPrivileges, EditUser, @@ -19,4 +20,4 @@ export { User, canUserChangePassword, getUserDisplayName, -} from '../../../../../plugins/security/common/model'; +} from '../../../../plugins/security/common/model'; diff --git a/x-pack/legacy/plugins/security/index.js b/x-pack/legacy/plugins/security/index.js index 115dd8b9b8206..3a6f3692bc0b6 100644 --- a/x-pack/legacy/plugins/security/index.js +++ b/x-pack/legacy/plugins/security/index.js @@ -5,10 +5,6 @@ */ import { resolve } from 'path'; -import { initAuthenticateApi } from './server/routes/api/v1/authenticate'; -import { initUsersApi } from './server/routes/api/v1/users'; -import { initApiKeysApi } from './server/routes/api/v1/api_keys'; -import { initIndicesApi } from './server/routes/api/v1/indices'; import { initOverwrittenSessionView } from './server/routes/views/overwritten_session'; import { initLoginView } from './server/routes/views/login'; import { initLogoutView } from './server/routes/views/logout'; @@ -34,7 +30,7 @@ export const security = (kibana) => new kibana.Plugin({ lifespan: Joi.any().description('This key is handled in the new platform security plugin ONLY'), }).default(), secureCookies: Joi.any().description('This key is handled in the new platform security plugin ONLY'), - loginAssistanceMessage: Joi.string().default(), + loginAssistanceMessage: Joi.any().description('This key is handled in the new platform security plugin ONLY'), authorization: Joi.object({ legacyFallback: Joi.object({ enabled: Joi.boolean().default(true) // deprecated @@ -144,10 +140,6 @@ export const security = (kibana) => new kibana.Plugin({ server.expose({ getUser: request => securityPlugin.authc.getCurrentUser(KibanaRequest.from(request)) }); - initAuthenticateApi(securityPlugin, server); - initUsersApi(securityPlugin, server); - initApiKeysApi(server); - initIndicesApi(server); initLoginView(securityPlugin, server); initLogoutView(server); initLoggedOutView(securityPlugin, server); diff --git a/x-pack/legacy/plugins/security/public/hacks/on_unauthorized_response.js b/x-pack/legacy/plugins/security/public/hacks/on_unauthorized_response.js index 6d03f3da6e2f2..efc227e2c2789 100644 --- a/x-pack/legacy/plugins/security/public/hacks/on_unauthorized_response.js +++ b/x-pack/legacy/plugins/security/public/hacks/on_unauthorized_response.js @@ -11,8 +11,8 @@ import 'plugins/security/services/auto_logout'; function isUnauthorizedResponseAllowed(response) { const API_WHITELIST = [ - '/api/security/v1/login', - '/api/security/v1/users/.*/password' + '/internal/security/login', + '/internal/security/users/.*/password' ]; const url = response.config.url; diff --git a/x-pack/legacy/plugins/security/public/lib/api.ts b/x-pack/legacy/plugins/security/public/lib/api.ts index e6e42ed5bd4da..ffa08ca44f376 100644 --- a/x-pack/legacy/plugins/security/public/lib/api.ts +++ b/x-pack/legacy/plugins/security/public/lib/api.ts @@ -7,12 +7,12 @@ import { kfetch } from 'ui/kfetch'; import { AuthenticatedUser, Role, User, EditUser } from '../../common/model'; -const usersUrl = '/api/security/v1/users'; +const usersUrl = '/internal/security/users'; const rolesUrl = '/api/security/role'; export class UserAPIClient { public async getCurrentUser(): Promise { - return await kfetch({ pathname: `/api/security/v1/me` }); + return await kfetch({ pathname: `/internal/security/me` }); } public async getUsers(): Promise { diff --git a/x-pack/legacy/plugins/security/public/lib/api_keys_api.ts b/x-pack/legacy/plugins/security/public/lib/api_keys_api.ts index c6dcef392af98..fbc0460c5908a 100644 --- a/x-pack/legacy/plugins/security/public/lib/api_keys_api.ts +++ b/x-pack/legacy/plugins/security/public/lib/api_keys_api.ts @@ -5,8 +5,7 @@ */ import { kfetch } from 'ui/kfetch'; -import { ApiKey, ApiKeyToInvalidate } from '../../common/model/api_key'; -import { INTERNAL_API_BASE_PATH } from '../../common/constants'; +import { ApiKey, ApiKeyToInvalidate } from '../../common/model'; interface CheckPrivilegesResponse { areApiKeysEnabled: boolean; @@ -22,7 +21,7 @@ interface GetApiKeysResponse { apiKeys: ApiKey[]; } -const apiKeysUrl = `${INTERNAL_API_BASE_PATH}/api_key`; +const apiKeysUrl = `/internal/security/api_key`; export class ApiKeysApi { public static async checkPrivileges(): Promise { diff --git a/x-pack/legacy/plugins/security/public/objects/lib/get_fields.ts b/x-pack/legacy/plugins/security/public/objects/lib/get_fields.ts index e0998eb8b8f6b..91d98782dab42 100644 --- a/x-pack/legacy/plugins/security/public/objects/lib/get_fields.ts +++ b/x-pack/legacy/plugins/security/public/objects/lib/get_fields.ts @@ -6,7 +6,7 @@ import { IHttpResponse } from 'angular'; import chrome from 'ui/chrome'; -const apiBase = chrome.addBasePath(`/api/security/v1/fields`); +const apiBase = chrome.addBasePath(`/internal/security/fields`); export async function getFields($http: any, query: string): Promise { return await $http diff --git a/x-pack/legacy/plugins/security/public/services/shield_indices.js b/x-pack/legacy/plugins/security/public/services/shield_indices.js index 2e25d73acbcee..973569eb6e9c3 100644 --- a/x-pack/legacy/plugins/security/public/services/shield_indices.js +++ b/x-pack/legacy/plugins/security/public/services/shield_indices.js @@ -10,7 +10,7 @@ const module = uiModules.get('security', []); module.service('shieldIndices', ($http, chrome) => { return { getFields: (query) => { - return $http.get(chrome.addBasePath(`/api/security/v1/fields/${query}`)) + return $http.get(chrome.addBasePath(`/internal/security/fields/${query}`)) .then(response => response.data); } }; diff --git a/x-pack/legacy/plugins/security/public/services/shield_user.js b/x-pack/legacy/plugins/security/public/services/shield_user.js index e77895caaa2ba..53252e851e353 100644 --- a/x-pack/legacy/plugins/security/public/services/shield_user.js +++ b/x-pack/legacy/plugins/security/public/services/shield_user.js @@ -10,7 +10,7 @@ import { uiModules } from 'ui/modules'; const module = uiModules.get('security', ['ngResource']); module.service('ShieldUser', ($resource, chrome) => { - const baseUrl = chrome.addBasePath('/api/security/v1/users/:username'); + const baseUrl = chrome.addBasePath('/internal/security/users/:username'); const ShieldUser = $resource(baseUrl, { username: '@username' }, { @@ -21,7 +21,7 @@ module.service('ShieldUser', ($resource, chrome) => { }, getCurrent: { method: 'GET', - url: chrome.addBasePath('/api/security/v1/me') + url: chrome.addBasePath('/internal/security/me') } }); diff --git a/x-pack/legacy/plugins/security/public/views/login/components/basic_login_form/basic_login_form.tsx b/x-pack/legacy/plugins/security/public/views/login/components/basic_login_form/basic_login_form.tsx index acdc29842d4c6..e6d3b5b7536b6 100644 --- a/x-pack/legacy/plugins/security/public/views/login/components/basic_login_form/basic_login_form.tsx +++ b/x-pack/legacy/plugins/security/public/views/login/components/basic_login_form/basic_login_form.tsx @@ -190,7 +190,7 @@ class BasicLoginFormUI extends Component { const { username, password } = this.state; - http.post('./api/security/v1/login', { username, password }).then( + http.post('./internal/security/login', { username, password }).then( () => (window.location.href = next), (error: any) => { const { statusCode = 500 } = error.data || {}; diff --git a/x-pack/legacy/plugins/security/public/views/logout/logout.js b/x-pack/legacy/plugins/security/public/views/logout/logout.js index 4411ecdade8e7..5d76dfc2908c8 100644 --- a/x-pack/legacy/plugins/security/public/views/logout/logout.js +++ b/x-pack/legacy/plugins/security/public/views/logout/logout.js @@ -12,5 +12,5 @@ chrome $window.sessionStorage.clear(); // Redirect user to the server logout endpoint to complete logout. - $window.location.href = chrome.addBasePath(`/api/security/v1/logout${$window.location.search}`); + $window.location.href = chrome.addBasePath(`/api/security/logout${$window.location.search}`); }); diff --git a/x-pack/legacy/plugins/security/public/views/management/api_keys_grid/components/api_keys_grid_page.tsx b/x-pack/legacy/plugins/security/public/views/management/api_keys_grid/components/api_keys_grid_page.tsx index 37838cfdb950d..1613e3804c31d 100644 --- a/x-pack/legacy/plugins/security/public/views/management/api_keys_grid/components/api_keys_grid_page.tsx +++ b/x-pack/legacy/plugins/security/public/views/management/api_keys_grid/components/api_keys_grid_page.tsx @@ -29,7 +29,7 @@ import _ from 'lodash'; import { toastNotifications } from 'ui/notify'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { SectionLoading } from '../../../../../../../../../src/plugins/es_ui_shared/public/components/section_loading'; -import { ApiKey, ApiKeyToInvalidate } from '../../../../../common/model/api_key'; +import { ApiKey, ApiKeyToInvalidate } from '../../../../../common/model'; import { ApiKeysApi } from '../../../../lib/api_keys_api'; import { PermissionDenied } from './permission_denied'; import { EmptyPrompt } from './empty_prompt'; diff --git a/x-pack/legacy/plugins/security/public/views/management/api_keys_grid/components/invalidate_provider/invalidate_provider.tsx b/x-pack/legacy/plugins/security/public/views/management/api_keys_grid/components/invalidate_provider/invalidate_provider.tsx index fe9ffc651db29..a1627442b89b8 100644 --- a/x-pack/legacy/plugins/security/public/views/management/api_keys_grid/components/invalidate_provider/invalidate_provider.tsx +++ b/x-pack/legacy/plugins/security/public/views/management/api_keys_grid/components/invalidate_provider/invalidate_provider.tsx @@ -8,7 +8,7 @@ import React, { Fragment, useRef, useState } from 'react'; import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; import { toastNotifications } from 'ui/notify'; import { i18n } from '@kbn/i18n'; -import { ApiKeyToInvalidate } from '../../../../../../common/model/api_key'; +import { ApiKeyToInvalidate } from '../../../../../../common/model'; import { ApiKeysApi } from '../../../../../lib/api_keys_api'; interface Props { diff --git a/x-pack/legacy/plugins/security/server/lib/__tests__/__fixtures__/request.ts b/x-pack/legacy/plugins/security/server/lib/__tests__/__fixtures__/request.ts deleted file mode 100644 index c928a38d88ef3..0000000000000 --- a/x-pack/legacy/plugins/security/server/lib/__tests__/__fixtures__/request.ts +++ /dev/null @@ -1,39 +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 { Request } from 'hapi'; -import url from 'url'; - -interface RequestFixtureOptions { - headers?: Record; - auth?: string; - params?: Record; - path?: string; - basePath?: string; - search?: string; - payload?: unknown; -} - -export function requestFixture({ - headers = { accept: 'something/html' }, - auth, - params, - path = '/wat', - search = '', - payload, -}: RequestFixtureOptions = {}) { - return ({ - raw: { req: { headers } }, - auth, - headers, - params, - url: { path, search }, - query: search ? url.parse(search, true /* parseQueryString */).query : {}, - payload, - state: { user: 'these are the contents of the user client cookie' }, - route: { settings: {} }, - } as any) as Request; -} diff --git a/x-pack/legacy/plugins/security/server/lib/__tests__/__fixtures__/server.ts b/x-pack/legacy/plugins/security/server/lib/__tests__/__fixtures__/server.ts deleted file mode 100644 index 55b6f735cfced..0000000000000 --- a/x-pack/legacy/plugins/security/server/lib/__tests__/__fixtures__/server.ts +++ /dev/null @@ -1,56 +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 { stub } from 'sinon'; - -export function serverFixture() { - return { - config: stub(), - register: stub(), - expose: stub(), - log: stub(), - route: stub(), - decorate: stub(), - - info: { - protocol: 'protocol', - }, - - auth: { - strategy: stub(), - test: stub(), - }, - - plugins: { - elasticsearch: { - createCluster: stub(), - }, - - kibana: { - systemApi: { isSystemApiRequest: stub() }, - }, - - security: { - getUser: stub(), - authenticate: stub(), - deauthenticate: stub(), - authorization: { - application: stub(), - }, - }, - - xpack_main: { - info: { - isAvailable: stub(), - feature: stub(), - license: { - isOneOf: stub(), - }, - }, - }, - }, - }; -} diff --git a/x-pack/legacy/plugins/security/server/lib/route_pre_check_license.js b/x-pack/legacy/plugins/security/server/lib/route_pre_check_license.js deleted file mode 100644 index 64816bf4d23d7..0000000000000 --- a/x-pack/legacy/plugins/security/server/lib/route_pre_check_license.js +++ /dev/null @@ -1,18 +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. - */ - -const Boom = require('boom'); - -export function routePreCheckLicense(server) { - return function forbidApiAccess() { - const licenseCheckResults = server.newPlatform.setup.plugins.security.__legacyCompat.license.getFeatures(); - if (!licenseCheckResults.showLinks) { - throw Boom.forbidden(licenseCheckResults.linksMessage); - } else { - return null; - } - }; -} diff --git a/x-pack/legacy/plugins/security/server/lib/user_schema.js b/x-pack/legacy/plugins/security/server/lib/user_schema.js deleted file mode 100644 index 57c66b2712025..0000000000000 --- a/x-pack/legacy/plugins/security/server/lib/user_schema.js +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import Joi from 'joi'; - -export const userSchema = Joi.object({ - username: Joi.string().required(), - password: Joi.string(), - roles: Joi.array().items(Joi.string()), - full_name: Joi.string().allow(null, ''), - email: Joi.string().allow(null, ''), - metadata: Joi.object(), - enabled: Joi.boolean().default(true) -}); diff --git a/x-pack/legacy/plugins/security/server/routes/api/v1/__tests__/authenticate.js b/x-pack/legacy/plugins/security/server/routes/api/v1/__tests__/authenticate.js deleted file mode 100644 index 5cea7c70b7781..0000000000000 --- a/x-pack/legacy/plugins/security/server/routes/api/v1/__tests__/authenticate.js +++ /dev/null @@ -1,260 +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 expect from '@kbn/expect'; -import Boom from 'boom'; -import Joi from 'joi'; -import sinon from 'sinon'; - -import { serverFixture } from '../../../../lib/__tests__/__fixtures__/server'; -import { requestFixture } from '../../../../lib/__tests__/__fixtures__/request'; -import { AuthenticationResult, DeauthenticationResult } from '../../../../../../../../plugins/security/server'; -import { initAuthenticateApi } from '../authenticate'; -import { KibanaRequest } from '../../../../../../../../../src/core/server'; - -describe('Authentication routes', () => { - let serverStub; - let hStub; - let loginStub; - let logoutStub; - - beforeEach(() => { - serverStub = serverFixture(); - hStub = { - authenticated: sinon.stub(), - continue: 'blah', - redirect: sinon.stub(), - response: sinon.stub() - }; - loginStub = sinon.stub(); - logoutStub = sinon.stub(); - - initAuthenticateApi({ - authc: { login: loginStub, logout: logoutStub }, - __legacyCompat: { config: { authc: { providers: ['basic'] } } }, - }, serverStub); - }); - - describe('login', () => { - let loginRoute; - let request; - - beforeEach(() => { - loginRoute = serverStub.route - .withArgs(sinon.match({ path: '/api/security/v1/login' })) - .firstCall - .args[0]; - - request = requestFixture({ - headers: {}, - payload: { username: 'user', password: 'password' } - }); - }); - - it('correctly defines route.', async () => { - expect(loginRoute.method).to.be('POST'); - expect(loginRoute.path).to.be('/api/security/v1/login'); - expect(loginRoute.handler).to.be.a(Function); - expect(loginRoute.config).to.eql({ - auth: false, - validate: { - payload: Joi.object({ - username: Joi.string().required(), - password: Joi.string().required() - }) - }, - response: { - emptyStatusCode: 204, - } - }); - }); - - it('returns 500 if authentication throws unhandled exception.', async () => { - const unhandledException = new Error('Something went wrong.'); - loginStub.throws(unhandledException); - - return loginRoute - .handler(request, hStub) - .catch((response) => { - expect(response.isBoom).to.be(true); - expect(response.output.payload).to.eql({ - statusCode: 500, - error: 'Internal Server Error', - message: 'An internal server error occurred' - }); - }); - }); - - it('returns 401 if authentication fails.', async () => { - const failureReason = new Error('Something went wrong.'); - loginStub.resolves(AuthenticationResult.failed(failureReason)); - - return loginRoute - .handler(request, hStub) - .catch((response) => { - expect(response.isBoom).to.be(true); - expect(response.message).to.be(failureReason.message); - expect(response.output.statusCode).to.be(401); - }); - }); - - it('returns 401 if authentication is not handled.', async () => { - loginStub.resolves(AuthenticationResult.notHandled()); - - return loginRoute - .handler(request, hStub) - .catch((response) => { - expect(response.isBoom).to.be(true); - expect(response.message).to.be('Unauthorized'); - expect(response.output.statusCode).to.be(401); - }); - }); - - describe('authentication succeeds', () => { - - it(`returns user data`, async () => { - loginStub.resolves(AuthenticationResult.succeeded({ username: 'user' })); - - await loginRoute.handler(request, hStub); - - sinon.assert.calledOnce(hStub.response); - sinon.assert.calledOnce(loginStub); - sinon.assert.calledWithExactly( - loginStub, - sinon.match.instanceOf(KibanaRequest), - { provider: 'basic', value: { username: 'user', password: 'password' } } - ); - }); - }); - - }); - - describe('logout', () => { - let logoutRoute; - - beforeEach(() => { - serverStub.config.returns({ - get: sinon.stub().withArgs('server.basePath').returns('/test-base-path') - }); - - logoutRoute = serverStub.route - .withArgs(sinon.match({ path: '/api/security/v1/logout' })) - .firstCall - .args[0]; - }); - - it('correctly defines route.', async () => { - expect(logoutRoute.method).to.be('GET'); - expect(logoutRoute.path).to.be('/api/security/v1/logout'); - expect(logoutRoute.handler).to.be.a(Function); - expect(logoutRoute.config).to.eql({ auth: false }); - }); - - it('returns 500 if deauthentication throws unhandled exception.', async () => { - const request = requestFixture(); - - const unhandledException = new Error('Something went wrong.'); - logoutStub.rejects(unhandledException); - - return logoutRoute - .handler(request, hStub) - .catch((response) => { - expect(response).to.be(Boom.boomify(unhandledException)); - sinon.assert.notCalled(hStub.redirect); - }); - }); - - it('returns 500 if authenticator fails to logout.', async () => { - const request = requestFixture(); - - const failureReason = Boom.forbidden(); - logoutStub.resolves(DeauthenticationResult.failed(failureReason)); - - return logoutRoute - .handler(request, hStub) - .catch((response) => { - expect(response).to.be(Boom.boomify(failureReason)); - sinon.assert.notCalled(hStub.redirect); - sinon.assert.calledOnce(logoutStub); - sinon.assert.calledWithExactly( - logoutStub, - sinon.match.instanceOf(KibanaRequest) - ); - }); - }); - - it('returns 400 for AJAX requests that can not handle redirect.', async () => { - const request = requestFixture({ headers: { 'kbn-xsrf': 'xsrf' } }); - - return logoutRoute - .handler(request, hStub) - .catch((response) => { - expect(response.isBoom).to.be(true); - expect(response.message).to.be('Client should be able to process redirect response.'); - expect(response.output.statusCode).to.be(400); - sinon.assert.notCalled(hStub.redirect); - }); - }); - - it('redirects user to the URL returned by authenticator.', async () => { - const request = requestFixture(); - - logoutStub.resolves(DeauthenticationResult.redirectTo('https://custom.logout')); - - await logoutRoute.handler(request, hStub); - - sinon.assert.calledOnce(hStub.redirect); - sinon.assert.calledWithExactly(hStub.redirect, 'https://custom.logout'); - }); - - it('redirects user to the base path if deauthentication succeeds.', async () => { - const request = requestFixture(); - - logoutStub.resolves(DeauthenticationResult.succeeded()); - - await logoutRoute.handler(request, hStub); - - sinon.assert.calledOnce(hStub.redirect); - sinon.assert.calledWithExactly(hStub.redirect, '/test-base-path/'); - }); - - it('redirects user to the base path if deauthentication is not handled.', async () => { - const request = requestFixture(); - - logoutStub.resolves(DeauthenticationResult.notHandled()); - - await logoutRoute.handler(request, hStub); - - sinon.assert.calledOnce(hStub.redirect); - sinon.assert.calledWithExactly(hStub.redirect, '/test-base-path/'); - }); - }); - - describe('me', () => { - let meRoute; - - beforeEach(() => { - meRoute = serverStub.route - .withArgs(sinon.match({ path: '/api/security/v1/me' })) - .firstCall - .args[0]; - }); - - it('correctly defines route.', async () => { - expect(meRoute.method).to.be('GET'); - expect(meRoute.path).to.be('/api/security/v1/me'); - expect(meRoute.handler).to.be.a(Function); - expect(meRoute.config).to.be(undefined); - }); - - it('returns user from the authenticated request property.', async () => { - const request = { auth: { credentials: { username: 'user' } } }; - const response = await meRoute.handler(request, hStub); - - expect(response).to.eql({ username: 'user' }); - }); - }); -}); diff --git a/x-pack/legacy/plugins/security/server/routes/api/v1/__tests__/users.js b/x-pack/legacy/plugins/security/server/routes/api/v1/__tests__/users.js deleted file mode 100644 index 4077ab52e86de..0000000000000 --- a/x-pack/legacy/plugins/security/server/routes/api/v1/__tests__/users.js +++ /dev/null @@ -1,214 +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 expect from '@kbn/expect'; -import Joi from 'joi'; -import sinon from 'sinon'; - -import { serverFixture } from '../../../../lib/__tests__/__fixtures__/server'; -import { requestFixture } from '../../../../lib/__tests__/__fixtures__/request'; -import { AuthenticationResult } from '../../../../../../../../plugins/security/server'; -import { initUsersApi } from '../users'; -import * as ClientShield from '../../../../../../../server/lib/get_client_shield'; -import { KibanaRequest } from '../../../../../../../../../src/core/server'; - -describe('User routes', () => { - const sandbox = sinon.createSandbox(); - - let clusterStub; - let serverStub; - let loginStub; - - beforeEach(() => { - serverStub = serverFixture(); - loginStub = sinon.stub(); - - // Cluster is returned by `getClient` function that is wrapped into `once` making cluster - // a static singleton, so we should use sandbox to set/reset its behavior between tests. - clusterStub = sinon.stub({ callWithRequest() {} }); - sandbox.stub(ClientShield, 'getClient').returns(clusterStub); - - initUsersApi({ authc: { login: loginStub }, __legacyCompat: { config: { authc: { providers: ['basic'] } } } }, serverStub); - }); - - afterEach(() => sandbox.restore()); - - describe('change password', () => { - let changePasswordRoute; - let request; - - beforeEach(() => { - changePasswordRoute = serverStub.route - .withArgs(sinon.match({ path: '/api/security/v1/users/{username}/password' })) - .firstCall - .args[0]; - - request = requestFixture({ - headers: {}, - auth: { credentials: { username: 'user' } }, - params: { username: 'target-user' }, - payload: { password: 'old-password', newPassword: 'new-password' } - }); - }); - - it('correctly defines route.', async () => { - expect(changePasswordRoute.method).to.be('POST'); - expect(changePasswordRoute.path).to.be('/api/security/v1/users/{username}/password'); - expect(changePasswordRoute.handler).to.be.a(Function); - - expect(changePasswordRoute.config).to.not.have.property('auth'); - expect(changePasswordRoute.config).to.have.property('pre'); - expect(changePasswordRoute.config.pre).to.have.length(1); - expect(changePasswordRoute.config.validate).to.eql({ - payload: Joi.object({ - password: Joi.string(), - newPassword: Joi.string().required() - }) - }); - }); - - describe('own password', () => { - beforeEach(() => { - request.params.username = request.auth.credentials.username; - loginStub = loginStub - .withArgs( - sinon.match.instanceOf(KibanaRequest), - { provider: 'basic', value: { username: 'user', password: 'old-password' }, stateless: true } - ) - .resolves(AuthenticationResult.succeeded({})); - }); - - it('returns 403 if old password is wrong.', async () => { - loginStub.resolves(AuthenticationResult.failed(new Error('Something went wrong.'))); - - const response = await changePasswordRoute.handler(request); - - sinon.assert.notCalled(clusterStub.callWithRequest); - expect(response.isBoom).to.be(true); - expect(response.output.payload).to.eql({ - statusCode: 403, - error: 'Forbidden', - message: 'Something went wrong.' - }); - }); - - it(`returns 401 if user can't authenticate with new password.`, async () => { - loginStub - .withArgs( - sinon.match.instanceOf(KibanaRequest), - { provider: 'basic', value: { username: 'user', password: 'new-password' } } - ) - .resolves(AuthenticationResult.failed(new Error('Something went wrong.'))); - - const response = await changePasswordRoute.handler(request); - - sinon.assert.calledOnce(clusterStub.callWithRequest); - sinon.assert.calledWithExactly( - clusterStub.callWithRequest, - sinon.match.same(request), - 'shield.changePassword', - { username: 'user', body: { password: 'new-password' } } - ); - - expect(response.isBoom).to.be(true); - expect(response.output.payload).to.eql({ - statusCode: 401, - error: 'Unauthorized', - message: 'Something went wrong.' - }); - }); - - it('returns 500 if password update request fails.', async () => { - clusterStub.callWithRequest - .withArgs( - sinon.match.same(request), - 'shield.changePassword', - { username: 'user', body: { password: 'new-password' } } - ) - .rejects(new Error('Request failed.')); - - const response = await changePasswordRoute.handler(request); - - expect(response.isBoom).to.be(true); - expect(response.output.payload).to.eql({ - statusCode: 500, - error: 'Internal Server Error', - message: 'An internal server error occurred' - }); - }); - - it('successfully changes own password if provided old password is correct.', async () => { - loginStub - .withArgs( - sinon.match.instanceOf(KibanaRequest), - { provider: 'basic', value: { username: 'user', password: 'new-password' } } - ) - .resolves(AuthenticationResult.succeeded({})); - - const hResponseStub = { code: sinon.stub() }; - const hStub = { response: sinon.stub().returns(hResponseStub) }; - - await changePasswordRoute.handler(request, hStub); - - sinon.assert.calledOnce(clusterStub.callWithRequest); - sinon.assert.calledWithExactly( - clusterStub.callWithRequest, - sinon.match.same(request), - 'shield.changePassword', - { username: 'user', body: { password: 'new-password' } } - ); - - sinon.assert.calledWithExactly(hStub.response); - sinon.assert.calledWithExactly(hResponseStub.code, 204); - }); - }); - - describe('other user password', () => { - it('returns 500 if password update request fails.', async () => { - clusterStub.callWithRequest - .withArgs( - sinon.match.same(request), - 'shield.changePassword', - { username: 'target-user', body: { password: 'new-password' } } - ) - .returns(Promise.reject(new Error('Request failed.'))); - - const response = await changePasswordRoute.handler(request); - - sinon.assert.notCalled(serverStub.plugins.security.getUser); - sinon.assert.notCalled(loginStub); - - expect(response.isBoom).to.be(true); - expect(response.output.payload).to.eql({ - statusCode: 500, - error: 'Internal Server Error', - message: 'An internal server error occurred' - }); - }); - - it('successfully changes user password.', async () => { - const hResponseStub = { code: sinon.stub() }; - const hStub = { response: sinon.stub().returns(hResponseStub) }; - - await changePasswordRoute.handler(request, hStub); - - sinon.assert.notCalled(serverStub.plugins.security.getUser); - sinon.assert.notCalled(loginStub); - - sinon.assert.calledOnce(clusterStub.callWithRequest); - sinon.assert.calledWithExactly( - clusterStub.callWithRequest, - sinon.match.same(request), - 'shield.changePassword', - { username: 'target-user', body: { password: 'new-password' } } - ); - - sinon.assert.calledWithExactly(hStub.response); - sinon.assert.calledWithExactly(hResponseStub.code, 204); - }); - }); - }); -}); diff --git a/x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/get.js b/x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/get.js deleted file mode 100644 index a236badcd0d6b..0000000000000 --- a/x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/get.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 Joi from 'joi'; -import { wrapError } from '../../../../../../../../plugins/security/server'; -import { INTERNAL_API_BASE_PATH } from '../../../../../common/constants'; - -export function initGetApiKeysApi(server, callWithRequest, routePreCheckLicenseFn) { - server.route({ - method: 'GET', - path: `${INTERNAL_API_BASE_PATH}/api_key`, - async handler(request) { - try { - const { isAdmin } = request.query; - - const result = await callWithRequest( - request, - 'shield.getAPIKeys', - { - owner: !isAdmin - } - ); - - const validKeys = result.api_keys.filter(({ invalidated }) => !invalidated); - - return { - apiKeys: validKeys, - }; - } catch (error) { - return wrapError(error); - } - }, - config: { - pre: [routePreCheckLicenseFn], - validate: { - query: Joi.object().keys({ - isAdmin: Joi.bool().required(), - }).required(), - }, - } - }); -} diff --git a/x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/get.test.js b/x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/get.test.js deleted file mode 100644 index 400e5b705aeb2..0000000000000 --- a/x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/get.test.js +++ /dev/null @@ -1,166 +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 Hapi from 'hapi'; -import Boom from 'boom'; - -import { initGetApiKeysApi } from './get'; -import { INTERNAL_API_BASE_PATH } from '../../../../../common/constants'; - -const createMockServer = () => new Hapi.Server({ debug: false, port: 8080 }); - -describe('GET API keys', () => { - const getApiKeysTest = ( - description, - { - preCheckLicenseImpl = () => null, - callWithRequestImpl, - asserts, - isAdmin = true, - } - ) => { - test(description, async () => { - const mockServer = createMockServer(); - const pre = jest.fn().mockImplementation(preCheckLicenseImpl); - const mockCallWithRequest = jest.fn(); - - if (callWithRequestImpl) { - mockCallWithRequest.mockImplementation(callWithRequestImpl); - } - - initGetApiKeysApi(mockServer, mockCallWithRequest, pre); - - const headers = { - authorization: 'foo', - }; - - const request = { - method: 'GET', - url: `${INTERNAL_API_BASE_PATH}/api_key?isAdmin=${isAdmin}`, - headers, - }; - - const { result, statusCode } = await mockServer.inject(request); - - expect(pre).toHaveBeenCalled(); - - if (callWithRequestImpl) { - expect(mockCallWithRequest).toHaveBeenCalledWith( - expect.objectContaining({ - headers: expect.objectContaining({ - authorization: headers.authorization, - }), - }), - 'shield.getAPIKeys', - { - owner: !isAdmin, - }, - ); - } else { - expect(mockCallWithRequest).not.toHaveBeenCalled(); - } - - expect(statusCode).toBe(asserts.statusCode); - expect(result).toEqual(asserts.result); - }); - }; - - describe('failure', () => { - getApiKeysTest('returns result of routePreCheckLicense', { - preCheckLicenseImpl: () => Boom.forbidden('test forbidden message'), - asserts: { - statusCode: 403, - result: { - error: 'Forbidden', - statusCode: 403, - message: 'test forbidden message', - }, - }, - }); - - getApiKeysTest('returns error from callWithRequest', { - callWithRequestImpl: async () => { - throw Boom.notAcceptable('test not acceptable message'); - }, - asserts: { - statusCode: 406, - result: { - error: 'Not Acceptable', - statusCode: 406, - message: 'test not acceptable message', - }, - }, - }); - }); - - describe('success', () => { - getApiKeysTest('returns API keys', { - callWithRequestImpl: async () => ({ - api_keys: - [{ - id: 'YCLV7m0BJ3xI4hhWB648', - name: 'test-api-key', - creation: 1571670001452, - expiration: 1571756401452, - invalidated: false, - username: 'elastic', - realm: 'reserved' - }] - }), - asserts: { - statusCode: 200, - result: { - apiKeys: - [{ - id: 'YCLV7m0BJ3xI4hhWB648', - name: 'test-api-key', - creation: 1571670001452, - expiration: 1571756401452, - invalidated: false, - username: 'elastic', - realm: 'reserved' - }] - }, - }, - }); - getApiKeysTest('returns only valid API keys', { - callWithRequestImpl: async () => ({ - api_keys: - [{ - id: 'YCLV7m0BJ3xI4hhWB648', - name: 'test-api-key1', - creation: 1571670001452, - expiration: 1571756401452, - invalidated: true, - username: 'elastic', - realm: 'reserved' - }, { - id: 'YCLV7m0BJ3xI4hhWB648', - name: 'test-api-key2', - creation: 1571670001452, - expiration: 1571756401452, - invalidated: false, - username: 'elastic', - realm: 'reserved' - }], - }), - asserts: { - statusCode: 200, - result: { - apiKeys: - [{ - id: 'YCLV7m0BJ3xI4hhWB648', - name: 'test-api-key2', - creation: 1571670001452, - expiration: 1571756401452, - invalidated: false, - username: 'elastic', - realm: 'reserved' - }] - }, - }, - }); - }); -}); diff --git a/x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/index.js b/x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/index.js deleted file mode 100644 index fc55bdcc38661..0000000000000 --- a/x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/index.js +++ /dev/null @@ -1,20 +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 { getClient } from '../../../../../../../server/lib/get_client_shield'; -import { routePreCheckLicense } from '../../../../lib/route_pre_check_license'; -import { initCheckPrivilegesApi } from './privileges'; -import { initGetApiKeysApi } from './get'; -import { initInvalidateApiKeysApi } from './invalidate'; - -export function initApiKeysApi(server) { - const callWithRequest = getClient(server).callWithRequest; - const routePreCheckLicenseFn = routePreCheckLicense(server); - - initCheckPrivilegesApi(server, callWithRequest, routePreCheckLicenseFn); - initGetApiKeysApi(server, callWithRequest, routePreCheckLicenseFn); - initInvalidateApiKeysApi(server, callWithRequest, routePreCheckLicenseFn); -} diff --git a/x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/invalidate.js b/x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/invalidate.js deleted file mode 100644 index 293142c60be67..0000000000000 --- a/x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/invalidate.js +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import Joi from 'joi'; -import { wrapError } from '../../../../../../../../plugins/security/server'; -import { INTERNAL_API_BASE_PATH } from '../../../../../common/constants'; - -export function initInvalidateApiKeysApi(server, callWithRequest, routePreCheckLicenseFn) { - server.route({ - method: 'POST', - path: `${INTERNAL_API_BASE_PATH}/api_key/invalidate`, - async handler(request) { - try { - const { apiKeys, isAdmin } = request.payload; - const itemsInvalidated = []; - const errors = []; - - // Send the request to invalidate the API key and return an error if it could not be deleted. - const sendRequestToInvalidateApiKey = async (id) => { - try { - const body = { id }; - - if (!isAdmin) { - body.owner = true; - } - - await callWithRequest(request, 'shield.invalidateAPIKey', { body }); - return null; - } catch (error) { - return wrapError(error); - } - }; - - const invalidateApiKey = async ({ id, name }) => { - const error = await sendRequestToInvalidateApiKey(id); - if (error) { - errors.push({ id, name, error }); - } else { - itemsInvalidated.push({ id, name }); - } - }; - - // Invalidate all API keys in parallel. - await Promise.all(apiKeys.map((key) => invalidateApiKey(key))); - - return { - itemsInvalidated, - errors, - }; - } catch (error) { - return wrapError(error); - } - }, - config: { - pre: [routePreCheckLicenseFn], - validate: { - payload: Joi.object({ - apiKeys: Joi.array().items(Joi.object({ - id: Joi.string().required(), - name: Joi.string().required(), - })).required(), - isAdmin: Joi.bool().required(), - }) - }, - } - }); -} diff --git a/x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/invalidate.test.js b/x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/invalidate.test.js deleted file mode 100644 index 3ed7ca94eb782..0000000000000 --- a/x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/invalidate.test.js +++ /dev/null @@ -1,200 +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 Hapi from 'hapi'; -import Boom from 'boom'; - -import { initInvalidateApiKeysApi } from './invalidate'; -import { INTERNAL_API_BASE_PATH } from '../../../../../common/constants'; - -const createMockServer = () => new Hapi.Server({ debug: false, port: 8080 }); - -describe('POST invalidate', () => { - const postInvalidateTest = ( - description, - { - preCheckLicenseImpl = () => null, - callWithRequestImpls = [], - asserts, - payload, - } - ) => { - test(description, async () => { - const mockServer = createMockServer(); - const pre = jest.fn().mockImplementation(preCheckLicenseImpl); - const mockCallWithRequest = jest.fn(); - - for (const impl of callWithRequestImpls) { - mockCallWithRequest.mockImplementationOnce(impl); - } - - initInvalidateApiKeysApi(mockServer, mockCallWithRequest, pre); - - const headers = { - authorization: 'foo', - }; - - const request = { - method: 'POST', - url: `${INTERNAL_API_BASE_PATH}/api_key/invalidate`, - headers, - payload, - }; - - const { result, statusCode } = await mockServer.inject(request); - - expect(pre).toHaveBeenCalled(); - - if (asserts.callWithRequests) { - for (const args of asserts.callWithRequests) { - expect(mockCallWithRequest).toHaveBeenCalledWith( - expect.objectContaining({ - headers: expect.objectContaining({ - authorization: headers.authorization, - }), - }), - ...args - ); - } - } else { - expect(mockCallWithRequest).not.toHaveBeenCalled(); - } - - expect(statusCode).toBe(asserts.statusCode); - expect(result).toEqual(asserts.result); - }); - }; - - describe('failure', () => { - postInvalidateTest('returns result of routePreCheckLicense', { - preCheckLicenseImpl: () => Boom.forbidden('test forbidden message'), - payload: { - apiKeys: [{ id: 'si8If24B1bKsmSLTAhJV', name: 'my-api-key' }], - isAdmin: true - }, - asserts: { - statusCode: 403, - result: { - error: 'Forbidden', - statusCode: 403, - message: 'test forbidden message', - }, - }, - }); - - postInvalidateTest('returns errors array from callWithRequest', { - callWithRequestImpls: [async () => { - throw Boom.notAcceptable('test not acceptable message'); - }], - payload: { - apiKeys: [{ id: 'si8If24B1bKsmSLTAhJV', name: 'my-api-key', }], - isAdmin: true - }, - asserts: { - callWithRequests: [ - ['shield.invalidateAPIKey', { - body: { - id: 'si8If24B1bKsmSLTAhJV', - }, - }], - ], - statusCode: 200, - result: { - itemsInvalidated: [], - errors: [{ - id: 'si8If24B1bKsmSLTAhJV', - name: 'my-api-key', - error: Boom.notAcceptable('test not acceptable message'), - }] - }, - }, - }); - }); - - describe('success', () => { - postInvalidateTest('invalidates API keys', { - callWithRequestImpls: [async () => null], - payload: { - apiKeys: [{ id: 'si8If24B1bKsmSLTAhJV', name: 'my-api-key', }], - isAdmin: true - }, - asserts: { - callWithRequests: [ - ['shield.invalidateAPIKey', { - body: { - id: 'si8If24B1bKsmSLTAhJV', - }, - }], - ], - statusCode: 200, - result: { - itemsInvalidated: [{ id: 'si8If24B1bKsmSLTAhJV', name: 'my-api-key', }], - errors: [], - }, - }, - }); - - postInvalidateTest('adds "owner" to body if isAdmin=false', { - callWithRequestImpls: [async () => null], - payload: { - apiKeys: [{ id: 'si8If24B1bKsmSLTAhJV', name: 'my-api-key', }], - isAdmin: false - }, - asserts: { - callWithRequests: [ - ['shield.invalidateAPIKey', { - body: { - id: 'si8If24B1bKsmSLTAhJV', - owner: true, - }, - }], - ], - statusCode: 200, - result: { - itemsInvalidated: [{ id: 'si8If24B1bKsmSLTAhJV', name: 'my-api-key' }], - errors: [], - }, - }, - }); - - postInvalidateTest('returns only successful invalidation requests', { - callWithRequestImpls: [ - async () => null, - async () => { - throw Boom.notAcceptable('test not acceptable message'); - }], - payload: { - apiKeys: [ - { id: 'si8If24B1bKsmSLTAhJV', name: 'my-api-key1' }, - { id: 'ab8If24B1bKsmSLTAhNC', name: 'my-api-key2' } - ], - isAdmin: true - }, - asserts: { - callWithRequests: [ - ['shield.invalidateAPIKey', { - body: { - id: 'si8If24B1bKsmSLTAhJV', - }, - }], - ['shield.invalidateAPIKey', { - body: { - id: 'ab8If24B1bKsmSLTAhNC', - }, - }], - ], - statusCode: 200, - result: { - itemsInvalidated: [{ id: 'si8If24B1bKsmSLTAhJV', name: 'my-api-key1' }], - errors: [{ - id: 'ab8If24B1bKsmSLTAhNC', - name: 'my-api-key2', - error: Boom.notAcceptable('test not acceptable message'), - }] - }, - }, - }); - }); -}); diff --git a/x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/privileges.js b/x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/privileges.js deleted file mode 100644 index 3aa30c9a3b9bb..0000000000000 --- a/x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/privileges.js +++ /dev/null @@ -1,75 +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 { wrapError } from '../../../../../../../../plugins/security/server'; -import { INTERNAL_API_BASE_PATH } from '../../../../../common/constants'; - -export function initCheckPrivilegesApi(server, callWithRequest, routePreCheckLicenseFn) { - server.route({ - method: 'GET', - path: `${INTERNAL_API_BASE_PATH}/api_key/privileges`, - async handler(request) { - try { - const result = await Promise.all([ - callWithRequest( - request, - 'shield.hasPrivileges', - { - body: { - cluster: [ - 'manage_security', - 'manage_api_key', - ], - }, - } - ), - new Promise(async (resolve, reject) => { - try { - const result = await callWithRequest( - request, - 'shield.getAPIKeys', - { - owner: true - } - ); - // If the API returns a truthy result that means it's enabled. - resolve({ areApiKeysEnabled: !!result }); - } catch (e) { - // This is a brittle dependency upon message. Tracked by https://github.com/elastic/elasticsearch/issues/47759. - if (e.message.includes('api keys are not enabled')) { - return resolve({ areApiKeysEnabled: false }); - } - - // It's a real error, so rethrow it. - reject(e); - } - }), - ]); - - const [{ - cluster: { - manage_security: manageSecurity, - manage_api_key: manageApiKey, - } - }, { - areApiKeysEnabled, - }] = result; - - const isAdmin = manageSecurity || manageApiKey; - - return { - areApiKeysEnabled, - isAdmin, - }; - } catch (error) { - return wrapError(error); - } - }, - config: { - pre: [routePreCheckLicenseFn] - } - }); -} diff --git a/x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/privileges.test.js b/x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/privileges.test.js deleted file mode 100644 index 2a6f935e00595..0000000000000 --- a/x-pack/legacy/plugins/security/server/routes/api/v1/api_keys/privileges.test.js +++ /dev/null @@ -1,254 +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 Hapi from 'hapi'; -import Boom from 'boom'; - -import { initCheckPrivilegesApi } from './privileges'; -import { INTERNAL_API_BASE_PATH } from '../../../../../common/constants'; - -const createMockServer = () => new Hapi.Server({ debug: false, port: 8080 }); - -describe('GET privileges', () => { - const getPrivilegesTest = ( - description, - { - preCheckLicenseImpl = () => null, - callWithRequestImpls = [], - asserts, - } - ) => { - test(description, async () => { - const mockServer = createMockServer(); - const pre = jest.fn().mockImplementation(preCheckLicenseImpl); - const mockCallWithRequest = jest.fn(); - - for (const impl of callWithRequestImpls) { - mockCallWithRequest.mockImplementationOnce(impl); - } - - initCheckPrivilegesApi(mockServer, mockCallWithRequest, pre); - - const headers = { - authorization: 'foo', - }; - - const request = { - method: 'GET', - url: `${INTERNAL_API_BASE_PATH}/api_key/privileges`, - headers, - }; - - const { result, statusCode } = await mockServer.inject(request); - - expect(pre).toHaveBeenCalled(); - - if (asserts.callWithRequests) { - for (const args of asserts.callWithRequests) { - expect(mockCallWithRequest).toHaveBeenCalledWith( - expect.objectContaining({ - headers: expect.objectContaining({ - authorization: headers.authorization, - }), - }), - ...args - ); - } - } else { - expect(mockCallWithRequest).not.toHaveBeenCalled(); - } - - expect(statusCode).toBe(asserts.statusCode); - expect(result).toEqual(asserts.result); - }); - }; - - describe('failure', () => { - getPrivilegesTest('returns result of routePreCheckLicense', { - preCheckLicenseImpl: () => Boom.forbidden('test forbidden message'), - asserts: { - statusCode: 403, - result: { - error: 'Forbidden', - statusCode: 403, - message: 'test forbidden message', - }, - }, - }); - - getPrivilegesTest('returns error from first callWithRequest', { - callWithRequestImpls: [async () => { - throw Boom.notAcceptable('test not acceptable message'); - }, async () => { }], - asserts: { - callWithRequests: [ - ['shield.hasPrivileges', { - body: { - cluster: [ - 'manage_security', - 'manage_api_key', - ], - }, - }], - ['shield.getAPIKeys', { owner: true }], - ], - statusCode: 406, - result: { - error: 'Not Acceptable', - statusCode: 406, - message: 'test not acceptable message', - }, - }, - }); - - getPrivilegesTest('returns error from second callWithRequest', { - callWithRequestImpls: [async () => { }, async () => { - throw Boom.notAcceptable('test not acceptable message'); - }], - asserts: { - callWithRequests: [ - ['shield.hasPrivileges', { - body: { - cluster: [ - 'manage_security', - 'manage_api_key', - ], - }, - }], - ['shield.getAPIKeys', { owner: true }], - ], - statusCode: 406, - result: { - error: 'Not Acceptable', - statusCode: 406, - message: 'test not acceptable message', - }, - }, - }); - }); - - describe('success', () => { - getPrivilegesTest('returns areApiKeysEnabled and isAdmin', { - callWithRequestImpls: [ - async () => ({ - username: 'elastic', - has_all_requested: true, - cluster: { manage_api_key: true, manage_security: true }, - index: {}, - application: {} - }), - async () => ( - { - api_keys: - [{ - id: 'si8If24B1bKsmSLTAhJV', - name: 'my-api-key', - creation: 1574089261632, - expiration: 1574175661632, - invalidated: false, - username: 'elastic', - realm: 'reserved' - }] - } - ), - ], - asserts: { - callWithRequests: [ - ['shield.getAPIKeys', { owner: true }], - ['shield.hasPrivileges', { - body: { - cluster: [ - 'manage_security', - 'manage_api_key', - ], - }, - }], - ], - statusCode: 200, - result: { - areApiKeysEnabled: true, - isAdmin: true, - }, - }, - }); - - getPrivilegesTest('returns areApiKeysEnabled=false when getAPIKeys error message includes "api keys are not enabled"', { - callWithRequestImpls: [ - async () => ({ - username: 'elastic', - has_all_requested: true, - cluster: { manage_api_key: true, manage_security: true }, - index: {}, - application: {} - }), - async () => { - throw Boom.unauthorized('api keys are not enabled'); - }, - ], - asserts: { - callWithRequests: [ - ['shield.getAPIKeys', { owner: true }], - ['shield.hasPrivileges', { - body: { - cluster: [ - 'manage_security', - 'manage_api_key', - ], - }, - }], - ], - statusCode: 200, - result: { - areApiKeysEnabled: false, - isAdmin: true, - }, - }, - }); - - getPrivilegesTest('returns isAdmin=false when user has insufficient privileges', { - callWithRequestImpls: [ - async () => ({ - username: 'elastic', - has_all_requested: true, - cluster: { manage_api_key: false, manage_security: false }, - index: {}, - application: {} - }), - async () => ( - { - api_keys: - [{ - id: 'si8If24B1bKsmSLTAhJV', - name: 'my-api-key', - creation: 1574089261632, - expiration: 1574175661632, - invalidated: false, - username: 'elastic', - realm: 'reserved' - }] - } - ), - ], - asserts: { - callWithRequests: [ - ['shield.getAPIKeys', { owner: true }], - ['shield.hasPrivileges', { - body: { - cluster: [ - 'manage_security', - 'manage_api_key', - ], - }, - }], - ], - statusCode: 200, - result: { - areApiKeysEnabled: true, - isAdmin: false, - }, - }, - }); - }); -}); diff --git a/x-pack/legacy/plugins/security/server/routes/api/v1/authenticate.js b/x-pack/legacy/plugins/security/server/routes/api/v1/authenticate.js deleted file mode 100644 index f37c9a2fd917f..0000000000000 --- a/x-pack/legacy/plugins/security/server/routes/api/v1/authenticate.js +++ /dev/null @@ -1,227 +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 Boom from 'boom'; -import Joi from 'joi'; -import { schema } from '@kbn/config-schema'; -import { canRedirectRequest, wrapError, OIDCAuthenticationFlow } from '../../../../../../../plugins/security/server'; -import { KibanaRequest } from '../../../../../../../../src/core/server'; -import { createCSPRuleString } from '../../../../../../../../src/legacy/server/csp'; - -export function initAuthenticateApi({ authc: { login, logout }, __legacyCompat: { config } }, server) { - function prepareCustomResourceResponse(response, contentType) { - return response - .header('cache-control', 'private, no-cache, no-store') - .header('content-security-policy', createCSPRuleString(server.config().get('csp.rules'))) - .type(contentType); - } - - server.route({ - method: 'POST', - path: '/api/security/v1/login', - config: { - auth: false, - validate: { - payload: Joi.object({ - username: Joi.string().required(), - password: Joi.string().required() - }) - }, - response: { - emptyStatusCode: 204, - } - }, - async handler(request, h) { - const { username, password } = request.payload; - - try { - // We should prefer `token` over `basic` if possible. - const providerToLoginWith = config.authc.providers.includes('token') - ? 'token' - : 'basic'; - const authenticationResult = await login(KibanaRequest.from(request), { - provider: providerToLoginWith, - value: { username, password } - }); - - if (!authenticationResult.succeeded()) { - throw Boom.unauthorized(authenticationResult.error); - } - - return h.response(); - } catch(err) { - throw wrapError(err); - } - } - }); - - /** - * The route should be configured as a redirect URI in OP when OpenID Connect implicit flow - * is used, so that we can extract authentication response from URL fragment and send it to - * the `/api/security/v1/oidc` route. - */ - server.route({ - method: 'GET', - path: '/api/security/v1/oidc/implicit', - config: { auth: false }, - async handler(request, h) { - return prepareCustomResourceResponse( - h.response(` - - Kibana OpenID Connect Login - - `), - 'text/html' - ); - } - }); - - /** - * The route that accompanies `/api/security/v1/oidc/implicit` and renders a JavaScript snippet - * that extracts fragment part from the URL and send it to the `/api/security/v1/oidc` route. - * We need this separate endpoint because of default CSP policy that forbids inline scripts. - */ - server.route({ - method: 'GET', - path: '/api/security/v1/oidc/implicit.js', - config: { auth: false }, - async handler(request, h) { - return prepareCustomResourceResponse( - h.response(` - window.location.replace( - '${server.config().get('server.basePath')}/api/security/v1/oidc?authenticationResponseURI=' + - encodeURIComponent(window.location.href) - ); - `), - 'text/javascript' - ); - } - }); - - server.route({ - // POST is only allowed for Third Party initiated authentication - // Consider splitting this route into two (GET and POST) when it's migrated to New Platform. - method: ['GET', 'POST'], - path: '/api/security/v1/oidc', - config: { - auth: false, - validate: { - query: Joi.object().keys({ - iss: Joi.string().uri({ scheme: 'https' }), - login_hint: Joi.string(), - target_link_uri: Joi.string().uri(), - code: Joi.string(), - error: Joi.string(), - error_description: Joi.string(), - error_uri: Joi.string().uri(), - state: Joi.string(), - authenticationResponseURI: Joi.string(), - }).unknown(), - } - }, - async handler(request, h) { - try { - const query = request.query || {}; - const payload = request.payload || {}; - - // An HTTP GET request with a query parameter named `authenticationResponseURI` that includes URL fragment OpenID - // Connect Provider sent during implicit authentication flow to the Kibana own proxy page that extracted that URL - // fragment and put it into `authenticationResponseURI` query string parameter for this endpoint. See more details - // at https://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth - let loginAttempt; - if (query.authenticationResponseURI) { - loginAttempt = { - flow: OIDCAuthenticationFlow.Implicit, - authenticationResponseURI: query.authenticationResponseURI, - }; - } else if (query.code || query.error) { - // An HTTP GET request with a query parameter named `code` (or `error`) as the response to a successful (or - // failed) authentication from an OpenID Connect Provider during authorization code authentication flow. - // See more details at https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth. - loginAttempt = { - flow: OIDCAuthenticationFlow.AuthorizationCode, - // We pass the path only as we can't be sure of the full URL and Elasticsearch doesn't need it anyway. - authenticationResponseURI: request.url.path, - }; - } else if (query.iss || payload.iss) { - // An HTTP GET request with a query parameter named `iss` or an HTTP POST request with the same parameter in the - // payload as part of a 3rd party initiated authentication. See more details at - // https://openid.net/specs/openid-connect-core-1_0.html#ThirdPartyInitiatedLogin - loginAttempt = { - flow: OIDCAuthenticationFlow.InitiatedBy3rdParty, - iss: query.iss || payload.iss, - loginHint: query.login_hint || payload.login_hint, - }; - } - - if (!loginAttempt) { - throw Boom.badRequest('Unrecognized login attempt.'); - } - - // We handle the fact that the user might get redirected to Kibana while already having an session - // Return an error notifying the user they are already logged in. - const authenticationResult = await login(KibanaRequest.from(request), { - provider: 'oidc', - value: loginAttempt - }); - if (authenticationResult.succeeded()) { - return Boom.forbidden( - 'Sorry, you already have an active Kibana session. ' + - 'If you want to start a new one, please logout from the existing session first.' - ); - } - - if (authenticationResult.redirected()) { - return h.redirect(authenticationResult.redirectURL); - } - - throw Boom.unauthorized(authenticationResult.error); - } catch (err) { - throw wrapError(err); - } - } - }); - - server.route({ - method: 'GET', - path: '/api/security/v1/logout', - config: { - auth: false - }, - async handler(request, h) { - if (!canRedirectRequest(KibanaRequest.from(request))) { - throw Boom.badRequest('Client should be able to process redirect response.'); - } - - try { - const deauthenticationResult = await logout( - // Allow unknown query parameters as this endpoint can be hit by the 3rd-party with any - // set of query string parameters (e.g. SAML/OIDC logout request parameters). - KibanaRequest.from(request, { - query: schema.object({}, { allowUnknowns: true }), - }) - ); - if (deauthenticationResult.failed()) { - throw wrapError(deauthenticationResult.error); - } - - return h.redirect( - deauthenticationResult.redirectURL || `${server.config().get('server.basePath')}/` - ); - } catch (err) { - throw wrapError(err); - } - } - }); - - server.route({ - method: 'GET', - path: '/api/security/v1/me', - handler(request) { - return request.auth.credentials; - } - }); -} diff --git a/x-pack/legacy/plugins/security/server/routes/api/v1/indices.js b/x-pack/legacy/plugins/security/server/routes/api/v1/indices.js deleted file mode 100644 index 7265b83783fdd..0000000000000 --- a/x-pack/legacy/plugins/security/server/routes/api/v1/indices.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 _ from 'lodash'; -import { getClient } from '../../../../../../server/lib/get_client_shield'; -import { wrapError } from '../../../../../../../plugins/security/server'; - -export function initIndicesApi(server) { - const callWithRequest = getClient(server).callWithRequest; - - server.route({ - method: 'GET', - path: '/api/security/v1/fields/{query}', - handler(request) { - return callWithRequest(request, 'indices.getFieldMapping', { - index: request.params.query, - fields: '*', - allowNoIndices: false, - includeDefaults: true - }) - .then((mappings) => - _(mappings) - .map('mappings') - .flatten() - .map(_.keys) - .flatten() - .uniq() - .value() - ) - .catch(wrapError); - } - }); -} diff --git a/x-pack/legacy/plugins/security/server/routes/api/v1/users.js b/x-pack/legacy/plugins/security/server/routes/api/v1/users.js deleted file mode 100644 index d6dc39da657b1..0000000000000 --- a/x-pack/legacy/plugins/security/server/routes/api/v1/users.js +++ /dev/null @@ -1,142 +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 _ from 'lodash'; -import Boom from 'boom'; -import Joi from 'joi'; -import { getClient } from '../../../../../../server/lib/get_client_shield'; -import { userSchema } from '../../../lib/user_schema'; -import { routePreCheckLicense } from '../../../lib/route_pre_check_license'; -import { wrapError } from '../../../../../../../plugins/security/server'; -import { KibanaRequest } from '../../../../../../../../src/core/server'; - -export function initUsersApi({ authc: { login }, __legacyCompat: { config } }, server) { - const callWithRequest = getClient(server).callWithRequest; - const routePreCheckLicenseFn = routePreCheckLicense(server); - - server.route({ - method: 'GET', - path: '/api/security/v1/users', - handler(request) { - return callWithRequest(request, 'shield.getUser').then( - _.values, - wrapError - ); - }, - config: { - pre: [routePreCheckLicenseFn] - } - }); - - server.route({ - method: 'GET', - path: '/api/security/v1/users/{username}', - handler(request) { - const username = request.params.username; - return callWithRequest(request, 'shield.getUser', { username }).then( - (response) => { - if (response[username]) return response[username]; - throw Boom.notFound(); - }, - wrapError); - }, - config: { - pre: [routePreCheckLicenseFn] - } - }); - - server.route({ - method: 'POST', - path: '/api/security/v1/users/{username}', - handler(request) { - const username = request.params.username; - const body = _(request.payload).omit(['username', 'enabled']).omit(_.isNull); - return callWithRequest(request, 'shield.putUser', { username, body }).then( - () => request.payload, - wrapError); - }, - config: { - validate: { - payload: userSchema - }, - pre: [routePreCheckLicenseFn] - } - }); - - server.route({ - method: 'DELETE', - path: '/api/security/v1/users/{username}', - handler(request, h) { - const username = request.params.username; - return callWithRequest(request, 'shield.deleteUser', { username }).then( - () => h.response().code(204), - wrapError); - }, - config: { - pre: [routePreCheckLicenseFn] - } - }); - - server.route({ - method: 'POST', - path: '/api/security/v1/users/{username}/password', - async handler(request, h) { - const username = request.params.username; - const { password, newPassword } = request.payload; - const isCurrentUser = username === request.auth.credentials.username; - - // We should prefer `token` over `basic` if possible. - const providerToLoginWith = config.authc.providers.includes('token') - ? 'token' - : 'basic'; - - // If user tries to change own password, let's check if old password is valid first by trying - // to login. - if (isCurrentUser) { - const authenticationResult = await login(KibanaRequest.from(request), { - provider: providerToLoginWith, - value: { username, password }, - // We shouldn't alter authentication state just yet. - stateless: true, - }); - - if (!authenticationResult.succeeded()) { - return Boom.forbidden(authenticationResult.error); - } - } - - try { - const body = { password: newPassword }; - await callWithRequest(request, 'shield.changePassword', { username, body }); - - // Now we authenticate user with the new password again updating current session if any. - if (isCurrentUser) { - const authenticationResult = await login(KibanaRequest.from(request), { - provider: providerToLoginWith, - value: { username, password: newPassword } - }); - - if (!authenticationResult.succeeded()) { - return Boom.unauthorized((authenticationResult.error)); - } - } - } catch(err) { - return wrapError(err); - } - - return h.response().code(204); - }, - config: { - validate: { - payload: Joi.object({ - password: Joi.string(), - newPassword: Joi.string().required() - }) - }, - pre: [routePreCheckLicenseFn] - } - }); -} diff --git a/x-pack/legacy/plugins/siem/cypress/integration/lib/login/helpers.ts b/x-pack/legacy/plugins/siem/cypress/integration/lib/login/helpers.ts index 8a9477ad67901..b2b8ce7b9c000 100644 --- a/x-pack/legacy/plugins/siem/cypress/integration/lib/login/helpers.ts +++ b/x-pack/legacy/plugins/siem/cypress/integration/lib/login/helpers.ts @@ -39,7 +39,7 @@ const ELASTICSEARCH_PASSWORD = 'ELASTICSEARCH_PASSWORD'; /** * The Kibana server endpoint used for authentication */ -const LOGIN_API_ENDPOINT = '/api/security/v1/login'; +const LOGIN_API_ENDPOINT = '/internal/security/login'; /** * Authenticates with Kibana using, if specified, credentials specified by @@ -68,7 +68,7 @@ const credentialsProvidedByEnvironment = (): boolean => * Authenticates with Kibana by reading credentials from the * `CYPRESS_ELASTICSEARCH_USERNAME` and `CYPRESS_ELASTICSEARCH_PASSWORD` * environment variables, and POSTing the username and password directly to - * Kibana's `security/v1/login` endpoint, bypassing the login page (for speed). + * Kibana's `/internal/security/login` endpoint, bypassing the login page (for speed). */ const loginViaEnvironmentCredentials = () => { cy.log( @@ -90,7 +90,7 @@ const loginViaEnvironmentCredentials = () => { /** * Authenticates with Kibana by reading credentials from the * `kibana.dev.yml` file and POSTing the username and password directly to - * Kibana's `security/v1/login` endpoint, bypassing the login page (for speed). + * Kibana's `/internal/security/login` endpoint, bypassing the login page (for speed). */ const loginViaConfig = () => { cy.log( diff --git a/x-pack/legacy/server/lib/esjs_shield_plugin.js b/x-pack/legacy/server/lib/esjs_shield_plugin.js deleted file mode 100644 index b6252035aa321..0000000000000 --- a/x-pack/legacy/server/lib/esjs_shield_plugin.js +++ /dev/null @@ -1,579 +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. - */ - -(function (root, factory) { - if (typeof define === 'function' && define.amd) { // eslint-disable-line no-undef - define([], factory); // eslint-disable-line no-undef - } else if (typeof exports === 'object') { - module.exports = factory(); - } else { - root.ElasticsearchShield = factory(); - } -}(this, function () { - return function addShieldApi(Client, config, components) { - const ca = components.clientAction.factory; - - Client.prototype.shield = components.clientAction.namespaceFactory(); - const shield = Client.prototype.shield.prototype; - - /** - * Perform a [shield.authenticate](Retrieve details about the currently authenticated user) request - * - * @param {Object} params - An object with parameters used to carry out this action - */ - shield.authenticate = ca({ - params: {}, - url: { - fmt: '/_security/_authenticate' - } - }); - - /** - * Perform a [shield.changePassword](Change the password of a user) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Boolean} params.refresh - Refresh the index after performing the operation - * @param {String} params.username - The username of the user to change the password for - */ - shield.changePassword = ca({ - params: { - refresh: { - type: 'boolean' - } - }, - urls: [ - { - fmt: '/_security/user/<%=username%>/_password', - req: { - username: { - type: 'string', - required: false - } - } - }, - { - fmt: '/_security/user/_password' - } - ], - needBody: true, - method: 'POST' - }); - - /** - * Perform a [shield.clearCachedRealms](Clears the internal user caches for specified realms) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String} params.usernames - Comma-separated list of usernames to clear from the cache - * @param {String} params.realms - Comma-separated list of realms to clear - */ - shield.clearCachedRealms = ca({ - params: { - usernames: { - type: 'string', - required: false - } - }, - url: { - fmt: '/_security/realm/<%=realms%>/_clear_cache', - req: { - realms: { - type: 'string', - required: true - } - } - }, - method: 'POST' - }); - - /** - * Perform a [shield.clearCachedRoles](Clears the internal caches for specified roles) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String} params.name - Role name - */ - shield.clearCachedRoles = ca({ - params: {}, - url: { - fmt: '/_security/role/<%=name%>/_clear_cache', - req: { - name: { - type: 'string', - required: true - } - } - }, - method: 'POST' - }); - - /** - * Perform a [shield.deleteRole](Remove a role from the native shield realm) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Boolean} params.refresh - Refresh the index after performing the operation - * @param {String} params.name - Role name - */ - shield.deleteRole = ca({ - params: { - refresh: { - type: 'boolean' - } - }, - url: { - fmt: '/_security/role/<%=name%>', - req: { - name: { - type: 'string', - required: true - } - } - }, - method: 'DELETE' - }); - - /** - * Perform a [shield.deleteUser](Remove a user from the native shield realm) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Boolean} params.refresh - Refresh the index after performing the operation - * @param {String} params.username - username - */ - shield.deleteUser = ca({ - params: { - refresh: { - type: 'boolean' - } - }, - url: { - fmt: '/_security/user/<%=username%>', - req: { - username: { - type: 'string', - required: true - } - } - }, - method: 'DELETE' - }); - - /** - * Perform a [shield.getRole](Retrieve one or more roles from the native shield realm) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String} params.name - Role name - */ - shield.getRole = ca({ - params: {}, - urls: [ - { - fmt: '/_security/role/<%=name%>', - req: { - name: { - type: 'string', - required: false - } - } - }, - { - fmt: '/_security/role' - } - ] - }); - - /** - * Perform a [shield.getUser](Retrieve one or more users from the native shield realm) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String, String[], Boolean} params.username - A comma-separated list of usernames - */ - shield.getUser = ca({ - params: {}, - urls: [ - { - fmt: '/_security/user/<%=username%>', - req: { - username: { - type: 'list', - required: false - } - } - }, - { - fmt: '/_security/user' - } - ] - }); - - /** - * Perform a [shield.putRole](Update or create a role for the native shield realm) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Boolean} params.refresh - Refresh the index after performing the operation - * @param {String} params.name - Role name - */ - shield.putRole = ca({ - params: { - refresh: { - type: 'boolean' - } - }, - url: { - fmt: '/_security/role/<%=name%>', - req: { - name: { - type: 'string', - required: true - } - } - }, - needBody: true, - method: 'PUT' - }); - - /** - * Perform a [shield.putUser](Update or create a user for the native shield realm) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Boolean} params.refresh - Refresh the index after performing the operation - * @param {String} params.username - The username of the User - */ - shield.putUser = ca({ - params: { - refresh: { - type: 'boolean' - } - }, - url: { - fmt: '/_security/user/<%=username%>', - req: { - username: { - type: 'string', - required: true - } - } - }, - needBody: true, - method: 'PUT' - }); - - /** - * Perform a [shield.getUserPrivileges](Retrieve a user's list of privileges) request - * - */ - shield.getUserPrivileges = ca({ - params: {}, - urls: [ - { - fmt: '/_security/user/_privileges' - } - ] - }); - - /** - * Asks Elasticsearch to prepare SAML authentication request to be sent to - * the 3rd-party SAML identity provider. - * - * @param {string} [acs] Optional assertion consumer service URL to use for SAML request or URL - * in the Kibana to which identity provider will post SAML response. Based on the ACS Elasticsearch - * will choose the right SAML realm. - * - * @param {string} [realm] Optional name of the Elasticsearch SAML realm to use to handle request. - * - * @returns {{realm: string, id: string, redirect: string}} Object that includes identifier - * of the SAML realm used to prepare authentication request, encrypted request token to be - * sent to Elasticsearch with SAML response and redirect URL to the identity provider that - * will be used to authenticate user. - */ - shield.samlPrepare = ca({ - method: 'POST', - needBody: true, - url: { - fmt: '/_security/saml/prepare' - } - }); - - /** - * Sends SAML response returned by identity provider to Elasticsearch for validation. - * - * @param {Array.} ids A list of encrypted request tokens returned within SAML - * preparation response. - * @param {string} content SAML response returned by identity provider. - * @param {string} [realm] Optional string used to identify the name of the OpenID Connect realm - * that should be used to authenticate request. - * - * @returns {{username: string, access_token: string, expires_in: number}} Object that - * includes name of the user, access token to use for any consequent requests that - * need to be authenticated and a number of seconds after which access token will expire. - */ - shield.samlAuthenticate = ca({ - method: 'POST', - needBody: true, - url: { - fmt: '/_security/saml/authenticate' - } - }); - - /** - * Invalidates SAML access token. - * - * @param {string} token SAML access token that needs to be invalidated. - * - * @returns {{redirect?: string}} - */ - shield.samlLogout = ca({ - method: 'POST', - needBody: true, - url: { - fmt: '/_security/saml/logout' - } - }); - - /** - * Invalidates SAML session based on Logout Request received from the Identity Provider. - * - * @param {string} queryString URL encoded query string provided by Identity Provider. - * @param {string} [acs] Optional assertion consumer service URL to use for SAML request or URL in the - * Kibana to which identity provider will post SAML response. Based on the ACS Elasticsearch - * will choose the right SAML realm to invalidate session. - * @param {string} [realm] Optional name of the Elasticsearch SAML realm to use to handle request. - * - * @returns {{redirect?: string}} - */ - shield.samlInvalidate = ca({ - method: 'POST', - needBody: true, - url: { - fmt: '/_security/saml/invalidate' - } - }); - - /** - * Asks Elasticsearch to prepare an OpenID Connect authentication request to be sent to - * the 3rd-party OpenID Connect provider. - * - * @param {string} realm The OpenID Connect realm name in Elasticsearch - * - * @returns {{state: string, nonce: string, redirect: string}} Object that includes two opaque parameters that need - * to be sent to Elasticsearch with the OpenID Connect response and redirect URL to the OpenID Connect provider that - * will be used to authenticate user. - */ - shield.oidcPrepare = ca({ - method: 'POST', - needBody: true, - url: { - fmt: '/_security/oidc/prepare' - } - }); - - /** - * Sends the URL to which the OpenID Connect Provider redirected the UA to Elasticsearch for validation. - * - * @param {string} state The state parameter that was returned by Elasticsearch in the - * preparation response. - * @param {string} nonce The nonce parameter that was returned by Elasticsearch in the - * preparation response. - * @param {string} redirect_uri The URL to where the UA was redirected by the OpenID Connect provider. - * @param {string} [realm] Optional string used to identify the name of the OpenID Connect realm - * that should be used to authenticate request. - * - * @returns {{username: string, access_token: string, refresh_token; string, expires_in: number}} Object that - * includes name of the user, access token to use for any consequent requests that - * need to be authenticated and a number of seconds after which access token will expire. - */ - shield.oidcAuthenticate = ca({ - method: 'POST', - needBody: true, - url: { - fmt: '/_security/oidc/authenticate' - } - }); - - /** - * Invalidates an access token and refresh token pair that was generated after an OpenID Connect authentication. - * - * @param {string} token An access token that was created by authenticating to an OpenID Connect realm and - * that needs to be invalidated. - * @param {string} refresh_token A refresh token that was created by authenticating to an OpenID Connect realm and - * that needs to be invalidated. - * - * @returns {{redirect?: string}} If the Elasticsearch OpenID Connect realm configuration and the - * OpenID Connect provider supports RP-initiated SLO, a URL to redirect the UA - */ - shield.oidcLogout = ca({ - method: 'POST', - needBody: true, - url: { - fmt: '/_security/oidc/logout' - } - }); - - /** - * Refreshes an access token. - * - * @param {string} grant_type Currently only "refresh_token" grant type is supported. - * @param {string} refresh_token One-time refresh token that will be exchanged to the new access/refresh token pair. - * - * @returns {{access_token: string, type: string, expires_in: number, refresh_token: string}} - */ - shield.getAccessToken = ca({ - method: 'POST', - needBody: true, - url: { - fmt: '/_security/oauth2/token' - } - }); - - /** - * Invalidates an access token. - * - * @param {string} token The access token to invalidate - * - * @returns {{created: boolean}} - */ - shield.deleteAccessToken = ca({ - method: 'DELETE', - needBody: true, - params: { - token: { - type: 'string' - } - }, - url: { - fmt: '/_security/oauth2/token' - } - }); - - shield.getPrivilege = ca({ - method: 'GET', - urls: [{ - fmt: '/_security/privilege/<%=privilege%>', - req: { - privilege: { - type: 'string', - required: false - } - } - }, { - fmt: '/_security/privilege' - }] - }); - - shield.deletePrivilege = ca({ - method: 'DELETE', - urls: [{ - fmt: '/_security/privilege/<%=application%>/<%=privilege%>', - req: { - application: { - type: 'string', - required: true - }, - privilege: { - type: 'string', - required: true - } - } - }] - }); - - shield.postPrivileges = ca({ - method: 'POST', - needBody: true, - url: { - fmt: '/_security/privilege' - } - }); - - shield.hasPrivileges = ca({ - method: 'POST', - needBody: true, - url: { - fmt: '/_security/user/_has_privileges' - } - }); - - shield.getBuiltinPrivileges = ca({ - params: {}, - urls: [ - { - fmt: '/_security/privilege/_builtin' - } - ] - }); - - /** - * Gets API keys in Elasticsearch - * @param {boolean} owner A boolean flag that can be used to query API keys owned by the currently authenticated user. - * Defaults to false. The realm_name or username parameters cannot be specified when this parameter is set to true as - * they are assumed to be the currently authenticated ones. - */ - shield.getAPIKeys = ca({ - method: 'GET', - urls: [{ - fmt: `/_security/api_key?owner=<%=owner%>`, - req: { - owner: { - type: 'boolean', - required: true - } - } - }] - }); - - /** - * Creates an API key in Elasticsearch for the current user. - * - * @param {string} name A name for this API key - * @param {object} role_descriptors Role descriptors for this API key, if not - * provided then permissions of authenticated user are applied. - * @param {string} [expiration] Optional expiration for the API key being generated. If expiration - * is not provided then the API keys do not expire. - * - * @returns {{id: string, name: string, api_key: string, expiration?: number}} - */ - shield.createAPIKey = ca({ - method: 'POST', - needBody: true, - url: { - fmt: '/_security/api_key', - }, - }); - - /** - * Invalidates an API key in Elasticsearch. - * - * @param {string} [id] An API key id. - * @param {string} [name] An API key name. - * @param {string} [realm_name] The name of an authentication realm. - * @param {string} [username] The username of a user. - * - * NOTE: While all parameters are optional, at least one of them is required. - * - * @returns {{invalidated_api_keys: string[], previously_invalidated_api_keys: string[], error_count: number, error_details?: object[]}} - */ - shield.invalidateAPIKey = ca({ - method: 'DELETE', - needBody: true, - url: { - fmt: '/_security/api_key', - }, - }); - - /** - * Gets an access token in exchange to the certificate chain for the target subject distinguished name. - * - * @param {string[]} x509_certificate_chain An ordered array of base64-encoded (Section 4 of RFC4648 - not - * base64url-encoded) DER PKIX certificate values. - * - * @returns {{access_token: string, type: string, expires_in: number}} - */ - shield.delegatePKI = ca({ - method: 'POST', - needBody: true, - url: { - fmt: '/_security/delegate_pki', - }, - }); - }; -})); diff --git a/x-pack/legacy/server/lib/get_client_shield.ts b/x-pack/legacy/server/lib/get_client_shield.ts deleted file mode 100644 index 1f68c2e6d3466..0000000000000 --- a/x-pack/legacy/server/lib/get_client_shield.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 { once } from 'lodash'; -import { Legacy } from 'kibana'; -// @ts-ignore -import esShield from './esjs_shield_plugin'; - -export const getClient = once((server: Legacy.Server) => { - return server.plugins.elasticsearch.createCluster('security', { plugins: [esShield] }); -}); diff --git a/x-pack/legacy/plugins/security/common/model/api_key.ts b/x-pack/plugins/security/common/model/api_key.ts similarity index 100% rename from x-pack/legacy/plugins/security/common/model/api_key.ts rename to x-pack/plugins/security/common/model/api_key.ts diff --git a/x-pack/plugins/security/common/model/index.ts b/x-pack/plugins/security/common/model/index.ts index c6ccd2518d261..226ea3b70afe2 100644 --- a/x-pack/plugins/security/common/model/index.ts +++ b/x-pack/plugins/security/common/model/index.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +export { ApiKey, ApiKeyToInvalidate } from './api_key'; export { User, EditUser, getUserDisplayName } from './user'; export { AuthenticatedUser, canUserChangePassword } from './authenticated_user'; export { BuiltinESPrivileges } from './builtin_es_privileges'; diff --git a/x-pack/plugins/security/server/authentication/providers/oidc.test.ts b/x-pack/plugins/security/server/authentication/providers/oidc.test.ts index c1d7dcca4c78f..ad7eab76db088 100644 --- a/x-pack/plugins/security/server/authentication/providers/oidc.test.ts +++ b/x-pack/plugins/security/server/authentication/providers/oidc.test.ts @@ -42,7 +42,7 @@ describe('OIDCAuthenticationProvider', () => { describe('`login` method', () => { it('redirects third party initiated login attempts to the OpenId Connect Provider.', async () => { - const request = httpServerMock.createKibanaRequest({ path: '/api/security/v1/oidc' }); + const request = httpServerMock.createKibanaRequest({ path: '/api/security/oidc' }); mockOptions.client.callAsInternalUser.withArgs('shield.oidcPrepare').resolves({ state: 'statevalue', @@ -205,13 +205,13 @@ describe('OIDCAuthenticationProvider', () => { describe('authorization code flow', () => { defineAuthenticationFlowTests(() => ({ request: httpServerMock.createKibanaRequest({ - path: '/api/security/v1/oidc?code=somecodehere&state=somestatehere', + path: '/api/security/oidc?code=somecodehere&state=somestatehere', }), attempt: { flow: OIDCAuthenticationFlow.AuthorizationCode, - authenticationResponseURI: '/api/security/v1/oidc?code=somecodehere&state=somestatehere', + authenticationResponseURI: '/api/security/oidc?code=somecodehere&state=somestatehere', }, - expectedRedirectURI: '/api/security/v1/oidc?code=somecodehere&state=somestatehere', + expectedRedirectURI: '/api/security/oidc?code=somecodehere&state=somestatehere', })); }); @@ -219,14 +219,13 @@ describe('OIDCAuthenticationProvider', () => { defineAuthenticationFlowTests(() => ({ request: httpServerMock.createKibanaRequest({ path: - '/api/security/v1/oidc?authenticationResponseURI=http://kibana/api/security/v1/oidc/implicit#id_token=sometoken', + '/api/security/oidc?authenticationResponseURI=http://kibana/api/security/oidc/implicit#id_token=sometoken', }), attempt: { flow: OIDCAuthenticationFlow.Implicit, - authenticationResponseURI: - 'http://kibana/api/security/v1/oidc/implicit#id_token=sometoken', + authenticationResponseURI: 'http://kibana/api/security/oidc/implicit#id_token=sometoken', }, - expectedRedirectURI: 'http://kibana/api/security/v1/oidc/implicit#id_token=sometoken', + expectedRedirectURI: 'http://kibana/api/security/oidc/implicit#id_token=sometoken', })); }); }); diff --git a/x-pack/plugins/security/server/elasticsearch_client_plugin.ts b/x-pack/plugins/security/server/elasticsearch_client_plugin.ts new file mode 100644 index 0000000000000..60d947bd65863 --- /dev/null +++ b/x-pack/plugins/security/server/elasticsearch_client_plugin.ts @@ -0,0 +1,576 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export function elasticsearchClientPlugin(Client: any, config: unknown, components: any) { + const ca = components.clientAction.factory; + + Client.prototype.shield = components.clientAction.namespaceFactory(); + const shield = Client.prototype.shield.prototype; + + /** + * Perform a [shield.authenticate](Retrieve details about the currently authenticated user) request + * + * @param {Object} params - An object with parameters used to carry out this action + */ + shield.authenticate = ca({ + params: {}, + url: { + fmt: '/_security/_authenticate', + }, + }); + + /** + * Perform a [shield.changePassword](Change the password of a user) request + * + * @param {Object} params - An object with parameters used to carry out this action + * @param {Boolean} params.refresh - Refresh the index after performing the operation + * @param {String} params.username - The username of the user to change the password for + */ + shield.changePassword = ca({ + params: { + refresh: { + type: 'boolean', + }, + }, + urls: [ + { + fmt: '/_security/user/<%=username%>/_password', + req: { + username: { + type: 'string', + required: false, + }, + }, + }, + { + fmt: '/_security/user/_password', + }, + ], + needBody: true, + method: 'POST', + }); + + /** + * Perform a [shield.clearCachedRealms](Clears the internal user caches for specified realms) request + * + * @param {Object} params - An object with parameters used to carry out this action + * @param {String} params.usernames - Comma-separated list of usernames to clear from the cache + * @param {String} params.realms - Comma-separated list of realms to clear + */ + shield.clearCachedRealms = ca({ + params: { + usernames: { + type: 'string', + required: false, + }, + }, + url: { + fmt: '/_security/realm/<%=realms%>/_clear_cache', + req: { + realms: { + type: 'string', + required: true, + }, + }, + }, + method: 'POST', + }); + + /** + * Perform a [shield.clearCachedRoles](Clears the internal caches for specified roles) request + * + * @param {Object} params - An object with parameters used to carry out this action + * @param {String} params.name - Role name + */ + shield.clearCachedRoles = ca({ + params: {}, + url: { + fmt: '/_security/role/<%=name%>/_clear_cache', + req: { + name: { + type: 'string', + required: true, + }, + }, + }, + method: 'POST', + }); + + /** + * Perform a [shield.deleteRole](Remove a role from the native shield realm) request + * + * @param {Object} params - An object with parameters used to carry out this action + * @param {Boolean} params.refresh - Refresh the index after performing the operation + * @param {String} params.name - Role name + */ + shield.deleteRole = ca({ + params: { + refresh: { + type: 'boolean', + }, + }, + url: { + fmt: '/_security/role/<%=name%>', + req: { + name: { + type: 'string', + required: true, + }, + }, + }, + method: 'DELETE', + }); + + /** + * Perform a [shield.deleteUser](Remove a user from the native shield realm) request + * + * @param {Object} params - An object with parameters used to carry out this action + * @param {Boolean} params.refresh - Refresh the index after performing the operation + * @param {String} params.username - username + */ + shield.deleteUser = ca({ + params: { + refresh: { + type: 'boolean', + }, + }, + url: { + fmt: '/_security/user/<%=username%>', + req: { + username: { + type: 'string', + required: true, + }, + }, + }, + method: 'DELETE', + }); + + /** + * Perform a [shield.getRole](Retrieve one or more roles from the native shield realm) request + * + * @param {Object} params - An object with parameters used to carry out this action + * @param {String} params.name - Role name + */ + shield.getRole = ca({ + params: {}, + urls: [ + { + fmt: '/_security/role/<%=name%>', + req: { + name: { + type: 'string', + required: false, + }, + }, + }, + { + fmt: '/_security/role', + }, + ], + }); + + /** + * Perform a [shield.getUser](Retrieve one or more users from the native shield realm) request + * + * @param {Object} params - An object with parameters used to carry out this action + * @param {String, String[], Boolean} params.username - A comma-separated list of usernames + */ + shield.getUser = ca({ + params: {}, + urls: [ + { + fmt: '/_security/user/<%=username%>', + req: { + username: { + type: 'list', + required: false, + }, + }, + }, + { + fmt: '/_security/user', + }, + ], + }); + + /** + * Perform a [shield.putRole](Update or create a role for the native shield realm) request + * + * @param {Object} params - An object with parameters used to carry out this action + * @param {Boolean} params.refresh - Refresh the index after performing the operation + * @param {String} params.name - Role name + */ + shield.putRole = ca({ + params: { + refresh: { + type: 'boolean', + }, + }, + url: { + fmt: '/_security/role/<%=name%>', + req: { + name: { + type: 'string', + required: true, + }, + }, + }, + needBody: true, + method: 'PUT', + }); + + /** + * Perform a [shield.putUser](Update or create a user for the native shield realm) request + * + * @param {Object} params - An object with parameters used to carry out this action + * @param {Boolean} params.refresh - Refresh the index after performing the operation + * @param {String} params.username - The username of the User + */ + shield.putUser = ca({ + params: { + refresh: { + type: 'boolean', + }, + }, + url: { + fmt: '/_security/user/<%=username%>', + req: { + username: { + type: 'string', + required: true, + }, + }, + }, + needBody: true, + method: 'PUT', + }); + + /** + * Perform a [shield.getUserPrivileges](Retrieve a user's list of privileges) request + * + */ + shield.getUserPrivileges = ca({ + params: {}, + urls: [ + { + fmt: '/_security/user/_privileges', + }, + ], + }); + + /** + * Asks Elasticsearch to prepare SAML authentication request to be sent to + * the 3rd-party SAML identity provider. + * + * @param {string} [acs] Optional assertion consumer service URL to use for SAML request or URL + * in the Kibana to which identity provider will post SAML response. Based on the ACS Elasticsearch + * will choose the right SAML realm. + * + * @param {string} [realm] Optional name of the Elasticsearch SAML realm to use to handle request. + * + * @returns {{realm: string, id: string, redirect: string}} Object that includes identifier + * of the SAML realm used to prepare authentication request, encrypted request token to be + * sent to Elasticsearch with SAML response and redirect URL to the identity provider that + * will be used to authenticate user. + */ + shield.samlPrepare = ca({ + method: 'POST', + needBody: true, + url: { + fmt: '/_security/saml/prepare', + }, + }); + + /** + * Sends SAML response returned by identity provider to Elasticsearch for validation. + * + * @param {Array.} ids A list of encrypted request tokens returned within SAML + * preparation response. + * @param {string} content SAML response returned by identity provider. + * @param {string} [realm] Optional string used to identify the name of the OpenID Connect realm + * that should be used to authenticate request. + * + * @returns {{username: string, access_token: string, expires_in: number}} Object that + * includes name of the user, access token to use for any consequent requests that + * need to be authenticated and a number of seconds after which access token will expire. + */ + shield.samlAuthenticate = ca({ + method: 'POST', + needBody: true, + url: { + fmt: '/_security/saml/authenticate', + }, + }); + + /** + * Invalidates SAML access token. + * + * @param {string} token SAML access token that needs to be invalidated. + * + * @returns {{redirect?: string}} + */ + shield.samlLogout = ca({ + method: 'POST', + needBody: true, + url: { + fmt: '/_security/saml/logout', + }, + }); + + /** + * Invalidates SAML session based on Logout Request received from the Identity Provider. + * + * @param {string} queryString URL encoded query string provided by Identity Provider. + * @param {string} [acs] Optional assertion consumer service URL to use for SAML request or URL in the + * Kibana to which identity provider will post SAML response. Based on the ACS Elasticsearch + * will choose the right SAML realm to invalidate session. + * @param {string} [realm] Optional name of the Elasticsearch SAML realm to use to handle request. + * + * @returns {{redirect?: string}} + */ + shield.samlInvalidate = ca({ + method: 'POST', + needBody: true, + url: { + fmt: '/_security/saml/invalidate', + }, + }); + + /** + * Asks Elasticsearch to prepare an OpenID Connect authentication request to be sent to + * the 3rd-party OpenID Connect provider. + * + * @param {string} realm The OpenID Connect realm name in Elasticsearch + * + * @returns {{state: string, nonce: string, redirect: string}} Object that includes two opaque parameters that need + * to be sent to Elasticsearch with the OpenID Connect response and redirect URL to the OpenID Connect provider that + * will be used to authenticate user. + */ + shield.oidcPrepare = ca({ + method: 'POST', + needBody: true, + url: { + fmt: '/_security/oidc/prepare', + }, + }); + + /** + * Sends the URL to which the OpenID Connect Provider redirected the UA to Elasticsearch for validation. + * + * @param {string} state The state parameter that was returned by Elasticsearch in the + * preparation response. + * @param {string} nonce The nonce parameter that was returned by Elasticsearch in the + * preparation response. + * @param {string} redirect_uri The URL to where the UA was redirected by the OpenID Connect provider. + * @param {string} [realm] Optional string used to identify the name of the OpenID Connect realm + * that should be used to authenticate request. + * + * @returns {{username: string, access_token: string, refresh_token; string, expires_in: number}} Object that + * includes name of the user, access token to use for any consequent requests that + * need to be authenticated and a number of seconds after which access token will expire. + */ + shield.oidcAuthenticate = ca({ + method: 'POST', + needBody: true, + url: { + fmt: '/_security/oidc/authenticate', + }, + }); + + /** + * Invalidates an access token and refresh token pair that was generated after an OpenID Connect authentication. + * + * @param {string} token An access token that was created by authenticating to an OpenID Connect realm and + * that needs to be invalidated. + * @param {string} refresh_token A refresh token that was created by authenticating to an OpenID Connect realm and + * that needs to be invalidated. + * + * @returns {{redirect?: string}} If the Elasticsearch OpenID Connect realm configuration and the + * OpenID Connect provider supports RP-initiated SLO, a URL to redirect the UA + */ + shield.oidcLogout = ca({ + method: 'POST', + needBody: true, + url: { + fmt: '/_security/oidc/logout', + }, + }); + + /** + * Refreshes an access token. + * + * @param {string} grant_type Currently only "refresh_token" grant type is supported. + * @param {string} refresh_token One-time refresh token that will be exchanged to the new access/refresh token pair. + * + * @returns {{access_token: string, type: string, expires_in: number, refresh_token: string}} + */ + shield.getAccessToken = ca({ + method: 'POST', + needBody: true, + url: { + fmt: '/_security/oauth2/token', + }, + }); + + /** + * Invalidates an access token. + * + * @param {string} token The access token to invalidate + * + * @returns {{created: boolean}} + */ + shield.deleteAccessToken = ca({ + method: 'DELETE', + needBody: true, + params: { + token: { + type: 'string', + }, + }, + url: { + fmt: '/_security/oauth2/token', + }, + }); + + shield.getPrivilege = ca({ + method: 'GET', + urls: [ + { + fmt: '/_security/privilege/<%=privilege%>', + req: { + privilege: { + type: 'string', + required: false, + }, + }, + }, + { + fmt: '/_security/privilege', + }, + ], + }); + + shield.deletePrivilege = ca({ + method: 'DELETE', + urls: [ + { + fmt: '/_security/privilege/<%=application%>/<%=privilege%>', + req: { + application: { + type: 'string', + required: true, + }, + privilege: { + type: 'string', + required: true, + }, + }, + }, + ], + }); + + shield.postPrivileges = ca({ + method: 'POST', + needBody: true, + url: { + fmt: '/_security/privilege', + }, + }); + + shield.hasPrivileges = ca({ + method: 'POST', + needBody: true, + url: { + fmt: '/_security/user/_has_privileges', + }, + }); + + shield.getBuiltinPrivileges = ca({ + params: {}, + urls: [ + { + fmt: '/_security/privilege/_builtin', + }, + ], + }); + + /** + * Gets API keys in Elasticsearch + * @param {boolean} owner A boolean flag that can be used to query API keys owned by the currently authenticated user. + * Defaults to false. The realm_name or username parameters cannot be specified when this parameter is set to true as + * they are assumed to be the currently authenticated ones. + */ + shield.getAPIKeys = ca({ + method: 'GET', + urls: [ + { + fmt: `/_security/api_key?owner=<%=owner%>`, + req: { + owner: { + type: 'boolean', + required: true, + }, + }, + }, + ], + }); + + /** + * Creates an API key in Elasticsearch for the current user. + * + * @param {string} name A name for this API key + * @param {object} role_descriptors Role descriptors for this API key, if not + * provided then permissions of authenticated user are applied. + * @param {string} [expiration] Optional expiration for the API key being generated. If expiration + * is not provided then the API keys do not expire. + * + * @returns {{id: string, name: string, api_key: string, expiration?: number}} + */ + shield.createAPIKey = ca({ + method: 'POST', + needBody: true, + url: { + fmt: '/_security/api_key', + }, + }); + + /** + * Invalidates an API key in Elasticsearch. + * + * @param {string} [id] An API key id. + * @param {string} [name] An API key name. + * @param {string} [realm_name] The name of an authentication realm. + * @param {string} [username] The username of a user. + * + * NOTE: While all parameters are optional, at least one of them is required. + * + * @returns {{invalidated_api_keys: string[], previously_invalidated_api_keys: string[], error_count: number, error_details?: object[]}} + */ + shield.invalidateAPIKey = ca({ + method: 'DELETE', + needBody: true, + url: { + fmt: '/_security/api_key', + }, + }); + + /** + * Gets an access token in exchange to the certificate chain for the target subject distinguished name. + * + * @param {string[]} x509_certificate_chain An ordered array of base64-encoded (Section 4 of RFC4648 - not + * base64url-encoded) DER PKIX certificate values. + * + * @returns {{access_token: string, type: string, expires_in: number}} + */ + shield.delegatePKI = ca({ + method: 'POST', + needBody: true, + url: { + fmt: '/_security/delegate_pki', + }, + }); +} diff --git a/x-pack/plugins/security/server/errors.ts b/x-pack/plugins/security/server/errors.ts index e0c2918991696..b5f3667558f55 100644 --- a/x-pack/plugins/security/server/errors.ts +++ b/x-pack/plugins/security/server/errors.ts @@ -5,11 +5,25 @@ */ import Boom from 'boom'; +import { CustomHttpResponseOptions, ResponseError } from '../../../../src/core/server'; export function wrapError(error: any) { return Boom.boomify(error, { statusCode: getErrorStatusCode(error) }); } +/** + * Wraps error into error suitable for Core's custom error response. + * @param error Any error instance. + */ +export function wrapIntoCustomErrorResponse(error: any) { + const wrappedError = wrapError(error); + return { + body: wrappedError, + headers: wrappedError.output.headers, + statusCode: wrappedError.output.statusCode, + } as CustomHttpResponseOptions; +} + /** * Extracts error code from Boom and Elasticsearch "native" errors. * @param error Error instance to extract status code from. diff --git a/x-pack/plugins/security/server/index.ts b/x-pack/plugins/security/server/index.ts index ec43bbd95901a..e72e94e9cd94b 100644 --- a/x-pack/plugins/security/server/index.ts +++ b/x-pack/plugins/security/server/index.ts @@ -9,18 +9,8 @@ import { ConfigSchema } from './config'; import { Plugin } from './plugin'; // These exports are part of public Security plugin contract, any change in signature of exported -// functions or removal of exports should be considered as a breaking change. Ideally we should -// reduce number of such exports to zero and provide everything we want to expose via Setup/Start -// run-time contracts. -export { wrapError } from './errors'; -export { - canRedirectRequest, - AuthenticationResult, - DeauthenticationResult, - OIDCAuthenticationFlow, - CreateAPIKeyResult, -} from './authentication'; - +// functions or removal of exports should be considered as a breaking change. +export { AuthenticationResult, DeauthenticationResult, CreateAPIKeyResult } from './authentication'; export { PluginSetupContract } from './plugin'; export const config = { schema: ConfigSchema }; diff --git a/x-pack/plugins/security/server/plugin.test.ts b/x-pack/plugins/security/server/plugin.test.ts index 26788c3ef9230..0569f5f4de3a6 100644 --- a/x-pack/plugins/security/server/plugin.test.ts +++ b/x-pack/plugins/security/server/plugin.test.ts @@ -7,6 +7,7 @@ import { of } from 'rxjs'; import { ByteSizeValue } from '@kbn/config-schema'; import { IClusterClient, CoreSetup } from '../../../../src/core/server'; +import { elasticsearchClientPlugin } from './elasticsearch_client_plugin'; import { Plugin, PluginSetupDependencies } from './plugin'; import { coreMock, elasticsearchServiceMock } from '../../../../src/core/server/mocks'; @@ -48,12 +49,6 @@ describe('Security Plugin', () => { Object { "__legacyCompat": Object { "config": Object { - "authc": Object { - "providers": Array [ - "saml", - "token", - ], - }, "cookieName": "sid", "loginAssistanceMessage": undefined, "secureCookies": true, @@ -115,7 +110,7 @@ describe('Security Plugin', () => { expect(mockCoreSetup.elasticsearch.createClient).toHaveBeenCalledTimes(1); expect(mockCoreSetup.elasticsearch.createClient).toHaveBeenCalledWith('security', { - plugins: [require('../../../legacy/server/lib/esjs_shield_plugin')], + plugins: [elasticsearchClientPlugin], }); }); }); diff --git a/x-pack/plugins/security/server/plugin.ts b/x-pack/plugins/security/server/plugin.ts index 84d448331cef2..633b064da6d61 100644 --- a/x-pack/plugins/security/server/plugin.ts +++ b/x-pack/plugins/security/server/plugin.ts @@ -28,6 +28,7 @@ import { defineRoutes } from './routes'; import { SecurityLicenseService, SecurityLicense } from './licensing'; import { setupSavedObjects } from './saved_objects'; import { SecurityAuditLogger } from './audit'; +import { elasticsearchClientPlugin } from './elasticsearch_client_plugin'; export type SpacesService = Pick< SpacesPluginSetup['spacesService'], @@ -76,7 +77,8 @@ export interface PluginSetupContract { lifespan: number | null; }; secureCookies: boolean; - authc: { providers: string[] }; + cookieName: string; + loginAssistanceMessage: string; }>; }; } @@ -128,7 +130,7 @@ export class Plugin { .toPromise(); this.clusterClient = core.elasticsearch.createClient('security', { - plugins: [require('../../../legacy/server/lib/esjs_shield_plugin')], + plugins: [elasticsearchClientPlugin], }); const { license, update: updateLicense } = new SecurityLicenseService().setup(); @@ -213,7 +215,6 @@ export class Plugin { }, secureCookies: config.secureCookies, cookieName: config.cookieName, - authc: { providers: config.authc.providers }, }, }, }); diff --git a/x-pack/plugins/security/server/routes/api_keys/get.test.ts b/x-pack/plugins/security/server/routes/api_keys/get.test.ts new file mode 100644 index 0000000000000..2b2283edea2e8 --- /dev/null +++ b/x-pack/plugins/security/server/routes/api_keys/get.test.ts @@ -0,0 +1,160 @@ +/* + * 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 { kibanaResponseFactory, RequestHandlerContext } from '../../../../../../src/core/server'; +import { LICENSE_CHECK_STATE, LicenseCheck } from '../../../../licensing/server'; +import { defineGetApiKeysRoutes } from './get'; + +import { elasticsearchServiceMock, httpServerMock } from '../../../../../../src/core/server/mocks'; +import { routeDefinitionParamsMock } from '../index.mock'; +import Boom from 'boom'; + +interface TestOptions { + isAdmin?: boolean; + licenseCheckResult?: LicenseCheck; + apiResponse?: () => Promise; + asserts: { statusCode: number; result?: Record }; +} + +describe('Get API keys', () => { + const getApiKeysTest = ( + description: string, + { + licenseCheckResult = { state: LICENSE_CHECK_STATE.Valid }, + apiResponse, + asserts, + isAdmin = true, + }: TestOptions + ) => { + test(description, async () => { + const mockRouteDefinitionParams = routeDefinitionParamsMock.create(); + + const mockScopedClusterClient = elasticsearchServiceMock.createScopedClusterClient(); + mockRouteDefinitionParams.clusterClient.asScoped.mockReturnValue(mockScopedClusterClient); + if (apiResponse) { + mockScopedClusterClient.callAsCurrentUser.mockImplementation(apiResponse); + } + + defineGetApiKeysRoutes(mockRouteDefinitionParams); + const [[, handler]] = mockRouteDefinitionParams.router.get.mock.calls; + + const headers = { authorization: 'foo' }; + const mockRequest = httpServerMock.createKibanaRequest({ + method: 'get', + path: '/internal/security/api_key', + query: { isAdmin: isAdmin.toString() }, + headers, + }); + const mockContext = ({ + licensing: { license: { check: jest.fn().mockReturnValue(licenseCheckResult) } }, + } as unknown) as RequestHandlerContext; + + const response = await handler(mockContext, mockRequest, kibanaResponseFactory); + expect(response.status).toBe(asserts.statusCode); + expect(response.payload).toEqual(asserts.result); + + if (apiResponse) { + expect(mockRouteDefinitionParams.clusterClient.asScoped).toHaveBeenCalledWith(mockRequest); + expect(mockScopedClusterClient.callAsCurrentUser).toHaveBeenCalledWith( + 'shield.getAPIKeys', + { owner: !isAdmin } + ); + } else { + expect(mockScopedClusterClient.callAsCurrentUser).not.toHaveBeenCalled(); + } + expect(mockContext.licensing.license.check).toHaveBeenCalledWith('security', 'basic'); + }); + }; + + describe('failure', () => { + getApiKeysTest('returns result of license checker', { + licenseCheckResult: { state: LICENSE_CHECK_STATE.Invalid, message: 'test forbidden message' }, + asserts: { statusCode: 403, result: { message: 'test forbidden message' } }, + }); + + const error = Boom.notAcceptable('test not acceptable message'); + getApiKeysTest('returns error from cluster client', { + apiResponse: async () => { + throw error; + }, + asserts: { statusCode: 406, result: error }, + }); + }); + + describe('success', () => { + getApiKeysTest('returns API keys', { + apiResponse: async () => ({ + api_keys: [ + { + id: 'YCLV7m0BJ3xI4hhWB648', + name: 'test-api-key', + creation: 1571670001452, + expiration: 1571756401452, + invalidated: false, + username: 'elastic', + realm: 'reserved', + }, + ], + }), + asserts: { + statusCode: 200, + result: { + apiKeys: [ + { + id: 'YCLV7m0BJ3xI4hhWB648', + name: 'test-api-key', + creation: 1571670001452, + expiration: 1571756401452, + invalidated: false, + username: 'elastic', + realm: 'reserved', + }, + ], + }, + }, + }); + getApiKeysTest('returns only valid API keys', { + apiResponse: async () => ({ + api_keys: [ + { + id: 'YCLV7m0BJ3xI4hhWB648', + name: 'test-api-key1', + creation: 1571670001452, + expiration: 1571756401452, + invalidated: true, + username: 'elastic', + realm: 'reserved', + }, + { + id: 'YCLV7m0BJ3xI4hhWB648', + name: 'test-api-key2', + creation: 1571670001452, + expiration: 1571756401452, + invalidated: false, + username: 'elastic', + realm: 'reserved', + }, + ], + }), + asserts: { + statusCode: 200, + result: { + apiKeys: [ + { + id: 'YCLV7m0BJ3xI4hhWB648', + name: 'test-api-key2', + creation: 1571670001452, + expiration: 1571756401452, + invalidated: false, + username: 'elastic', + realm: 'reserved', + }, + ], + }, + }, + }); + }); +}); diff --git a/x-pack/plugins/security/server/routes/api_keys/get.ts b/x-pack/plugins/security/server/routes/api_keys/get.ts new file mode 100644 index 0000000000000..6e98b4b098405 --- /dev/null +++ b/x-pack/plugins/security/server/routes/api_keys/get.ts @@ -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 { schema } from '@kbn/config-schema'; +import { ApiKey } from '../../../common/model'; +import { wrapIntoCustomErrorResponse } from '../../errors'; +import { createLicensedRouteHandler } from '../licensed_route_handler'; +import { RouteDefinitionParams } from '..'; + +export function defineGetApiKeysRoutes({ router, clusterClient }: RouteDefinitionParams) { + router.get( + { + path: '/internal/security/api_key', + validate: { + query: schema.object({ + // We don't use `schema.boolean` here, because all query string parameters are treated as + // strings and @kbn/config-schema doesn't coerce strings to booleans. + // + // A boolean flag that can be used to query API keys owned by the currently authenticated + // user. `false` means that only API keys of currently authenticated user will be returned. + isAdmin: schema.oneOf([schema.literal('true'), schema.literal('false')]), + }), + }, + }, + createLicensedRouteHandler(async (context, request, response) => { + try { + const isAdmin = request.query.isAdmin === 'true'; + const { api_keys: apiKeys } = (await clusterClient + .asScoped(request) + .callAsCurrentUser('shield.getAPIKeys', { owner: !isAdmin })) as { api_keys: ApiKey[] }; + + const validKeys = apiKeys.filter(({ invalidated }) => !invalidated); + + return response.ok({ body: { apiKeys: validKeys } }); + } catch (error) { + return response.customError(wrapIntoCustomErrorResponse(error)); + } + }) + ); +} diff --git a/x-pack/plugins/security/server/routes/api_keys/index.ts b/x-pack/plugins/security/server/routes/api_keys/index.ts new file mode 100644 index 0000000000000..d75eb1bcbe961 --- /dev/null +++ b/x-pack/plugins/security/server/routes/api_keys/index.ts @@ -0,0 +1,16 @@ +/* + * 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 { defineGetApiKeysRoutes } from './get'; +import { defineCheckPrivilegesRoutes } from './privileges'; +import { defineInvalidateApiKeysRoutes } from './invalidate'; +import { RouteDefinitionParams } from '..'; + +export function defineApiKeysRoutes(params: RouteDefinitionParams) { + defineGetApiKeysRoutes(params); + defineCheckPrivilegesRoutes(params); + defineInvalidateApiKeysRoutes(params); +} diff --git a/x-pack/plugins/security/server/routes/api_keys/invalidate.test.ts b/x-pack/plugins/security/server/routes/api_keys/invalidate.test.ts new file mode 100644 index 0000000000000..4ea21bda5f743 --- /dev/null +++ b/x-pack/plugins/security/server/routes/api_keys/invalidate.test.ts @@ -0,0 +1,220 @@ +/* + * 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 Boom from 'boom'; +import { Type } from '@kbn/config-schema'; +import { kibanaResponseFactory, RequestHandlerContext } from '../../../../../../src/core/server'; +import { LICENSE_CHECK_STATE, LicenseCheck } from '../../../../licensing/server'; +import { defineInvalidateApiKeysRoutes } from './invalidate'; + +import { elasticsearchServiceMock, httpServerMock } from '../../../../../../src/core/server/mocks'; +import { routeDefinitionParamsMock } from '../index.mock'; + +interface TestOptions { + licenseCheckResult?: LicenseCheck; + apiResponses?: Array<() => Promise>; + payload?: Record; + asserts: { statusCode: number; result?: Record; apiArguments?: unknown[][] }; +} + +describe('Invalidate API keys', () => { + const postInvalidateTest = ( + description: string, + { + licenseCheckResult = { state: LICENSE_CHECK_STATE.Valid }, + apiResponses = [], + asserts, + payload, + }: TestOptions + ) => { + test(description, async () => { + const mockRouteDefinitionParams = routeDefinitionParamsMock.create(); + const mockScopedClusterClient = elasticsearchServiceMock.createScopedClusterClient(); + mockRouteDefinitionParams.clusterClient.asScoped.mockReturnValue(mockScopedClusterClient); + for (const apiResponse of apiResponses) { + mockScopedClusterClient.callAsCurrentUser.mockImplementationOnce(apiResponse); + } + + defineInvalidateApiKeysRoutes(mockRouteDefinitionParams); + const [[{ validate }, handler]] = mockRouteDefinitionParams.router.post.mock.calls; + + const headers = { authorization: 'foo' }; + const mockRequest = httpServerMock.createKibanaRequest({ + method: 'post', + path: '/internal/security/api_key/invalidate', + body: payload !== undefined ? (validate as any).body.validate(payload) : undefined, + headers, + }); + const mockContext = ({ + licensing: { license: { check: jest.fn().mockReturnValue(licenseCheckResult) } }, + } as unknown) as RequestHandlerContext; + + const response = await handler(mockContext, mockRequest, kibanaResponseFactory); + expect(response.status).toBe(asserts.statusCode); + expect(response.payload).toEqual(asserts.result); + + if (Array.isArray(asserts.apiArguments)) { + for (const apiArguments of asserts.apiArguments) { + expect(mockRouteDefinitionParams.clusterClient.asScoped).toHaveBeenCalledWith( + mockRequest + ); + expect(mockScopedClusterClient.callAsCurrentUser).toHaveBeenCalledWith(...apiArguments); + } + } else { + expect(mockScopedClusterClient.callAsCurrentUser).not.toHaveBeenCalled(); + } + expect(mockContext.licensing.license.check).toHaveBeenCalledWith('security', 'basic'); + }); + }; + + describe('request validation', () => { + let requestBodySchema: Type; + beforeEach(() => { + const mockRouteDefinitionParams = routeDefinitionParamsMock.create(); + defineInvalidateApiKeysRoutes(mockRouteDefinitionParams); + + const [[{ validate }]] = mockRouteDefinitionParams.router.post.mock.calls; + requestBodySchema = (validate as any).body; + }); + + test('requires both isAdmin and apiKeys parameters', () => { + expect(() => + requestBodySchema.validate({}, {}, 'request body') + ).toThrowErrorMatchingInlineSnapshot( + `"[request body.apiKeys]: expected value of type [array] but got [undefined]"` + ); + + expect(() => + requestBodySchema.validate({ apiKeys: [] }, {}, 'request body') + ).toThrowErrorMatchingInlineSnapshot( + `"[request body.isAdmin]: expected value of type [boolean] but got [undefined]"` + ); + + expect(() => + requestBodySchema.validate({ apiKeys: {}, isAdmin: true }, {}, 'request body') + ).toThrowErrorMatchingInlineSnapshot( + `"[request body.apiKeys]: expected value of type [array] but got [Object]"` + ); + + expect(() => + requestBodySchema.validate( + { + apiKeys: [{ id: 'some-id', name: 'some-name', unknown: 'some-unknown' }], + isAdmin: true, + }, + {}, + 'request body' + ) + ).toThrowErrorMatchingInlineSnapshot( + `"[request body.apiKeys.0.unknown]: definition for this key is missing"` + ); + }); + }); + + describe('failure', () => { + postInvalidateTest('returns result of license checker', { + licenseCheckResult: { state: LICENSE_CHECK_STATE.Invalid, message: 'test forbidden message' }, + payload: { apiKeys: [{ id: 'si8If24B1bKsmSLTAhJV', name: 'my-api-key' }], isAdmin: true }, + asserts: { statusCode: 403, result: { message: 'test forbidden message' } }, + }); + + const error = Boom.notAcceptable('test not acceptable message'); + postInvalidateTest('returns error from cluster client', { + apiResponses: [ + async () => { + throw error; + }, + ], + payload: { + apiKeys: [{ id: 'si8If24B1bKsmSLTAhJV', name: 'my-api-key' }], + isAdmin: true, + }, + asserts: { + apiArguments: [['shield.invalidateAPIKey', { body: { id: 'si8If24B1bKsmSLTAhJV' } }]], + statusCode: 200, + result: { + itemsInvalidated: [], + errors: [ + { + id: 'si8If24B1bKsmSLTAhJV', + name: 'my-api-key', + error: Boom.notAcceptable('test not acceptable message'), + }, + ], + }, + }, + }); + }); + + describe('success', () => { + postInvalidateTest('invalidates API keys', { + apiResponses: [async () => null], + payload: { + apiKeys: [{ id: 'si8If24B1bKsmSLTAhJV', name: 'my-api-key' }], + isAdmin: true, + }, + asserts: { + apiArguments: [['shield.invalidateAPIKey', { body: { id: 'si8If24B1bKsmSLTAhJV' } }]], + statusCode: 200, + result: { + itemsInvalidated: [{ id: 'si8If24B1bKsmSLTAhJV', name: 'my-api-key' }], + errors: [], + }, + }, + }); + + postInvalidateTest('adds "owner" to body if isAdmin=false', { + apiResponses: [async () => null], + payload: { + apiKeys: [{ id: 'si8If24B1bKsmSLTAhJV', name: 'my-api-key' }], + isAdmin: false, + }, + asserts: { + apiArguments: [ + ['shield.invalidateAPIKey', { body: { id: 'si8If24B1bKsmSLTAhJV', owner: true } }], + ], + statusCode: 200, + result: { + itemsInvalidated: [{ id: 'si8If24B1bKsmSLTAhJV', name: 'my-api-key' }], + errors: [], + }, + }, + }); + + postInvalidateTest('returns only successful invalidation requests', { + apiResponses: [ + async () => null, + async () => { + throw Boom.notAcceptable('test not acceptable message'); + }, + ], + payload: { + apiKeys: [ + { id: 'si8If24B1bKsmSLTAhJV', name: 'my-api-key1' }, + { id: 'ab8If24B1bKsmSLTAhNC', name: 'my-api-key2' }, + ], + isAdmin: true, + }, + asserts: { + apiArguments: [ + ['shield.invalidateAPIKey', { body: { id: 'si8If24B1bKsmSLTAhJV' } }], + ['shield.invalidateAPIKey', { body: { id: 'ab8If24B1bKsmSLTAhNC' } }], + ], + statusCode: 200, + result: { + itemsInvalidated: [{ id: 'si8If24B1bKsmSLTAhJV', name: 'my-api-key1' }], + errors: [ + { + id: 'ab8If24B1bKsmSLTAhNC', + name: 'my-api-key2', + error: Boom.notAcceptable('test not acceptable message'), + }, + ], + }, + }, + }); + }); +}); diff --git a/x-pack/plugins/security/server/routes/api_keys/invalidate.ts b/x-pack/plugins/security/server/routes/api_keys/invalidate.ts new file mode 100644 index 0000000000000..cb86c1024ae9a --- /dev/null +++ b/x-pack/plugins/security/server/routes/api_keys/invalidate.ts @@ -0,0 +1,69 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { createLicensedRouteHandler } from '../licensed_route_handler'; +import { ApiKey } from '../../../common/model'; +import { wrapError, wrapIntoCustomErrorResponse } from '../../errors'; +import { RouteDefinitionParams } from '..'; + +interface ResponseType { + itemsInvalidated: Array>; + errors: Array & { error: Error }>; +} + +export function defineInvalidateApiKeysRoutes({ router, clusterClient }: RouteDefinitionParams) { + router.post( + { + path: '/internal/security/api_key/invalidate', + validate: { + body: schema.object({ + apiKeys: schema.arrayOf(schema.object({ id: schema.string(), name: schema.string() })), + isAdmin: schema.boolean(), + }), + }, + }, + createLicensedRouteHandler(async (context, request, response) => { + try { + const scopedClusterClient = clusterClient.asScoped(request); + + // Invalidate all API keys in parallel. + const invalidationResult = ( + await Promise.all( + request.body.apiKeys.map(async key => { + try { + const body: { id: string; owner?: boolean } = { id: key.id }; + if (!request.body.isAdmin) { + body.owner = true; + } + + // Send the request to invalidate the API key and return an error if it could not be deleted. + await scopedClusterClient.callAsCurrentUser('shield.invalidateAPIKey', { body }); + return { key, error: undefined }; + } catch (error) { + return { key, error: wrapError(error) }; + } + }) + ) + ).reduce( + (responseBody, { key, error }) => { + if (error) { + responseBody.errors.push({ ...key, error }); + } else { + responseBody.itemsInvalidated.push(key); + } + return responseBody; + }, + { itemsInvalidated: [], errors: [] } as ResponseType + ); + + return response.ok({ body: invalidationResult }); + } catch (error) { + return response.customError(wrapIntoCustomErrorResponse(error)); + } + }) + ); +} diff --git a/x-pack/plugins/security/server/routes/api_keys/privileges.test.ts b/x-pack/plugins/security/server/routes/api_keys/privileges.test.ts new file mode 100644 index 0000000000000..866e455063bdc --- /dev/null +++ b/x-pack/plugins/security/server/routes/api_keys/privileges.test.ts @@ -0,0 +1,187 @@ +/* + * 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 Boom from 'boom'; +import { LICENSE_CHECK_STATE, LicenseCheck } from '../../../../licensing/server'; +import { kibanaResponseFactory, RequestHandlerContext } from '../../../../../../src/core/server'; + +import { elasticsearchServiceMock, httpServerMock } from '../../../../../../src/core/server/mocks'; +import { routeDefinitionParamsMock } from '../index.mock'; +import { defineCheckPrivilegesRoutes } from './privileges'; + +interface TestOptions { + licenseCheckResult?: LicenseCheck; + apiResponses?: Array<() => Promise>; + asserts: { statusCode: number; result?: Record; apiArguments?: unknown[][] }; +} + +describe('Check API keys privileges', () => { + const getPrivilegesTest = ( + description: string, + { + licenseCheckResult = { state: LICENSE_CHECK_STATE.Valid }, + apiResponses = [], + asserts, + }: TestOptions + ) => { + test(description, async () => { + const mockRouteDefinitionParams = routeDefinitionParamsMock.create(); + const mockScopedClusterClient = elasticsearchServiceMock.createScopedClusterClient(); + mockRouteDefinitionParams.clusterClient.asScoped.mockReturnValue(mockScopedClusterClient); + for (const apiResponse of apiResponses) { + mockScopedClusterClient.callAsCurrentUser.mockImplementationOnce(apiResponse); + } + + defineCheckPrivilegesRoutes(mockRouteDefinitionParams); + const [[, handler]] = mockRouteDefinitionParams.router.get.mock.calls; + + const headers = { authorization: 'foo' }; + const mockRequest = httpServerMock.createKibanaRequest({ + method: 'get', + path: '/internal/security/api_key/privileges', + headers, + }); + const mockContext = ({ + licensing: { license: { check: jest.fn().mockReturnValue(licenseCheckResult) } }, + } as unknown) as RequestHandlerContext; + + const response = await handler(mockContext, mockRequest, kibanaResponseFactory); + expect(response.status).toBe(asserts.statusCode); + expect(response.payload).toEqual(asserts.result); + + if (Array.isArray(asserts.apiArguments)) { + for (const apiArguments of asserts.apiArguments) { + expect(mockRouteDefinitionParams.clusterClient.asScoped).toHaveBeenCalledWith( + mockRequest + ); + expect(mockScopedClusterClient.callAsCurrentUser).toHaveBeenCalledWith(...apiArguments); + } + } else { + expect(mockScopedClusterClient.callAsCurrentUser).not.toHaveBeenCalled(); + } + expect(mockContext.licensing.license.check).toHaveBeenCalledWith('security', 'basic'); + }); + }; + + describe('failure', () => { + getPrivilegesTest('returns result of license checker', { + licenseCheckResult: { state: LICENSE_CHECK_STATE.Invalid, message: 'test forbidden message' }, + asserts: { statusCode: 403, result: { message: 'test forbidden message' } }, + }); + + const error = Boom.notAcceptable('test not acceptable message'); + getPrivilegesTest('returns error from cluster client', { + apiResponses: [ + async () => { + throw error; + }, + async () => {}, + ], + asserts: { + apiArguments: [ + ['shield.hasPrivileges', { body: { cluster: ['manage_security', 'manage_api_key'] } }], + ['shield.getAPIKeys', { owner: true }], + ], + statusCode: 406, + result: error, + }, + }); + }); + + describe('success', () => { + getPrivilegesTest('returns areApiKeysEnabled and isAdmin', { + apiResponses: [ + async () => ({ + username: 'elastic', + has_all_requested: true, + cluster: { manage_api_key: true, manage_security: true }, + index: {}, + application: {}, + }), + async () => ({ + api_keys: [ + { + id: 'si8If24B1bKsmSLTAhJV', + name: 'my-api-key', + creation: 1574089261632, + expiration: 1574175661632, + invalidated: false, + username: 'elastic', + realm: 'reserved', + }, + ], + }), + ], + asserts: { + apiArguments: [ + ['shield.getAPIKeys', { owner: true }], + ['shield.hasPrivileges', { body: { cluster: ['manage_security', 'manage_api_key'] } }], + ], + statusCode: 200, + result: { areApiKeysEnabled: true, isAdmin: true }, + }, + }); + + getPrivilegesTest( + 'returns areApiKeysEnabled=false when getAPIKeys error message includes "api keys are not enabled"', + { + apiResponses: [ + async () => ({ + username: 'elastic', + has_all_requested: true, + cluster: { manage_api_key: true, manage_security: true }, + index: {}, + application: {}, + }), + async () => { + throw Boom.unauthorized('api keys are not enabled'); + }, + ], + asserts: { + apiArguments: [ + ['shield.getAPIKeys', { owner: true }], + ['shield.hasPrivileges', { body: { cluster: ['manage_security', 'manage_api_key'] } }], + ], + statusCode: 200, + result: { areApiKeysEnabled: false, isAdmin: true }, + }, + } + ); + + getPrivilegesTest('returns isAdmin=false when user has insufficient privileges', { + apiResponses: [ + async () => ({ + username: 'elastic', + has_all_requested: true, + cluster: { manage_api_key: false, manage_security: false }, + index: {}, + application: {}, + }), + async () => ({ + api_keys: [ + { + id: 'si8If24B1bKsmSLTAhJV', + name: 'my-api-key', + creation: 1574089261632, + expiration: 1574175661632, + invalidated: false, + username: 'elastic', + realm: 'reserved', + }, + ], + }), + ], + asserts: { + apiArguments: [ + ['shield.getAPIKeys', { owner: true }], + ['shield.hasPrivileges', { body: { cluster: ['manage_security', 'manage_api_key'] } }], + ], + statusCode: 200, + result: { areApiKeysEnabled: true, isAdmin: false }, + }, + }); + }); +}); diff --git a/x-pack/plugins/security/server/routes/api_keys/privileges.ts b/x-pack/plugins/security/server/routes/api_keys/privileges.ts new file mode 100644 index 0000000000000..216d1ef1bf4a4 --- /dev/null +++ b/x-pack/plugins/security/server/routes/api_keys/privileges.ts @@ -0,0 +1,49 @@ +/* + * 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 { wrapIntoCustomErrorResponse } from '../../errors'; +import { createLicensedRouteHandler } from '../licensed_route_handler'; +import { RouteDefinitionParams } from '..'; + +export function defineCheckPrivilegesRoutes({ router, clusterClient }: RouteDefinitionParams) { + router.get( + { + path: '/internal/security/api_key/privileges', + validate: false, + }, + createLicensedRouteHandler(async (context, request, response) => { + try { + const scopedClusterClient = clusterClient.asScoped(request); + + const [ + { + cluster: { manage_security: manageSecurity, manage_api_key: manageApiKey }, + }, + { areApiKeysEnabled }, + ] = await Promise.all([ + scopedClusterClient.callAsCurrentUser('shield.hasPrivileges', { + body: { cluster: ['manage_security', 'manage_api_key'] }, + }), + scopedClusterClient.callAsCurrentUser('shield.getAPIKeys', { owner: true }).then( + // If the API returns a truthy result that means it's enabled. + result => ({ areApiKeysEnabled: !!result }), + // This is a brittle dependency upon message. Tracked by https://github.com/elastic/elasticsearch/issues/47759. + e => + e.message.includes('api keys are not enabled') + ? Promise.resolve({ areApiKeysEnabled: false }) + : Promise.reject(e) + ), + ]); + + return response.ok({ + body: { areApiKeysEnabled, isAdmin: manageSecurity || manageApiKey }, + }); + } catch (error) { + return response.customError(wrapIntoCustomErrorResponse(error)); + } + }) + ); +} diff --git a/x-pack/plugins/security/server/routes/authentication/basic.test.ts b/x-pack/plugins/security/server/routes/authentication/basic.test.ts new file mode 100644 index 0000000000000..8e24f99b1302d --- /dev/null +++ b/x-pack/plugins/security/server/routes/authentication/basic.test.ts @@ -0,0 +1,172 @@ +/* + * 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 { Type } from '@kbn/config-schema'; +import { + IRouter, + kibanaResponseFactory, + RequestHandler, + RequestHandlerContext, + RouteConfig, +} from '../../../../../../src/core/server'; +import { LICENSE_CHECK_STATE } from '../../../../licensing/server'; +import { Authentication, AuthenticationResult } from '../../authentication'; +import { ConfigType } from '../../config'; +import { LegacyAPI } from '../../plugin'; +import { defineBasicRoutes } from './basic'; + +import { + elasticsearchServiceMock, + httpServerMock, + httpServiceMock, + loggingServiceMock, +} from '../../../../../../src/core/server/mocks'; +import { mockAuthenticatedUser } from '../../../common/model/authenticated_user.mock'; +import { authenticationMock } from '../../authentication/index.mock'; +import { authorizationMock } from '../../authorization/index.mock'; + +describe('Basic authentication routes', () => { + let router: jest.Mocked; + let authc: jest.Mocked; + let mockContext: RequestHandlerContext; + beforeEach(() => { + router = httpServiceMock.createRouter(); + authc = authenticationMock.create(); + + mockContext = ({ + licensing: { + license: { check: jest.fn().mockReturnValue({ check: LICENSE_CHECK_STATE.Valid }) }, + }, + } as unknown) as RequestHandlerContext; + + defineBasicRoutes({ + router, + clusterClient: elasticsearchServiceMock.createClusterClient(), + basePath: httpServiceMock.createBasePath(), + logger: loggingServiceMock.create().get(), + config: { authc: { providers: ['saml'] } } as ConfigType, + authc, + authz: authorizationMock.create(), + getLegacyAPI: () => ({ cspRules: 'test-csp-rule' } as LegacyAPI), + }); + }); + + describe('login', () => { + let routeHandler: RequestHandler; + let routeConfig: RouteConfig; + + const mockRequest = httpServerMock.createKibanaRequest({ + body: { username: 'user', password: 'password' }, + }); + + beforeEach(() => { + const [loginRouteConfig, loginRouteHandler] = router.post.mock.calls.find( + ([{ path }]) => path === '/internal/security/login' + )!; + + routeConfig = loginRouteConfig; + routeHandler = loginRouteHandler; + }); + + it('correctly defines route.', async () => { + expect(routeConfig.options).toEqual({ authRequired: false }); + expect(routeConfig.validate).toEqual({ + body: expect.any(Type), + query: undefined, + params: undefined, + }); + + const bodyValidator = (routeConfig.validate as any).body as Type; + expect(bodyValidator.validate({ username: 'user', password: 'password' })).toEqual({ + username: 'user', + password: 'password', + }); + + expect(() => bodyValidator.validate({})).toThrowErrorMatchingInlineSnapshot( + `"[username]: expected value of type [string] but got [undefined]"` + ); + expect(() => bodyValidator.validate({ username: 'user' })).toThrowErrorMatchingInlineSnapshot( + `"[password]: expected value of type [string] but got [undefined]"` + ); + expect(() => + bodyValidator.validate({ password: 'password' }) + ).toThrowErrorMatchingInlineSnapshot( + `"[username]: expected value of type [string] but got [undefined]"` + ); + expect(() => + bodyValidator.validate({ username: '', password: '' }) + ).toThrowErrorMatchingInlineSnapshot( + `"[username]: value is [] but it must have a minimum length of [1]."` + ); + expect(() => + bodyValidator.validate({ username: 'user', password: '' }) + ).toThrowErrorMatchingInlineSnapshot( + `"[password]: value is [] but it must have a minimum length of [1]."` + ); + expect(() => + bodyValidator.validate({ username: '', password: 'password' }) + ).toThrowErrorMatchingInlineSnapshot( + `"[username]: value is [] but it must have a minimum length of [1]."` + ); + }); + + it('returns 500 if authentication throws unhandled exception.', async () => { + const unhandledException = new Error('Something went wrong.'); + authc.login.mockRejectedValue(unhandledException); + + const response = await routeHandler(mockContext, mockRequest, kibanaResponseFactory); + + expect(response.status).toBe(500); + expect(response.payload).toEqual(unhandledException); + expect(authc.login).toHaveBeenCalledWith(mockRequest, { + provider: 'basic', + value: { username: 'user', password: 'password' }, + }); + }); + + it('returns 401 if authentication fails.', async () => { + const failureReason = new Error('Something went wrong.'); + authc.login.mockResolvedValue(AuthenticationResult.failed(failureReason)); + + const response = await routeHandler(mockContext, mockRequest, kibanaResponseFactory); + + expect(response.status).toBe(401); + expect(response.payload).toEqual(failureReason); + expect(authc.login).toHaveBeenCalledWith(mockRequest, { + provider: 'basic', + value: { username: 'user', password: 'password' }, + }); + }); + + it('returns 401 if authentication is not handled.', async () => { + authc.login.mockResolvedValue(AuthenticationResult.notHandled()); + + const response = await routeHandler(mockContext, mockRequest, kibanaResponseFactory); + + expect(response.status).toBe(401); + expect(response.payload).toEqual('Unauthorized'); + expect(authc.login).toHaveBeenCalledWith(mockRequest, { + provider: 'basic', + value: { username: 'user', password: 'password' }, + }); + }); + + describe('authentication succeeds', () => { + it(`returns user data`, async () => { + authc.login.mockResolvedValue(AuthenticationResult.succeeded(mockAuthenticatedUser())); + + const response = await routeHandler(mockContext, mockRequest, kibanaResponseFactory); + + expect(response.status).toBe(204); + expect(response.payload).toBeUndefined(); + expect(authc.login).toHaveBeenCalledWith(mockRequest, { + provider: 'basic', + value: { username: 'user', password: 'password' }, + }); + }); + }); + }); +}); diff --git a/x-pack/plugins/security/server/routes/authentication/basic.ts b/x-pack/plugins/security/server/routes/authentication/basic.ts new file mode 100644 index 0000000000000..453dc1c4ea3b5 --- /dev/null +++ b/x-pack/plugins/security/server/routes/authentication/basic.ts @@ -0,0 +1,48 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { wrapIntoCustomErrorResponse } from '../../errors'; +import { createLicensedRouteHandler } from '../licensed_route_handler'; +import { RouteDefinitionParams } from '..'; + +/** + * Defines routes required for Basic/Token authentication. + */ +export function defineBasicRoutes({ router, authc, config }: RouteDefinitionParams) { + router.post( + { + path: '/internal/security/login', + validate: { + body: schema.object({ + username: schema.string({ minLength: 1 }), + password: schema.string({ minLength: 1 }), + }), + }, + options: { authRequired: false }, + }, + createLicensedRouteHandler(async (context, request, response) => { + const { username, password } = request.body; + + try { + // We should prefer `token` over `basic` if possible. + const providerToLoginWith = config.authc.providers.includes('token') ? 'token' : 'basic'; + const authenticationResult = await authc.login(request, { + provider: providerToLoginWith, + value: { username, password }, + }); + + if (!authenticationResult.succeeded()) { + return response.unauthorized({ body: authenticationResult.error }); + } + + return response.noContent(); + } catch (error) { + return response.customError(wrapIntoCustomErrorResponse(error)); + } + }) + ); +} diff --git a/x-pack/plugins/security/server/routes/authentication/common.test.ts b/x-pack/plugins/security/server/routes/authentication/common.test.ts new file mode 100644 index 0000000000000..f57fb1d5a7d66 --- /dev/null +++ b/x-pack/plugins/security/server/routes/authentication/common.test.ts @@ -0,0 +1,202 @@ +/* + * 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 { Type } from '@kbn/config-schema'; +import { + IRouter, + kibanaResponseFactory, + RequestHandler, + RequestHandlerContext, + RouteConfig, +} from '../../../../../../src/core/server'; +import { LICENSE_CHECK_STATE } from '../../../../licensing/server'; +import { Authentication, DeauthenticationResult } from '../../authentication'; +import { ConfigType } from '../../config'; +import { LegacyAPI } from '../../plugin'; +import { defineCommonRoutes } from './common'; + +import { + elasticsearchServiceMock, + httpServerMock, + httpServiceMock, + loggingServiceMock, +} from '../../../../../../src/core/server/mocks'; +import { mockAuthenticatedUser } from '../../../common/model/authenticated_user.mock'; +import { authenticationMock } from '../../authentication/index.mock'; +import { authorizationMock } from '../../authorization/index.mock'; + +describe('Common authentication routes', () => { + let router: jest.Mocked; + let authc: jest.Mocked; + let mockContext: RequestHandlerContext; + beforeEach(() => { + router = httpServiceMock.createRouter(); + authc = authenticationMock.create(); + + mockContext = ({ + licensing: { + license: { check: jest.fn().mockReturnValue({ check: LICENSE_CHECK_STATE.Valid }) }, + }, + } as unknown) as RequestHandlerContext; + + defineCommonRoutes({ + router, + clusterClient: elasticsearchServiceMock.createClusterClient(), + basePath: httpServiceMock.createBasePath(), + logger: loggingServiceMock.create().get(), + config: { authc: { providers: ['saml'] } } as ConfigType, + authc, + authz: authorizationMock.create(), + getLegacyAPI: () => ({ cspRules: 'test-csp-rule' } as LegacyAPI), + }); + }); + + describe('logout', () => { + let routeHandler: RequestHandler; + let routeConfig: RouteConfig; + + const mockRequest = httpServerMock.createKibanaRequest({ + body: { username: 'user', password: 'password' }, + }); + + beforeEach(() => { + const [loginRouteConfig, loginRouteHandler] = router.get.mock.calls.find( + ([{ path }]) => path === '/api/security/logout' + )!; + + routeConfig = loginRouteConfig; + routeHandler = loginRouteHandler; + }); + + it('correctly defines route.', async () => { + expect(routeConfig.options).toEqual({ authRequired: false }); + expect(routeConfig.validate).toEqual({ + body: undefined, + query: expect.any(Type), + params: undefined, + }); + + const queryValidator = (routeConfig.validate as any).query as Type; + expect(queryValidator.validate({ someRandomField: 'some-random' })).toEqual({ + someRandomField: 'some-random', + }); + expect(queryValidator.validate({})).toEqual({}); + expect(queryValidator.validate(undefined)).toEqual({}); + }); + + it('returns 500 if deauthentication throws unhandled exception.', async () => { + const unhandledException = new Error('Something went wrong.'); + authc.logout.mockRejectedValue(unhandledException); + + const response = await routeHandler(mockContext, mockRequest, kibanaResponseFactory); + + expect(response.status).toBe(500); + expect(response.payload).toEqual(unhandledException); + expect(authc.logout).toHaveBeenCalledWith(mockRequest); + }); + + it('returns 500 if authenticator fails to logout.', async () => { + const failureReason = new Error('Something went wrong.'); + authc.logout.mockResolvedValue(DeauthenticationResult.failed(failureReason)); + + const response = await routeHandler(mockContext, mockRequest, kibanaResponseFactory); + + expect(response.status).toBe(500); + expect(response.payload).toEqual(failureReason); + expect(authc.logout).toHaveBeenCalledWith(mockRequest); + }); + + it('returns 400 for AJAX requests that can not handle redirect.', async () => { + const mockAjaxRequest = httpServerMock.createKibanaRequest({ + headers: { 'kbn-xsrf': 'xsrf' }, + }); + + const response = await routeHandler(mockContext, mockAjaxRequest, kibanaResponseFactory); + + expect(response.status).toBe(400); + expect(response.payload).toEqual('Client should be able to process redirect response.'); + expect(authc.logout).not.toHaveBeenCalled(); + }); + + it('redirects user to the URL returned by authenticator.', async () => { + authc.logout.mockResolvedValue(DeauthenticationResult.redirectTo('https://custom.logout')); + + const response = await routeHandler(mockContext, mockRequest, kibanaResponseFactory); + + expect(response.status).toBe(302); + expect(response.payload).toBeUndefined(); + expect(response.options).toEqual({ headers: { location: 'https://custom.logout' } }); + expect(authc.logout).toHaveBeenCalledWith(mockRequest); + }); + + it('redirects user to the base path if deauthentication succeeds.', async () => { + authc.logout.mockResolvedValue(DeauthenticationResult.succeeded()); + + const response = await routeHandler(mockContext, mockRequest, kibanaResponseFactory); + + expect(response.status).toBe(302); + expect(response.payload).toBeUndefined(); + expect(response.options).toEqual({ headers: { location: '/mock-server-basepath/' } }); + expect(authc.logout).toHaveBeenCalledWith(mockRequest); + }); + + it('redirects user to the base path if deauthentication is not handled.', async () => { + authc.logout.mockResolvedValue(DeauthenticationResult.notHandled()); + + const response = await routeHandler(mockContext, mockRequest, kibanaResponseFactory); + + expect(response.status).toBe(302); + expect(response.payload).toBeUndefined(); + expect(response.options).toEqual({ headers: { location: '/mock-server-basepath/' } }); + expect(authc.logout).toHaveBeenCalledWith(mockRequest); + }); + }); + + describe('me', () => { + let routeHandler: RequestHandler; + let routeConfig: RouteConfig; + + const mockRequest = httpServerMock.createKibanaRequest({ + body: { username: 'user', password: 'password' }, + }); + + beforeEach(() => { + const [loginRouteConfig, loginRouteHandler] = router.get.mock.calls.find( + ([{ path }]) => path === '/internal/security/me' + )!; + + routeConfig = loginRouteConfig; + routeHandler = loginRouteHandler; + }); + + it('correctly defines route.', async () => { + expect(routeConfig.options).toBeUndefined(); + expect(routeConfig.validate).toBe(false); + }); + + it('returns 500 if cannot retrieve current user due to unhandled exception.', async () => { + const unhandledException = new Error('Something went wrong.'); + authc.getCurrentUser.mockRejectedValue(unhandledException); + + const response = await routeHandler(mockContext, mockRequest, kibanaResponseFactory); + + expect(response.status).toBe(500); + expect(response.payload).toEqual(unhandledException); + expect(authc.getCurrentUser).toHaveBeenCalledWith(mockRequest); + }); + + it('returns current user.', async () => { + const mockUser = mockAuthenticatedUser(); + authc.getCurrentUser.mockResolvedValue(mockUser); + + const response = await routeHandler(mockContext, mockRequest, kibanaResponseFactory); + + expect(response.status).toBe(200); + expect(response.payload).toEqual(mockUser); + expect(authc.getCurrentUser).toHaveBeenCalledWith(mockRequest); + }); + }); +}); diff --git a/x-pack/plugins/security/server/routes/authentication/common.ts b/x-pack/plugins/security/server/routes/authentication/common.ts new file mode 100644 index 0000000000000..cb4ec196459ee --- /dev/null +++ b/x-pack/plugins/security/server/routes/authentication/common.ts @@ -0,0 +1,78 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { canRedirectRequest } from '../../authentication'; +import { wrapIntoCustomErrorResponse } from '../../errors'; +import { createLicensedRouteHandler } from '../licensed_route_handler'; +import { RouteDefinitionParams } from '..'; + +/** + * Defines routes that are common to various authentication mechanisms. + */ +export function defineCommonRoutes({ router, authc, basePath, logger }: RouteDefinitionParams) { + // Generate two identical routes with new and deprecated URL and issue a warning if route with deprecated URL is ever used. + for (const path of ['/api/security/logout', '/api/security/v1/logout']) { + router.get( + { + path, + // Allow unknown query parameters as this endpoint can be hit by the 3rd-party with any + // set of query string parameters (e.g. SAML/OIDC logout request parameters). + validate: { query: schema.object({}, { allowUnknowns: true }) }, + options: { authRequired: false }, + }, + async (context, request, response) => { + const serverBasePath = basePath.serverBasePath; + if (path === '/api/security/v1/logout') { + logger.warn( + `The "${serverBasePath}${path}" URL is deprecated and will stop working in the next major version, please use "${serverBasePath}/api/security/logout" URL instead.`, + { tags: ['deprecation'] } + ); + } + + if (!canRedirectRequest(request)) { + return response.badRequest({ + body: 'Client should be able to process redirect response.', + }); + } + + try { + const deauthenticationResult = await authc.logout(request); + if (deauthenticationResult.failed()) { + return response.customError(wrapIntoCustomErrorResponse(deauthenticationResult.error)); + } + + return response.redirected({ + headers: { location: deauthenticationResult.redirectURL || `${serverBasePath}/` }, + }); + } catch (error) { + return response.customError(wrapIntoCustomErrorResponse(error)); + } + } + ); + } + + // Generate two identical routes with new and deprecated URL and issue a warning if route with deprecated URL is ever used. + for (const path of ['/internal/security/me', '/api/security/v1/me']) { + router.get( + { path, validate: false }, + createLicensedRouteHandler(async (context, request, response) => { + if (path === '/api/security/v1/me') { + logger.warn( + `The "${basePath.serverBasePath}${path}" endpoint is deprecated and will be removed in the next major version.`, + { tags: ['deprecation'] } + ); + } + + try { + return response.ok({ body: (await authc.getCurrentUser(request)) as any }); + } catch (error) { + return response.customError(wrapIntoCustomErrorResponse(error)); + } + }) + ); + } +} diff --git a/x-pack/plugins/security/server/routes/authentication/index.ts b/x-pack/plugins/security/server/routes/authentication/index.ts index 086647dcb3459..21f015cc23b68 100644 --- a/x-pack/plugins/security/server/routes/authentication/index.ts +++ b/x-pack/plugins/security/server/routes/authentication/index.ts @@ -6,11 +6,39 @@ import { defineSessionRoutes } from './session'; import { defineSAMLRoutes } from './saml'; +import { defineBasicRoutes } from './basic'; +import { defineCommonRoutes } from './common'; +import { defineOIDCRoutes } from './oidc'; import { RouteDefinitionParams } from '..'; +export function createCustomResourceResponse(body: string, contentType: string, cspRules: string) { + return { + body, + headers: { + 'content-type': contentType, + 'cache-control': 'private, no-cache, no-store', + 'content-security-policy': cspRules, + }, + statusCode: 200, + }; +} + export function defineAuthenticationRoutes(params: RouteDefinitionParams) { defineSessionRoutes(params); + defineCommonRoutes(params); + + if ( + params.config.authc.providers.includes('basic') || + params.config.authc.providers.includes('token') + ) { + defineBasicRoutes(params); + } + if (params.config.authc.providers.includes('saml')) { defineSAMLRoutes(params); } + + if (params.config.authc.providers.includes('oidc')) { + defineOIDCRoutes(params); + } } diff --git a/x-pack/plugins/security/server/routes/authentication/oidc.ts b/x-pack/plugins/security/server/routes/authentication/oidc.ts new file mode 100644 index 0000000000000..8483630763ae6 --- /dev/null +++ b/x-pack/plugins/security/server/routes/authentication/oidc.ts @@ -0,0 +1,274 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { i18n } from '@kbn/i18n'; +import { KibanaRequest, KibanaResponseFactory } from '../../../../../../src/core/server'; +import { OIDCAuthenticationFlow } from '../../authentication'; +import { createCustomResourceResponse } from '.'; +import { createLicensedRouteHandler } from '../licensed_route_handler'; +import { wrapIntoCustomErrorResponse } from '../../errors'; +import { ProviderLoginAttempt } from '../../authentication/providers/oidc'; +import { RouteDefinitionParams } from '..'; + +/** + * Defines routes required for SAML authentication. + */ +export function defineOIDCRoutes({ + router, + logger, + authc, + getLegacyAPI, + basePath, +}: RouteDefinitionParams) { + // Generate two identical routes with new and deprecated URL and issue a warning if route with deprecated URL is ever used. + for (const path of ['/api/security/oidc/implicit', '/api/security/v1/oidc/implicit']) { + /** + * The route should be configured as a redirect URI in OP when OpenID Connect implicit flow + * is used, so that we can extract authentication response from URL fragment and send it to + * the `/api/security/oidc` route. + */ + router.get( + { + path, + validate: false, + options: { authRequired: false }, + }, + (context, request, response) => { + const serverBasePath = basePath.serverBasePath; + if (path === '/api/security/v1/oidc/implicit') { + logger.warn( + `The "${serverBasePath}${path}" URL is deprecated and will stop working in the next major version, please use "${serverBasePath}/api/security/oidc/implicit" URL instead.`, + { tags: ['deprecation'] } + ); + } + return response.custom( + createCustomResourceResponse( + ` + + Kibana OpenID Connect Login + + + `, + 'text/html', + getLegacyAPI().cspRules + ) + ); + } + ); + } + + /** + * The route that accompanies `/api/security/oidc/implicit` and renders a JavaScript snippet + * that extracts fragment part from the URL and send it to the `/api/security/oidc` route. + * We need this separate endpoint because of default CSP policy that forbids inline scripts. + */ + router.get( + { + path: '/internal/security/oidc/implicit.js', + validate: false, + options: { authRequired: false }, + }, + (context, request, response) => { + const serverBasePath = basePath.serverBasePath; + return response.custom( + createCustomResourceResponse( + ` + window.location.replace( + '${serverBasePath}/api/security/oidc?authenticationResponseURI=' + encodeURIComponent(window.location.href) + ); + `, + 'text/javascript', + getLegacyAPI().cspRules + ) + ); + } + ); + + // Generate two identical routes with new and deprecated URL and issue a warning if route with deprecated URL is ever used. + for (const path of ['/api/security/oidc', '/api/security/v1/oidc']) { + router.get( + { + path, + validate: { + query: schema.object( + { + authenticationResponseURI: schema.maybe(schema.uri()), + code: schema.maybe(schema.string()), + error: schema.maybe(schema.string()), + error_description: schema.maybe(schema.string()), + error_uri: schema.maybe(schema.uri()), + iss: schema.maybe(schema.uri({ scheme: ['https'] })), + login_hint: schema.maybe(schema.string()), + target_link_uri: schema.maybe(schema.uri()), + state: schema.maybe(schema.string()), + }, + // The client MUST ignore unrecognized response parameters according to + // https://openid.net/specs/openid-connect-core-1_0.html#AuthResponseValidation and + // https://tools.ietf.org/html/rfc6749#section-4.1.2. + { allowUnknowns: true } + ), + }, + options: { authRequired: false }, + }, + createLicensedRouteHandler(async (context, request, response) => { + const serverBasePath = basePath.serverBasePath; + + // An HTTP GET request with a query parameter named `authenticationResponseURI` that includes URL fragment OpenID + // Connect Provider sent during implicit authentication flow to the Kibana own proxy page that extracted that URL + // fragment and put it into `authenticationResponseURI` query string parameter for this endpoint. See more details + // at https://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth + let loginAttempt: ProviderLoginAttempt | undefined; + if (request.query.authenticationResponseURI) { + loginAttempt = { + flow: OIDCAuthenticationFlow.Implicit, + authenticationResponseURI: request.query.authenticationResponseURI, + }; + } else if (request.query.code || request.query.error) { + if (path === '/api/security/v1/oidc') { + logger.warn( + `The "${serverBasePath}${path}" URL is deprecated and will stop working in the next major version, please use "${serverBasePath}/api/security/oidc" URL instead.`, + { tags: ['deprecation'] } + ); + } + + // An HTTP GET request with a query parameter named `code` (or `error`) as the response to a successful (or + // failed) authentication from an OpenID Connect Provider during authorization code authentication flow. + // See more details at https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth. + loginAttempt = { + flow: OIDCAuthenticationFlow.AuthorizationCode, + // We pass the path only as we can't be sure of the full URL and Elasticsearch doesn't need it anyway. + authenticationResponseURI: request.url.path!, + }; + } else if (request.query.iss) { + logger.warn( + `The "${serverBasePath}${path}" URL is deprecated and will stop working in the next major version, please use "${serverBasePath}/api/security/oidc/initiate_login" URL for Third-Party Initiated login instead.`, + { tags: ['deprecation'] } + ); + // An HTTP GET request with a query parameter named `iss` as part of a 3rd party initiated authentication. + // See more details at https://openid.net/specs/openid-connect-core-1_0.html#ThirdPartyInitiatedLogin + loginAttempt = { + flow: OIDCAuthenticationFlow.InitiatedBy3rdParty, + iss: request.query.iss, + loginHint: request.query.login_hint, + }; + } + + if (!loginAttempt) { + return response.badRequest({ body: 'Unrecognized login attempt.' }); + } + + return performOIDCLogin(request, response, loginAttempt); + }) + ); + } + + // Generate two identical routes with new and deprecated URL and issue a warning if route with deprecated URL is ever used. + for (const path of ['/api/security/oidc/initiate_login', '/api/security/v1/oidc']) { + /** + * An HTTP POST request with the payload parameter named `iss` as part of a 3rd party initiated authentication. + * See more details at https://openid.net/specs/openid-connect-core-1_0.html#ThirdPartyInitiatedLogin + */ + router.post( + { + path, + validate: { + body: schema.object( + { + iss: schema.uri({ scheme: ['https'] }), + login_hint: schema.maybe(schema.string()), + target_link_uri: schema.maybe(schema.uri()), + }, + // Other parameters MAY be sent, if defined by extensions. Any parameters used that are not understood MUST + // be ignored by the Client according to https://openid.net/specs/openid-connect-core-1_0.html#ThirdPartyInitiatedLogin. + { allowUnknowns: true } + ), + }, + options: { authRequired: false }, + }, + createLicensedRouteHandler(async (context, request, response) => { + const serverBasePath = basePath.serverBasePath; + if (path === '/api/security/v1/oidc') { + logger.warn( + `The "${serverBasePath}${path}" URL is deprecated and will stop working in the next major version, please use "${serverBasePath}/api/security/oidc/initiate_login" URL for Third-Party Initiated login instead.`, + { tags: ['deprecation'] } + ); + } + + return performOIDCLogin(request, response, { + flow: OIDCAuthenticationFlow.InitiatedBy3rdParty, + iss: request.body.iss, + loginHint: request.body.login_hint, + }); + }) + ); + } + + /** + * An HTTP GET request with the query string parameter named `iss` as part of a 3rd party initiated authentication. + * See more details at https://openid.net/specs/openid-connect-core-1_0.html#ThirdPartyInitiatedLogin + */ + router.get( + { + path: '/api/security/oidc/initiate_login', + validate: { + query: schema.object( + { + iss: schema.uri({ scheme: ['https'] }), + login_hint: schema.maybe(schema.string()), + target_link_uri: schema.maybe(schema.uri()), + }, + // Other parameters MAY be sent, if defined by extensions. Any parameters used that are not understood MUST + // be ignored by the Client according to https://openid.net/specs/openid-connect-core-1_0.html#ThirdPartyInitiatedLogin. + { allowUnknowns: true } + ), + }, + options: { authRequired: false }, + }, + createLicensedRouteHandler(async (context, request, response) => { + return performOIDCLogin(request, response, { + flow: OIDCAuthenticationFlow.InitiatedBy3rdParty, + iss: request.query.iss, + loginHint: request.query.login_hint, + }); + }) + ); + + async function performOIDCLogin( + request: KibanaRequest, + response: KibanaResponseFactory, + loginAttempt: ProviderLoginAttempt + ) { + try { + // We handle the fact that the user might get redirected to Kibana while already having a session + // Return an error notifying the user they are already logged in. + const authenticationResult = await authc.login(request, { + provider: 'oidc', + value: loginAttempt, + }); + + if (authenticationResult.succeeded()) { + return response.forbidden({ + body: i18n.translate('xpack.security.conflictingSessionError', { + defaultMessage: + 'Sorry, you already have an active Kibana session. ' + + 'If you want to start a new one, please logout from the existing session first.', + }), + }); + } + + if (authenticationResult.redirected()) { + return response.redirected({ + headers: { location: authenticationResult.redirectURL! }, + }); + } + + return response.unauthorized({ body: authenticationResult.error }); + } catch (error) { + return response.customError(wrapIntoCustomErrorResponse(error)); + } + } +} diff --git a/x-pack/plugins/security/server/routes/authentication/saml.ts b/x-pack/plugins/security/server/routes/authentication/saml.ts index 61f40e583d24e..f724d0e7708be 100644 --- a/x-pack/plugins/security/server/routes/authentication/saml.ts +++ b/x-pack/plugins/security/server/routes/authentication/saml.ts @@ -6,6 +6,7 @@ import { schema } from '@kbn/config-schema'; import { SAMLLoginStep } from '../../authentication'; +import { createCustomResourceResponse } from '.'; import { RouteDefinitionParams } from '..'; /** @@ -18,18 +19,6 @@ export function defineSAMLRoutes({ getLegacyAPI, basePath, }: RouteDefinitionParams) { - function createCustomResourceResponse(body: string, contentType: string) { - return { - body, - headers: { - 'content-type': contentType, - 'cache-control': 'private, no-cache, no-store', - 'content-security-policy': getLegacyAPI().cspRules, - }, - statusCode: 200, - }; - } - router.get( { path: '/api/security/saml/capture-url-fragment', @@ -46,7 +35,8 @@ export function defineSAMLRoutes({ `, - 'text/html' + 'text/html', + getLegacyAPI().cspRules ) ); } @@ -66,7 +56,8 @@ export function defineSAMLRoutes({ '${basePath.serverBasePath}/api/security/saml/start?redirectURLFragment=' + encodeURIComponent(window.location.hash) ); `, - 'text/javascript' + 'text/javascript', + getLegacyAPI().cspRules ) ); } diff --git a/x-pack/plugins/security/server/routes/authorization/privileges/get.test.ts b/x-pack/plugins/security/server/routes/authorization/privileges/get.test.ts index 10fe0cdd67811..6afbad8e83ebe 100644 --- a/x-pack/plugins/security/server/routes/authorization/privileges/get.test.ts +++ b/x-pack/plugins/security/server/routes/authorization/privileges/get.test.ts @@ -81,7 +81,7 @@ describe('GET privileges', () => { }; describe('failure', () => { - getPrivilegesTest(`returns result of routePreCheckLicense`, { + getPrivilegesTest('returns result of license checker', { licenseCheckResult: { state: LICENSE_CHECK_STATE.Invalid, message: 'test forbidden message' }, asserts: { statusCode: 403, result: { message: 'test forbidden message' } }, }); diff --git a/x-pack/plugins/security/server/routes/authorization/roles/delete.test.ts b/x-pack/plugins/security/server/routes/authorization/roles/delete.test.ts index 61c5747550d75..22268245c3a44 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/delete.test.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/delete.test.ts @@ -73,16 +73,18 @@ describe('DELETE role', () => { }; describe('failure', () => { - deleteRoleTest(`returns result of license checker`, { + deleteRoleTest('returns result of license checker', { name: 'foo-role', licenseCheckResult: { state: LICENSE_CHECK_STATE.Invalid, message: 'test forbidden message' }, asserts: { statusCode: 403, result: { message: 'test forbidden message' } }, }); const error = Boom.notFound('test not found message'); - deleteRoleTest(`returns error from cluster client`, { + deleteRoleTest('returns error from cluster client', { name: 'foo-role', - apiResponse: () => Promise.reject(error), + apiResponse: async () => { + throw error; + }, asserts: { statusCode: 404, result: error }, }); }); diff --git a/x-pack/plugins/security/server/routes/authorization/roles/delete.ts b/x-pack/plugins/security/server/routes/authorization/roles/delete.ts index aab815fbe449f..de966d6f2a758 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/delete.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/delete.ts @@ -7,7 +7,7 @@ import { schema } from '@kbn/config-schema'; import { RouteDefinitionParams } from '../../index'; import { createLicensedRouteHandler } from '../../licensed_route_handler'; -import { wrapError } from '../../../errors'; +import { wrapIntoCustomErrorResponse } from '../../../errors'; export function defineDeleteRolesRoutes({ router, clusterClient }: RouteDefinitionParams) { router.delete( @@ -23,11 +23,7 @@ export function defineDeleteRolesRoutes({ router, clusterClient }: RouteDefiniti return response.noContent(); } catch (error) { - const wrappedError = wrapError(error); - return response.customError({ - body: wrappedError, - statusCode: wrappedError.output.statusCode, - }); + return response.customError(wrapIntoCustomErrorResponse(error)); } }) ); diff --git a/x-pack/plugins/security/server/routes/authorization/roles/get.test.ts b/x-pack/plugins/security/server/routes/authorization/roles/get.test.ts index 447d890605cc9..bb9edbd17b2c8 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/get.test.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/get.test.ts @@ -75,15 +75,17 @@ describe('GET role', () => { }; describe('failure', () => { - getRoleTest(`returns result of license check`, { + getRoleTest('returns result of license checker', { licenseCheckResult: { state: LICENSE_CHECK_STATE.Invalid, message: 'test forbidden message' }, asserts: { statusCode: 403, result: { message: 'test forbidden message' } }, }); const error = Boom.notAcceptable('test not acceptable message'); - getRoleTest(`returns error from cluster client`, { + getRoleTest('returns error from cluster client', { name: 'first_role', - apiResponse: () => Promise.reject(error), + apiResponse: async () => { + throw error; + }, asserts: { statusCode: 406, result: error }, }); diff --git a/x-pack/plugins/security/server/routes/authorization/roles/get.ts b/x-pack/plugins/security/server/routes/authorization/roles/get.ts index 1173d37cba64f..8c158bee1a15e 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/get.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/get.ts @@ -7,7 +7,7 @@ import { schema } from '@kbn/config-schema'; import { RouteDefinitionParams } from '../..'; import { createLicensedRouteHandler } from '../../licensed_route_handler'; -import { wrapError } from '../../../errors'; +import { wrapIntoCustomErrorResponse } from '../../../errors'; import { transformElasticsearchRoleToRole } from './model'; export function defineGetRolesRoutes({ router, authz, clusterClient }: RouteDefinitionParams) { @@ -35,11 +35,7 @@ export function defineGetRolesRoutes({ router, authz, clusterClient }: RouteDefi return response.notFound(); } catch (error) { - const wrappedError = wrapError(error); - return response.customError({ - body: wrappedError, - statusCode: wrappedError.output.statusCode, - }); + return response.customError(wrapIntoCustomErrorResponse(error)); } }) ); diff --git a/x-pack/plugins/security/server/routes/authorization/roles/get_all.test.ts b/x-pack/plugins/security/server/routes/authorization/roles/get_all.test.ts index 3bd85122c95d1..96f065d6c765a 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/get_all.test.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/get_all.test.ts @@ -67,14 +67,16 @@ describe('GET all roles', () => { }; describe('failure', () => { - getRolesTest(`returns result of license check`, { + getRolesTest('returns result of license checker', { licenseCheckResult: { state: LICENSE_CHECK_STATE.Invalid, message: 'test forbidden message' }, asserts: { statusCode: 403, result: { message: 'test forbidden message' } }, }); const error = Boom.notAcceptable('test not acceptable message'); - getRolesTest(`returns error from cluster client`, { - apiResponse: () => Promise.reject(error), + getRolesTest('returns error from cluster client', { + apiResponse: async () => { + throw error; + }, asserts: { statusCode: 406, result: error }, }); diff --git a/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts b/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts index 6ff431f0f8b6a..24be6c60e4b12 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts @@ -6,7 +6,7 @@ import { RouteDefinitionParams } from '../..'; import { createLicensedRouteHandler } from '../../licensed_route_handler'; -import { wrapError } from '../../../errors'; +import { wrapIntoCustomErrorResponse } from '../../../errors'; import { ElasticsearchRole, transformElasticsearchRoleToRole } from './model'; export function defineGetAllRolesRoutes({ router, authz, clusterClient }: RouteDefinitionParams) { @@ -37,11 +37,7 @@ export function defineGetAllRolesRoutes({ router, authz, clusterClient }: RouteD }), }); } catch (error) { - const wrappedError = wrapError(error); - return response.customError({ - body: wrappedError, - statusCode: wrappedError.output.statusCode, - }); + return response.customError(wrapIntoCustomErrorResponse(error)); } }) ); diff --git a/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts b/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts index cb80549df8417..d19debe692460 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts @@ -138,7 +138,7 @@ describe('PUT role', () => { }); describe('failure', () => { - putRoleTest(`returns result of license checker`, { + putRoleTest('returns result of license checker', { name: 'foo-role', licenseCheckResult: { state: LICENSE_CHECK_STATE.Invalid, message: 'test forbidden message' }, asserts: { statusCode: 403, result: { message: 'test forbidden message' } }, diff --git a/x-pack/plugins/security/server/routes/authorization/roles/put.ts b/x-pack/plugins/security/server/routes/authorization/roles/put.ts index e0245e7260446..5db83375afa96 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/put.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/put.ts @@ -7,7 +7,7 @@ import { schema } from '@kbn/config-schema'; import { RouteDefinitionParams } from '../../index'; import { createLicensedRouteHandler } from '../../licensed_route_handler'; -import { wrapError } from '../../../errors'; +import { wrapIntoCustomErrorResponse } from '../../../errors'; import { ElasticsearchRole, getPutPayloadSchema, @@ -52,11 +52,7 @@ export function definePutRolesRoutes({ router, authz, clusterClient }: RouteDefi return response.noContent(); } catch (error) { - const wrappedError = wrapError(error); - return response.customError({ - body: wrappedError, - statusCode: wrappedError.output.statusCode, - }); + return response.customError(wrapIntoCustomErrorResponse(error)); } }) ); diff --git a/x-pack/plugins/security/server/routes/index.ts b/x-pack/plugins/security/server/routes/index.ts index 73e276832f474..756eaa76e2c2e 100644 --- a/x-pack/plugins/security/server/routes/index.ts +++ b/x-pack/plugins/security/server/routes/index.ts @@ -12,6 +12,9 @@ import { LegacyAPI } from '../plugin'; import { defineAuthenticationRoutes } from './authentication'; import { defineAuthorizationRoutes } from './authorization'; +import { defineApiKeysRoutes } from './api_keys'; +import { defineIndicesRoutes } from './indices'; +import { defineUsersRoutes } from './users'; /** * Describes parameters used to define HTTP routes. @@ -30,4 +33,7 @@ export interface RouteDefinitionParams { export function defineRoutes(params: RouteDefinitionParams) { defineAuthenticationRoutes(params); defineAuthorizationRoutes(params); + defineApiKeysRoutes(params); + defineIndicesRoutes(params); + defineUsersRoutes(params); } diff --git a/x-pack/plugins/security/server/routes/indices/get_fields.ts b/x-pack/plugins/security/server/routes/indices/get_fields.ts new file mode 100644 index 0000000000000..64c3d4f7471ef --- /dev/null +++ b/x-pack/plugins/security/server/routes/indices/get_fields.ts @@ -0,0 +1,47 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { RouteDefinitionParams } from '../index'; +import { wrapIntoCustomErrorResponse } from '../../errors'; + +export function defineGetFieldsRoutes({ router, clusterClient }: RouteDefinitionParams) { + router.get( + { + path: '/internal/security/fields/{query}', + validate: { params: schema.object({ query: schema.string() }) }, + }, + async (context, request, response) => { + try { + const indexMappings = (await clusterClient + .asScoped(request) + .callAsCurrentUser('indices.getFieldMapping', { + index: request.params.query, + fields: '*', + allowNoIndices: false, + includeDefaults: true, + })) as Record }>; + + // The flow is the following (see response format at https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-get-field-mapping.html): + // 1. Iterate over all matched indices. + // 2. Extract all the field names from the `mappings` field of the particular index. + // 3. Collect and flatten the list of the field names. + // 4. Use `Set` to get only unique field names. + return response.ok({ + body: Array.from( + new Set( + Object.values(indexMappings) + .map(indexMapping => Object.keys(indexMapping.mappings)) + .flat() + ) + ), + }); + } catch (error) { + return response.customError(wrapIntoCustomErrorResponse(error)); + } + } + ); +} diff --git a/x-pack/legacy/plugins/security/common/constants.ts b/x-pack/plugins/security/server/routes/indices/index.ts similarity index 54% rename from x-pack/legacy/plugins/security/common/constants.ts rename to x-pack/plugins/security/server/routes/indices/index.ts index 08e49ad995550..d6b5eccf0fada 100644 --- a/x-pack/legacy/plugins/security/common/constants.ts +++ b/x-pack/plugins/security/server/routes/indices/index.ts @@ -4,4 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -export const INTERNAL_API_BASE_PATH = '/internal/security'; +import { defineGetFieldsRoutes } from './get_fields'; +import { RouteDefinitionParams } from '..'; + +export function defineIndicesRoutes(params: RouteDefinitionParams) { + defineGetFieldsRoutes(params); +} diff --git a/x-pack/plugins/security/server/routes/users/change_password.test.ts b/x-pack/plugins/security/server/routes/users/change_password.test.ts new file mode 100644 index 0000000000000..9f88d28bc115f --- /dev/null +++ b/x-pack/plugins/security/server/routes/users/change_password.test.ts @@ -0,0 +1,207 @@ +/* + * 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 { ObjectType } from '@kbn/config-schema'; +import { + IClusterClient, + IRouter, + IScopedClusterClient, + kibanaResponseFactory, + RequestHandler, + RequestHandlerContext, + RouteConfig, +} from '../../../../../../src/core/server'; +import { LICENSE_CHECK_STATE } from '../../../../licensing/server'; +import { Authentication, AuthenticationResult } from '../../authentication'; +import { ConfigType } from '../../config'; +import { LegacyAPI } from '../../plugin'; +import { defineChangeUserPasswordRoutes } from './change_password'; + +import { + elasticsearchServiceMock, + loggingServiceMock, + httpServiceMock, + httpServerMock, +} from '../../../../../../src/core/server/mocks'; +import { mockAuthenticatedUser } from '../../../common/model/authenticated_user.mock'; +import { authorizationMock } from '../../authorization/index.mock'; +import { authenticationMock } from '../../authentication/index.mock'; + +describe('Change password', () => { + let router: jest.Mocked; + let authc: jest.Mocked; + let mockClusterClient: jest.Mocked; + let mockScopedClusterClient: jest.Mocked; + let routeHandler: RequestHandler; + let routeConfig: RouteConfig; + let mockContext: RequestHandlerContext; + + function checkPasswordChangeAPICall( + username: string, + request: ReturnType + ) { + expect(mockClusterClient.asScoped).toHaveBeenCalledTimes(1); + expect(mockClusterClient.asScoped).toHaveBeenCalledWith(request); + expect(mockScopedClusterClient.callAsCurrentUser).toHaveBeenCalledTimes(1); + expect(mockScopedClusterClient.callAsCurrentUser).toHaveBeenCalledWith( + 'shield.changePassword', + { username, body: { password: 'new-password' } } + ); + } + + beforeEach(() => { + router = httpServiceMock.createRouter(); + authc = authenticationMock.create(); + + authc.getCurrentUser.mockResolvedValue(mockAuthenticatedUser({ username: 'user' })); + authc.login.mockResolvedValue(AuthenticationResult.succeeded(mockAuthenticatedUser())); + + mockScopedClusterClient = elasticsearchServiceMock.createScopedClusterClient(); + mockClusterClient = elasticsearchServiceMock.createClusterClient(); + mockClusterClient.asScoped.mockReturnValue(mockScopedClusterClient); + + mockContext = ({ + licensing: { + license: { check: jest.fn().mockReturnValue({ check: LICENSE_CHECK_STATE.Valid }) }, + }, + } as unknown) as RequestHandlerContext; + + defineChangeUserPasswordRoutes({ + router, + clusterClient: mockClusterClient, + basePath: httpServiceMock.createBasePath(), + logger: loggingServiceMock.create().get(), + config: { authc: { providers: ['saml'] } } as ConfigType, + authc, + authz: authorizationMock.create(), + getLegacyAPI: () => ({ cspRules: 'test-csp-rule' } as LegacyAPI), + }); + + const [changePasswordRouteConfig, changePasswordRouteHandler] = router.post.mock.calls[0]; + routeConfig = changePasswordRouteConfig; + routeHandler = changePasswordRouteHandler; + }); + + it('correctly defines route.', async () => { + expect(routeConfig.path).toBe('/internal/security/users/{username}/password'); + + const paramsSchema = (routeConfig.validate as any).params as ObjectType; + expect(() => paramsSchema.validate({})).toThrowErrorMatchingInlineSnapshot( + `"[username]: expected value of type [string] but got [undefined]"` + ); + expect(() => paramsSchema.validate({ username: '' })).toThrowErrorMatchingInlineSnapshot( + `"[username]: value is [] but it must have a minimum length of [1]."` + ); + expect(() => + paramsSchema.validate({ username: 'a'.repeat(1025) }) + ).toThrowErrorMatchingInlineSnapshot( + `"[username]: value is [aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] but it must have a maximum length of [1024]."` + ); + + const bodySchema = (routeConfig.validate as any).body as ObjectType; + expect(() => bodySchema.validate({})).toThrowErrorMatchingInlineSnapshot( + `"[newPassword]: expected value of type [string] but got [undefined]"` + ); + expect(() => bodySchema.validate({ newPassword: '' })).toThrowErrorMatchingInlineSnapshot( + `"[newPassword]: value is [] but it must have a minimum length of [1]."` + ); + expect(() => + bodySchema.validate({ newPassword: '123456', password: '' }) + ).toThrowErrorMatchingInlineSnapshot( + `"[password]: value is [] but it must have a minimum length of [1]."` + ); + }); + + describe('own password', () => { + const username = 'user'; + const mockRequest = httpServerMock.createKibanaRequest({ + params: { username }, + body: { password: 'old-password', newPassword: 'new-password' }, + }); + + it('returns 403 if old password is wrong.', async () => { + const loginFailureReason = new Error('Something went wrong.'); + authc.login.mockResolvedValue(AuthenticationResult.failed(loginFailureReason)); + + const response = await routeHandler(mockContext, mockRequest, kibanaResponseFactory); + + expect(response.status).toBe(403); + expect(response.payload).toEqual(loginFailureReason); + expect(mockScopedClusterClient.callAsCurrentUser).not.toHaveBeenCalled(); + }); + + it(`returns 401 if user can't authenticate with new password.`, async () => { + const loginFailureReason = new Error('Something went wrong.'); + authc.login.mockImplementation(async (request, attempt) => { + const credentials = attempt.value as { username: string; password: string }; + if (credentials.username === 'user' && credentials.password === 'new-password') { + return AuthenticationResult.failed(loginFailureReason); + } + + return AuthenticationResult.succeeded(mockAuthenticatedUser()); + }); + + const response = await routeHandler(mockContext, mockRequest, kibanaResponseFactory); + + expect(response.status).toBe(401); + expect(response.payload).toEqual(loginFailureReason); + + checkPasswordChangeAPICall(username, mockRequest); + }); + + it('returns 500 if password update request fails.', async () => { + const failureReason = new Error('Request failed.'); + mockScopedClusterClient.callAsCurrentUser.mockRejectedValue(failureReason); + + const response = await routeHandler(mockContext, mockRequest, kibanaResponseFactory); + + expect(response.status).toBe(500); + expect(response.payload).toEqual(failureReason); + + checkPasswordChangeAPICall(username, mockRequest); + }); + + it('successfully changes own password if provided old password is correct.', async () => { + const response = await routeHandler(mockContext, mockRequest, kibanaResponseFactory); + + expect(response.status).toBe(204); + expect(response.payload).toBeUndefined(); + + checkPasswordChangeAPICall(username, mockRequest); + }); + }); + + describe('other user password', () => { + const username = 'target-user'; + const mockRequest = httpServerMock.createKibanaRequest({ + params: { username }, + body: { newPassword: 'new-password' }, + }); + + it('returns 500 if password update request fails.', async () => { + const failureReason = new Error('Request failed.'); + mockScopedClusterClient.callAsCurrentUser.mockRejectedValue(failureReason); + + const response = await routeHandler(mockContext, mockRequest, kibanaResponseFactory); + + expect(response.status).toBe(500); + expect(response.payload).toEqual(failureReason); + expect(authc.login).not.toHaveBeenCalled(); + + checkPasswordChangeAPICall(username, mockRequest); + }); + + it('successfully changes user password.', async () => { + const response = await routeHandler(mockContext, mockRequest, kibanaResponseFactory); + + expect(response.status).toBe(204); + expect(response.payload).toBeUndefined(); + expect(authc.login).not.toHaveBeenCalled(); + + checkPasswordChangeAPICall(username, mockRequest); + }); + }); +}); diff --git a/x-pack/plugins/security/server/routes/users/change_password.ts b/x-pack/plugins/security/server/routes/users/change_password.ts new file mode 100644 index 0000000000000..b9d04b4bd1e0e --- /dev/null +++ b/x-pack/plugins/security/server/routes/users/change_password.ts @@ -0,0 +1,80 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { wrapIntoCustomErrorResponse } from '../../errors'; +import { createLicensedRouteHandler } from '../licensed_route_handler'; +import { RouteDefinitionParams } from '..'; + +export function defineChangeUserPasswordRoutes({ + authc, + router, + clusterClient, + config, +}: RouteDefinitionParams) { + router.post( + { + path: '/internal/security/users/{username}/password', + validate: { + params: schema.object({ username: schema.string({ minLength: 1, maxLength: 1024 }) }), + body: schema.object({ + password: schema.maybe(schema.string({ minLength: 1 })), + newPassword: schema.string({ minLength: 1 }), + }), + }, + }, + createLicensedRouteHandler(async (context, request, response) => { + const username = request.params.username; + const { password, newPassword } = request.body; + const isCurrentUser = username === (await authc.getCurrentUser(request))!.username; + + // We should prefer `token` over `basic` if possible. + const providerToLoginWith = config.authc.providers.includes('token') ? 'token' : 'basic'; + + // If user tries to change own password, let's check if old password is valid first by trying + // to login. + if (isCurrentUser) { + try { + const authenticationResult = await authc.login(request, { + provider: providerToLoginWith, + value: { username, password }, + // We shouldn't alter authentication state just yet. + stateless: true, + }); + + if (!authenticationResult.succeeded()) { + return response.forbidden({ body: authenticationResult.error }); + } + } catch (error) { + return response.customError(wrapIntoCustomErrorResponse(error)); + } + } + + try { + await clusterClient.asScoped(request).callAsCurrentUser('shield.changePassword', { + username, + body: { password: newPassword }, + }); + + // Now we authenticate user with the new password again updating current session if any. + if (isCurrentUser) { + const authenticationResult = await authc.login(request, { + provider: providerToLoginWith, + value: { username, password: newPassword }, + }); + + if (!authenticationResult.succeeded()) { + return response.unauthorized({ body: authenticationResult.error }); + } + } + + return response.noContent(); + } catch (error) { + return response.customError(wrapIntoCustomErrorResponse(error)); + } + }) + ); +} diff --git a/x-pack/plugins/security/server/routes/users/create_or_update.ts b/x-pack/plugins/security/server/routes/users/create_or_update.ts new file mode 100644 index 0000000000000..5a3e50bb11d5c --- /dev/null +++ b/x-pack/plugins/security/server/routes/users/create_or_update.ts @@ -0,0 +1,47 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { wrapIntoCustomErrorResponse } from '../../errors'; +import { createLicensedRouteHandler } from '../licensed_route_handler'; +import { RouteDefinitionParams } from '..'; + +export function defineCreateOrUpdateUserRoutes({ router, clusterClient }: RouteDefinitionParams) { + router.post( + { + path: '/internal/security/users/{username}', + validate: { + params: schema.object({ username: schema.string({ minLength: 1, maxLength: 1024 }) }), + body: schema.object({ + username: schema.string({ minLength: 1, maxLength: 1024 }), + password: schema.maybe(schema.string({ minLength: 1 })), + roles: schema.arrayOf(schema.string({ minLength: 1 })), + full_name: schema.maybe(schema.oneOf([schema.literal(null), schema.string()])), + email: schema.maybe(schema.oneOf([schema.literal(null), schema.string()])), + metadata: schema.maybe(schema.recordOf(schema.string(), schema.any())), + enabled: schema.boolean({ defaultValue: true }), + }), + }, + }, + createLicensedRouteHandler(async (context, request, response) => { + try { + await clusterClient.asScoped(request).callAsCurrentUser('shield.putUser', { + username: request.params.username, + // Omit `username`, `enabled` and all fields with `null` value. + body: Object.fromEntries( + Object.entries(request.body).filter( + ([key, value]) => value !== null && key !== 'enabled' && key !== 'username' + ) + ), + }); + + return response.ok({ body: request.body }); + } catch (error) { + return response.customError(wrapIntoCustomErrorResponse(error)); + } + }) + ); +} diff --git a/x-pack/plugins/security/server/routes/users/delete.ts b/x-pack/plugins/security/server/routes/users/delete.ts new file mode 100644 index 0000000000000..99a8d5c18ab3d --- /dev/null +++ b/x-pack/plugins/security/server/routes/users/delete.ts @@ -0,0 +1,32 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { RouteDefinitionParams } from '../index'; +import { wrapIntoCustomErrorResponse } from '../../errors'; +import { createLicensedRouteHandler } from '../licensed_route_handler'; + +export function defineDeleteUserRoutes({ router, clusterClient }: RouteDefinitionParams) { + router.delete( + { + path: '/internal/security/users/{username}', + validate: { + params: schema.object({ username: schema.string({ minLength: 1, maxLength: 1024 }) }), + }, + }, + createLicensedRouteHandler(async (context, request, response) => { + try { + await clusterClient + .asScoped(request) + .callAsCurrentUser('shield.deleteUser', { username: request.params.username }); + + return response.noContent(); + } catch (error) { + return response.customError(wrapIntoCustomErrorResponse(error)); + } + }) + ); +} diff --git a/x-pack/plugins/security/server/routes/users/get.ts b/x-pack/plugins/security/server/routes/users/get.ts new file mode 100644 index 0000000000000..0867910372546 --- /dev/null +++ b/x-pack/plugins/security/server/routes/users/get.ts @@ -0,0 +1,37 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { wrapIntoCustomErrorResponse } from '../../errors'; +import { createLicensedRouteHandler } from '../licensed_route_handler'; +import { RouteDefinitionParams } from '..'; + +export function defineGetUserRoutes({ router, clusterClient }: RouteDefinitionParams) { + router.get( + { + path: '/internal/security/users/{username}', + validate: { + params: schema.object({ username: schema.string({ minLength: 1, maxLength: 1024 }) }), + }, + }, + createLicensedRouteHandler(async (context, request, response) => { + try { + const username = request.params.username; + const users = (await clusterClient + .asScoped(request) + .callAsCurrentUser('shield.getUser', { username })) as Record; + + if (!users[username]) { + return response.notFound(); + } + + return response.ok({ body: users[username] }); + } catch (error) { + return response.customError(wrapIntoCustomErrorResponse(error)); + } + }) + ); +} diff --git a/x-pack/plugins/security/server/routes/users/get_all.ts b/x-pack/plugins/security/server/routes/users/get_all.ts new file mode 100644 index 0000000000000..492ab27ab27ad --- /dev/null +++ b/x-pack/plugins/security/server/routes/users/get_all.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { RouteDefinitionParams } from '../index'; +import { wrapIntoCustomErrorResponse } from '../../errors'; +import { createLicensedRouteHandler } from '../licensed_route_handler'; + +export function defineGetAllUsersRoutes({ router, clusterClient }: RouteDefinitionParams) { + router.get( + { path: '/internal/security/users', validate: false }, + createLicensedRouteHandler(async (context, request, response) => { + try { + return response.ok({ + // Return only values since keys (user names) are already duplicated there. + body: Object.values( + await clusterClient.asScoped(request).callAsCurrentUser('shield.getUser') + ), + }); + } catch (error) { + return response.customError(wrapIntoCustomErrorResponse(error)); + } + }) + ); +} diff --git a/x-pack/plugins/security/server/routes/users/index.ts b/x-pack/plugins/security/server/routes/users/index.ts new file mode 100644 index 0000000000000..931af0734b416 --- /dev/null +++ b/x-pack/plugins/security/server/routes/users/index.ts @@ -0,0 +1,20 @@ +/* + * 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 { RouteDefinitionParams } from '../index'; +import { defineGetUserRoutes } from './get'; +import { defineGetAllUsersRoutes } from './get_all'; +import { defineCreateOrUpdateUserRoutes } from './create_or_update'; +import { defineDeleteUserRoutes } from './delete'; +import { defineChangeUserPasswordRoutes } from './change_password'; + +export function defineUsersRoutes(params: RouteDefinitionParams) { + defineGetUserRoutes(params); + defineGetAllUsersRoutes(params); + defineCreateOrUpdateUserRoutes(params); + defineDeleteUserRoutes(params); + defineChangeUserPasswordRoutes(params); +} diff --git a/x-pack/test/api_integration/apis/security/basic_login.js b/x-pack/test/api_integration/apis/security/basic_login.js index 1d10b3f8803a5..cd85e6906d65e 100644 --- a/x-pack/test/api_integration/apis/security/basic_login.js +++ b/x-pack/test/api_integration/apis/security/basic_login.js @@ -32,7 +32,7 @@ export default function ({ getService }) { it('should reject API requests if client is not authenticated', async () => { await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .expect(401); }); @@ -41,24 +41,24 @@ export default function ({ getService }) { const wrongUsername = `wrong-${validUsername}`; const wrongPassword = `wrong-${validPassword}`; - await supertest.post('/api/security/v1/login') + await supertest.post('/internal/security/login') .set('kbn-xsrf', 'xxx') .send({ username: wrongUsername, password: wrongPassword }) .expect(401); - await supertest.post('/api/security/v1/login') + await supertest.post('/internal/security/login') .set('kbn-xsrf', 'xxx') .send({ username: validUsername, password: wrongPassword }) .expect(401); - await supertest.post('/api/security/v1/login') + await supertest.post('/internal/security/login') .set('kbn-xsrf', 'xxx') .send({ username: wrongUsername, password: validPassword }) .expect(401); }); it('should set authentication cookie for login with valid credentials', async () => { - const loginResponse = await supertest.post('/api/security/v1/login') + const loginResponse = await supertest.post('/internal/security/login') .set('kbn-xsrf', 'xxx') .send({ username: validUsername, password: validPassword }) .expect(204); @@ -77,17 +77,17 @@ export default function ({ getService }) { const wrongUsername = `wrong-${validUsername}`; const wrongPassword = `wrong-${validPassword}`; - await supertest.get('/api/security/v1/me') + await supertest.get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Authorization', `Basic ${Buffer.from(`${wrongUsername}:${wrongPassword}`).toString('base64')}`) .expect(401); - await supertest.get('/api/security/v1/me') + await supertest.get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Authorization', `Basic ${Buffer.from(`${validUsername}:${wrongPassword}`).toString('base64')}`) .expect(401); - await supertest.get('/api/security/v1/me') + await supertest.get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Authorization', `Basic ${Buffer.from(`${wrongUsername}:${validPassword}`).toString('base64')}`) .expect(401); @@ -95,7 +95,7 @@ export default function ({ getService }) { it('should allow access to the API with valid credentials in the header', async () => { const apiResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Authorization', `Basic ${Buffer.from(`${validUsername}:${validPassword}`).toString('base64')}`) .expect(200); @@ -116,7 +116,7 @@ export default function ({ getService }) { describe('with session cookie', () => { let sessionCookie; beforeEach(async () => { - const loginResponse = await supertest.post('/api/security/v1/login') + const loginResponse = await supertest.post('/internal/security/login') .set('kbn-xsrf', 'xxx') .send({ username: validUsername, password: validPassword }) .expect(204); @@ -128,12 +128,12 @@ export default function ({ getService }) { // There is no session cookie provided and no server side session should have // been established, so request should be rejected. await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .expect(401); const apiResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(200); @@ -153,7 +153,7 @@ export default function ({ getService }) { it('should extend cookie on every successful non-system API call', async () => { const apiResponseOne = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(200); @@ -165,7 +165,7 @@ export default function ({ getService }) { expect(sessionCookieOne.value).to.not.equal(sessionCookie.value); const apiResponseTwo = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(200); @@ -179,7 +179,7 @@ export default function ({ getService }) { it('should not extend cookie for system API calls', async () => { const systemAPIResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('kbn-system-api', 'true') .set('Cookie', sessionCookie.cookieString()) @@ -190,7 +190,7 @@ export default function ({ getService }) { it('should fail and preserve session cookie if unsupported authentication schema is used', async () => { const apiResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Authorization', 'Bearer AbCdEf') .set('Cookie', sessionCookie.cookieString()) @@ -200,7 +200,7 @@ export default function ({ getService }) { }); it('should clear cookie on logout and redirect to login', async ()=> { - const logoutResponse = await supertest.get('/api/security/v1/logout?next=%2Fabc%2Fxyz&msg=test') + const logoutResponse = await supertest.get('/api/security/logout?next=%2Fabc%2Fxyz&msg=test') .set('Cookie', sessionCookie.cookieString()) .expect(302); @@ -256,7 +256,7 @@ export default function ({ getService }) { }); it('should redirect to home page if cookie is not provided', async ()=> { - const logoutResponse = await supertest.get('/api/security/v1/logout') + const logoutResponse = await supertest.get('/api/security/logout') .expect(302); expect(logoutResponse.headers['set-cookie']).to.be(undefined); diff --git a/x-pack/test/api_integration/apis/security/change_password.ts b/x-pack/test/api_integration/apis/security/change_password.ts index 09751d4a3641a..3efb7eb2bb1dd 100644 --- a/x-pack/test/api_integration/apis/security/change_password.ts +++ b/x-pack/test/api_integration/apis/security/change_password.ts @@ -20,7 +20,7 @@ export default function({ getService }: FtrProviderContext) { await security.user.create(mockUserName, { password: mockUserPassword, roles: [] }); const loginResponse = await supertest - .post('/api/security/v1/login') + .post('/internal/security/login') .set('kbn-xsrf', 'xxx') .send({ username: mockUserName, password: mockUserPassword }) .expect(204); @@ -34,7 +34,7 @@ export default function({ getService }: FtrProviderContext) { const newPassword = `xxx-${mockUserPassword}-xxx`; await supertest - .post(`/api/security/v1/users/${mockUserName}/password`) + .post(`/internal/security/users/${mockUserName}/password`) .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .send({ password: wrongPassword, newPassword }) @@ -42,21 +42,21 @@ export default function({ getService }: FtrProviderContext) { // Let's check that we can't login with wrong password, just in case. await supertest - .post('/api/security/v1/login') + .post('/internal/security/login') .set('kbn-xsrf', 'xxx') .send({ username: mockUserName, password: wrongPassword }) .expect(401); // Let's check that we can't login with the password we were supposed to set. await supertest - .post('/api/security/v1/login') + .post('/internal/security/login') .set('kbn-xsrf', 'xxx') .send({ username: mockUserName, password: newPassword }) .expect(401); // And can login with the current password. await supertest - .post('/api/security/v1/login') + .post('/internal/security/login') .set('kbn-xsrf', 'xxx') .send({ username: mockUserName, password: mockUserPassword }) .expect(204); @@ -66,7 +66,7 @@ export default function({ getService }: FtrProviderContext) { const newPassword = `xxx-${mockUserPassword}-xxx`; const passwordChangeResponse = await supertest - .post(`/api/security/v1/users/${mockUserName}/password`) + .post(`/internal/security/users/${mockUserName}/password`) .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .send({ password: mockUserPassword, newPassword }) @@ -76,28 +76,28 @@ export default function({ getService }: FtrProviderContext) { // Let's check that previous cookie isn't valid anymore. await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(401); // And that we can't login with the old password. await supertest - .post('/api/security/v1/login') + .post('/internal/security/login') .set('kbn-xsrf', 'xxx') .send({ username: mockUserName, password: mockUserPassword }) .expect(401); // But new cookie should be valid. await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', newSessionCookie.cookieString()) .expect(200); // And that we can login with new credentials. await supertest - .post('/api/security/v1/login') + .post('/internal/security/login') .set('kbn-xsrf', 'xxx') .send({ username: mockUserName, password: newPassword }) .expect(204); diff --git a/x-pack/test/api_integration/apis/security/index_fields.ts b/x-pack/test/api_integration/apis/security/index_fields.ts index 60c6e800c40b2..7adc589fbec3e 100644 --- a/x-pack/test/api_integration/apis/security/index_fields.ts +++ b/x-pack/test/api_integration/apis/security/index_fields.ts @@ -11,10 +11,10 @@ export default function({ getService }: FtrProviderContext) { const supertest = getService('supertest'); describe('Index Fields', () => { - describe('GET /api/security/v1/fields/{query}', () => { + describe('GET /internal/security/fields/{query}', () => { it('should return a list of available index mapping fields', async () => { await supertest - .get('/api/security/v1/fields/.kibana') + .get('/internal/security/fields/.kibana') .set('kbn-xsrf', 'xxx') .send() .expect(200) diff --git a/x-pack/test/api_integration/apis/security/session.ts b/x-pack/test/api_integration/apis/security/session.ts index 7c7883f58cb30..5d0935bb1ae2d 100644 --- a/x-pack/test/api_integration/apis/security/session.ts +++ b/x-pack/test/api_integration/apis/security/session.ts @@ -43,7 +43,7 @@ export default function({ getService }: FtrProviderContext) { beforeEach(async () => { await supertest - .post('/api/security/v1/login') + .post('/internal/security/login') .set('kbn-xsrf', 'xxx') .send({ username: validUsername, password: validPassword }) .expect(204) diff --git a/x-pack/test/api_integration/services/legacy_es.js b/x-pack/test/api_integration/services/legacy_es.js index 1518550407529..12a1576f78982 100644 --- a/x-pack/test/api_integration/services/legacy_es.js +++ b/x-pack/test/api_integration/services/legacy_es.js @@ -8,7 +8,7 @@ import { format as formatUrl } from 'url'; import * as legacyElasticsearch from 'elasticsearch'; -import shieldPlugin from '../../../legacy/server/lib/esjs_shield_plugin'; +import { elasticsearchClientPlugin } from '../../../plugins/security/server/elasticsearch_client_plugin'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { DEFAULT_API_VERSION } from '../../../../src/core/server/elasticsearch/elasticsearch_config'; @@ -19,6 +19,6 @@ export function LegacyEsProvider({ getService }) { apiVersion: DEFAULT_API_VERSION, host: formatUrl(config.get('servers.elasticsearch')), requestTimeout: config.get('timeouts.esRequestTimeout'), - plugins: [shieldPlugin], + plugins: [elasticsearchClientPlugin], }); } diff --git a/x-pack/test/kerberos_api_integration/apis/security/kerberos_login.ts b/x-pack/test/kerberos_api_integration/apis/security/kerberos_login.ts index 450f7b1a427dc..0346da334d2f2 100644 --- a/x-pack/test/kerberos_api_integration/apis/security/kerberos_login.ts +++ b/x-pack/test/kerberos_api_integration/apis/security/kerberos_login.ts @@ -47,7 +47,7 @@ export default function({ getService }: FtrProviderContext) { it('should reject API requests if client is not authenticated', async () => { await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .expect(401); }); @@ -55,7 +55,7 @@ export default function({ getService }: FtrProviderContext) { it('does not prevent basic login', async () => { const [username, password] = config.get('servers.elasticsearch.auth').split(':'); const response = await supertest - .post('/api/security/v1/login') + .post('/internal/security/login') .set('kbn-xsrf', 'xxx') .send({ username, password }) .expect(204); @@ -67,7 +67,7 @@ export default function({ getService }: FtrProviderContext) { checkCookieIsSet(cookie); const { body: user } = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', cookie.cookieString()) .expect(200); @@ -98,7 +98,7 @@ export default function({ getService }: FtrProviderContext) { describe('finishing SPNEGO', () => { it('should properly set cookie and authenticate user', async () => { const response = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('Authorization', `Negotiate ${spnegoToken}`) .expect(200); @@ -114,7 +114,7 @@ export default function({ getService }: FtrProviderContext) { checkCookieIsSet(sessionCookie); await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(200, { @@ -134,7 +134,7 @@ export default function({ getService }: FtrProviderContext) { it('should re-initiate SPNEGO handshake if token is rejected with 401', async () => { const spnegoResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('Authorization', `Negotiate ${Buffer.from('Hello').toString('base64')}`) .expect(401); expect(spnegoResponse.headers['set-cookie']).to.be(undefined); @@ -143,7 +143,7 @@ export default function({ getService }: FtrProviderContext) { it('should fail if SPNEGO token is rejected because of unknown reason', async () => { const spnegoResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('Authorization', 'Negotiate (:I am malformed:)') .expect(500); expect(spnegoResponse.headers['set-cookie']).to.be(undefined); @@ -156,7 +156,7 @@ export default function({ getService }: FtrProviderContext) { beforeEach(async () => { const response = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('Authorization', `Negotiate ${spnegoToken}`) .expect(200); @@ -169,7 +169,7 @@ export default function({ getService }: FtrProviderContext) { it('should extend cookie on every successful non-system API call', async () => { const apiResponseOne = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(200); @@ -181,7 +181,7 @@ export default function({ getService }: FtrProviderContext) { expect(sessionCookieOne.value).to.not.equal(sessionCookie.value); const apiResponseTwo = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(200); @@ -195,7 +195,7 @@ export default function({ getService }: FtrProviderContext) { it('should not extend cookie for system API calls', async () => { const systemAPIResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('kbn-system-api', 'true') .set('Cookie', sessionCookie.cookieString()) @@ -206,7 +206,7 @@ export default function({ getService }: FtrProviderContext) { it('should fail and preserve session cookie if unsupported authentication schema is used', async () => { const apiResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Authorization', 'Basic a3JiNTprcmI1') .set('Cookie', sessionCookie.cookieString()) @@ -220,7 +220,7 @@ export default function({ getService }: FtrProviderContext) { it('should redirect to `logged_out` page after successful logout', async () => { // First authenticate user to retrieve session cookie. const response = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('Authorization', `Negotiate ${spnegoToken}`) .expect(200); @@ -232,7 +232,7 @@ export default function({ getService }: FtrProviderContext) { // And then log user out. const logoutResponse = await supertest - .get('/api/security/v1/logout') + .get('/api/security/logout') .set('Cookie', sessionCookie.cookieString()) .expect(302); @@ -245,7 +245,7 @@ export default function({ getService }: FtrProviderContext) { // Token that was stored in the previous cookie should be invalidated as well and old // session cookie should not allow API access. const apiResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(401); @@ -259,7 +259,7 @@ export default function({ getService }: FtrProviderContext) { }); it('should redirect to home page if session cookie is not provided', async () => { - const logoutResponse = await supertest.get('/api/security/v1/logout').expect(302); + const logoutResponse = await supertest.get('/api/security/logout').expect(302); expect(logoutResponse.headers['set-cookie']).to.be(undefined); expect(logoutResponse.headers.location).to.be('/'); @@ -271,7 +271,7 @@ export default function({ getService }: FtrProviderContext) { beforeEach(async () => { const response = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('Authorization', `Negotiate ${spnegoToken}`) .expect(200); @@ -292,7 +292,7 @@ export default function({ getService }: FtrProviderContext) { // This api call should succeed and automatically refresh token. Returned cookie will contain // the new access and refresh token pair. const apiResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(200); @@ -305,7 +305,7 @@ export default function({ getService }: FtrProviderContext) { // The first new cookie with fresh pair of access and refresh tokens should work. await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', refreshedCookie.cookieString()) .expect(200); @@ -335,7 +335,7 @@ export default function({ getService }: FtrProviderContext) { // The first new cookie with fresh pair of access and refresh tokens should work. await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', refreshedCookie.cookieString()) .expect(200); @@ -349,7 +349,7 @@ export default function({ getService }: FtrProviderContext) { beforeEach(async () => { const response = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('Authorization', `Negotiate ${spnegoToken}`) .expect(200); @@ -374,7 +374,7 @@ export default function({ getService }: FtrProviderContext) { it('AJAX call should initiate SPNEGO and clear existing cookie', async function() { const apiResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(401); diff --git a/x-pack/test/oidc_api_integration/apis/authorization_code_flow/oidc_auth.js b/x-pack/test/oidc_api_integration/apis/authorization_code_flow/oidc_auth.js index 80ef6bd6df4ff..95958d12a42d7 100644 --- a/x-pack/test/oidc_api_integration/apis/authorization_code_flow/oidc_auth.js +++ b/x-pack/test/oidc_api_integration/apis/authorization_code_flow/oidc_auth.js @@ -16,7 +16,7 @@ export default function ({ getService }) { describe('OpenID Connect authentication', () => { it('should reject API requests if client is not authenticated', async () => { await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .expect(401); }); @@ -46,7 +46,8 @@ export default function ({ getService }) { }); it('should properly set cookie, return all parameters and redirect user for Third Party initiated', async () => { - const handshakeResponse = await supertest.get('/api/security/v1/oidc?iss=https://test-op.elastic.co') + const handshakeResponse = await supertest.post('/api/security/oidc/initiate_login') + .send({ iss: 'https://test-op.elastic.co' }) .expect(302); const cookies = handshakeResponse.headers['set-cookie']; @@ -74,7 +75,7 @@ export default function ({ getService }) { const handshakeCookie = request.cookie(handshakeResponse.headers['set-cookie'][0]); await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', handshakeCookie.cookieString()) .expect(401); @@ -108,20 +109,20 @@ export default function ({ getService }) { }); it('should fail if OpenID Connect response is not complemented with handshake cookie', async () => { - await supertest.get(`/api/security/v1/oidc?code=thisisthecode&state=${stateAndNonce.state}`) + await supertest.get(`/api/security/oidc?code=thisisthecode&state=${stateAndNonce.state}`) .set('kbn-xsrf', 'xxx') .expect(401); }); it('should fail if state is not matching', async () => { - await supertest.get(`/api/security/v1/oidc?code=thisisthecode&state=someothervalue`) + await supertest.get(`/api/security/oidc?code=thisisthecode&state=someothervalue`) .set('kbn-xsrf', 'xxx') .set('Cookie', handshakeCookie.cookieString()) .expect(401); }); it('should succeed if both the OpenID Connect response and the cookie are provided', async () => { - const oidcAuthenticationResponse = await supertest.get(`/api/security/v1/oidc?code=code1&state=${stateAndNonce.state}`) + const oidcAuthenticationResponse = await supertest.get(`/api/security/oidc?code=code1&state=${stateAndNonce.state}`) .set('kbn-xsrf', 'xxx') .set('Cookie', handshakeCookie.cookieString()) .expect(302); @@ -139,7 +140,7 @@ export default function ({ getService }) { expect(sessionCookie.httpOnly).to.be(true); const apiResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(200); @@ -160,7 +161,7 @@ export default function ({ getService }) { describe('Complete third party initiated authentication', () => { it('should authenticate a user when a third party initiates the authentication', async () => { - const handshakeResponse = await supertest.get('/api/security/v1/oidc?iss=https://test-op.elastic.co') + const handshakeResponse = await supertest.get('/api/security/oidc/initiate_login?iss=https://test-op.elastic.co') .expect(302); const handshakeCookie = request.cookie(handshakeResponse.headers['set-cookie'][0]); const stateAndNonce = getStateAndNonce(handshakeResponse.headers.location); @@ -172,7 +173,7 @@ export default function ({ getService }) { .send({ nonce: stateAndNonce.nonce }) .expect(200); - const oidcAuthenticationResponse = await supertest.get(`/api/security/v1/oidc?code=code2&state=${stateAndNonce.state}`) + const oidcAuthenticationResponse = await supertest.get(`/api/security/oidc?code=code2&state=${stateAndNonce.state}`) .set('kbn-xsrf', 'xxx') .set('Cookie', handshakeCookie.cookieString()) .expect(302); @@ -186,7 +187,7 @@ export default function ({ getService }) { expect(sessionCookie.httpOnly).to.be(true); const apiResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(200); @@ -222,7 +223,7 @@ export default function ({ getService }) { .send({ nonce: stateAndNonce.nonce }) .expect(200); - const oidcAuthenticationResponse = await supertest.get(`/api/security/v1/oidc?code=code1&state=${stateAndNonce.state}`) + const oidcAuthenticationResponse = await supertest.get(`/api/security/oidc?code=code1&state=${stateAndNonce.state}`) .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(302); @@ -232,7 +233,7 @@ export default function ({ getService }) { it('should extend cookie on every successful non-system API call', async () => { const apiResponseOne = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(200); @@ -244,7 +245,7 @@ export default function ({ getService }) { expect(sessionCookieOne.value).to.not.equal(sessionCookie.value); const apiResponseTwo = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(200); @@ -258,7 +259,7 @@ export default function ({ getService }) { it('should not extend cookie for system API calls', async () => { const systemAPIResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('kbn-system-api', 'true') .set('Cookie', sessionCookie.cookieString()) @@ -269,7 +270,7 @@ export default function ({ getService }) { it('should fail and preserve session cookie if unsupported authentication schema is used', async () => { const apiResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Authorization', 'Basic AbCdEf') .set('Cookie', sessionCookie.cookieString()) @@ -295,7 +296,7 @@ export default function ({ getService }) { .send({ nonce: stateAndNonce.nonce }) .expect(200); - const oidcAuthenticationResponse = await supertest.get(`/api/security/v1/oidc?code=code1&state=${stateAndNonce.state}`) + const oidcAuthenticationResponse = await supertest.get(`/api/security/oidc?code=code1&state=${stateAndNonce.state}`) .set('kbn-xsrf', 'xxx') .set('Cookie', handshakeCookie.cookieString()) .expect(302); @@ -307,7 +308,7 @@ export default function ({ getService }) { }); it('should redirect to home page if session cookie is not provided', async () => { - const logoutResponse = await supertest.get('/api/security/v1/logout') + const logoutResponse = await supertest.get('/api/security/logout') .expect(302); expect(logoutResponse.headers['set-cookie']).to.be(undefined); @@ -315,7 +316,7 @@ export default function ({ getService }) { }); it('should redirect to the OPs endsession endpoint to complete logout', async () => { - const logoutResponse = await supertest.get('/api/security/v1/logout') + const logoutResponse = await supertest.get('/api/security/logout') .set('Cookie', sessionCookie.cookieString()) .expect(302); @@ -336,7 +337,7 @@ export default function ({ getService }) { // Tokens that were stored in the previous cookie should be invalidated as well and old // session cookie should not allow API access. const apiResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(400); @@ -349,7 +350,7 @@ export default function ({ getService }) { }); it('should reject AJAX requests', async () => { - const ajaxResponse = await supertest.get('/api/security/v1/logout') + const ajaxResponse = await supertest.get('/api/security/logout') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(400); @@ -379,7 +380,7 @@ export default function ({ getService }) { .send({ nonce: stateAndNonce.nonce }) .expect(200); - const oidcAuthenticationResponse = await supertest.get(`/api/security/v1/oidc?code=code1&state=${stateAndNonce.state}`) + const oidcAuthenticationResponse = await supertest.get(`/api/security/oidc?code=code1&state=${stateAndNonce.state}`) .set('kbn-xsrf', 'xxx') .set('Cookie', handshakeCookie.cookieString()) .expect(302); @@ -408,7 +409,7 @@ export default function ({ getService }) { // This api call should succeed and automatically refresh token. Returned cookie will contain // the new access and refresh token pair. const firstResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(200); @@ -422,7 +423,7 @@ export default function ({ getService }) { // Request with old cookie should reuse the same refresh token if within 60 seconds. // Returned cookie will contain the same new access and refresh token pairs as the first request const secondResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(200); @@ -437,14 +438,14 @@ export default function ({ getService }) { // The first new cookie with fresh pair of access and refresh tokens should work. await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', firstNewCookie.cookieString()) .expect(200); // The second new cookie with fresh pair of access and refresh tokens should work. await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', secondNewCookie.cookieString()) .expect(200); @@ -467,7 +468,7 @@ export default function ({ getService }) { .send({ nonce: stateAndNonce.nonce }) .expect(200); - const oidcAuthenticationResponse = await supertest.get(`/api/security/v1/oidc?code=code1&state=${stateAndNonce.state}`) + const oidcAuthenticationResponse = await supertest.get(`/api/security/oidc?code=code1&state=${stateAndNonce.state}`) .set('kbn-xsrf', 'xxx') .set('Cookie', handshakeCookie.cookieString()) .expect(302); diff --git a/x-pack/test/oidc_api_integration/apis/implicit_flow/oidc_auth.ts b/x-pack/test/oidc_api_integration/apis/implicit_flow/oidc_auth.ts index 23cbb312b092a..0e07f01776713 100644 --- a/x-pack/test/oidc_api_integration/apis/implicit_flow/oidc_auth.ts +++ b/x-pack/test/oidc_api_integration/apis/implicit_flow/oidc_auth.ts @@ -31,7 +31,7 @@ export default function({ getService }: FtrProviderContext) { }); it('should return an HTML page that will parse URL fragment', async () => { - const response = await supertest.get('/api/security/v1/oidc/implicit').expect(200); + const response = await supertest.get('/api/security/oidc/implicit').expect(200); const dom = new JSDOM(response.text, { url: formatURL({ ...config.get('servers.kibana'), auth: false }), runScripts: 'dangerously', @@ -44,7 +44,7 @@ export default function({ getService }: FtrProviderContext) { Object.defineProperty(window, 'location', { value: { href: - 'https://kibana.com/api/security/v1/oidc/implicit#token=some_token&access_token=some_access_token', + 'https://kibana.com/api/security/oidc/implicit#token=some_token&access_token=some_access_token', replace(newLocation: string) { this.href = newLocation; resolve(); @@ -66,17 +66,17 @@ export default function({ getService }: FtrProviderContext) { // Check that script that forwards URL fragment worked correctly. expect(dom.window.location.href).to.be( - '/api/security/v1/oidc?authenticationResponseURI=https%3A%2F%2Fkibana.com%2Fapi%2Fsecurity%2Fv1%2Foidc%2Fimplicit%23token%3Dsome_token%26access_token%3Dsome_access_token' + '/api/security/oidc?authenticationResponseURI=https%3A%2F%2Fkibana.com%2Fapi%2Fsecurity%2Foidc%2Fimplicit%23token%3Dsome_token%26access_token%3Dsome_access_token' ); }); it('should fail if OpenID Connect response is not complemented with handshake cookie', async () => { const { idToken, accessToken } = createTokens('1', stateAndNonce.nonce); - const authenticationResponse = `https://kibana.com/api/security/v1/oidc/implicit#id_token=${idToken}&state=${stateAndNonce.state}&token_type=bearer&access_token=${accessToken}`; + const authenticationResponse = `https://kibana.com/api/security/oidc/implicit#id_token=${idToken}&state=${stateAndNonce.state}&token_type=bearer&access_token=${accessToken}`; await supertest .get( - `/api/security/v1/oidc?authenticationResponseURI=${encodeURIComponent( + `/api/security/oidc?authenticationResponseURI=${encodeURIComponent( authenticationResponse )}` ) @@ -86,11 +86,11 @@ export default function({ getService }: FtrProviderContext) { it('should fail if state is not matching', async () => { const { idToken, accessToken } = createTokens('1', stateAndNonce.nonce); - const authenticationResponse = `https://kibana.com/api/security/v1/oidc/implicit#id_token=${idToken}&state=$someothervalue&token_type=bearer&access_token=${accessToken}`; + const authenticationResponse = `https://kibana.com/api/security/oidc/implicit#id_token=${idToken}&state=$someothervalue&token_type=bearer&access_token=${accessToken}`; await supertest .get( - `/api/security/v1/oidc?authenticationResponseURI=${encodeURIComponent( + `/api/security/oidc?authenticationResponseURI=${encodeURIComponent( authenticationResponse )}` ) @@ -102,11 +102,11 @@ export default function({ getService }: FtrProviderContext) { // FLAKY: https://github.com/elastic/kibana/issues/43938 it.skip('should succeed if both the OpenID Connect response and the cookie are provided', async () => { const { idToken, accessToken } = createTokens('1', stateAndNonce.nonce); - const authenticationResponse = `https://kibana.com/api/security/v1/oidc/implicit#id_token=${idToken}&state=${stateAndNonce.state}&token_type=bearer&access_token=${accessToken}`; + const authenticationResponse = `https://kibana.com/api/security/oidc/implicit#id_token=${idToken}&state=${stateAndNonce.state}&token_type=bearer&access_token=${accessToken}`; const oidcAuthenticationResponse = await supertest .get( - `/api/security/v1/oidc?authenticationResponseURI=${encodeURIComponent( + `/api/security/oidc?authenticationResponseURI=${encodeURIComponent( authenticationResponse )}` ) @@ -129,7 +129,7 @@ export default function({ getService }: FtrProviderContext) { expect(sessionCookie.httpOnly).to.be(true); const apiResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(200); diff --git a/x-pack/test/oidc_api_integration/config.ts b/x-pack/test/oidc_api_integration/config.ts index f40db4ccbba0a..184ccbcdfa691 100644 --- a/x-pack/test/oidc_api_integration/config.ts +++ b/x-pack/test/oidc_api_integration/config.ts @@ -32,7 +32,7 @@ export default async function({ readConfigFile }: FtrConfigProviderContext) { `xpack.security.authc.realms.oidc.oidc1.rp.client_id=0oa8sqpov3TxMWJOt356`, `xpack.security.authc.realms.oidc.oidc1.rp.client_secret=0oa8sqpov3TxMWJOt356`, `xpack.security.authc.realms.oidc.oidc1.rp.response_type=code`, - `xpack.security.authc.realms.oidc.oidc1.rp.redirect_uri=http://localhost:${kibanaPort}/api/security/v1/oidc`, + `xpack.security.authc.realms.oidc.oidc1.rp.redirect_uri=http://localhost:${kibanaPort}/api/security/oidc`, `xpack.security.authc.realms.oidc.oidc1.op.authorization_endpoint=https://test-op.elastic.co/oauth2/v1/authorize`, `xpack.security.authc.realms.oidc.oidc1.op.endsession_endpoint=https://test-op.elastic.co/oauth2/v1/endsession`, `xpack.security.authc.realms.oidc.oidc1.op.token_endpoint=http://localhost:${kibanaPort}/api/oidc_provider/token_endpoint`, @@ -52,7 +52,7 @@ export default async function({ readConfigFile }: FtrConfigProviderContext) { '--xpack.security.authc.oidc.realm="oidc1"', '--server.xsrf.whitelist', JSON.stringify([ - '/api/security/v1/oidc', + '/api/security/oidc/initiate_login', '/api/oidc_provider/token_endpoint', '/api/oidc_provider/userinfo_endpoint', ]), diff --git a/x-pack/test/pki_api_integration/apis/security/pki_auth.ts b/x-pack/test/pki_api_integration/apis/security/pki_auth.ts index afb27168d6d5c..4eee900e68bec 100644 --- a/x-pack/test/pki_api_integration/apis/security/pki_auth.ts +++ b/x-pack/test/pki_api_integration/apis/security/pki_auth.ts @@ -57,7 +57,7 @@ export default function({ getService }: FtrProviderContext) { it('should reject API requests that use untrusted certificate', async () => { await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .ca(CA_CERT) .pfx(UNTRUSTED_CLIENT_CERT) .set('kbn-xsrf', 'xxx') @@ -67,7 +67,7 @@ export default function({ getService }: FtrProviderContext) { it('does not prevent basic login', async () => { const [username, password] = config.get('servers.elasticsearch.auth').split(':'); const response = await supertest - .post('/api/security/v1/login') + .post('/internal/security/login') .ca(CA_CERT) .pfx(UNTRUSTED_CLIENT_CERT) .set('kbn-xsrf', 'xxx') @@ -81,7 +81,7 @@ export default function({ getService }: FtrProviderContext) { checkCookieIsSet(cookie); const { body: user } = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .ca(CA_CERT) .pfx(UNTRUSTED_CLIENT_CERT) .set('kbn-xsrf', 'xxx') @@ -94,7 +94,7 @@ export default function({ getService }: FtrProviderContext) { it('should properly set cookie and authenticate user', async () => { const response = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .ca(CA_CERT) .pfx(FIRST_CLIENT_CERT) .expect(200); @@ -122,7 +122,7 @@ export default function({ getService }: FtrProviderContext) { // Cookie should be accepted. await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .ca(CA_CERT) .pfx(FIRST_CLIENT_CERT) .set('Cookie', sessionCookie.cookieString()) @@ -131,7 +131,7 @@ export default function({ getService }: FtrProviderContext) { it('should update session if new certificate is provided', async () => { let response = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .ca(CA_CERT) .pfx(FIRST_CLIENT_CERT) .expect(200); @@ -143,7 +143,7 @@ export default function({ getService }: FtrProviderContext) { checkCookieIsSet(sessionCookie); response = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .ca(CA_CERT) .pfx(SECOND_CLIENT_CERT) .set('Cookie', sessionCookie.cookieString()) @@ -167,7 +167,7 @@ export default function({ getService }: FtrProviderContext) { it('should reject valid cookie if used with untrusted certificate', async () => { const response = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .ca(CA_CERT) .pfx(FIRST_CLIENT_CERT) .expect(200); @@ -179,7 +179,7 @@ export default function({ getService }: FtrProviderContext) { checkCookieIsSet(sessionCookie); await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .ca(CA_CERT) .pfx(UNTRUSTED_CLIENT_CERT) .set('Cookie', sessionCookie.cookieString()) @@ -191,7 +191,7 @@ export default function({ getService }: FtrProviderContext) { beforeEach(async () => { const response = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .ca(CA_CERT) .pfx(FIRST_CLIENT_CERT) .expect(200); @@ -205,7 +205,7 @@ export default function({ getService }: FtrProviderContext) { it('should extend cookie on every successful non-system API call', async () => { const apiResponseOne = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .ca(CA_CERT) .pfx(FIRST_CLIENT_CERT) .set('kbn-xsrf', 'xxx') @@ -219,7 +219,7 @@ export default function({ getService }: FtrProviderContext) { expect(sessionCookieOne.value).to.not.equal(sessionCookie.value); const apiResponseTwo = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .ca(CA_CERT) .pfx(FIRST_CLIENT_CERT) .set('kbn-xsrf', 'xxx') @@ -235,7 +235,7 @@ export default function({ getService }: FtrProviderContext) { it('should not extend cookie for system API calls', async () => { const systemAPIResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .ca(CA_CERT) .pfx(FIRST_CLIENT_CERT) .set('kbn-xsrf', 'xxx') @@ -248,7 +248,7 @@ export default function({ getService }: FtrProviderContext) { it('should fail and preserve session cookie if unsupported authentication schema is used', async () => { const apiResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .ca(CA_CERT) .pfx(FIRST_CLIENT_CERT) .set('kbn-xsrf', 'xxx') @@ -264,7 +264,7 @@ export default function({ getService }: FtrProviderContext) { it('should redirect to `logged_out` page after successful logout', async () => { // First authenticate user to retrieve session cookie. const response = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .ca(CA_CERT) .pfx(FIRST_CLIENT_CERT) .expect(200); @@ -277,7 +277,7 @@ export default function({ getService }: FtrProviderContext) { // And then log user out. const logoutResponse = await supertest - .get('/api/security/v1/logout') + .get('/api/security/logout') .ca(CA_CERT) .pfx(FIRST_CLIENT_CERT) .set('Cookie', sessionCookie.cookieString()) @@ -292,7 +292,7 @@ export default function({ getService }: FtrProviderContext) { it('should redirect to home page if session cookie is not provided', async () => { const logoutResponse = await supertest - .get('/api/security/v1/logout') + .get('/api/security/logout') .ca(CA_CERT) .pfx(FIRST_CLIENT_CERT) .expect(302); @@ -307,7 +307,7 @@ export default function({ getService }: FtrProviderContext) { beforeEach(async () => { const response = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .ca(CA_CERT) .pfx(FIRST_CLIENT_CERT) .expect(200); @@ -329,7 +329,7 @@ export default function({ getService }: FtrProviderContext) { // This api call should succeed and automatically refresh token. Returned cookie will contain // the new access token. const apiResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .ca(CA_CERT) .pfx(FIRST_CLIENT_CERT) .set('kbn-xsrf', 'xxx') diff --git a/x-pack/test/saml_api_integration/apis/security/saml_login.ts b/x-pack/test/saml_api_integration/apis/security/saml_login.ts index 3815788aa746e..0436d59906ea8 100644 --- a/x-pack/test/saml_api_integration/apis/security/saml_login.ts +++ b/x-pack/test/saml_api_integration/apis/security/saml_login.ts @@ -42,7 +42,7 @@ export default function({ getService }: FtrProviderContext) { expect(sessionCookie.httpOnly).to.be(true); const apiResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(200); @@ -64,7 +64,7 @@ export default function({ getService }: FtrProviderContext) { describe('SAML authentication', () => { it('should reject API requests if client is not authenticated', async () => { await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .expect(401); }); @@ -72,7 +72,7 @@ export default function({ getService }: FtrProviderContext) { it('does not prevent basic login', async () => { const [username, password] = config.get('servers.elasticsearch.auth').split(':'); const response = await supertest - .post('/api/security/v1/login') + .post('/internal/security/login') .set('kbn-xsrf', 'xxx') .send({ username, password }) .expect(204); @@ -81,7 +81,7 @@ export default function({ getService }: FtrProviderContext) { expect(cookies).to.have.length(1); const { body: user } = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', request.cookie(cookies[0])!.cookieString()) .expect(200); @@ -192,7 +192,7 @@ export default function({ getService }: FtrProviderContext) { const handshakeCookie = request.cookie(handshakeResponse.headers['set-cookie'][0])!; await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', handshakeCookie.cookieString()) .expect(401); @@ -300,7 +300,7 @@ export default function({ getService }: FtrProviderContext) { it('should extend cookie on every successful non-system API call', async () => { const apiResponseOne = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(200); @@ -312,7 +312,7 @@ export default function({ getService }: FtrProviderContext) { expect(sessionCookieOne.value).to.not.equal(sessionCookie.value); const apiResponseTwo = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(200); @@ -326,7 +326,7 @@ export default function({ getService }: FtrProviderContext) { it('should not extend cookie for system API calls', async () => { const systemAPIResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('kbn-system-api', 'true') .set('Cookie', sessionCookie.cookieString()) @@ -337,7 +337,7 @@ export default function({ getService }: FtrProviderContext) { it('should fail and preserve session cookie if unsupported authentication schema is used', async () => { const apiResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Authorization', 'Basic AbCdEf') .set('Cookie', sessionCookie.cookieString()) @@ -383,7 +383,7 @@ export default function({ getService }: FtrProviderContext) { it('should redirect to IdP with SAML request to complete logout', async () => { const logoutResponse = await supertest - .get('/api/security/v1/logout') + .get('/api/security/logout') .set('Cookie', sessionCookie.cookieString()) .expect(302); @@ -404,7 +404,7 @@ export default function({ getService }: FtrProviderContext) { // Tokens that were stored in the previous cookie should be invalidated as well and old // session cookie should not allow API access. const apiResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(400); @@ -417,7 +417,7 @@ export default function({ getService }: FtrProviderContext) { }); it('should redirect to home page if session cookie is not provided', async () => { - const logoutResponse = await supertest.get('/api/security/v1/logout').expect(302); + const logoutResponse = await supertest.get('/api/security/logout').expect(302); expect(logoutResponse.headers['set-cookie']).to.be(undefined); expect(logoutResponse.headers.location).to.be('/'); @@ -425,7 +425,7 @@ export default function({ getService }: FtrProviderContext) { it('should reject AJAX requests', async () => { const ajaxResponse = await supertest - .get('/api/security/v1/logout') + .get('/api/security/logout') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(400); @@ -441,7 +441,7 @@ export default function({ getService }: FtrProviderContext) { it('should invalidate access token on IdP initiated logout', async () => { const logoutRequest = await createLogoutRequest({ sessionIndex: idpSessionIndex }); const logoutResponse = await supertest - .get(`/api/security/v1/logout?${querystring.stringify(logoutRequest)}`) + .get(`/api/security/logout?${querystring.stringify(logoutRequest)}`) .set('Cookie', sessionCookie.cookieString()) .expect(302); @@ -462,7 +462,7 @@ export default function({ getService }: FtrProviderContext) { // Tokens that were stored in the previous cookie should be invalidated as well and old session // cookie should not allow API access. const apiResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(400); @@ -477,7 +477,7 @@ export default function({ getService }: FtrProviderContext) { it('should invalidate access token on IdP initiated logout even if there is no Kibana session', async () => { const logoutRequest = await createLogoutRequest({ sessionIndex: idpSessionIndex }); const logoutResponse = await supertest - .get(`/api/security/v1/logout?${querystring.stringify(logoutRequest)}`) + .get(`/api/security/logout?${querystring.stringify(logoutRequest)}`) .expect(302); expect(logoutResponse.headers['set-cookie']).to.be(undefined); @@ -490,7 +490,7 @@ export default function({ getService }: FtrProviderContext) { // IdP session id (encoded in SAML LogoutRequest) even if Kibana doesn't provide them and session // cookie with these tokens should not allow API access. const apiResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(400); @@ -548,7 +548,7 @@ export default function({ getService }: FtrProviderContext) { // This api call should succeed and automatically refresh token. Returned cookie will contain // the new access and refresh token pair. const firstResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(200); @@ -562,7 +562,7 @@ export default function({ getService }: FtrProviderContext) { // Request with old cookie should reuse the same refresh token if within 60 seconds. // Returned cookie will contain the same new access and refresh token pairs as the first request const secondResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', sessionCookie.cookieString()) .expect(200); @@ -577,14 +577,14 @@ export default function({ getService }: FtrProviderContext) { // The first new cookie with fresh pair of access and refresh tokens should work. await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', firstNewCookie.cookieString()) .expect(200); // The second new cookie with fresh pair of access and refresh tokens should work. await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', secondNewCookie.cookieString()) .expect(200); @@ -701,7 +701,7 @@ export default function({ getService }: FtrProviderContext) { // Tokens from old cookie are invalidated. const rejectedResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', existingSessionCookie.cookieString()) .expect(400); @@ -712,7 +712,7 @@ export default function({ getService }: FtrProviderContext) { // Only tokens from new session are valid. const acceptedResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', newSessionCookie.cookieString()) .expect(200); @@ -737,7 +737,7 @@ export default function({ getService }: FtrProviderContext) { // Tokens from old cookie are invalidated. const rejectedResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', existingSessionCookie.cookieString()) .expect(400); @@ -748,7 +748,7 @@ export default function({ getService }: FtrProviderContext) { // Only tokens from new session are valid. const acceptedResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'xxx') .set('Cookie', newSessionCookie.cookieString()) .expect(200); diff --git a/x-pack/test/saved_object_api_integration/common/services/legacy_es.js b/x-pack/test/saved_object_api_integration/common/services/legacy_es.js index 94aa6025aa699..9267fa312ed06 100644 --- a/x-pack/test/saved_object_api_integration/common/services/legacy_es.js +++ b/x-pack/test/saved_object_api_integration/common/services/legacy_es.js @@ -8,7 +8,7 @@ import { format as formatUrl } from 'url'; import * as legacyElasticsearch from 'elasticsearch'; -import shieldPlugin from '../../../../legacy/server/lib/esjs_shield_plugin'; +import { elasticsearchClientPlugin } from '../../../../plugins/security/server/elasticsearch_client_plugin'; export function LegacyEsProvider({ getService }) { const config = getService('config'); @@ -16,6 +16,6 @@ export function LegacyEsProvider({ getService }) { return new legacyElasticsearch.Client({ host: formatUrl(config.get('servers.elasticsearch')), requestTimeout: config.get('timeouts.esRequestTimeout'), - plugins: [shieldPlugin], + plugins: [elasticsearchClientPlugin], }); } diff --git a/x-pack/test/spaces_api_integration/common/services/legacy_es.js b/x-pack/test/spaces_api_integration/common/services/legacy_es.js index 5e8137f0d11b5..5862fe877ba5c 100644 --- a/x-pack/test/spaces_api_integration/common/services/legacy_es.js +++ b/x-pack/test/spaces_api_integration/common/services/legacy_es.js @@ -8,7 +8,7 @@ import { format as formatUrl } from 'url'; import * as legacyElasticsearch from 'elasticsearch'; -import shieldPlugin from '../../../../legacy/server/lib/esjs_shield_plugin'; +import { elasticsearchClientPlugin } from '../../../../plugins/security/server/elasticsearch_client_plugin'; export function LegacyEsProvider({ getService }) { const config = getService('config'); @@ -16,6 +16,6 @@ export function LegacyEsProvider({ getService }) { return new legacyElasticsearch.Client({ host: formatUrl(config.get('servers.elasticsearch')), requestTimeout: config.get('timeouts.esRequestTimeout'), - plugins: [shieldPlugin] + plugins: [elasticsearchClientPlugin] }); } diff --git a/x-pack/test/token_api_integration/auth/header.js b/x-pack/test/token_api_integration/auth/header.js index 4b27fd5db3166..1c88f28a65541 100644 --- a/x-pack/test/token_api_integration/auth/header.js +++ b/x-pack/test/token_api_integration/auth/header.js @@ -25,7 +25,7 @@ export default function ({ getService }) { const token = await createToken(); await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'true') .set('authorization', `Bearer ${token}`) .expect(200); @@ -36,14 +36,14 @@ export default function ({ getService }) { // try it once await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'true') .set('authorization', `Bearer ${token}`) .expect(200); // try it again to verity it isn't invalidated after a single request await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'true') .set('authorization', `Bearer ${token}`) .expect(200); @@ -51,7 +51,7 @@ export default function ({ getService }) { it('rejects invalid access token via authorization Bearer header', async () => { await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'true') .set('authorization', 'Bearer notreal') .expect(401); @@ -67,7 +67,7 @@ export default function ({ getService }) { await new Promise(resolve => setTimeout(() => resolve(), 20000)); await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'true') .set('authorization', `Bearer ${token}`) .expect(401); diff --git a/x-pack/test/token_api_integration/auth/login.js b/x-pack/test/token_api_integration/auth/login.js index 2e6a2e2f81e4f..aba7e3852aa1f 100644 --- a/x-pack/test/token_api_integration/auth/login.js +++ b/x-pack/test/token_api_integration/auth/login.js @@ -17,7 +17,7 @@ export default function ({ getService }) { describe('login', () => { it('accepts valid login credentials as 204 status', async () => { await supertest - .post('/api/security/v1/login') + .post('/internal/security/login') .set('kbn-xsrf', 'true') .send({ username: 'elastic', password: 'changeme' }) .expect(204); @@ -25,7 +25,7 @@ export default function ({ getService }) { it('sets HttpOnly cookie with valid login', async () => { const response = await supertest - .post('/api/security/v1/login') + .post('/internal/security/login') .set('kbn-xsrf', 'true') .send({ username: 'elastic', password: 'changeme' }) .expect(204); @@ -42,7 +42,7 @@ export default function ({ getService }) { it('rejects without kbn-xsrf header as 400 status even if credentials are valid', async () => { const response = await supertest - .post('/api/security/v1/login') + .post('/internal/security/login') .send({ username: 'elastic', password: 'changeme' }) .expect(400); @@ -53,7 +53,7 @@ export default function ({ getService }) { it('rejects without credentials as 400 status', async () => { const response = await supertest - .post('/api/security/v1/login') + .post('/internal/security/login') .set('kbn-xsrf', 'true') .expect(400); @@ -64,7 +64,7 @@ export default function ({ getService }) { it('rejects without password as 400 status', async () => { const response = await supertest - .post('/api/security/v1/login') + .post('/internal/security/login') .set('kbn-xsrf', 'true') .send({ username: 'elastic' }) .expect(400); @@ -76,7 +76,7 @@ export default function ({ getService }) { it('rejects without username as 400 status', async () => { const response = await supertest - .post('/api/security/v1/login') + .post('/internal/security/login') .set('kbn-xsrf', 'true') .send({ password: 'changme' }) .expect(400); @@ -88,7 +88,7 @@ export default function ({ getService }) { it('rejects invalid credentials as 401 status', async () => { const response = await supertest - .post('/api/security/v1/login') + .post('/internal/security/login') .set('kbn-xsrf', 'true') .send({ username: 'elastic', password: 'notvalidpassword' }) .expect(401); diff --git a/x-pack/test/token_api_integration/auth/logout.js b/x-pack/test/token_api_integration/auth/logout.js index 9063488681958..fa7a0606c3770 100644 --- a/x-pack/test/token_api_integration/auth/logout.js +++ b/x-pack/test/token_api_integration/auth/logout.js @@ -16,7 +16,7 @@ export default function ({ getService }) { async function createSessionCookie() { const response = await supertest - .post('/api/security/v1/login') + .post('/internal/security/login') .set('kbn-xsrf', 'true') .send({ username: 'elastic', password: 'changeme' }); @@ -33,7 +33,7 @@ export default function ({ getService }) { const cookie = await createSessionCookie(); await supertest - .get('/api/security/v1/logout') + .get('/api/security/logout') .set('cookie', cookie.cookieString()) .expect(302) .expect('location', '/login?msg=LOGGED_OUT'); @@ -43,7 +43,7 @@ export default function ({ getService }) { const cookie = await createSessionCookie(); const response = await supertest - .get('/api/security/v1/logout') + .get('/api/security/logout') .set('cookie', cookie.cookieString()); const newCookie = extractSessionCookie(response); @@ -60,12 +60,12 @@ export default function ({ getService }) { // destroy it await supertest - .get('/api/security/v1/logout') + .get('/api/security/logout') .set('cookie', cookie.cookieString()); // verify that the cookie no longer works await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'true') .set('cookie', cookie.cookieString()) .expect(400); diff --git a/x-pack/test/token_api_integration/auth/session.js b/x-pack/test/token_api_integration/auth/session.js index 8a9f1d7a3f229..6e8e8c01f3da6 100644 --- a/x-pack/test/token_api_integration/auth/session.js +++ b/x-pack/test/token_api_integration/auth/session.js @@ -19,7 +19,7 @@ export default function ({ getService }) { async function createSessionCookie() { const response = await supertest - .post('/api/security/v1/login') + .post('/internal/security/login') .set('kbn-xsrf', 'true') .send({ username: 'elastic', password: 'changeme' }); @@ -36,7 +36,7 @@ export default function ({ getService }) { const cookie = await createSessionCookie(); await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'true') .set('cookie', cookie.cookieString()) .expect(200); @@ -47,14 +47,14 @@ export default function ({ getService }) { // try it once await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'true') .set('cookie', cookie.cookieString()) .expect(200); // try it again to verity it isn't invalidated after a single request await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'true') .set('cookie', cookie.cookieString()) .expect(200); @@ -85,7 +85,7 @@ export default function ({ getService }) { // This api call should succeed and automatically refresh token. Returned cookie will contain // the new access and refresh token pair. const firstResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'true') .set('cookie', originalCookie.cookieString()) .expect(200); @@ -96,7 +96,7 @@ export default function ({ getService }) { // Request with old cookie should return another valid cookie we can use to authenticate requests // if it happens within 60 seconds of the refresh token being used const secondResponse = await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'true') .set('Cookie', originalCookie.cookieString()) .expect(200); @@ -110,14 +110,14 @@ export default function ({ getService }) { // The first new cookie should authenticate a subsequent request await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'true') .set('Cookie', firstNewCookie.cookieString()) .expect(200); // The second new cookie should authenticate a subsequent request await supertest - .get('/api/security/v1/me') + .get('/internal/security/me') .set('kbn-xsrf', 'true') .set('Cookie', secondNewCookie.cookieString()) .expect(200); From b91c24c0b3b28863fb907f196c649dce41790a81 Mon Sep 17 00:00:00 2001 From: Brandon Morelli Date: Wed, 11 Dec 2019 09:53:44 -0800 Subject: [PATCH 13/79] docs: unknown route (#52703) --- docs/apm/troubleshooting.asciidoc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/apm/troubleshooting.asciidoc b/docs/apm/troubleshooting.asciidoc index 0e902e3608e72..ec0863b09d653 100644 --- a/docs/apm/troubleshooting.asciidoc +++ b/docs/apm/troubleshooting.asciidoc @@ -42,3 +42,22 @@ Finally, this problem can also occur if you've changed the index name that you w The default index pattern can be found {apm-server-ref}/elasticsearch-output.html#index-option-es[here]. If you change this setting, you must also configure the `setup.template.name` and `setup.template.pattern` options. See {apm-server-ref}/configuration-template.html[Load the Elasticsearch index template]. + +==== Unknown route + +The {apm-app-ref}/transactions.html[transaction overview] will only display helpful information +when the transactions in your services are named correctly. +If you're seeing "GET unknown route" or "unknown route" in the APM app, +it could be a sign that something isn't working like it should. + +Elastic APM Agents come with built-in support for popular frameworks out-of-the-box. +This means, among other things, that the Agent will try to automatically name HTTP requests. +As an example, the Node.js Agent uses the route that handled the request, while the Java Agent uses the Servlet name. + +"Unknown route" indicates that the Agent can't determine what to name the request, +perhaps because the technology you're using isn't supported, the Agent has been installed incorrectly, +or because something is happening to the request that the Agent doesn't understand. + +To resolve this, you'll need to head over to the relevant {apm-agents-ref}[Agent documentation]. +Specifically, view the Agent's supported technologies page. +You can also use the Agent's public API to manually set a name for the transaction. From 8395596159d649947091f07541d2129bcfb99227 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Wed, 11 Dec 2019 10:57:19 -0700 Subject: [PATCH 14/79] [Search service] Add timeout parameter from config to requests (#52352) * Add timeout parameter to requests * export SharedGlobalConfig from `core/server` --- .../core/server/kibana-plugin-server.md | 1 + ...kibana-plugin-server.sharedglobalconfig.md | 16 +++++++++++++ src/core/server/index.ts | 1 + src/core/server/plugins/types.ts | 3 +++ src/core/server/server.api.md | 12 +++++++++- src/plugins/data/server/search/create_api.ts | 2 +- .../es_search/es_search_strategy.test.ts | 23 ++++++++++++------- .../search/es_search/es_search_strategy.ts | 3 +++ .../data/server/search/i_search_context.ts | 5 +++- .../data/server/search/search_service.ts | 5 ++++ 10 files changed, 60 insertions(+), 11 deletions(-) create mode 100644 docs/development/core/server/kibana-plugin-server.sharedglobalconfig.md diff --git a/docs/development/core/server/kibana-plugin-server.md b/docs/development/core/server/kibana-plugin-server.md index fceabd1237665..1506fdbb2b37f 100644 --- a/docs/development/core/server/kibana-plugin-server.md +++ b/docs/development/core/server/kibana-plugin-server.md @@ -197,5 +197,6 @@ The plugin integrates with the core system via lifecycle events: `setup` | [SavedObjectsClientContract](./kibana-plugin-server.savedobjectsclientcontract.md) | Saved Objects is Kibana's data persisentence mechanism allowing plugins to use Elasticsearch for storing plugin state.\#\# SavedObjectsClient errorsSince the SavedObjectsClient has its hands in everything we are a little paranoid about the way we present errors back to to application code. Ideally, all errors will be either:1. Caused by bad implementation (ie. undefined is not a function) and as such unpredictable 2. An error that has been classified and decorated appropriately by the decorators in [SavedObjectsErrorHelpers](./kibana-plugin-server.savedobjectserrorhelpers.md)Type 1 errors are inevitable, but since all expected/handle-able errors should be Type 2 the isXYZError() helpers exposed at SavedObjectsErrorHelpers should be used to understand and manage error responses from the SavedObjectsClient.Type 2 errors are decorated versions of the source error, so if the elasticsearch client threw an error it will be decorated based on its type. That means that rather than looking for error.body.error.type or doing substring checks on error.body.error.reason, just use the helpers to understand the meaning of the error:\`\`\`js if (SavedObjectsErrorHelpers.isNotFoundError(error)) { // handle 404 }if (SavedObjectsErrorHelpers.isNotAuthorizedError(error)) { // 401 handling should be automatic, but in case you wanted to know }// always rethrow the error unless you handle it throw error; \`\`\`\#\#\# 404s from missing indexFrom the perspective of application code and APIs the SavedObjectsClient is a black box that persists objects. One of the internal details that users have no control over is that we use an elasticsearch index for persistance and that index might be missing.At the time of writing we are in the process of transitioning away from the operating assumption that the SavedObjects index is always available. Part of this transition is handling errors resulting from an index missing. These used to trigger a 500 error in most cases, and in others cause 404s with different error messages.From my (Spencer) perspective, a 404 from the SavedObjectsApi is a 404; The object the request/call was targeting could not be found. This is why \#14141 takes special care to ensure that 404 errors are generic and don't distinguish between index missing or document missing.\#\#\# 503s from missing indexUnlike all other methods, create requests are supposed to succeed even when the Kibana index does not exist because it will be automatically created by elasticsearch. When that is not the case it is because Elasticsearch's action.auto_create_index setting prevents it from being created automatically so we throw a special 503 with the intention of informing the user that their Elasticsearch settings need to be updated.See [SavedObjectsClient](./kibana-plugin-server.savedobjectsclient.md) See [SavedObjectsErrorHelpers](./kibana-plugin-server.savedobjectserrorhelpers.md) | | [SavedObjectsClientFactory](./kibana-plugin-server.savedobjectsclientfactory.md) | Describes the factory used to create instances of the Saved Objects Client. | | [SavedObjectsClientWrapperFactory](./kibana-plugin-server.savedobjectsclientwrapperfactory.md) | Describes the factory used to create instances of Saved Objects Client Wrappers. | +| [SharedGlobalConfig](./kibana-plugin-server.sharedglobalconfig.md) | | | [UiSettingsType](./kibana-plugin-server.uisettingstype.md) | UI element type to represent the settings. | diff --git a/docs/development/core/server/kibana-plugin-server.sharedglobalconfig.md b/docs/development/core/server/kibana-plugin-server.sharedglobalconfig.md new file mode 100644 index 0000000000000..418d406d4c890 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.sharedglobalconfig.md @@ -0,0 +1,16 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SharedGlobalConfig](./kibana-plugin-server.sharedglobalconfig.md) + +## SharedGlobalConfig type + + +Signature: + +```typescript +export declare type SharedGlobalConfig = RecursiveReadonly<{ + kibana: Pick; + elasticsearch: Pick; + path: Pick; +}>; +``` diff --git a/src/core/server/index.ts b/src/core/server/index.ts index 57156322e2849..51444a76f1737 100644 --- a/src/core/server/index.ts +++ b/src/core/server/index.ts @@ -143,6 +143,7 @@ export { PluginInitializerContext, PluginManifest, PluginName, + SharedGlobalConfig, } from './plugins'; export { diff --git a/src/core/server/plugins/types.ts b/src/core/server/plugins/types.ts index b4c8c98864263..36205cb7f047b 100644 --- a/src/core/server/plugins/types.ts +++ b/src/core/server/plugins/types.ts @@ -206,6 +206,9 @@ export const SharedGlobalConfigKeys = { path: ['data'] as const, }; +/** + * @public + */ export type SharedGlobalConfig = RecursiveReadonly<{ kibana: Pick; elasticsearch: Pick; diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index c855e04e420f7..142332d613dc9 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -1748,6 +1748,13 @@ export interface SessionStorageFactory { asScoped: (request: KibanaRequest) => SessionStorage; } +// @public (undocumented) +export type SharedGlobalConfig = RecursiveReadonly_2<{ + kibana: Pick; + elasticsearch: Pick; + path: Pick; +}>; + // @public export interface UiSettingsParams { category?: string[]; @@ -1785,6 +1792,9 @@ export const validBodyOutput: readonly ["data", "stream"]; // // src/core/server/http/router/response.ts:316:3 - (ae-forgotten-export) The symbol "KibanaResponse" needs to be exported by the entry point index.d.ts // src/core/server/plugins/plugins_service.ts:43:5 - (ae-forgotten-export) The symbol "InternalPluginInfo" needs to be exported by the entry point index.d.ts -// src/core/server/plugins/types.ts:228:15 - (ae-forgotten-export) The symbol "SharedGlobalConfig" needs to be exported by the entry point index.d.ts +// src/core/server/plugins/types.ts:213:3 - (ae-forgotten-export) The symbol "KibanaConfigType" needs to be exported by the entry point index.d.ts +// src/core/server/plugins/types.ts:213:3 - (ae-forgotten-export) The symbol "SharedGlobalConfigKeys" needs to be exported by the entry point index.d.ts +// src/core/server/plugins/types.ts:214:3 - (ae-forgotten-export) The symbol "ElasticsearchConfigType" needs to be exported by the entry point index.d.ts +// src/core/server/plugins/types.ts:215:3 - (ae-forgotten-export) The symbol "PathConfigType" needs to be exported by the entry point index.d.ts ``` diff --git a/src/plugins/data/server/search/create_api.ts b/src/plugins/data/server/search/create_api.ts index 2a874869526d7..e1613103ac399 100644 --- a/src/plugins/data/server/search/create_api.ts +++ b/src/plugins/data/server/search/create_api.ts @@ -38,7 +38,7 @@ export function createApi({ } // Give providers access to other search strategies by injecting this function const strategy = await strategyProvider(caller, api.search); - return strategy.search(request); + return strategy.search(request, options); }, }; return api; diff --git a/src/plugins/data/server/search/es_search/es_search_strategy.test.ts b/src/plugins/data/server/search/es_search/es_search_strategy.test.ts index 7b725a47aa13b..99ccb4dcbebab 100644 --- a/src/plugins/data/server/search/es_search/es_search_strategy.test.ts +++ b/src/plugins/data/server/search/es_search/es_search_strategy.test.ts @@ -17,7 +17,7 @@ * under the License. */ -import { coreMock } from '../../../../../core/server/mocks'; +import { coreMock, pluginInitializerContextConfigMock } from '../../../../../core/server/mocks'; import { esSearchStrategyProvider } from './es_search_strategy'; describe('ES search strategy', () => { @@ -31,6 +31,7 @@ describe('ES search strategy', () => { }, }); const mockSearch = jest.fn(); + const mockConfig$ = pluginInitializerContextConfigMock({}).legacy.globalConfig$; beforeEach(() => { mockApiCaller.mockClear(); @@ -41,6 +42,7 @@ describe('ES search strategy', () => { const esSearch = esSearchStrategyProvider( { core: mockCoreSetup, + config$: mockConfig$, }, mockApiCaller, mockSearch @@ -49,11 +51,12 @@ describe('ES search strategy', () => { expect(typeof esSearch.search).toBe('function'); }); - it('logs the response if `debug` is set to `true`', () => { + it('logs the response if `debug` is set to `true`', async () => { const spy = jest.spyOn(console, 'log'); const esSearch = esSearchStrategyProvider( { core: mockCoreSetup, + config$: mockConfig$, }, mockApiCaller, mockSearch @@ -61,43 +64,46 @@ describe('ES search strategy', () => { expect(spy).not.toBeCalled(); - esSearch.search({ params: {}, debug: true }); + await esSearch.search({ params: {}, debug: true }); expect(spy).toBeCalled(); }); - it('calls the API caller with the params with defaults', () => { + it('calls the API caller with the params with defaults', async () => { const params = { index: 'logstash-*' }; const esSearch = esSearchStrategyProvider( { core: mockCoreSetup, + config$: mockConfig$, }, mockApiCaller, mockSearch ); - esSearch.search({ params }); + await esSearch.search({ params }); expect(mockApiCaller).toBeCalled(); expect(mockApiCaller.mock.calls[0][0]).toBe('search'); expect(mockApiCaller.mock.calls[0][1]).toEqual({ ...params, + timeout: '0ms', ignoreUnavailable: true, restTotalHitsAsInt: true, }); }); - it('calls the API caller with overridden defaults', () => { - const params = { index: 'logstash-*', ignoreUnavailable: false }; + it('calls the API caller with overridden defaults', async () => { + const params = { index: 'logstash-*', ignoreUnavailable: false, timeout: '1000ms' }; const esSearch = esSearchStrategyProvider( { core: mockCoreSetup, + config$: mockConfig$, }, mockApiCaller, mockSearch ); - esSearch.search({ params }); + await esSearch.search({ params }); expect(mockApiCaller).toBeCalled(); expect(mockApiCaller.mock.calls[0][0]).toBe('search'); @@ -112,6 +118,7 @@ describe('ES search strategy', () => { const esSearch = esSearchStrategyProvider( { core: mockCoreSetup, + config$: mockConfig$, }, mockApiCaller, mockSearch diff --git a/src/plugins/data/server/search/es_search/es_search_strategy.ts b/src/plugins/data/server/search/es_search/es_search_strategy.ts index c5fc1d9d3a11c..20bc964effc02 100644 --- a/src/plugins/data/server/search/es_search/es_search_strategy.ts +++ b/src/plugins/data/server/search/es_search/es_search_strategy.ts @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +import { first } from 'rxjs/operators'; import { APICaller } from 'kibana/server'; import { SearchResponse } from 'elasticsearch'; import { ES_SEARCH_STRATEGY } from '../../../common/search'; @@ -28,7 +29,9 @@ export const esSearchStrategyProvider: TSearchStrategyProvider => { return { search: async (request, options) => { + const config = await context.config$.pipe(first()).toPromise(); const params = { + timeout: `${config.elasticsearch.shardTimeout.asMilliseconds()}ms`, ignoreUnavailable: true, // Don't fail if the index/indices don't exist restTotalHitsAsInt: true, // Get the number of hits as an int rather than a range ...request.params, diff --git a/src/plugins/data/server/search/i_search_context.ts b/src/plugins/data/server/search/i_search_context.ts index 5f2df5d8e819e..9d9de055d994f 100644 --- a/src/plugins/data/server/search/i_search_context.ts +++ b/src/plugins/data/server/search/i_search_context.ts @@ -16,8 +16,11 @@ * specific language governing permissions and limitations * under the License. */ -import { CoreSetup } from '../../../../core/server'; + +import { Observable } from 'rxjs'; +import { CoreSetup, SharedGlobalConfig } from '../../../../core/server'; export interface ISearchContext { core: CoreSetup; + config$: Observable; } diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index 3409a72326121..8ca314ad7bfd8 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -83,6 +83,11 @@ export class SearchService implements Plugin { }; api.registerSearchStrategyContext(this.initializerContext.opaqueId, 'core', () => core); + api.registerSearchStrategyContext( + this.initializerContext.opaqueId, + 'config$', + () => this.initializerContext.config.legacy.globalConfig$ + ); // ES search capabilities are written in a way that it could easily be a separate plugin, // however these two plugins are tightly coupled due to the default search strategy using From 19fec54e0b9ad7043fd764b03ed6e8f044f920fb Mon Sep 17 00:00:00 2001 From: Poff Poffenberger Date: Wed, 11 Dec 2019 11:59:44 -0600 Subject: [PATCH 15/79] [Canvas] Add NP routing for custom elements (#52561) * [Canvas] Add NP routing for custom elements * Remove unused type * Cleanup * Adding await to delete * Cleanup --- .../canvas/server/routes/custom_elements.ts | 192 ------------------ .../plugins/canvas/server/routes/index.ts | 2 - .../routes/custom_elements/create.test.ts | 102 ++++++++++ .../server/routes/custom_elements/create.ts | 54 +++++ .../custom_element_attributes.ts | 12 ++ .../custom_elements/custom_element_schema.ts | 26 +++ .../routes/custom_elements/delete.test.ts | 81 ++++++++ .../server/routes/custom_elements/delete.ts | 32 +++ .../routes/custom_elements/find.test.ts | 113 +++++++++++ .../server/routes/custom_elements/find.ts | 72 +++++++ .../server/routes/custom_elements/get.test.ts | 109 ++++++++++ .../server/routes/custom_elements/get.ts | 41 ++++ .../server/routes/custom_elements/index.ts | 20 ++ .../routes/custom_elements/update.test.ts | 164 +++++++++++++++ .../server/routes/custom_elements/update.ts | 63 ++++++ x-pack/plugins/canvas/server/routes/index.ts | 2 + .../routes/{workpad => }/ok_response.ts | 0 .../canvas/server/routes/workpad/create.ts | 8 +- .../canvas/server/routes/workpad/delete.ts | 2 +- .../canvas/server/routes/workpad/get.ts | 7 +- .../server/routes/workpad/update.test.ts | 2 +- .../canvas/server/routes/workpad/update.ts | 9 +- .../routes/workpad/workpad_attributes.ts | 11 + 23 files changed, 909 insertions(+), 215 deletions(-) delete mode 100644 x-pack/legacy/plugins/canvas/server/routes/custom_elements.ts create mode 100644 x-pack/plugins/canvas/server/routes/custom_elements/create.test.ts create mode 100644 x-pack/plugins/canvas/server/routes/custom_elements/create.ts create mode 100644 x-pack/plugins/canvas/server/routes/custom_elements/custom_element_attributes.ts create mode 100644 x-pack/plugins/canvas/server/routes/custom_elements/custom_element_schema.ts create mode 100644 x-pack/plugins/canvas/server/routes/custom_elements/delete.test.ts create mode 100644 x-pack/plugins/canvas/server/routes/custom_elements/delete.ts create mode 100644 x-pack/plugins/canvas/server/routes/custom_elements/find.test.ts create mode 100644 x-pack/plugins/canvas/server/routes/custom_elements/find.ts create mode 100644 x-pack/plugins/canvas/server/routes/custom_elements/get.test.ts create mode 100644 x-pack/plugins/canvas/server/routes/custom_elements/get.ts create mode 100644 x-pack/plugins/canvas/server/routes/custom_elements/index.ts create mode 100644 x-pack/plugins/canvas/server/routes/custom_elements/update.test.ts create mode 100644 x-pack/plugins/canvas/server/routes/custom_elements/update.ts rename x-pack/plugins/canvas/server/routes/{workpad => }/ok_response.ts (100%) create mode 100644 x-pack/plugins/canvas/server/routes/workpad/workpad_attributes.ts diff --git a/x-pack/legacy/plugins/canvas/server/routes/custom_elements.ts b/x-pack/legacy/plugins/canvas/server/routes/custom_elements.ts deleted file mode 100644 index 3fe78befd2f50..0000000000000 --- a/x-pack/legacy/plugins/canvas/server/routes/custom_elements.ts +++ /dev/null @@ -1,192 +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 boom from 'boom'; -import { omit } from 'lodash'; -import { SavedObjectsClientContract } from 'src/core/server'; - -import { API_ROUTE_CUSTOM_ELEMENT, CUSTOM_ELEMENT_TYPE } from '../../common/lib/constants'; -import { getId } from '../../public/lib/get_id'; -// @ts-ignore Untyped Local -import { formatResponse as formatRes } from '../lib/format_response'; -import { CustomElement } from '../../types'; - -import { CoreSetup } from '../shim'; - -// Exclude ID attribute for the type used for SavedObjectClient -type CustomElementAttributes = Pick> & { - '@timestamp': string; - '@created': string; -}; - -interface CustomElementRequestFacade { - getSavedObjectsClient: () => SavedObjectsClientContract; -} - -type CustomElementRequest = CustomElementRequestFacade & { - params: { - id: string; - }; - payload: CustomElement; -}; - -type FindCustomElementRequest = CustomElementRequestFacade & { - query: { - name: string; - page: number; - perPage: number; - }; -}; - -export function customElements( - route: CoreSetup['http']['route'], - elasticsearch: CoreSetup['elasticsearch'] -) { - // @ts-ignore: errors not on Cluster type - const { errors: esErrors } = elasticsearch.getCluster('data'); - - const routePrefix = API_ROUTE_CUSTOM_ELEMENT; - const formatResponse = formatRes(esErrors); - - const createCustomElement = (req: CustomElementRequest) => { - const savedObjectsClient = req.getSavedObjectsClient(); - - if (!req.payload) { - return Promise.reject(boom.badRequest('A custom element payload is required')); - } - - const now = new Date().toISOString(); - const { id, ...payload } = req.payload; - return savedObjectsClient.create( - CUSTOM_ELEMENT_TYPE, - { - ...payload, - '@timestamp': now, - '@created': now, - }, - { id: id || getId('custom-element') } - ); - }; - - const updateCustomElement = (req: CustomElementRequest, newPayload?: CustomElement) => { - const savedObjectsClient = req.getSavedObjectsClient(); - const { id } = req.params; - const payload = newPayload ? newPayload : req.payload; - - const now = new Date().toISOString(); - - return savedObjectsClient - .get(CUSTOM_ELEMENT_TYPE, id) - .then(element => { - // TODO: Using create with force over-write because of version conflict issues with update - return savedObjectsClient.create( - CUSTOM_ELEMENT_TYPE, - { - ...element.attributes, - ...omit(payload, 'id'), // never write the id property - '@timestamp': now, // always update the modified time - '@created': element.attributes['@created'], // ensure created is not modified - }, - { overwrite: true, id } - ); - }); - }; - - const deleteCustomElement = (req: CustomElementRequest) => { - const savedObjectsClient = req.getSavedObjectsClient(); - const { id } = req.params; - - return savedObjectsClient.delete(CUSTOM_ELEMENT_TYPE, id); - }; - - const findCustomElement = (req: FindCustomElementRequest) => { - const savedObjectsClient = req.getSavedObjectsClient(); - const { name, page, perPage } = req.query; - - return savedObjectsClient.find({ - type: CUSTOM_ELEMENT_TYPE, - sortField: '@timestamp', - sortOrder: 'desc', - search: name ? `${name}* | ${name}` : '*', - searchFields: ['name'], - fields: ['id', 'name', 'displayName', 'help', 'image', 'content', '@created', '@timestamp'], - page, - perPage, - }); - }; - - const getCustomElementById = (req: CustomElementRequest) => { - const savedObjectsClient = req.getSavedObjectsClient(); - const { id } = req.params; - return savedObjectsClient.get(CUSTOM_ELEMENT_TYPE, id); - }; - - // get custom element by id - route({ - method: 'GET', - path: `${routePrefix}/{id}`, - handler: (req: CustomElementRequest) => - getCustomElementById(req) - .then(obj => ({ id: obj.id, ...obj.attributes })) - .then(formatResponse) - .catch(formatResponse), - }); - - // create custom element - route({ - method: 'POST', - path: routePrefix, - // @ts-ignore config option missing on route method type - config: { payload: { allow: 'application/json', maxBytes: 26214400 } }, // 25MB payload limit - handler: (req: CustomElementRequest) => - createCustomElement(req) - .then(() => ({ ok: true })) - .catch(formatResponse), - }); - - // update custom element - route({ - method: 'PUT', - path: `${routePrefix}/{id}`, - // @ts-ignore config option missing on route method type - config: { payload: { allow: 'application/json', maxBytes: 26214400 } }, // 25MB payload limit - handler: (req: CustomElementRequest) => - updateCustomElement(req) - .then(() => ({ ok: true })) - .catch(formatResponse), - }); - - // delete custom element - route({ - method: 'DELETE', - path: `${routePrefix}/{id}`, - handler: (req: CustomElementRequest) => - deleteCustomElement(req) - .then(() => ({ ok: true })) - .catch(formatResponse), - }); - - // find custom elements - route({ - method: 'GET', - path: `${routePrefix}/find`, - handler: (req: FindCustomElementRequest) => - findCustomElement(req) - .then(formatResponse) - .then(resp => { - return { - total: resp.total, - customElements: resp.saved_objects.map(hit => ({ id: hit.id, ...hit.attributes })), - }; - }) - .catch(() => { - return { - total: 0, - customElements: [], - }; - }), - }); -} diff --git a/x-pack/legacy/plugins/canvas/server/routes/index.ts b/x-pack/legacy/plugins/canvas/server/routes/index.ts index 515d5b5e895ed..2f6b706fc7edb 100644 --- a/x-pack/legacy/plugins/canvas/server/routes/index.ts +++ b/x-pack/legacy/plugins/canvas/server/routes/index.ts @@ -5,12 +5,10 @@ */ import { esFields } from './es_fields'; -import { customElements } from './custom_elements'; import { shareableWorkpads } from './shareables'; import { CoreSetup } from '../shim'; export function routes(setup: CoreSetup): void { - customElements(setup.http.route, setup.elasticsearch); esFields(setup.http.route, setup.elasticsearch); shareableWorkpads(setup.http.route); } diff --git a/x-pack/plugins/canvas/server/routes/custom_elements/create.test.ts b/x-pack/plugins/canvas/server/routes/custom_elements/create.test.ts new file mode 100644 index 0000000000000..d3a69c01732fa --- /dev/null +++ b/x-pack/plugins/canvas/server/routes/custom_elements/create.test.ts @@ -0,0 +1,102 @@ +/* + * 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 sinon from 'sinon'; +import { + savedObjectsClientMock, + httpServiceMock, + httpServerMock, + loggingServiceMock, +} from 'src/core/server/mocks'; +import { CUSTOM_ELEMENT_TYPE } from '../../../../../legacy/plugins/canvas/common/lib/constants'; +import { initializeCreateCustomElementRoute } from './create'; +import { + IRouter, + kibanaResponseFactory, + RequestHandlerContext, + RequestHandler, +} from 'src/core/server'; + +const mockRouteContext = ({ + core: { + savedObjects: { + client: savedObjectsClientMock.create(), + }, + }, +} as unknown) as RequestHandlerContext; + +const mockedUUID = '123abc'; +const now = new Date(); +const nowIso = now.toISOString(); + +jest.mock('uuid/v4', () => jest.fn().mockReturnValue('123abc')); + +describe('POST custom element', () => { + let routeHandler: RequestHandler; + let clock: sinon.SinonFakeTimers; + + beforeEach(() => { + clock = sinon.useFakeTimers(now); + + const httpService = httpServiceMock.createSetupContract(); + + const router = httpService.createRouter('') as jest.Mocked; + initializeCreateCustomElementRoute({ + router, + logger: loggingServiceMock.create().get(), + }); + + routeHandler = router.post.mock.calls[0][1]; + }); + + afterEach(() => { + clock.restore(); + }); + + it(`returns 200 when the custom element is created`, async () => { + const mockCustomElement = { + displayName: 'My Custom Element', + }; + + const request = httpServerMock.createKibanaRequest({ + method: 'post', + path: 'api/canvas/custom-element', + body: mockCustomElement, + }); + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + + expect(response.status).toBe(200); + expect(response.payload).toEqual({ ok: true }); + expect(mockRouteContext.core.savedObjects.client.create).toBeCalledWith( + CUSTOM_ELEMENT_TYPE, + { + ...mockCustomElement, + '@timestamp': nowIso, + '@created': nowIso, + }, + { + id: `custom-element-${mockedUUID}`, + } + ); + }); + + it(`returns bad request if create is unsuccessful`, async () => { + const request = httpServerMock.createKibanaRequest({ + method: 'post', + path: 'api/canvas/custom-element', + body: {}, + }); + + (mockRouteContext.core.savedObjects.client.create as jest.Mock).mockImplementation(() => { + throw mockRouteContext.core.savedObjects.client.errors.createBadRequestError('bad request'); + }); + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + + expect(response.status).toBe(400); + }); +}); diff --git a/x-pack/plugins/canvas/server/routes/custom_elements/create.ts b/x-pack/plugins/canvas/server/routes/custom_elements/create.ts new file mode 100644 index 0000000000000..b882829124696 --- /dev/null +++ b/x-pack/plugins/canvas/server/routes/custom_elements/create.ts @@ -0,0 +1,54 @@ +/* + * 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 { RouteInitializerDeps } from '../'; +import { + CUSTOM_ELEMENT_TYPE, + API_ROUTE_CUSTOM_ELEMENT, +} from '../../../../../legacy/plugins/canvas/common/lib/constants'; +import { getId } from '../../../../../legacy/plugins/canvas/public/lib/get_id'; +import { CustomElementSchema } from './custom_element_schema'; +import { CustomElementAttributes } from './custom_element_attributes'; +import { okResponse } from '../ok_response'; +import { catchErrorHandler } from '../catch_error_handler'; + +export function initializeCreateCustomElementRoute(deps: RouteInitializerDeps) { + const { router } = deps; + router.post( + { + path: `${API_ROUTE_CUSTOM_ELEMENT}`, + validate: { + body: CustomElementSchema, + }, + options: { + body: { + maxBytes: 26214400, // 25MB payload limit + accepts: ['application/json'], + }, + }, + }, + catchErrorHandler(async (context, request, response) => { + const customElement = request.body; + + const now = new Date().toISOString(); + const { id, ...payload } = customElement; + + await context.core.savedObjects.client.create( + CUSTOM_ELEMENT_TYPE, + { + ...payload, + '@timestamp': now, + '@created': now, + }, + { id: id || getId('custom-element') } + ); + + return response.ok({ + body: okResponse, + }); + }) + ); +} diff --git a/x-pack/plugins/canvas/server/routes/custom_elements/custom_element_attributes.ts b/x-pack/plugins/canvas/server/routes/custom_elements/custom_element_attributes.ts new file mode 100644 index 0000000000000..e76526eeeb27b --- /dev/null +++ b/x-pack/plugins/canvas/server/routes/custom_elements/custom_element_attributes.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 { CustomElement } from '../../../../../legacy/plugins/canvas/types'; + +// Exclude ID attribute for the type used for SavedObjectClient +export type CustomElementAttributes = Pick> & { + '@timestamp': string; + '@created': string; +}; diff --git a/x-pack/plugins/canvas/server/routes/custom_elements/custom_element_schema.ts b/x-pack/plugins/canvas/server/routes/custom_elements/custom_element_schema.ts new file mode 100644 index 0000000000000..956dccc5aaea2 --- /dev/null +++ b/x-pack/plugins/canvas/server/routes/custom_elements/custom_element_schema.ts @@ -0,0 +1,26 @@ +/* + * 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 { schema } from '@kbn/config-schema'; + +export const CustomElementSchema = schema.object({ + '@created': schema.maybe(schema.string()), + '@timestamp': schema.maybe(schema.string()), + content: schema.string(), + displayName: schema.string(), + help: schema.maybe(schema.string()), + id: schema.string(), + image: schema.maybe(schema.string()), + name: schema.string(), + tags: schema.maybe(schema.arrayOf(schema.string())), +}); + +export const CustomElementUpdateSchema = schema.object({ + displayName: schema.string(), + help: schema.maybe(schema.string()), + image: schema.maybe(schema.string()), + name: schema.string(), +}); diff --git a/x-pack/plugins/canvas/server/routes/custom_elements/delete.test.ts b/x-pack/plugins/canvas/server/routes/custom_elements/delete.test.ts new file mode 100644 index 0000000000000..c108f2316db27 --- /dev/null +++ b/x-pack/plugins/canvas/server/routes/custom_elements/delete.test.ts @@ -0,0 +1,81 @@ +/* + * 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 { CUSTOM_ELEMENT_TYPE } from '../../../../../legacy/plugins/canvas/common/lib/constants'; +import { initializeDeleteCustomElementRoute } from './delete'; +import { + IRouter, + kibanaResponseFactory, + RequestHandlerContext, + RequestHandler, +} from 'src/core/server'; +import { + savedObjectsClientMock, + httpServiceMock, + httpServerMock, + loggingServiceMock, +} from 'src/core/server/mocks'; + +const mockRouteContext = ({ + core: { + savedObjects: { + client: savedObjectsClientMock.create(), + }, + }, +} as unknown) as RequestHandlerContext; + +describe('DELETE custom element', () => { + let routeHandler: RequestHandler; + + beforeEach(() => { + const httpService = httpServiceMock.createSetupContract(); + const router = httpService.createRouter('') as jest.Mocked; + initializeDeleteCustomElementRoute({ + router, + logger: loggingServiceMock.create().get(), + }); + + routeHandler = router.delete.mock.calls[0][1]; + }); + + it(`returns 200 ok when the custom element is deleted`, async () => { + const id = 'some-id'; + const request = httpServerMock.createKibanaRequest({ + method: 'delete', + path: `api/canvas/custom-element/${id}`, + params: { + id, + }, + }); + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + + expect(response.status).toBe(200); + expect(response.payload).toEqual({ ok: true }); + expect(mockRouteContext.core.savedObjects.client.delete).toBeCalledWith( + CUSTOM_ELEMENT_TYPE, + id + ); + }); + + it(`returns bad request if delete is unsuccessful`, async () => { + const request = httpServerMock.createKibanaRequest({ + method: 'delete', + path: `api/canvas/custom-element/some-id`, + params: { + id: 'some-id', + }, + }); + + (mockRouteContext.core.savedObjects.client.delete as jest.Mock).mockImplementationOnce(() => { + throw mockRouteContext.core.savedObjects.client.errors.createBadRequestError('bad request'); + }); + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + + expect(response.status).toBe(400); + }); +}); diff --git a/x-pack/plugins/canvas/server/routes/custom_elements/delete.ts b/x-pack/plugins/canvas/server/routes/custom_elements/delete.ts new file mode 100644 index 0000000000000..5867539b95b53 --- /dev/null +++ b/x-pack/plugins/canvas/server/routes/custom_elements/delete.ts @@ -0,0 +1,32 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { RouteInitializerDeps } from '../'; +import { + CUSTOM_ELEMENT_TYPE, + API_ROUTE_CUSTOM_ELEMENT, +} from '../../../../../legacy/plugins/canvas/common/lib/constants'; +import { okResponse } from '../ok_response'; +import { catchErrorHandler } from '../catch_error_handler'; + +export function initializeDeleteCustomElementRoute(deps: RouteInitializerDeps) { + const { router } = deps; + router.delete( + { + path: `${API_ROUTE_CUSTOM_ELEMENT}/{id}`, + validate: { + params: schema.object({ + id: schema.string(), + }), + }, + }, + catchErrorHandler(async (context, request, response) => { + await context.core.savedObjects.client.delete(CUSTOM_ELEMENT_TYPE, request.params.id); + return response.ok({ body: okResponse }); + }) + ); +} diff --git a/x-pack/plugins/canvas/server/routes/custom_elements/find.test.ts b/x-pack/plugins/canvas/server/routes/custom_elements/find.test.ts new file mode 100644 index 0000000000000..6644d3b56c681 --- /dev/null +++ b/x-pack/plugins/canvas/server/routes/custom_elements/find.test.ts @@ -0,0 +1,113 @@ +/* + * 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 { initializeFindCustomElementsRoute } from './find'; +import { + IRouter, + kibanaResponseFactory, + RequestHandlerContext, + RequestHandler, +} from 'src/core/server'; +import { + savedObjectsClientMock, + httpServiceMock, + httpServerMock, + loggingServiceMock, +} from 'src/core/server/mocks'; + +const mockRouteContext = ({ + core: { + savedObjects: { + client: savedObjectsClientMock.create(), + }, + }, +} as unknown) as RequestHandlerContext; + +describe('Find custom element', () => { + let routeHandler: RequestHandler; + + beforeEach(() => { + const httpService = httpServiceMock.createSetupContract(); + const router = httpService.createRouter('') as jest.Mocked; + initializeFindCustomElementsRoute({ + router, + logger: loggingServiceMock.create().get(), + }); + + routeHandler = router.get.mock.calls[0][1]; + }); + + it(`returns 200 with the found custom elements`, async () => { + const name = 'something'; + const perPage = 10000; + const mockResults = { + total: 2, + saved_objects: [ + { id: 1, attributes: { key: 'value' } }, + { id: 2, attributes: { key: 'other-value' } }, + ], + }; + + const findMock = mockRouteContext.core.savedObjects.client.find as jest.Mock; + + findMock.mockResolvedValueOnce(mockResults); + + const request = httpServerMock.createKibanaRequest({ + method: 'get', + path: `api/canvas/custom-elements/find`, + query: { + name, + perPage, + }, + }); + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + expect(response.status).toBe(200); + expect(findMock.mock.calls[0][0].search).toBe(`${name}* | ${name}`); + expect(findMock.mock.calls[0][0].perPage).toBe(perPage); + + expect(response.payload).toMatchInlineSnapshot(` + Object { + "customElements": Array [ + Object { + "id": 1, + "key": "value", + }, + Object { + "id": 2, + "key": "other-value", + }, + ], + "total": 2, + } + `); + }); + + it(`returns 200 with empty results on error`, async () => { + (mockRouteContext.core.savedObjects.client.find as jest.Mock).mockImplementationOnce(() => { + throw new Error('generic error'); + }); + + const request = httpServerMock.createKibanaRequest({ + method: 'get', + path: `api/canvas/custom-elements/find`, + query: { + name: 'something', + perPage: 1000, + }, + }); + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + + expect(response.status).toBe(200); + expect(response.payload).toMatchInlineSnapshot(` + Object { + "customElements": Array [], + "total": 0, + } + `); + }); +}); diff --git a/x-pack/plugins/canvas/server/routes/custom_elements/find.ts b/x-pack/plugins/canvas/server/routes/custom_elements/find.ts new file mode 100644 index 0000000000000..5041ceb3e4711 --- /dev/null +++ b/x-pack/plugins/canvas/server/routes/custom_elements/find.ts @@ -0,0 +1,72 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { SavedObjectAttributes } from 'src/core/server'; +import { RouteInitializerDeps } from '../'; +import { + CUSTOM_ELEMENT_TYPE, + API_ROUTE_CUSTOM_ELEMENT, +} from '../../../../../legacy/plugins/canvas/common/lib/constants'; + +export function initializeFindCustomElementsRoute(deps: RouteInitializerDeps) { + const { router } = deps; + router.get( + { + path: `${API_ROUTE_CUSTOM_ELEMENT}/find`, + validate: { + query: schema.object({ + name: schema.string(), + page: schema.maybe(schema.number()), + perPage: schema.number(), + }), + }, + }, + async (context, request, response) => { + const savedObjectsClient = context.core.savedObjects.client; + const { name, page, perPage } = request.query; + + try { + const customElements = await savedObjectsClient.find({ + type: CUSTOM_ELEMENT_TYPE, + sortField: '@timestamp', + sortOrder: 'desc', + search: name ? `${name}* | ${name}` : '*', + searchFields: ['name'], + fields: [ + 'id', + 'name', + 'displayName', + 'help', + 'image', + 'content', + '@created', + '@timestamp', + ], + page, + perPage, + }); + + return response.ok({ + body: { + total: customElements.total, + customElements: customElements.saved_objects.map(hit => ({ + id: hit.id, + ...hit.attributes, + })), + }, + }); + } catch (error) { + return response.ok({ + body: { + total: 0, + customElements: [], + }, + }); + } + } + ); +} diff --git a/x-pack/plugins/canvas/server/routes/custom_elements/get.test.ts b/x-pack/plugins/canvas/server/routes/custom_elements/get.test.ts new file mode 100644 index 0000000000000..5e8d536f779a9 --- /dev/null +++ b/x-pack/plugins/canvas/server/routes/custom_elements/get.test.ts @@ -0,0 +1,109 @@ +/* + * 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 { CUSTOM_ELEMENT_TYPE } from '../../../../../legacy/plugins/canvas/common/lib/constants'; +import { initializeGetCustomElementRoute } from './get'; +import { + IRouter, + kibanaResponseFactory, + RequestHandlerContext, + RequestHandler, +} from 'src/core/server'; +import { + savedObjectsClientMock, + httpServiceMock, + httpServerMock, + loggingServiceMock, +} from 'src/core/server/mocks'; + +const mockRouteContext = ({ + core: { + savedObjects: { + client: savedObjectsClientMock.create(), + }, + }, +} as unknown) as RequestHandlerContext; + +describe('GET custom element', () => { + let routeHandler: RequestHandler; + + beforeEach(() => { + const httpService = httpServiceMock.createSetupContract(); + const router = httpService.createRouter('') as jest.Mocked; + initializeGetCustomElementRoute({ + router, + logger: loggingServiceMock.create().get(), + }); + + routeHandler = router.get.mock.calls[0][1]; + }); + + it(`returns 200 when the custom element is found`, async () => { + const request = httpServerMock.createKibanaRequest({ + method: 'get', + path: 'api/canvas/custom-element/123', + params: { + id: '123', + }, + }); + + const savedObjectsClient = savedObjectsClientMock.create(); + savedObjectsClient.get.mockResolvedValueOnce({ + id: '123', + type: CUSTOM_ELEMENT_TYPE, + attributes: { foo: true }, + references: [], + }); + + mockRouteContext.core.savedObjects.client = savedObjectsClient; + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + + expect(response.status).toBe(200); + expect(response.payload).toMatchInlineSnapshot(` + Object { + "foo": true, + "id": "123", + } + `); + + expect(savedObjectsClient.get.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "canvas-element", + "123", + ], + ] + `); + }); + + it('returns 404 if the custom element is not found', async () => { + const id = '123'; + const request = httpServerMock.createKibanaRequest({ + method: 'get', + path: 'api/canvas/custom-element/123', + params: { + id, + }, + }); + + const savedObjectsClient = savedObjectsClientMock.create(); + savedObjectsClient.get.mockImplementation(() => { + throw savedObjectsClient.errors.createGenericNotFoundError(CUSTOM_ELEMENT_TYPE, id); + }); + mockRouteContext.core.savedObjects.client = savedObjectsClient; + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + + expect(response.payload).toMatchInlineSnapshot(` + Object { + "error": "Not Found", + "message": "Saved object [canvas-element/123] not found", + "statusCode": 404, + } + `); + }); +}); diff --git a/x-pack/plugins/canvas/server/routes/custom_elements/get.ts b/x-pack/plugins/canvas/server/routes/custom_elements/get.ts new file mode 100644 index 0000000000000..f092b001e141f --- /dev/null +++ b/x-pack/plugins/canvas/server/routes/custom_elements/get.ts @@ -0,0 +1,41 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { RouteInitializerDeps } from '../'; +import { + CUSTOM_ELEMENT_TYPE, + API_ROUTE_CUSTOM_ELEMENT, +} from '../../../../../legacy/plugins/canvas/common/lib/constants'; +import { CustomElementAttributes } from './custom_element_attributes'; +import { catchErrorHandler } from '../catch_error_handler'; + +export function initializeGetCustomElementRoute(deps: RouteInitializerDeps) { + const { router } = deps; + router.get( + { + path: `${API_ROUTE_CUSTOM_ELEMENT}/{id}`, + validate: { + params: schema.object({ + id: schema.string(), + }), + }, + }, + catchErrorHandler(async (context, request, response) => { + const customElement = await context.core.savedObjects.client.get( + CUSTOM_ELEMENT_TYPE, + request.params.id + ); + + return response.ok({ + body: { + id: customElement.id, + ...customElement.attributes, + }, + }); + }) + ); +} diff --git a/x-pack/plugins/canvas/server/routes/custom_elements/index.ts b/x-pack/plugins/canvas/server/routes/custom_elements/index.ts new file mode 100644 index 0000000000000..ade641e491371 --- /dev/null +++ b/x-pack/plugins/canvas/server/routes/custom_elements/index.ts @@ -0,0 +1,20 @@ +/* + * 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 { RouteInitializerDeps } from '../'; +import { initializeFindCustomElementsRoute } from './find'; +import { initializeGetCustomElementRoute } from './get'; +import { initializeCreateCustomElementRoute } from './create'; +import { initializeUpdateCustomElementRoute } from './update'; +import { initializeDeleteCustomElementRoute } from './delete'; + +export function initCustomElementsRoutes(deps: RouteInitializerDeps) { + initializeFindCustomElementsRoute(deps); + initializeGetCustomElementRoute(deps); + initializeCreateCustomElementRoute(deps); + initializeUpdateCustomElementRoute(deps); + initializeDeleteCustomElementRoute(deps); +} diff --git a/x-pack/plugins/canvas/server/routes/custom_elements/update.test.ts b/x-pack/plugins/canvas/server/routes/custom_elements/update.test.ts new file mode 100644 index 0000000000000..f21a9c25b6e64 --- /dev/null +++ b/x-pack/plugins/canvas/server/routes/custom_elements/update.test.ts @@ -0,0 +1,164 @@ +/* + * 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 sinon from 'sinon'; +import { CustomElement } from '../../../../../legacy/plugins/canvas/types'; +import { CUSTOM_ELEMENT_TYPE } from '../../../../../legacy/plugins/canvas/common/lib/constants'; +import { initializeUpdateCustomElementRoute } from './update'; +import { + IRouter, + kibanaResponseFactory, + RequestHandlerContext, + RequestHandler, +} from 'src/core/server'; +import { + savedObjectsClientMock, + httpServiceMock, + httpServerMock, + loggingServiceMock, +} from 'src/core/server/mocks'; +import { okResponse } from '../ok_response'; + +const mockRouteContext = ({ + core: { + savedObjects: { + client: savedObjectsClientMock.create(), + }, + }, +} as unknown) as RequestHandlerContext; + +const now = new Date(); +const nowIso = now.toISOString(); + +jest.mock('uuid/v4', () => jest.fn().mockReturnValue('123abc')); + +type CustomElementPayload = CustomElement & { + '@timestamp': string; + '@created': string; +}; + +const customElement: CustomElementPayload = { + id: 'my-custom-element', + name: 'MyCustomElement', + displayName: 'My Wonderful Custom Element', + content: 'This is content', + tags: ['filter', 'graphic'], + '@created': '2019-02-08T18:35:23.029Z', + '@timestamp': '2019-02-08T18:35:23.029Z', +}; + +describe('PUT custom element', () => { + let routeHandler: RequestHandler; + let clock: sinon.SinonFakeTimers; + + beforeEach(() => { + clock = sinon.useFakeTimers(now); + + const httpService = httpServiceMock.createSetupContract(); + const router = httpService.createRouter('') as jest.Mocked; + initializeUpdateCustomElementRoute({ + router, + logger: loggingServiceMock.create().get(), + }); + + routeHandler = router.put.mock.calls[0][1]; + }); + + afterEach(() => { + jest.resetAllMocks(); + clock.restore(); + }); + + it(`returns 200 ok when the custom element is updated`, async () => { + const updatedCustomElement = { name: 'new name' }; + const { id, ...customElementAttributes } = customElement; + + const request = httpServerMock.createKibanaRequest({ + method: 'put', + path: `api/canvas/custom-element/${id}`, + params: { + id, + }, + body: updatedCustomElement, + }); + + const savedObjectsClient = savedObjectsClientMock.create(); + savedObjectsClient.get.mockResolvedValueOnce({ + id, + type: CUSTOM_ELEMENT_TYPE, + attributes: customElementAttributes as any, + references: [], + }); + + mockRouteContext.core.savedObjects.client = savedObjectsClient; + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + + expect(response.status).toBe(200); + expect(response.payload).toEqual(okResponse); + expect(mockRouteContext.core.savedObjects.client.create).toBeCalledWith( + CUSTOM_ELEMENT_TYPE, + { + ...customElementAttributes, + ...updatedCustomElement, + '@timestamp': nowIso, + '@created': customElement['@created'], + }, + { + overwrite: true, + id, + } + ); + }); + + it(`returns not found if existing custom element is not found`, async () => { + const request = httpServerMock.createKibanaRequest({ + method: 'put', + path: 'api/canvas/custom-element/some-id', + params: { + id: 'not-found', + }, + body: {}, + }); + + (mockRouteContext.core.savedObjects.client.get as jest.Mock).mockImplementationOnce(() => { + throw mockRouteContext.core.savedObjects.client.errors.createGenericNotFoundError( + 'not found' + ); + }); + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + expect(response.status).toBe(404); + }); + + it(`returns bad request if the write fails`, async () => { + const request = httpServerMock.createKibanaRequest({ + method: 'put', + path: 'api/canvas/custom-element/some-id', + params: { + id: 'some-id', + }, + body: {}, + }); + + const savedObjectsClient = savedObjectsClientMock.create(); + savedObjectsClient.get.mockResolvedValueOnce({ + id: 'some-id', + type: CUSTOM_ELEMENT_TYPE, + attributes: {}, + references: [], + }); + + mockRouteContext.core.savedObjects.client = savedObjectsClient; + (mockRouteContext.core.savedObjects.client.create as jest.Mock).mockImplementationOnce(() => { + throw mockRouteContext.core.savedObjects.client.errors.createBadRequestError('bad request'); + }); + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + + expect(response.status).toBe(400); + }); +}); diff --git a/x-pack/plugins/canvas/server/routes/custom_elements/update.ts b/x-pack/plugins/canvas/server/routes/custom_elements/update.ts new file mode 100644 index 0000000000000..51c363249dd79 --- /dev/null +++ b/x-pack/plugins/canvas/server/routes/custom_elements/update.ts @@ -0,0 +1,63 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { omit } from 'lodash'; +import { RouteInitializerDeps } from '../'; +import { + CUSTOM_ELEMENT_TYPE, + API_ROUTE_CUSTOM_ELEMENT, +} from '../../../../../legacy/plugins/canvas/common/lib/constants'; +import { CustomElementUpdateSchema } from './custom_element_schema'; +import { CustomElementAttributes } from './custom_element_attributes'; +import { okResponse } from '../ok_response'; +import { catchErrorHandler } from '../catch_error_handler'; + +export function initializeUpdateCustomElementRoute(deps: RouteInitializerDeps) { + const { router } = deps; + router.put( + { + path: `${API_ROUTE_CUSTOM_ELEMENT}/{id}`, + validate: { + params: schema.object({ + id: schema.string(), + }), + body: CustomElementUpdateSchema, + }, + options: { + body: { + maxBytes: 26214400, // 25MB payload limit + accepts: ['application/json'], + }, + }, + }, + catchErrorHandler(async (context, request, response) => { + const payload = request.body; + const id = request.params.id; + + const now = new Date().toISOString(); + + const customElementObject = await context.core.savedObjects.client.get< + CustomElementAttributes + >(CUSTOM_ELEMENT_TYPE, id); + + await context.core.savedObjects.client.create( + CUSTOM_ELEMENT_TYPE, + { + ...customElementObject.attributes, + ...omit(payload, 'id'), // never write the id property + '@timestamp': now, + '@created': customElementObject.attributes['@created'], // ensure created is not modified + }, + { overwrite: true, id } + ); + + return response.ok({ + body: okResponse, + }); + }) + ); +} diff --git a/x-pack/plugins/canvas/server/routes/index.ts b/x-pack/plugins/canvas/server/routes/index.ts index 46873a6b32542..8b2d77d634760 100644 --- a/x-pack/plugins/canvas/server/routes/index.ts +++ b/x-pack/plugins/canvas/server/routes/index.ts @@ -6,6 +6,7 @@ import { IRouter, Logger } from 'src/core/server'; import { initWorkpadRoutes } from './workpad'; +import { initCustomElementsRoutes } from './custom_elements'; export interface RouteInitializerDeps { router: IRouter; @@ -14,4 +15,5 @@ export interface RouteInitializerDeps { export function initRoutes(deps: RouteInitializerDeps) { initWorkpadRoutes(deps); + initCustomElementsRoutes(deps); } diff --git a/x-pack/plugins/canvas/server/routes/workpad/ok_response.ts b/x-pack/plugins/canvas/server/routes/ok_response.ts similarity index 100% rename from x-pack/plugins/canvas/server/routes/workpad/ok_response.ts rename to x-pack/plugins/canvas/server/routes/ok_response.ts diff --git a/x-pack/plugins/canvas/server/routes/workpad/create.ts b/x-pack/plugins/canvas/server/routes/workpad/create.ts index be904356720b6..fc847d4816dbd 100644 --- a/x-pack/plugins/canvas/server/routes/workpad/create.ts +++ b/x-pack/plugins/canvas/server/routes/workpad/create.ts @@ -11,15 +11,11 @@ import { } from '../../../../../legacy/plugins/canvas/common/lib/constants'; import { CanvasWorkpad } from '../../../../../legacy/plugins/canvas/types'; import { getId } from '../../../../../legacy/plugins/canvas/public/lib/get_id'; +import { WorkpadAttributes } from './workpad_attributes'; import { WorkpadSchema } from './workpad_schema'; -import { okResponse } from './ok_response'; +import { okResponse } from '../ok_response'; import { catchErrorHandler } from '../catch_error_handler'; -export type WorkpadAttributes = Pick> & { - '@timestamp': string; - '@created': string; -}; - export function initializeCreateWorkpadRoute(deps: RouteInitializerDeps) { const { router } = deps; router.post( diff --git a/x-pack/plugins/canvas/server/routes/workpad/delete.ts b/x-pack/plugins/canvas/server/routes/workpad/delete.ts index 7adf11e7a887b..8de4ea0f9a27f 100644 --- a/x-pack/plugins/canvas/server/routes/workpad/delete.ts +++ b/x-pack/plugins/canvas/server/routes/workpad/delete.ts @@ -10,7 +10,7 @@ import { CANVAS_TYPE, API_ROUTE_WORKPAD, } from '../../../../../legacy/plugins/canvas/common/lib/constants'; -import { okResponse } from './ok_response'; +import { okResponse } from '../ok_response'; import { catchErrorHandler } from '../catch_error_handler'; export function initializeDeleteWorkpadRoute(deps: RouteInitializerDeps) { diff --git a/x-pack/plugins/canvas/server/routes/workpad/get.ts b/x-pack/plugins/canvas/server/routes/workpad/get.ts index 7a51006aa9f02..d7a5e77670f6e 100644 --- a/x-pack/plugins/canvas/server/routes/workpad/get.ts +++ b/x-pack/plugins/canvas/server/routes/workpad/get.ts @@ -10,14 +10,9 @@ import { CANVAS_TYPE, API_ROUTE_WORKPAD, } from '../../../../../legacy/plugins/canvas/common/lib/constants'; -import { CanvasWorkpad } from '../../../../../legacy/plugins/canvas/types'; +import { WorkpadAttributes } from './workpad_attributes'; import { catchErrorHandler } from '../catch_error_handler'; -export type WorkpadAttributes = Pick> & { - '@timestamp': string; - '@created': string; -}; - export function initializeGetWorkpadRoute(deps: RouteInitializerDeps) { const { router } = deps; router.get( diff --git a/x-pack/plugins/canvas/server/routes/workpad/update.test.ts b/x-pack/plugins/canvas/server/routes/workpad/update.test.ts index 492a6c98d71ee..de098dd9717ed 100644 --- a/x-pack/plugins/canvas/server/routes/workpad/update.test.ts +++ b/x-pack/plugins/canvas/server/routes/workpad/update.test.ts @@ -20,7 +20,7 @@ import { loggingServiceMock, } from 'src/core/server/mocks'; import { workpads } from '../../../../../legacy/plugins/canvas/__tests__/fixtures/workpads'; -import { okResponse } from './ok_response'; +import { okResponse } from '../ok_response'; const mockRouteContext = ({ core: { diff --git a/x-pack/plugins/canvas/server/routes/workpad/update.ts b/x-pack/plugins/canvas/server/routes/workpad/update.ts index 460aa174038ae..74dedb605472c 100644 --- a/x-pack/plugins/canvas/server/routes/workpad/update.ts +++ b/x-pack/plugins/canvas/server/routes/workpad/update.ts @@ -15,16 +15,11 @@ import { API_ROUTE_WORKPAD_STRUCTURES, API_ROUTE_WORKPAD_ASSETS, } from '../../../../../legacy/plugins/canvas/common/lib/constants'; -import { CanvasWorkpad } from '../../../../../legacy/plugins/canvas/types'; +import { WorkpadAttributes } from './workpad_attributes'; import { WorkpadSchema, WorkpadAssetSchema } from './workpad_schema'; -import { okResponse } from './ok_response'; +import { okResponse } from '../ok_response'; import { catchErrorHandler } from '../catch_error_handler'; -export type WorkpadAttributes = Pick> & { - '@timestamp': string; - '@created': string; -}; - const AssetsRecordSchema = schema.recordOf(schema.string(), WorkpadAssetSchema); const AssetPayloadSchema = schema.object({ diff --git a/x-pack/plugins/canvas/server/routes/workpad/workpad_attributes.ts b/x-pack/plugins/canvas/server/routes/workpad/workpad_attributes.ts new file mode 100644 index 0000000000000..2b7b6cca4ba2b --- /dev/null +++ b/x-pack/plugins/canvas/server/routes/workpad/workpad_attributes.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. + */ +import { CanvasWorkpad } from '../../../../../legacy/plugins/canvas/types'; + +export type WorkpadAttributes = Pick> & { + '@timestamp': string; + '@created': string; +}; From f2b48910a024d9b0e96cffa4d83449a9aac10a9f Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Wed, 11 Dec 2019 21:25:18 +0300 Subject: [PATCH 16/79] [ui/public/utils] Move items into agg_types (#52744) Closes #51855 --- .../buckets/create_filter/ip_range.ts | 2 +- .../ui/public/agg_types/buckets/date_range.ts | 17 +++- .../ui/public/agg_types/buckets/geo_hash.ts | 19 +++-- .../ui/public/agg_types/buckets/ip_range.ts | 13 ++- .../agg_types/buckets/lib/cidr_mask.test.ts | 75 +++++++++++++++++ .../buckets/lib}/cidr_mask.ts | 3 +- .../buckets/lib/geo_utils.ts} | 47 +++++++---- .../metrics/lib/ordinal_suffix.test.ts} | 19 ++--- .../metrics/lib/ordinal_suffix.ts} | 4 +- .../public/agg_types/metrics/percentiles.ts | 2 +- .../ui/public/utils/__tests__/cidr_mask.ts | 84 ------------------- src/legacy/ui/public/utils/date_range.ts | 32 ------- src/legacy/ui/public/utils/ip_range.ts | 31 ------- .../default/controls/components/mask_list.tsx | 2 +- .../loader/pipeline_helpers/utilities.ts | 10 +-- 15 files changed, 159 insertions(+), 201 deletions(-) create mode 100644 src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.test.ts rename src/legacy/ui/public/{utils => agg_types/buckets/lib}/cidr_mask.ts (96%) rename src/legacy/ui/public/{utils/geo_utils.js => agg_types/buckets/lib/geo_utils.ts} (55%) rename src/legacy/ui/public/{utils/__tests__/ordinal_suffix.js => agg_types/metrics/lib/ordinal_suffix.test.ts} (76%) rename src/legacy/ui/public/{utils/ordinal_suffix.js => agg_types/metrics/lib/ordinal_suffix.ts} (93%) delete mode 100644 src/legacy/ui/public/utils/__tests__/cidr_mask.ts delete mode 100644 src/legacy/ui/public/utils/date_range.ts delete mode 100644 src/legacy/ui/public/utils/ip_range.ts diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.ts b/src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.ts index 803f6d97ae42d..a513b8c782739 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.ts +++ b/src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.ts @@ -17,7 +17,7 @@ * under the License. */ -import { CidrMask } from '../../../utils/cidr_mask'; +import { CidrMask } from '../lib/cidr_mask'; import { IBucketAggConfig } from '../_bucket_agg_type'; import { IpRangeKey } from '../ip_range'; import { esFilters } from '../../../../../../plugins/data/public'; diff --git a/src/legacy/ui/public/agg_types/buckets/date_range.ts b/src/legacy/ui/public/agg_types/buckets/date_range.ts index 860d76ff2aa7b..4bc5814184d57 100644 --- a/src/legacy/ui/public/agg_types/buckets/date_range.ts +++ b/src/legacy/ui/public/agg_types/buckets/date_range.ts @@ -25,8 +25,6 @@ import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; import { createFilterDateRange } from './create_filter/date_range'; import { DateRangesParamEditor } from '../../vis/editors/default/controls/date_ranges'; -// @ts-ignore -import { dateRange } from '../../utils/date_range'; import { KBN_FIELD_TYPES, TEXT_CONTEXT_TYPE, @@ -57,7 +55,7 @@ export const dateRangeBucketAgg = new BucketAggType({ fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.DATE) ); const DateRangeFormat = FieldFormat.from(function(range: DateRangeKey) { - return dateRange.toString(range, formatter); + return convertDateRangeToString(range, formatter); }); return new DateRangeFormat(); }, @@ -114,3 +112,16 @@ export const dateRangeBucketAgg = new BucketAggType({ }, ], }); + +export const convertDateRangeToString = ( + { from, to }: DateRangeKey, + format: (val: any) => string +) => { + if (!from) { + return 'Before ' + format(to); + } else if (!to) { + return 'After ' + format(from); + } else { + return format(from) + ' to ' + format(to); + } +}; diff --git a/src/legacy/ui/public/agg_types/buckets/geo_hash.ts b/src/legacy/ui/public/agg_types/buckets/geo_hash.ts index 0acbaf4aa02a2..546e51c1492e8 100644 --- a/src/legacy/ui/public/agg_types/buckets/geo_hash.ts +++ b/src/legacy/ui/public/agg_types/buckets/geo_hash.ts @@ -28,8 +28,7 @@ import { PrecisionParamEditor } from '../../vis/editors/default/controls/precisi import { AggGroupNames } from '../../vis/editors/default/agg_groups'; import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; -// @ts-ignore -import { geoContains, scaleBounds } from '../../utils/geo_utils'; +import { geoContains, scaleBounds, GeoBoundingBox } from './lib/geo_utils'; import { BUCKET_TYPES } from './bucket_agg_types'; const config = chrome.getUiSettingsClient(); @@ -70,15 +69,15 @@ function getPrecision(val: string) { return precision; } -const isOutsideCollar = (bounds: unknown, collar: MapCollar) => +const isOutsideCollar = (bounds: GeoBoundingBox, collar: MapCollar) => bounds && collar && !geoContains(collar, bounds); const geohashGridTitle = i18n.translate('common.ui.aggTypes.buckets.geohashGridTitle', { defaultMessage: 'Geohash', }); -interface MapCollar { - zoom: unknown; +interface MapCollar extends GeoBoundingBox { + zoom?: unknown; } export interface IBucketGeoHashGridAggConfig extends IBucketAggConfig { @@ -148,11 +147,13 @@ export const geoHashBucketAgg = new BucketAggType({ if (params.isFilteredByCollar && agg.getField()) { const { mapBounds, mapZoom } = params; if (mapBounds) { - let mapCollar; + let mapCollar: MapCollar; + if ( - !agg.lastMapCollar || - agg.lastMapCollar.zoom !== mapZoom || - isOutsideCollar(mapBounds, agg.lastMapCollar) + mapBounds && + (!agg.lastMapCollar || + agg.lastMapCollar.zoom !== mapZoom || + isOutsideCollar(mapBounds, agg.lastMapCollar)) ) { mapCollar = scaleBounds(mapBounds); mapCollar.zoom = mapZoom; diff --git a/src/legacy/ui/public/agg_types/buckets/ip_range.ts b/src/legacy/ui/public/agg_types/buckets/ip_range.ts index 35155a482734c..fefe69cbf8e79 100644 --- a/src/legacy/ui/public/agg_types/buckets/ip_range.ts +++ b/src/legacy/ui/public/agg_types/buckets/ip_range.ts @@ -23,7 +23,6 @@ import { npStart } from 'ui/new_platform'; import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; import { IpRangeTypeParamEditor } from '../../vis/editors/default/controls/ip_range_type'; import { IpRangesParamEditor } from '../../vis/editors/default/controls/ip_ranges'; -import { ipRange } from '../../utils/ip_range'; import { BUCKET_TYPES } from './bucket_agg_types'; // @ts-ignore @@ -59,7 +58,7 @@ export const ipRangeBucketAgg = new BucketAggType({ fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.IP) ); const IpRangeFormat = FieldFormat.from(function(range: IpRangeKey) { - return ipRange.toString(range, formatter); + return convertIPRangeToString(range, formatter); }); return new IpRangeFormat(); }, @@ -106,3 +105,13 @@ export const ipRangeBucketAgg = new BucketAggType({ }, ], }); + +export const convertIPRangeToString = (range: IpRangeKey, format: (val: any) => string) => { + if (range.type === 'mask') { + return format(range.mask); + } + const from = range.from ? format(range.from) : '-Infinity'; + const to = range.to ? format(range.to) : 'Infinity'; + + return `${from} to ${to}`; +}; diff --git a/src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.test.ts b/src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.test.ts new file mode 100644 index 0000000000000..01dd3ddf1b874 --- /dev/null +++ b/src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.test.ts @@ -0,0 +1,75 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { CidrMask } from './cidr_mask'; + +describe('CidrMask', () => { + test('should throw errors with invalid CIDR masks', () => { + expect( + () => + // @ts-ignore + new CidrMask() + ).toThrowError(); + + expect(() => new CidrMask('')).toThrowError(); + expect(() => new CidrMask('hello, world')).toThrowError(); + expect(() => new CidrMask('0.0.0.0')).toThrowError(); + expect(() => new CidrMask('0.0.0.0/0')).toThrowError(); + expect(() => new CidrMask('0.0.0.0/33')).toThrowError(); + expect(() => new CidrMask('256.0.0.0/32')).toThrowError(); + expect(() => new CidrMask('0.0.0.0/32/32')).toThrowError(); + expect(() => new CidrMask('1.2.3/1')).toThrowError(); + expect(() => new CidrMask('0.0.0.0/123d')).toThrowError(); + }); + + test('should correctly grab IP address and prefix length', () => { + let mask = new CidrMask('0.0.0.0/1'); + expect(mask.initialAddress.toString()).toBe('0.0.0.0'); + expect(mask.prefixLength).toBe(1); + + mask = new CidrMask('128.0.0.1/31'); + expect(mask.initialAddress.toString()).toBe('128.0.0.1'); + expect(mask.prefixLength).toBe(31); + }); + + test('should calculate a range of IP addresses', () => { + let mask = new CidrMask('0.0.0.0/1'); + let range = mask.getRange(); + expect(range.from.toString()).toBe('0.0.0.0'); + expect(range.to.toString()).toBe('127.255.255.255'); + + mask = new CidrMask('1.2.3.4/2'); + range = mask.getRange(); + expect(range.from.toString()).toBe('0.0.0.0'); + expect(range.to.toString()).toBe('63.255.255.255'); + + mask = new CidrMask('67.129.65.201/27'); + range = mask.getRange(); + expect(range.from.toString()).toBe('67.129.65.192'); + expect(range.to.toString()).toBe('67.129.65.223'); + }); + + test('toString()', () => { + let mask = new CidrMask('.../1'); + expect(mask.toString()).toBe('0.0.0.0/1'); + + mask = new CidrMask('128.0.0.1/31'); + expect(mask.toString()).toBe('128.0.0.1/31'); + }); +}); diff --git a/src/legacy/ui/public/utils/cidr_mask.ts b/src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.ts similarity index 96% rename from src/legacy/ui/public/utils/cidr_mask.ts rename to src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.ts index 249c60dedfebf..aadbbc8c82276 100644 --- a/src/legacy/ui/public/utils/cidr_mask.ts +++ b/src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.ts @@ -17,7 +17,8 @@ * under the License. */ -import { Ipv4Address } from '../../../../plugins/kibana_utils/public'; +import { Ipv4Address } from '../../../../../../plugins/kibana_utils/public'; + const NUM_BITS = 32; function throwError(mask: string) { diff --git a/src/legacy/ui/public/utils/geo_utils.js b/src/legacy/ui/public/agg_types/buckets/lib/geo_utils.ts similarity index 55% rename from src/legacy/ui/public/utils/geo_utils.js rename to src/legacy/ui/public/agg_types/buckets/lib/geo_utils.ts index 44b7670d16c11..639b6d1fbb03e 100644 --- a/src/legacy/ui/public/utils/geo_utils.js +++ b/src/legacy/ui/public/agg_types/buckets/lib/geo_utils.ts @@ -19,46 +19,57 @@ import _ from 'lodash'; -export function geoContains(collar, bounds) { - //test if bounds top_left is outside collar - if(bounds.top_left.lat > collar.top_left.lat || bounds.top_left.lon < collar.top_left.lon) { +interface GeoBoundingBoxCoordinate { + lat: number; + lon: number; +} + +export interface GeoBoundingBox { + top_left: GeoBoundingBoxCoordinate; + bottom_right: GeoBoundingBoxCoordinate; +} + +export function geoContains(collar: GeoBoundingBox, bounds: GeoBoundingBox) { + // test if bounds top_left is outside collar + if (bounds.top_left.lat > collar.top_left.lat || bounds.top_left.lon < collar.top_left.lon) { return false; } - //test if bounds bottom_right is outside collar - if(bounds.bottom_right.lat < collar.bottom_right.lat || bounds.bottom_right.lon > collar.bottom_right.lon) { + // test if bounds bottom_right is outside collar + if ( + bounds.bottom_right.lat < collar.bottom_right.lat || + bounds.bottom_right.lon > collar.bottom_right.lon + ) { return false; } - //both corners are inside collar so collar contains bounds + // both corners are inside collar so collar contains bounds return true; } -export function scaleBounds(bounds) { - if (!bounds) return; - - const scale = .5; // scale bounds by 50% +export function scaleBounds(bounds: GeoBoundingBox): GeoBoundingBox { + const scale = 0.5; // scale bounds by 50% const topLeft = bounds.top_left; const bottomRight = bounds.bottom_right; let latDiff = _.round(Math.abs(topLeft.lat - bottomRight.lat), 5); const lonDiff = _.round(Math.abs(bottomRight.lon - topLeft.lon), 5); - //map height can be zero when vis is first created - if(latDiff === 0) latDiff = lonDiff; + // map height can be zero when vis is first created + if (latDiff === 0) latDiff = lonDiff; const latDelta = latDiff * scale; let topLeftLat = _.round(topLeft.lat, 5) + latDelta; - if(topLeftLat > 90) topLeftLat = 90; + if (topLeftLat > 90) topLeftLat = 90; let bottomRightLat = _.round(bottomRight.lat, 5) - latDelta; - if(bottomRightLat < -90) bottomRightLat = -90; + if (bottomRightLat < -90) bottomRightLat = -90; const lonDelta = lonDiff * scale; let topLeftLon = _.round(topLeft.lon, 5) - lonDelta; - if(topLeftLon < -180) topLeftLon = -180; + if (topLeftLon < -180) topLeftLon = -180; let bottomRightLon = _.round(bottomRight.lon, 5) + lonDelta; - if(bottomRightLon > 180) bottomRightLon = 180; + if (bottomRightLon > 180) bottomRightLon = 180; return { - 'top_left': { lat: topLeftLat, lon: topLeftLon }, - 'bottom_right': { lat: bottomRightLat, lon: bottomRightLon } + top_left: { lat: topLeftLat, lon: topLeftLon }, + bottom_right: { lat: bottomRightLat, lon: bottomRightLon }, }; } diff --git a/src/legacy/ui/public/utils/__tests__/ordinal_suffix.js b/src/legacy/ui/public/agg_types/metrics/lib/ordinal_suffix.test.ts similarity index 76% rename from src/legacy/ui/public/utils/__tests__/ordinal_suffix.js rename to src/legacy/ui/public/agg_types/metrics/lib/ordinal_suffix.test.ts index dae12d41cfb5b..18ee6b4de3204 100644 --- a/src/legacy/ui/public/utils/__tests__/ordinal_suffix.js +++ b/src/legacy/ui/public/agg_types/metrics/lib/ordinal_suffix.test.ts @@ -17,11 +17,10 @@ * under the License. */ -import _ from 'lodash'; -import { ordinalSuffix } from '../ordinal_suffix'; -import expect from '@kbn/expect'; +import { forOwn } from 'lodash'; +import { ordinalSuffix } from './ordinal_suffix'; -describe('ordinal suffix util', function () { +describe('ordinal suffix util', () => { const checks = { 1: 'st', 2: 'nd', @@ -52,19 +51,19 @@ describe('ordinal suffix util', function () { 27: 'th', 28: 'th', 29: 'th', - 30: 'th' + 30: 'th', }; - _.forOwn(checks, function (expected, num) { + forOwn(checks, (expected, num: any) => { const int = parseInt(num, 10); const float = int + Math.random(); - it('knowns ' + int, function () { - expect(ordinalSuffix(num)).to.be(num + '' + expected); + it('knowns ' + int, () => { + expect(ordinalSuffix(num)).toBe(num + '' + expected); }); - it('knows ' + float, function () { - expect(ordinalSuffix(num)).to.be(num + '' + expected); + it('knows ' + float, () => { + expect(ordinalSuffix(num)).toBe(num + '' + expected); }); }); }); diff --git a/src/legacy/ui/public/utils/ordinal_suffix.js b/src/legacy/ui/public/agg_types/metrics/lib/ordinal_suffix.ts similarity index 93% rename from src/legacy/ui/public/utils/ordinal_suffix.js rename to src/legacy/ui/public/agg_types/metrics/lib/ordinal_suffix.ts index 64fb29c8ae534..21903995ebb2f 100644 --- a/src/legacy/ui/public/utils/ordinal_suffix.js +++ b/src/legacy/ui/public/agg_types/metrics/lib/ordinal_suffix.ts @@ -18,11 +18,11 @@ */ // adopted from http://stackoverflow.com/questions/3109978/php-display-number-with-ordinal-suffix -export function ordinalSuffix(num) { +export function ordinalSuffix(num: any): string { return num + '' + suffix(num); } -function suffix(num) { +function suffix(num: any): string { const int = Math.floor(parseFloat(num)); const hunth = int % 100; diff --git a/src/legacy/ui/public/agg_types/metrics/percentiles.ts b/src/legacy/ui/public/agg_types/metrics/percentiles.ts index 1a3606d677951..60946b6162b3b 100644 --- a/src/legacy/ui/public/agg_types/metrics/percentiles.ts +++ b/src/legacy/ui/public/agg_types/metrics/percentiles.ts @@ -28,7 +28,7 @@ import { getPercentileValue } from './percentiles_get_value'; import { PercentilesEditor } from '../../vis/editors/default/controls/percentiles'; // @ts-ignore -import { ordinalSuffix } from '../../utils/ordinal_suffix'; +import { ordinalSuffix } from './lib/ordinal_suffix'; export type IPercentileAggConfig = IResponseAggConfig; diff --git a/src/legacy/ui/public/utils/__tests__/cidr_mask.ts b/src/legacy/ui/public/utils/__tests__/cidr_mask.ts deleted file mode 100644 index 5277344448bd8..0000000000000 --- a/src/legacy/ui/public/utils/__tests__/cidr_mask.ts +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import expect from '@kbn/expect'; -import { CidrMask } from '../cidr_mask'; - -describe('CidrMask', () => { - it('should throw errors with invalid CIDR masks', () => { - expect( - () => - // @ts-ignore - new CidrMask() - ).to.throwError(); - - expect(() => new CidrMask('')).to.throwError(); - - expect(() => new CidrMask('hello, world')).to.throwError(); - - expect(() => new CidrMask('0.0.0.0')).to.throwError(); - - expect(() => new CidrMask('0.0.0.0/0')).to.throwError(); - - expect(() => new CidrMask('0.0.0.0/33')).to.throwError(); - - expect(() => new CidrMask('256.0.0.0/32')).to.throwError(); - - expect(() => new CidrMask('0.0.0.0/32/32')).to.throwError(); - - expect(() => new CidrMask('1.2.3/1')).to.throwError(); - - expect(() => new CidrMask('0.0.0.0/123d')).to.throwError(); - }); - - it('should correctly grab IP address and prefix length', () => { - let mask = new CidrMask('0.0.0.0/1'); - expect(mask.initialAddress.toString()).to.be('0.0.0.0'); - expect(mask.prefixLength).to.be(1); - - mask = new CidrMask('128.0.0.1/31'); - expect(mask.initialAddress.toString()).to.be('128.0.0.1'); - expect(mask.prefixLength).to.be(31); - }); - - it('should calculate a range of IP addresses', () => { - let mask = new CidrMask('0.0.0.0/1'); - let range = mask.getRange(); - expect(range.from.toString()).to.be('0.0.0.0'); - expect(range.to.toString()).to.be('127.255.255.255'); - - mask = new CidrMask('1.2.3.4/2'); - range = mask.getRange(); - expect(range.from.toString()).to.be('0.0.0.0'); - expect(range.to.toString()).to.be('63.255.255.255'); - - mask = new CidrMask('67.129.65.201/27'); - range = mask.getRange(); - expect(range.from.toString()).to.be('67.129.65.192'); - expect(range.to.toString()).to.be('67.129.65.223'); - }); - - it('toString()', () => { - let mask = new CidrMask('.../1'); - expect(mask.toString()).to.be('0.0.0.0/1'); - - mask = new CidrMask('128.0.0.1/31'); - expect(mask.toString()).to.be('128.0.0.1/31'); - }); -}); diff --git a/src/legacy/ui/public/utils/date_range.ts b/src/legacy/ui/public/utils/date_range.ts deleted file mode 100644 index ca44183b8d68b..0000000000000 --- a/src/legacy/ui/public/utils/date_range.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { DateRangeKey } from '../agg_types/buckets/date_range'; - -export const dateRange = { - toString({ from, to }: DateRangeKey, format: (val: any) => string) { - if (!from) { - return 'Before ' + format(to); - } else if (!to) { - return 'After ' + format(from); - } else { - return format(from) + ' to ' + format(to); - } - }, -}; diff --git a/src/legacy/ui/public/utils/ip_range.ts b/src/legacy/ui/public/utils/ip_range.ts deleted file mode 100644 index 45ce21709d68c..0000000000000 --- a/src/legacy/ui/public/utils/ip_range.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { IpRangeKey } from '../agg_types/buckets/ip_range'; - -export const ipRange = { - toString(range: IpRangeKey, format: (val: any) => string) { - if (range.type === 'mask') { - return format(range.mask); - } - const from = range.from ? format(range.from) : '-Infinity'; - const to = range.to ? format(range.to) : 'Infinity'; - return `${from} to ${to}`; - }, -}; diff --git a/src/legacy/ui/public/vis/editors/default/controls/components/mask_list.tsx b/src/legacy/ui/public/vis/editors/default/controls/components/mask_list.tsx index 7d964204ff90c..b48f07512332e 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/components/mask_list.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/components/mask_list.tsx @@ -20,7 +20,7 @@ import React from 'react'; import { EuiFieldText, EuiFlexItem } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { CidrMask } from '../../../../../utils/cidr_mask'; +import { CidrMask } from '../../../../../agg_types/buckets/lib/cidr_mask'; import { InputList, InputListConfig, InputObject, InputModel, InputItem } from './input_list'; const EMPTY_STRING = ''; diff --git a/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts b/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts index 377e2cd97b72e..d754c1d395595 100644 --- a/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts +++ b/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts @@ -26,10 +26,8 @@ import { SerializedFieldFormat } from 'src/plugins/expressions/public'; import { IFieldFormatId, FieldFormat } from '../../../../../../plugins/data/public'; import { tabifyGetColumns } from '../../../agg_response/tabify/_get_columns'; -import { dateRange } from '../../../utils/date_range'; -import { ipRange } from '../../../utils/ip_range'; -import { DateRangeKey } from '../../../agg_types/buckets/date_range'; -import { IpRangeKey } from '../../../agg_types/buckets/ip_range'; +import { DateRangeKey, convertDateRangeToString } from '../../../agg_types/buckets/date_range'; +import { IpRangeKey, convertIPRangeToString } from '../../../agg_types/buckets/ip_range'; interface TermsFieldFormatParams { otherBucketLabel: string; @@ -120,14 +118,14 @@ export const getFormat: FormatFactory = mapping => { const nestedFormatter = mapping.params as SerializedFieldFormat; const DateRangeFormat = FieldFormat.from((range: DateRangeKey) => { const format = getFieldFormat(nestedFormatter.id, nestedFormatter.params); - return dateRange.toString(range, format.convert.bind(format)); + return convertDateRangeToString(range, format.convert.bind(format)); }); return new DateRangeFormat(); } else if (id === 'ip_range') { const nestedFormatter = mapping.params as SerializedFieldFormat; const IpRangeFormat = FieldFormat.from((range: IpRangeKey) => { const format = getFieldFormat(nestedFormatter.id, nestedFormatter.params); - return ipRange.toString(range, format.convert.bind(format)); + return convertIPRangeToString(range, format.convert.bind(format)); }); return new IpRangeFormat(); } else if (isTermsFieldFormat(mapping) && mapping.params) { From 7658e9c631d7a823028a37baa87ef39227a54b8d Mon Sep 17 00:00:00 2001 From: Dmitry Lemeshko Date: Wed, 11 Dec 2019 19:41:25 +0100 Subject: [PATCH 17/79] FTR: add 'throttle' option to cli (#33241) * [ftr/cli] add throttling option * [ftr/cli] add headless option, fix test --- .../kbn-test/src/functional_test_runner/cli.ts | 12 +++++++++++- .../functional_tests/cli/run_tests/cli.test.js | 16 ++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/packages/kbn-test/src/functional_test_runner/cli.ts b/packages/kbn-test/src/functional_test_runner/cli.ts index 36412961ce75b..11b9450f2af6e 100644 --- a/packages/kbn-test/src/functional_test_runner/cli.ts +++ b/packages/kbn-test/src/functional_test_runner/cli.ts @@ -57,6 +57,14 @@ export function runFtrCli() { } ); + if (flags.throttle) { + process.env.TEST_THROTTLE_NETWORK = '1'; + } + + if (flags.headless) { + process.env.TEST_BROWSER_HEADLESS = '1'; + } + let teardownRun = false; const teardown = async (err?: Error) => { if (teardownRun) return; @@ -97,7 +105,7 @@ export function runFtrCli() { { flags: { string: ['config', 'grep', 'exclude', 'include-tag', 'exclude-tag', 'kibana-install-dir'], - boolean: ['bail', 'invert', 'test-stats', 'updateBaselines'], + boolean: ['bail', 'invert', 'test-stats', 'updateBaselines', 'throttle', 'headless'], default: { config: 'test/functional/config.js', debug: true, @@ -113,6 +121,8 @@ export function runFtrCli() { --test-stats print the number of tests (included and excluded) to STDERR --updateBaselines replace baseline screenshots with whatever is generated from the test --kibana-install-dir directory where the Kibana install being tested resides + --throttle enable network throttling in Chrome browser + --headless run browser in headless mode `, }, } diff --git a/packages/kbn-test/src/functional_tests/cli/run_tests/cli.test.js b/packages/kbn-test/src/functional_tests/cli/run_tests/cli.test.js index 97b74a3b2b541..9f9a8f59fde9a 100644 --- a/packages/kbn-test/src/functional_tests/cli/run_tests/cli.test.js +++ b/packages/kbn-test/src/functional_tests/cli/run_tests/cli.test.js @@ -182,6 +182,22 @@ describe('run tests CLI', () => { expect(exitMock).not.toHaveBeenCalled(); }); + it('accepts network throttle option', async () => { + global.process.argv.push('--throttle'); + + await runTestsCli(['foo']); + + expect(exitMock).toHaveBeenCalledWith(1); + }); + + it('accepts headless option', async () => { + global.process.argv.push('--headless'); + + await runTestsCli(['foo']); + + expect(exitMock).toHaveBeenCalledWith(1); + }); + it('accepts extra server options', async () => { global.process.argv.push('--', '--server.foo=bar'); From f53e1a9dbd95c793111e650b60563429bc1124bb Mon Sep 17 00:00:00 2001 From: Frank Hassanabad Date: Wed, 11 Dec 2019 11:52:11 -0700 Subject: [PATCH 18/79] [SIEM][Detection Engine] Adds privileges API endpoint ## Summary Adds a privileges API endpoint for the UI and people to query to check to see if their namespaced index is going to have the correct privileges or not. Usage: Testing: Set up your user name and password to a test space for the CLI. Give whatever permissions you want for restricted access to the test-space user, test-space role, and the test-space actual space to ensure everything works out as expected. ```sh export ELASTICSEARCH_USERNAME=test-space export ELASTICSEARCH_PASSWORD=(passwword) export SPACE_URL=/s/test-space ``` Then use it like so API: ```sh GET /api/detection_engine/privileges ``` CLI: ```sh ./get_privileges.sh ``` Return will be something like this: ```sh { "username": "test-space", "has_all_requested": false, "cluster": { "monitor_ml": true, "manage_ccr": false, "manage_index_templates": true, "monitor_watcher": true, "monitor_transform": true, "read_ilm": true, "manage_api_key": false, "manage_security": false, "manage_own_api_key": false, "manage_saml": false, "all": false, "manage_ilm": true, "manage_ingest_pipelines": true, "read_ccr": false, "manage_rollup": true, "monitor": true, "manage_watcher": true, "manage": true, "manage_transform": true, "manage_token": false, "manage_ml": true, "manage_pipeline": true, "monitor_rollup": true, "transport_client": true, "create_snapshot": true }, "index": { ".siem-signals-test-space": { "all": false, "manage_ilm": true, "read": false, "create_index": true, "read_cross_cluster": false, "index": false, "monitor": true, "delete": false, "manage": true, "delete_index": true, "create_doc": false, "view_index_metadata": true, "create": false, "manage_follow_index": true, "manage_leader_index": true, "write": false } }, "application": {} } ``` Example permissions that work for managing all signal indexes across all spaces so that the user in question can create it for each space: Screen Shot 2019-12-10 at 4 48 19 PM Example permissions that work for managing only a specific signal index: Screen Shot 2019-12-10 at 3 49 24 PM Example permissions that work for an end user using signals across all spaces: Screen Shot 2019-12-10 at 3 49 41 PM Example permissions that work for an end user using signals for a a specific index: Screen Shot 2019-12-10 at 3 49 24 PM ### Checklist Use ~~strikethroughs~~ to remove checklist items you don't feel are applicable to this PR. ~~- [ ] This was checked for cross-browser compatibility, [including a check against IE11](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility)~~ ~~- [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/master/packages/kbn-i18n/README.md)~~ ~~- [ ] [Documentation](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#writing-documentation) was added for features that require explanation or tutorials~~ - [x] [Unit or functional tests](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility) were updated or added to match the most common scenarios ~~- [ ] This was checked for [keyboard-only and screenreader accessibility](https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Accessibility_testing_checklist)~~ ### For maintainers ~~- [ ] This was checked for breaking API changes and was [labeled appropriately](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#release-notes-process)~~ - [x] This includes a feature addition or change that requires a release note and was [labeled appropriately](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#release-notes-process) --- .../legacy/plugins/siem/common/constants.ts | 1 + .../plugins/siem/server/kibana.index.ts | 4 ++ .../index/create_bootstrap_index.ts | 2 +- .../index/delete_all_index.ts | 2 +- .../detection_engine/index/delete_policy.ts | 2 +- .../detection_engine/index/delete_template.ts | 2 +- .../index/get_index_exists.ts | 2 +- .../index/get_policy_exists.ts | 2 +- .../index/get_template_exists.ts | 2 +- .../lib/detection_engine/index/read_index.ts | 2 +- .../lib/detection_engine/index/set_policy.ts | 2 +- .../detection_engine/index/set_template.ts | 2 +- .../lib/detection_engine/index/types.ts | 7 -- .../privileges/read_privileges.ts | 69 +++++++++++++++++++ .../routes/__mocks__/request_responses.ts | 59 ++++++++++++++++ .../routes/index/create_index_route.ts | 2 +- .../privileges/read_privileges_route.test.ts | 39 +++++++++++ .../privileges/read_privileges_route.ts | 41 +++++++++++ .../scripts/get_privileges.sh | 15 ++++ .../siem/server/lib/detection_engine/types.ts | 2 + 20 files changed, 241 insertions(+), 18 deletions(-) delete mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/index/types.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/privileges/read_privileges.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/privileges/read_privileges_route.test.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/privileges/read_privileges_route.ts create mode 100755 x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/get_privileges.sh diff --git a/x-pack/legacy/plugins/siem/common/constants.ts b/x-pack/legacy/plugins/siem/common/constants.ts index c3494c0969900..f08a6e66c3400 100644 --- a/x-pack/legacy/plugins/siem/common/constants.ts +++ b/x-pack/legacy/plugins/siem/common/constants.ts @@ -45,6 +45,7 @@ export const SIGNALS_ID = `${APP_ID}.signals`; */ export const DETECTION_ENGINE_URL = '/api/detection_engine'; export const DETECTION_ENGINE_RULES_URL = `${DETECTION_ENGINE_URL}/rules`; +export const DETECTION_ENGINE_PRIVILEGES_URL = `${DETECTION_ENGINE_URL}/privileges`; export const DETECTION_ENGINE_INDEX_URL = `${DETECTION_ENGINE_URL}/index`; /** diff --git a/x-pack/legacy/plugins/siem/server/kibana.index.ts b/x-pack/legacy/plugins/siem/server/kibana.index.ts index 65b673e1c72a5..219c59dbf11a3 100644 --- a/x-pack/legacy/plugins/siem/server/kibana.index.ts +++ b/x-pack/legacy/plugins/siem/server/kibana.index.ts @@ -19,6 +19,7 @@ import { querySignalsRoute } from './lib/detection_engine/routes/signals/query_s import { ServerFacade } from './types'; import { deleteIndexRoute } from './lib/detection_engine/routes/index/delete_index_route'; import { isAlertExecutor } from './lib/detection_engine/signals/types'; +import { readPrivilegesRoute } from './lib/detection_engine/routes/privileges/read_privileges_route'; const APP_ID = 'siem'; @@ -52,4 +53,7 @@ export const initServerWithKibana = (context: PluginInitializerContext, __legacy createIndexRoute(__legacy); readIndexRoute(__legacy); deleteIndexRoute(__legacy); + + // Privileges API to get the generic user privileges + readPrivilegesRoute(__legacy); }; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/create_bootstrap_index.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/create_bootstrap_index.ts index 9c8dca0cb370f..d7cb922b5b6c3 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/create_bootstrap_index.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/create_bootstrap_index.ts @@ -5,7 +5,7 @@ */ import { CallClusterOptions } from 'src/legacy/core_plugins/elasticsearch'; -import { CallWithRequest } from './types'; +import { CallWithRequest } from '../types'; // See the reference(s) below on explanations about why -000001 was chosen and // why the is_write_index is true as well as the bootstrapping step which is needed. diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/delete_all_index.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/delete_all_index.ts index 6f16eb8fbdeb1..b1d8f994615ae 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/delete_all_index.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/delete_all_index.ts @@ -6,7 +6,7 @@ import { IndicesDeleteParams } from 'elasticsearch'; import { CallClusterOptions } from 'src/legacy/core_plugins/elasticsearch'; -import { CallWithRequest } from './types'; +import { CallWithRequest } from '../types'; export const deleteAllIndex = async ( callWithRequest: CallWithRequest, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/delete_policy.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/delete_policy.ts index 153b9ae4e4136..92003f165d996 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/delete_policy.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/delete_policy.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { CallWithRequest } from './types'; +import { CallWithRequest } from '../types'; export const deletePolicy = async ( callWithRequest: CallWithRequest<{ path: string; method: 'DELETE' }, {}, unknown>, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/delete_template.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/delete_template.ts index b048dd27efb83..63c32d13ccb8d 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/delete_template.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/delete_template.ts @@ -6,7 +6,7 @@ import { IndicesDeleteTemplateParams } from 'elasticsearch'; import { CallClusterOptions } from 'src/legacy/core_plugins/elasticsearch'; -import { CallWithRequest } from './types'; +import { CallWithRequest } from '../types'; export const deleteTemplate = async ( callWithRequest: CallWithRequest, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/get_index_exists.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/get_index_exists.ts index 24164e894788a..ff65caa59a866 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/get_index_exists.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/get_index_exists.ts @@ -6,7 +6,7 @@ import { IndicesExistsParams } from 'elasticsearch'; import { CallClusterOptions } from 'src/legacy/core_plugins/elasticsearch'; -import { CallWithRequest } from './types'; +import { CallWithRequest } from '../types'; export const getIndexExists = async ( callWithRequest: CallWithRequest, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/get_policy_exists.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/get_policy_exists.ts index 847c32d9d61fb..7541c4217b387 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/get_policy_exists.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/get_policy_exists.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { CallWithRequest } from './types'; +import { CallWithRequest } from '../types'; export const getPolicyExists = async ( callWithRequest: CallWithRequest<{ path: string; method: 'GET' }, {}, unknown>, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/get_template_exists.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/get_template_exists.ts index 482fc8d855828..fac402155619e 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/get_template_exists.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/get_template_exists.ts @@ -6,7 +6,7 @@ import { IndicesExistsTemplateParams } from 'elasticsearch'; import { CallClusterOptions } from 'src/legacy/core_plugins/elasticsearch'; -import { CallWithRequest } from './types'; +import { CallWithRequest } from '../types'; export const getTemplateExists = async ( callWithRequest: CallWithRequest, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/read_index.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/read_index.ts index 6c9d529078a77..0abe2b992b780 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/read_index.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/read_index.ts @@ -6,7 +6,7 @@ import { IndicesGetSettingsParams } from 'elasticsearch'; import { CallClusterOptions } from 'src/legacy/core_plugins/elasticsearch'; -import { CallWithRequest } from './types'; +import { CallWithRequest } from '../types'; export const readIndex = async ( callWithRequest: CallWithRequest, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/set_policy.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/set_policy.ts index 2511984b412f3..115f0af75898c 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/set_policy.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/set_policy.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { CallWithRequest } from './types'; +import { CallWithRequest } from '../types'; export const setPolicy = async ( callWithRequest: CallWithRequest<{ path: string; method: 'PUT'; body: unknown }, {}, unknown>, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/set_template.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/set_template.ts index a679a61e10c00..dc9ad5dda9f7d 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/set_template.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/set_template.ts @@ -6,7 +6,7 @@ import { IndicesPutTemplateParams } from 'elasticsearch'; import { CallClusterOptions } from 'src/legacy/core_plugins/elasticsearch'; -import { CallWithRequest } from './types'; +import { CallWithRequest } from '../types'; export const setTemplate = async ( callWithRequest: CallWithRequest, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/types.ts deleted file mode 100644 index 70b33ad274ee1..0000000000000 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/index/types.ts +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -export type CallWithRequest = (endpoint: string, params: T, options?: U) => Promise; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/privileges/read_privileges.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/privileges/read_privileges.ts new file mode 100644 index 0000000000000..3b84075b9e435 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/privileges/read_privileges.ts @@ -0,0 +1,69 @@ +/* + * 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 { CallWithRequest } from '../types'; + +export const readPrivileges = async ( + callWithRequest: CallWithRequest, + index: string +): Promise => { + return callWithRequest('transport.request', { + path: `_security/user/_has_privileges`, + method: 'POST', + body: { + cluster: [ + 'all', + 'create_snapshot', + 'manage', + 'manage_api_key', + 'manage_ccr', + 'manage_transform', + 'manage_ilm', + 'manage_index_templates', + 'manage_ingest_pipelines', + 'manage_ml', + 'manage_own_api_key', + 'manage_pipeline', + 'manage_rollup', + 'manage_saml', + 'manage_security', + 'manage_token', + 'manage_watcher', + 'monitor', + 'monitor_transform', + 'monitor_ml', + 'monitor_rollup', + 'monitor_watcher', + 'read_ccr', + 'read_ilm', + 'transport_client', + ], + index: [ + { + names: [index], + privileges: [ + 'all', + 'create', + 'create_doc', + 'create_index', + 'delete', + 'delete_index', + 'index', + 'manage', + 'manage_follow_index', + 'manage_ilm', + 'manage_leader_index', + 'monitor', + 'read', + 'read_cross_cluster', + 'view_index_metadata', + 'write', + ], + }, + ], + }, + }); +}; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts index 86726187c4fbd..cb24b0d0c89b1 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -10,6 +10,7 @@ import { SignalsStatusRestParams, SignalsQueryRestParams } from '../../signals/t import { DETECTION_ENGINE_RULES_URL, DETECTION_ENGINE_SIGNALS_STATUS_URL, + DETECTION_ENGINE_PRIVILEGES_URL, DETECTION_ENGINE_QUERY_SIGNALS_URL, } from '../../../../../common/constants'; import { RuleAlertType } from '../../rules/types'; @@ -81,6 +82,11 @@ export const getFindRequest = (): ServerInjectOptions => ({ url: `${DETECTION_ENGINE_RULES_URL}/_find`, }); +export const getPrivilegeRequest = (): ServerInjectOptions => ({ + method: 'GET', + url: `${DETECTION_ENGINE_PRIVILEGES_URL}`, +}); + interface FindHit { page: number; perPage: number; @@ -225,3 +231,56 @@ export const updateActionResult = (): ActionResult => ({ name: '', config: {}, }); + +export const getMockPrivileges = () => ({ + username: 'test-space', + has_all_requested: false, + cluster: { + monitor_ml: true, + manage_ccr: false, + manage_index_templates: true, + monitor_watcher: true, + monitor_transform: true, + read_ilm: true, + manage_api_key: false, + manage_security: false, + manage_own_api_key: false, + manage_saml: false, + all: false, + manage_ilm: true, + manage_ingest_pipelines: true, + read_ccr: false, + manage_rollup: true, + monitor: true, + manage_watcher: true, + manage: true, + manage_transform: true, + manage_token: false, + manage_ml: true, + manage_pipeline: true, + monitor_rollup: true, + transport_client: true, + create_snapshot: true, + }, + index: { + '.siem-signals-frank-hassanabad-test-space': { + all: false, + manage_ilm: true, + read: false, + create_index: true, + read_cross_cluster: false, + index: false, + monitor: true, + delete: false, + manage: true, + delete_index: true, + create_doc: false, + view_index_metadata: true, + create: false, + manage_follow_index: true, + manage_leader_index: true, + write: false, + }, + }, + application: {}, +}); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/index/create_index_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/index/create_index_route.ts index 94c42664c281d..0eb090179b192 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/index/create_index_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/index/create_index_route.ts @@ -48,7 +48,7 @@ export const createCreateIndexRoute = (server: ServerFacade): Hapi.ServerRoute = const template = getSignalsTemplate(index); await setTemplate(callWithRequest, index, template); } - createBootstrapIndex(callWithRequest, index); + await createBootstrapIndex(callWithRequest, index); return { acknowledged: true }; } } catch (err) { diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/privileges/read_privileges_route.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/privileges/read_privileges_route.test.ts new file mode 100644 index 0000000000000..1ea681afb7949 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/privileges/read_privileges_route.test.ts @@ -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 { createMockServer } from '../__mocks__/_mock_server'; +import { getPrivilegeRequest, getMockPrivileges } from '../__mocks__/request_responses'; +import { readPrivilegesRoute } from './read_privileges_route'; +import * as myUtils from '../utils'; + +describe('read_privileges', () => { + let { server, elasticsearch } = createMockServer(); + + beforeEach(() => { + jest.spyOn(myUtils, 'getIndex').mockReturnValue('fakeindex'); + ({ server, elasticsearch } = createMockServer()); + elasticsearch.getCluster = jest.fn(() => ({ + callWithRequest: jest.fn(() => getMockPrivileges()), + })); + readPrivilegesRoute(server); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + describe('normal status codes', () => { + test('returns 200 when doing a normal request', async () => { + const { statusCode } = await server.inject(getPrivilegeRequest()); + expect(statusCode).toBe(200); + }); + + test('returns the payload when doing a normal request', async () => { + const { payload } = await server.inject(getPrivilegeRequest()); + expect(JSON.parse(payload)).toEqual(getMockPrivileges()); + }); + }); +}); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/privileges/read_privileges_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/privileges/read_privileges_route.ts new file mode 100644 index 0000000000000..457de05674f66 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/privileges/read_privileges_route.ts @@ -0,0 +1,41 @@ +/* + * 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 Hapi from 'hapi'; +import { DETECTION_ENGINE_PRIVILEGES_URL } from '../../../../../common/constants'; +import { RulesRequest } from '../../rules/types'; +import { ServerFacade } from '../../../../types'; +import { callWithRequestFactory, transformError, getIndex } from '../utils'; +import { readPrivileges } from '../../privileges/read_privileges'; + +export const createReadPrivilegesRulesRoute = (server: ServerFacade): Hapi.ServerRoute => { + return { + method: 'GET', + path: DETECTION_ENGINE_PRIVILEGES_URL, + options: { + tags: ['access:siem'], + validate: { + options: { + abortEarly: false, + }, + }, + }, + async handler(request: RulesRequest) { + try { + const callWithRequest = callWithRequestFactory(request, server); + const index = getIndex(request, server); + const permissions = await readPrivileges(callWithRequest, index); + return permissions; + } catch (err) { + return transformError(err); + } + }, + }; +}; + +export const readPrivilegesRoute = (server: ServerFacade): void => { + server.route(createReadPrivilegesRulesRoute(server)); +}; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/get_privileges.sh b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/get_privileges.sh new file mode 100755 index 0000000000000..f82a0b6b34abf --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/get_privileges.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +# +# 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. +# + +set -e +./check_env_variables.sh + +# Example: ./get_privileges.sh +curl -s -k \ + -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ + -X GET ${KIBANA_URL}${SPACE_URL}/api/detection_engine/privileges | jq . diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts index d02595c368aa7..bb616554042f4 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/types.ts @@ -65,3 +65,5 @@ export type OutputRuleAlertRest = RuleAlertParamsRest & { created_by: string | undefined | null; updated_by: string | undefined | null; }; + +export type CallWithRequest = (endpoint: string, params: T, options?: U) => Promise; From 711b44b7fb147201374bad3204134e6d492c60ed Mon Sep 17 00:00:00 2001 From: Tim Sullivan Date: Wed, 11 Dec 2019 12:11:07 -0700 Subject: [PATCH 19/79] [Reporting/NP Migration] Remove server.expose of ExportTypeRegistry (#50973) * [Reporting/NPMigration] typescriptify ExportTypeRegistry, remove from server.expose * Minor routes registration cleanup * move the ETR test file * Re-pack the route registration, reduce LOC changes * add EnqueueJobFn type * Fix usage collector test * remove a throw error used for development/debugging * fix imports error * Fix execute job tests * wip test fixes * test fixes for real * fix more tests * fix diffs * Add TODOs about the ExportTypesRegistry.register unwrap the factory functions. * really make headlessbrowserdriver required as an execute job factory option * fix tests * Use constants for license type keywords --- .../plugins/reporting/common/constants.ts | 6 + .../reporting/common/export_types_registry.js | 64 --------- .../common/lib/screenshots/index.ts | 14 +- .../reporting/export_types/csv/index.ts | 39 ++++++ .../export_types/csv/server/index.ts | 22 --- .../csv_from_savedobject/index.ts | 34 +++++ .../csv_from_savedobject/server/index.ts | 22 --- .../reporting/export_types/png/index.ts | 38 ++++++ .../png/server/execute_job/index.test.js | 6 +- .../png/server/execute_job/index.ts | 18 ++- .../export_types/png/server/index.ts | 23 ---- .../png/server/lib/generate_png.ts | 9 +- .../export_types/printable_pdf/index.ts | 38 ++++++ .../server/execute_job/index.test.js | 6 +- .../printable_pdf/server/execute_job/index.ts | 18 ++- .../printable_pdf/server/index.ts | 23 ---- .../printable_pdf/server/lib/generate_pdf.ts | 9 +- x-pack/legacy/plugins/reporting/index.ts | 25 ++-- .../lib}/__tests__/export_types_registry.js | 0 .../reporting/server/lib/create_queue.ts | 19 ++- .../server/lib/create_worker.test.ts | 40 +++--- .../reporting/server/lib/create_worker.ts | 17 ++- .../reporting/server/lib/enqueue_job.ts | 21 ++- .../server/lib/export_types_registry.ts | 128 ++++++++++++++---- .../plugins/reporting/server/lib/index.ts | 5 +- .../generate_from_savedobject_immediate.ts | 12 +- .../reporting/server/routes/generation.ts | 83 ++++++++++++ .../plugins/reporting/server/routes/index.ts | 82 +++-------- .../reporting/server/routes/jobs.test.js | 26 ++-- .../plugins/reporting/server/routes/jobs.ts | 26 ++-- .../server/routes/lib/get_document_payload.ts | 8 +- .../server/routes/lib/job_response_handler.js | 4 +- ..._handler.js => get_export_type_handler.ts} | 25 ++-- .../server/usage/get_reporting_usage.ts | 13 +- .../usage/reporting_usage_collector.test.js | 45 ++++-- .../server/usage/reporting_usage_collector.ts | 18 ++- x-pack/legacy/plugins/reporting/types.d.ts | 55 ++++---- 37 files changed, 638 insertions(+), 403 deletions(-) delete mode 100644 x-pack/legacy/plugins/reporting/common/export_types_registry.js create mode 100644 x-pack/legacy/plugins/reporting/export_types/csv/index.ts delete mode 100644 x-pack/legacy/plugins/reporting/export_types/csv/server/index.ts delete mode 100644 x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/index.ts create mode 100644 x-pack/legacy/plugins/reporting/export_types/png/index.ts delete mode 100644 x-pack/legacy/plugins/reporting/export_types/png/server/index.ts create mode 100644 x-pack/legacy/plugins/reporting/export_types/printable_pdf/index.ts delete mode 100644 x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/index.ts rename x-pack/legacy/plugins/reporting/{common => server/lib}/__tests__/export_types_registry.js (100%) create mode 100644 x-pack/legacy/plugins/reporting/server/routes/generation.ts rename x-pack/legacy/plugins/reporting/server/usage/{get_export_type_handler.js => get_export_type_handler.ts} (61%) diff --git a/x-pack/legacy/plugins/reporting/common/constants.ts b/x-pack/legacy/plugins/reporting/common/constants.ts index 723320e74bfbd..03b2d51c7b396 100644 --- a/x-pack/legacy/plugins/reporting/common/constants.ts +++ b/x-pack/legacy/plugins/reporting/common/constants.ts @@ -50,3 +50,9 @@ export const PNG_JOB_TYPE = 'PNG'; export const CSV_JOB_TYPE = 'csv'; export const CSV_FROM_SAVEDOBJECT_JOB_TYPE = 'csv_from_savedobject'; export const USES_HEADLESS_JOB_TYPES = [PDF_JOB_TYPE, PNG_JOB_TYPE]; + +export const LICENSE_TYPE_TRIAL = 'trial'; +export const LICENSE_TYPE_BASIC = 'basic'; +export const LICENSE_TYPE_STANDARD = 'standard'; +export const LICENSE_TYPE_GOLD = 'gold'; +export const LICENSE_TYPE_PLATINUM = 'platinum'; diff --git a/x-pack/legacy/plugins/reporting/common/export_types_registry.js b/x-pack/legacy/plugins/reporting/common/export_types_registry.js deleted file mode 100644 index 39abd8911e751..0000000000000 --- a/x-pack/legacy/plugins/reporting/common/export_types_registry.js +++ /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 { isString } from 'lodash'; - -export class ExportTypesRegistry { - - constructor() { - this._map = new Map(); - } - - register(item) { - if (!isString(item.id)) { - throw new Error(`'item' must have a String 'id' property `); - } - - if (this._map.has(item.id)) { - throw new Error(`'item' with id ${item.id} has already been registered`); - } - - this._map.set(item.id, item); - } - - getAll() { - return this._map.values(); - } - - getSize() { - return this._map.size; - } - - getById(id) { - if (!this._map.has(id)) { - throw new Error(`Unknown id ${id}`); - } - - return this._map.get(id); - } - - get(callback) { - let result; - for (const value of this._map.values()) { - if (!callback(value)) { - continue; - } - - if (result) { - throw new Error('Found multiple items matching predicate.'); - } - - result = value; - } - - if (!result) { - throw new Error('Found no items matching predicate'); - } - - return result; - } - -} diff --git a/x-pack/legacy/plugins/reporting/export_types/common/lib/screenshots/index.ts b/x-pack/legacy/plugins/reporting/export_types/common/lib/screenshots/index.ts index 2b4411584d752..152ef32e331b9 100644 --- a/x-pack/legacy/plugins/reporting/export_types/common/lib/screenshots/index.ts +++ b/x-pack/legacy/plugins/reporting/export_types/common/lib/screenshots/index.ts @@ -6,8 +6,12 @@ import * as Rx from 'rxjs'; import { first, mergeMap } from 'rxjs/operators'; -import { ServerFacade, CaptureConfig } from '../../../../types'; -import { HeadlessChromiumDriver as HeadlessBrowser } from '../../../../server/browsers/chromium/driver'; +import { + ServerFacade, + CaptureConfig, + HeadlessChromiumDriverFactory, + HeadlessChromiumDriver as HeadlessBrowser, +} from '../../../../types'; import { ElementsPositionAndAttribute, ScreenshotResults, @@ -26,10 +30,12 @@ import { getElementPositionAndAttributes } from './get_element_position_data'; import { getScreenshots } from './get_screenshots'; import { skipTelemetry } from './skip_telemetry'; -export function screenshotsObservableFactory(server: ServerFacade) { +export function screenshotsObservableFactory( + server: ServerFacade, + browserDriverFactory: HeadlessChromiumDriverFactory +) { const config = server.config(); const captureConfig: CaptureConfig = config.get('xpack.reporting.capture'); - const { browserDriverFactory } = server.plugins.reporting!; return function screenshotsObservable({ logger, diff --git a/x-pack/legacy/plugins/reporting/export_types/csv/index.ts b/x-pack/legacy/plugins/reporting/export_types/csv/index.ts new file mode 100644 index 0000000000000..4f8aeb2be0c99 --- /dev/null +++ b/x-pack/legacy/plugins/reporting/export_types/csv/index.ts @@ -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 { + CSV_JOB_TYPE as jobType, + LICENSE_TYPE_TRIAL, + LICENSE_TYPE_BASIC, + LICENSE_TYPE_STANDARD, + LICENSE_TYPE_GOLD, + LICENSE_TYPE_PLATINUM, +} from '../../common/constants'; +import { ExportTypeDefinition, ESQueueCreateJobFn, ESQueueWorkerExecuteFn } from '../../types'; +import { metadata } from './metadata'; +import { createJobFactory } from './server/create_job'; +import { executeJobFactory } from './server/execute_job'; +import { JobParamsDiscoverCsv, JobDocPayloadDiscoverCsv } from './types'; + +export const getExportType = (): ExportTypeDefinition< + JobParamsDiscoverCsv, + ESQueueCreateJobFn, + JobDocPayloadDiscoverCsv, + ESQueueWorkerExecuteFn +> => ({ + ...metadata, + jobType, + jobContentExtension: 'csv', + createJobFactory, + executeJobFactory, + validLicenses: [ + LICENSE_TYPE_TRIAL, + LICENSE_TYPE_BASIC, + LICENSE_TYPE_STANDARD, + LICENSE_TYPE_GOLD, + LICENSE_TYPE_PLATINUM, + ], +}); diff --git a/x-pack/legacy/plugins/reporting/export_types/csv/server/index.ts b/x-pack/legacy/plugins/reporting/export_types/csv/server/index.ts deleted file mode 100644 index d752cdcd9779d..0000000000000 --- a/x-pack/legacy/plugins/reporting/export_types/csv/server/index.ts +++ /dev/null @@ -1,22 +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 { ExportTypesRegistry } from '../../../types'; -import { createJobFactory } from './create_job'; -import { executeJobFactory } from './execute_job'; -import { metadata } from '../metadata'; -import { CSV_JOB_TYPE as jobType } from '../../../common/constants'; - -export function register(registry: ExportTypesRegistry) { - registry.register({ - ...metadata, - jobType, - jobContentExtension: 'csv', - createJobFactory, - executeJobFactory, - validLicenses: ['trial', 'basic', 'standard', 'gold', 'platinum'], - }); -} diff --git a/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/index.ts b/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/index.ts index 68ad4a4b49155..4876cea0b1b28 100644 --- a/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/index.ts +++ b/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/index.ts @@ -4,9 +4,43 @@ * you may not use this file except in compliance with the Elastic License. */ +import { + CSV_FROM_SAVEDOBJECT_JOB_TYPE, + LICENSE_TYPE_TRIAL, + LICENSE_TYPE_BASIC, + LICENSE_TYPE_STANDARD, + LICENSE_TYPE_GOLD, + LICENSE_TYPE_PLATINUM, +} from '../../common/constants'; +import { ExportTypeDefinition, ImmediateCreateJobFn, ImmediateExecuteFn } from '../../types'; +import { createJobFactory } from './server/create_job'; +import { executeJobFactory } from './server/execute_job'; +import { metadata } from './metadata'; +import { JobParamsPanelCsv } from './types'; + /* * These functions are exported to share with the API route handler that * generates csv from saved object immediately on request. */ export { executeJobFactory } from './server/execute_job'; export { createJobFactory } from './server/create_job'; + +export const getExportType = (): ExportTypeDefinition< + JobParamsPanelCsv, + ImmediateCreateJobFn, + JobParamsPanelCsv, + ImmediateExecuteFn +> => ({ + ...metadata, + jobType: CSV_FROM_SAVEDOBJECT_JOB_TYPE, + jobContentExtension: 'csv', + createJobFactory, + executeJobFactory, + validLicenses: [ + LICENSE_TYPE_TRIAL, + LICENSE_TYPE_BASIC, + LICENSE_TYPE_STANDARD, + LICENSE_TYPE_GOLD, + LICENSE_TYPE_PLATINUM, + ], +}); diff --git a/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/index.ts b/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/index.ts deleted file mode 100644 index b614fd3c681b3..0000000000000 --- a/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/index.ts +++ /dev/null @@ -1,22 +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 { CSV_FROM_SAVEDOBJECT_JOB_TYPE } from '../../../common/constants'; -import { ExportTypesRegistry } from '../../../types'; -import { metadata } from '../metadata'; -import { createJobFactory } from './create_job'; -import { executeJobFactory } from './execute_job'; - -export function register(registry: ExportTypesRegistry) { - registry.register({ - ...metadata, - jobType: CSV_FROM_SAVEDOBJECT_JOB_TYPE, - jobContentExtension: 'csv', - createJobFactory, - executeJobFactory, - validLicenses: ['trial', 'basic', 'standard', 'gold', 'platinum'], - }); -} diff --git a/x-pack/legacy/plugins/reporting/export_types/png/index.ts b/x-pack/legacy/plugins/reporting/export_types/png/index.ts new file mode 100644 index 0000000000000..bc00bc428f306 --- /dev/null +++ b/x-pack/legacy/plugins/reporting/export_types/png/index.ts @@ -0,0 +1,38 @@ +/* + * 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 { + PNG_JOB_TYPE as jobType, + LICENSE_TYPE_TRIAL, + LICENSE_TYPE_STANDARD, + LICENSE_TYPE_GOLD, + LICENSE_TYPE_PLATINUM, +} from '../../common/constants'; +import { ExportTypeDefinition, ESQueueCreateJobFn, ESQueueWorkerExecuteFn } from '../../types'; +import { createJobFactory } from './server/create_job'; +import { executeJobFactory } from './server/execute_job'; +import { metadata } from './metadata'; +import { JobParamsPNG, JobDocPayloadPNG } from './types'; + +export const getExportType = (): ExportTypeDefinition< + JobParamsPNG, + ESQueueCreateJobFn, + JobDocPayloadPNG, + ESQueueWorkerExecuteFn +> => ({ + ...metadata, + jobType, + jobContentEncoding: 'base64', + jobContentExtension: 'PNG', + createJobFactory, + executeJobFactory, + validLicenses: [ + LICENSE_TYPE_TRIAL, + LICENSE_TYPE_STANDARD, + LICENSE_TYPE_GOLD, + LICENSE_TYPE_PLATINUM, + ], +}); diff --git a/x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/index.test.js b/x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/index.test.js index 867d537017f41..267c606449c3a 100644 --- a/x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/index.test.js +++ b/x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/index.test.js @@ -68,7 +68,7 @@ test(`passes browserTimezone to generatePng`, async () => { const generatePngObservable = generatePngObservableFactory(); generatePngObservable.mockReturnValue(Rx.of(Buffer.from(''))); - const executeJob = executeJobFactory(mockServer); + const executeJob = executeJobFactory(mockServer, { browserDriverFactory: {} }); const browserTimezone = 'UTC'; await executeJob('pngJobId', { relativeUrl: '/app/kibana#/something', browserTimezone, headers: encryptedHeaders }, cancellationToken); @@ -76,7 +76,7 @@ test(`passes browserTimezone to generatePng`, async () => { }); test(`returns content_type of application/png`, async () => { - const executeJob = executeJobFactory(mockServer); + const executeJob = executeJobFactory(mockServer, { browserDriverFactory: {} }); const encryptedHeaders = await encryptHeaders({}); const generatePngObservable = generatePngObservableFactory(); @@ -93,7 +93,7 @@ test(`returns content of generatePng getBuffer base64 encoded`, async () => { const generatePngObservable = generatePngObservableFactory(); generatePngObservable.mockReturnValue(Rx.of(Buffer.from(testContent))); - const executeJob = executeJobFactory(mockServer); + const executeJob = executeJobFactory(mockServer, { browserDriverFactory: {} }); const encryptedHeaders = await encryptHeaders({}); const { content } = await executeJob('pngJobId', { relativeUrl: '/app/kibana#/something', timeRange: {}, headers: encryptedHeaders }, cancellationToken); diff --git a/x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/index.ts b/x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/index.ts index 6678a83079d31..b289ae45dde67 100644 --- a/x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/index.ts +++ b/x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/index.ts @@ -7,7 +7,12 @@ import * as Rx from 'rxjs'; import { mergeMap, catchError, map, takeUntil } from 'rxjs/operators'; import { PLUGIN_ID, PNG_JOB_TYPE } from '../../../../common/constants'; -import { ServerFacade, ExecuteJobFactory, ESQueueWorkerExecuteFn } from '../../../../types'; +import { + ServerFacade, + ExecuteJobFactory, + ESQueueWorkerExecuteFn, + HeadlessChromiumDriverFactory, +} from '../../../../types'; import { LevelLogger } from '../../../../server/lib'; import { decryptJobHeaders, @@ -18,10 +23,13 @@ import { import { JobDocPayloadPNG } from '../../types'; import { generatePngObservableFactory } from '../lib/generate_png'; -export const executeJobFactory: ExecuteJobFactory> = function executeJobFactoryFn(server: ServerFacade) { - const generatePngObservable = generatePngObservableFactory(server); +type QueuedPngExecutorFactory = ExecuteJobFactory>; + +export const executeJobFactory: QueuedPngExecutorFactory = function executeJobFactoryFn( + server: ServerFacade, + { browserDriverFactory }: { browserDriverFactory: HeadlessChromiumDriverFactory } +) { + const generatePngObservable = generatePngObservableFactory(server, browserDriverFactory); const logger = LevelLogger.createForServer(server, [PLUGIN_ID, PNG_JOB_TYPE, 'execute']); return function executeJob( diff --git a/x-pack/legacy/plugins/reporting/export_types/png/server/index.ts b/x-pack/legacy/plugins/reporting/export_types/png/server/index.ts deleted file mode 100644 index a569719f02324..0000000000000 --- a/x-pack/legacy/plugins/reporting/export_types/png/server/index.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 { ExportTypesRegistry } from '../../../types'; -import { createJobFactory } from './create_job'; -import { executeJobFactory } from './execute_job'; -import { metadata } from '../metadata'; -import { PNG_JOB_TYPE as jobType } from '../../../common/constants'; - -export function register(registry: ExportTypesRegistry) { - registry.register({ - ...metadata, - jobType, - jobContentEncoding: 'base64', - jobContentExtension: 'PNG', - createJobFactory, - executeJobFactory, - validLicenses: ['trial', 'standard', 'gold', 'platinum'], - }); -} diff --git a/x-pack/legacy/plugins/reporting/export_types/png/server/lib/generate_png.ts b/x-pack/legacy/plugins/reporting/export_types/png/server/lib/generate_png.ts index 90aeea25db858..e2b1474515786 100644 --- a/x-pack/legacy/plugins/reporting/export_types/png/server/lib/generate_png.ts +++ b/x-pack/legacy/plugins/reporting/export_types/png/server/lib/generate_png.ts @@ -7,13 +7,16 @@ import * as Rx from 'rxjs'; import { map } from 'rxjs/operators'; import { LevelLogger } from '../../../../server/lib'; -import { ServerFacade, ConditionalHeaders } from '../../../../types'; +import { ServerFacade, HeadlessChromiumDriverFactory, ConditionalHeaders } from '../../../../types'; import { screenshotsObservableFactory } from '../../../common/lib/screenshots'; import { PreserveLayout } from '../../../common/layouts/preserve_layout'; import { LayoutParams } from '../../../common/layouts/layout'; -export function generatePngObservableFactory(server: ServerFacade) { - const screenshotsObservable = screenshotsObservableFactory(server); +export function generatePngObservableFactory( + server: ServerFacade, + browserDriverFactory: HeadlessChromiumDriverFactory +) { + const screenshotsObservable = screenshotsObservableFactory(server, browserDriverFactory); return function generatePngObservable( logger: LevelLogger, diff --git a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/index.ts b/x-pack/legacy/plugins/reporting/export_types/printable_pdf/index.ts new file mode 100644 index 0000000000000..99880c1237a7a --- /dev/null +++ b/x-pack/legacy/plugins/reporting/export_types/printable_pdf/index.ts @@ -0,0 +1,38 @@ +/* + * 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 { + PDF_JOB_TYPE as jobType, + LICENSE_TYPE_TRIAL, + LICENSE_TYPE_STANDARD, + LICENSE_TYPE_GOLD, + LICENSE_TYPE_PLATINUM, +} from '../../common/constants'; +import { ExportTypeDefinition, ESQueueCreateJobFn, ESQueueWorkerExecuteFn } from '../../types'; +import { createJobFactory } from './server/create_job'; +import { executeJobFactory } from './server/execute_job'; +import { metadata } from './metadata'; +import { JobParamsPDF, JobDocPayloadPDF } from './types'; + +export const getExportType = (): ExportTypeDefinition< + JobParamsPDF, + ESQueueCreateJobFn, + JobDocPayloadPDF, + ESQueueWorkerExecuteFn +> => ({ + ...metadata, + jobType, + jobContentEncoding: 'base64', + jobContentExtension: 'pdf', + createJobFactory, + executeJobFactory, + validLicenses: [ + LICENSE_TYPE_TRIAL, + LICENSE_TYPE_STANDARD, + LICENSE_TYPE_GOLD, + LICENSE_TYPE_PLATINUM, + ], +}); diff --git a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/index.test.js b/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/index.test.js index 8084c077ed23f..6a5c47829fd19 100644 --- a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/index.test.js +++ b/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/index.test.js @@ -67,7 +67,7 @@ test(`passes browserTimezone to generatePdf`, async () => { const generatePdfObservable = generatePdfObservableFactory(); generatePdfObservable.mockReturnValue(Rx.of(Buffer.from(''))); - const executeJob = executeJobFactory(mockServer); + const executeJob = executeJobFactory(mockServer, { browserDriverFactory: {} }); const browserTimezone = 'UTC'; await executeJob('pdfJobId', { objects: [], browserTimezone, headers: encryptedHeaders }, cancellationToken); @@ -84,7 +84,7 @@ test(`passes browserTimezone to generatePdf`, async () => { }); test(`returns content_type of application/pdf`, async () => { - const executeJob = executeJobFactory(mockServer); + const executeJob = executeJobFactory(mockServer, { browserDriverFactory: {} }); const encryptedHeaders = await encryptHeaders({}); const generatePdfObservable = generatePdfObservableFactory(); @@ -104,7 +104,7 @@ test(`returns content of generatePdf getBuffer base64 encoded`, async () => { const generatePdfObservable = generatePdfObservableFactory(); generatePdfObservable.mockReturnValue(Rx.of(Buffer.from(testContent))); - const executeJob = executeJobFactory(mockServer); + const executeJob = executeJobFactory(mockServer, { browserDriverFactory: {} }); const encryptedHeaders = await encryptHeaders({}); const { content } = await executeJob('pdfJobId', { objects: [], timeRange: {}, headers: encryptedHeaders }, cancellationToken); diff --git a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/index.ts b/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/index.ts index 543d5b587906d..e2b3183464cf2 100644 --- a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/index.ts +++ b/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/index.ts @@ -6,7 +6,12 @@ import * as Rx from 'rxjs'; import { mergeMap, catchError, map, takeUntil } from 'rxjs/operators'; -import { ExecuteJobFactory, ESQueueWorkerExecuteFn, ServerFacade } from '../../../../types'; +import { + ServerFacade, + ExecuteJobFactory, + ESQueueWorkerExecuteFn, + HeadlessChromiumDriverFactory, +} from '../../../../types'; import { JobDocPayloadPDF } from '../../types'; import { PLUGIN_ID, PDF_JOB_TYPE } from '../../../../common/constants'; import { LevelLogger } from '../../../../server/lib'; @@ -19,10 +24,13 @@ import { getCustomLogo, } from '../../../common/execute_job/'; -export const executeJobFactory: ExecuteJobFactory> = function executeJobFactoryFn(server: ServerFacade) { - const generatePdfObservable = generatePdfObservableFactory(server); +type QueuedPdfExecutorFactory = ExecuteJobFactory>; + +export const executeJobFactory: QueuedPdfExecutorFactory = function executeJobFactoryFn( + server: ServerFacade, + { browserDriverFactory }: { browserDriverFactory: HeadlessChromiumDriverFactory } +) { + const generatePdfObservable = generatePdfObservableFactory(server, browserDriverFactory); const logger = LevelLogger.createForServer(server, [PLUGIN_ID, PDF_JOB_TYPE, 'execute']); return function executeJob( diff --git a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/index.ts b/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/index.ts deleted file mode 100644 index df798a7af23ec..0000000000000 --- a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/index.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 { ExportTypesRegistry } from '../../../types'; -import { createJobFactory } from './create_job'; -import { executeJobFactory } from './execute_job'; -import { metadata } from '../metadata'; -import { PDF_JOB_TYPE as jobType } from '../../../common/constants'; - -export function register(registry: ExportTypesRegistry) { - registry.register({ - ...metadata, - jobType, - jobContentEncoding: 'base64', - jobContentExtension: 'pdf', - createJobFactory, - executeJobFactory, - validLicenses: ['trial', 'standard', 'gold', 'platinum'], - }); -} diff --git a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/lib/generate_pdf.ts b/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/lib/generate_pdf.ts index 1e0245ebd513f..898a13a2dfe80 100644 --- a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/lib/generate_pdf.ts +++ b/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/lib/generate_pdf.ts @@ -8,7 +8,7 @@ import * as Rx from 'rxjs'; import { toArray, mergeMap } from 'rxjs/operators'; import { groupBy } from 'lodash'; import { LevelLogger } from '../../../../server/lib'; -import { ServerFacade, ConditionalHeaders } from '../../../../types'; +import { ServerFacade, HeadlessChromiumDriverFactory, ConditionalHeaders } from '../../../../types'; // @ts-ignore untyped module import { pdf } from './pdf'; import { screenshotsObservableFactory } from '../../../common/lib/screenshots'; @@ -26,8 +26,11 @@ const getTimeRange = (urlScreenshots: ScreenshotResults[]) => { return null; }; -export function generatePdfObservableFactory(server: ServerFacade) { - const screenshotsObservable = screenshotsObservableFactory(server); +export function generatePdfObservableFactory( + server: ServerFacade, + browserDriverFactory: HeadlessChromiumDriverFactory +) { + const screenshotsObservable = screenshotsObservableFactory(server, browserDriverFactory); const captureConcurrency = 1; return function generatePdfObservable( diff --git a/x-pack/legacy/plugins/reporting/index.ts b/x-pack/legacy/plugins/reporting/index.ts index 9add3accd262f..c0c9e458132f0 100644 --- a/x-pack/legacy/plugins/reporting/index.ts +++ b/x-pack/legacy/plugins/reporting/index.ts @@ -13,8 +13,7 @@ import { registerRoutes } from './server/routes'; import { LevelLogger, checkLicenseFactory, - createQueueFactory, - exportTypesRegistryFactory, + getExportTypesRegistry, runValidations, } from './server/lib'; import { config as reportingConfig } from './config'; @@ -74,20 +73,23 @@ export const reporting = (kibana: any) => { // TODO: Decouple Hapi: Build a server facade object based on the server to // pass through to the libs. Do not pass server directly async init(server: ServerFacade) { + const exportTypesRegistry = getExportTypesRegistry(); + let isCollectorReady = false; // Register a function with server to manage the collection of usage stats const { usageCollection } = server.newPlatform.setup.plugins; - registerReportingUsageCollector(usageCollection, server, () => isCollectorReady); + registerReportingUsageCollector( + usageCollection, + server, + () => isCollectorReady, + exportTypesRegistry + ); const logger = LevelLogger.createForServer(server, [PLUGIN_ID]); - const [exportTypesRegistry, browserFactory] = await Promise.all([ - exportTypesRegistryFactory(server), - createBrowserDriverFactory(server), - ]); - server.expose('exportTypesRegistry', exportTypesRegistry); + const browserDriverFactory = await createBrowserDriverFactory(server); logConfiguration(server, logger); - runValidations(server, logger, browserFactory); + runValidations(server, logger, browserDriverFactory); const { xpack_main: xpackMainPlugin } = server.plugins; mirrorPluginStatus(xpackMainPlugin, this); @@ -101,11 +103,8 @@ export const reporting = (kibana: any) => { // Post initialization of the above code, the collector is now ready to fetch its data isCollectorReady = true; - server.expose('browserDriverFactory', browserFactory); - server.expose('queue', createQueueFactory(server)); - // Reporting routes - registerRoutes(server, logger); + registerRoutes(server, exportTypesRegistry, browserDriverFactory, logger); }, deprecations({ unused }: any) { diff --git a/x-pack/legacy/plugins/reporting/common/__tests__/export_types_registry.js b/x-pack/legacy/plugins/reporting/server/lib/__tests__/export_types_registry.js similarity index 100% rename from x-pack/legacy/plugins/reporting/common/__tests__/export_types_registry.js rename to x-pack/legacy/plugins/reporting/server/lib/__tests__/export_types_registry.js diff --git a/x-pack/legacy/plugins/reporting/server/lib/create_queue.ts b/x-pack/legacy/plugins/reporting/server/lib/create_queue.ts index 174c6d587e523..5cf760250ec0e 100644 --- a/x-pack/legacy/plugins/reporting/server/lib/create_queue.ts +++ b/x-pack/legacy/plugins/reporting/server/lib/create_queue.ts @@ -5,7 +5,12 @@ */ import { PLUGIN_ID } from '../../common/constants'; -import { ServerFacade, QueueConfig } from '../../types'; +import { + ServerFacade, + ExportTypesRegistry, + HeadlessChromiumDriverFactory, + QueueConfig, +} from '../../types'; // @ts-ignore import { Esqueue } from './esqueue'; import { createWorkerFactory } from './create_worker'; @@ -13,7 +18,15 @@ import { LevelLogger } from './level_logger'; // @ts-ignore import { createTaggedLogger } from './create_tagged_logger'; // TODO remove createTaggedLogger once esqueue is removed -export function createQueueFactory(server: ServerFacade): Esqueue { +interface CreateQueueFactoryOpts { + exportTypesRegistry: ExportTypesRegistry; + browserDriverFactory: HeadlessChromiumDriverFactory; +} + +export function createQueueFactory( + server: ServerFacade, + { exportTypesRegistry, browserDriverFactory }: CreateQueueFactoryOpts +): Esqueue { const queueConfig: QueueConfig = server.config().get('xpack.reporting.queue'); const index = server.config().get('xpack.reporting.index'); @@ -29,7 +42,7 @@ export function createQueueFactory(server: ServerFacade): Esqueue { if (queueConfig.pollEnabled) { // create workers to poll the index for idle jobs waiting to be claimed and executed - const createWorker = createWorkerFactory(server); + const createWorker = createWorkerFactory(server, { exportTypesRegistry, browserDriverFactory }); createWorker(queue); } else { const logger = LevelLogger.createForServer(server, [PLUGIN_ID, 'create_queue']); diff --git a/x-pack/legacy/plugins/reporting/server/lib/create_worker.test.ts b/x-pack/legacy/plugins/reporting/server/lib/create_worker.test.ts index afad8f096a8bb..8f843752491ec 100644 --- a/x-pack/legacy/plugins/reporting/server/lib/create_worker.test.ts +++ b/x-pack/legacy/plugins/reporting/server/lib/create_worker.test.ts @@ -5,7 +5,8 @@ */ import * as sinon from 'sinon'; -import { ServerFacade } from '../../types'; +import { ServerFacade, HeadlessChromiumDriverFactory } from '../../types'; +import { ExportTypesRegistry } from './export_types_registry'; import { createWorkerFactory } from './create_worker'; // @ts-ignore import { Esqueue } from './esqueue'; @@ -22,16 +23,17 @@ configGetStub.withArgs('server.uuid').returns('g9ymiujthvy6v8yrh7567g6fwzgzftzfr const executeJobFactoryStub = sinon.stub(); -const getMockServer = ( - exportTypes: any[] = [{ executeJobFactory: executeJobFactoryStub }] -): ServerFacade => { +const getMockServer = (): ServerFacade => { return ({ log: sinon.stub(), - expose: sinon.stub(), config: () => ({ get: configGetStub }), - plugins: { reporting: { exportTypesRegistry: { getAll: () => exportTypes } } }, } as unknown) as ServerFacade; }; +const getMockExportTypesRegistry = ( + exportTypes: any[] = [{ executeJobFactory: executeJobFactoryStub }] +) => ({ + getAll: () => exportTypes, +}); describe('Create Worker', () => { let queue: Esqueue; @@ -44,7 +46,11 @@ describe('Create Worker', () => { }); test('Creates a single Esqueue worker for Reporting', async () => { - const createWorker = createWorkerFactory(getMockServer()); + const exportTypesRegistry = getMockExportTypesRegistry(); + const createWorker = createWorkerFactory(getMockServer(), { + exportTypesRegistry: exportTypesRegistry as ExportTypesRegistry, + browserDriverFactory: {} as HeadlessChromiumDriverFactory, + }); const registerWorkerSpy = sinon.spy(queue, 'registerWorker'); createWorker(queue); @@ -68,15 +74,17 @@ Object { }); test('Creates a single Esqueue worker for Reporting, even if there are multiple export types', async () => { - const createWorker = createWorkerFactory( - getMockServer([ - { executeJobFactory: executeJobFactoryStub }, - { executeJobFactory: executeJobFactoryStub }, - { executeJobFactory: executeJobFactoryStub }, - { executeJobFactory: executeJobFactoryStub }, - { executeJobFactory: executeJobFactoryStub }, - ]) - ); + const exportTypesRegistry = getMockExportTypesRegistry([ + { executeJobFactory: executeJobFactoryStub }, + { executeJobFactory: executeJobFactoryStub }, + { executeJobFactory: executeJobFactoryStub }, + { executeJobFactory: executeJobFactoryStub }, + { executeJobFactory: executeJobFactoryStub }, + ]); + const createWorker = createWorkerFactory(getMockServer(), { + exportTypesRegistry: exportTypesRegistry as ExportTypesRegistry, + browserDriverFactory: {} as HeadlessChromiumDriverFactory, + }); const registerWorkerSpy = sinon.spy(queue, 'registerWorker'); createWorker(queue); diff --git a/x-pack/legacy/plugins/reporting/server/lib/create_worker.ts b/x-pack/legacy/plugins/reporting/server/lib/create_worker.ts index 01f59099a1d99..1326e411b6c5c 100644 --- a/x-pack/legacy/plugins/reporting/server/lib/create_worker.ts +++ b/x-pack/legacy/plugins/reporting/server/lib/create_worker.ts @@ -5,6 +5,7 @@ */ import { PLUGIN_ID } from '../../common/constants'; +import { ExportTypesRegistry, HeadlessChromiumDriverFactory } from '../../types'; import { CancellationToken } from '../../common/cancellation_token'; import { ESQueueInstance, @@ -21,14 +22,21 @@ import { import { events as esqueueEvents } from './esqueue'; import { LevelLogger } from './level_logger'; -export function createWorkerFactory(server: ServerFacade) { +interface CreateWorkerFactoryOpts { + exportTypesRegistry: ExportTypesRegistry; + browserDriverFactory: HeadlessChromiumDriverFactory; +} + +export function createWorkerFactory( + server: ServerFacade, + { exportTypesRegistry, browserDriverFactory }: CreateWorkerFactoryOpts +) { type JobDocPayloadType = JobDocPayload; const config = server.config(); const logger = LevelLogger.createForServer(server, [PLUGIN_ID, 'queue-worker']); const queueConfig: QueueConfig = config.get('xpack.reporting.queue'); const kibanaName: string = config.get('server.name'); const kibanaId: string = config.get('server.uuid'); - const { exportTypesRegistry } = server.plugins.reporting!; // Once more document types are added, this will need to be passed in return function createWorker(queue: ESQueueInstance) { @@ -41,8 +49,9 @@ export function createWorkerFactory(server: ServerFacade) { for (const exportType of exportTypesRegistry.getAll() as Array< ExportTypeDefinition >) { - const executeJobFactory = exportType.executeJobFactory(server); - jobExecutors.set(exportType.jobType, executeJobFactory); + // TODO: the executeJobFn should be unwrapped in the register method of the export types registry + const jobExecutor = exportType.executeJobFactory(server, { browserDriverFactory }); + jobExecutors.set(exportType.jobType, jobExecutor); } const workerFn = (jobSource: JobSource, ...workerRestArgs: any[]) => { diff --git a/x-pack/legacy/plugins/reporting/server/lib/enqueue_job.ts b/x-pack/legacy/plugins/reporting/server/lib/enqueue_job.ts index a8cefa3fdc49b..2d044ab31a160 100644 --- a/x-pack/legacy/plugins/reporting/server/lib/enqueue_job.ts +++ b/x-pack/legacy/plugins/reporting/server/lib/enqueue_job.ts @@ -8,12 +8,14 @@ import { get } from 'lodash'; // @ts-ignore import { events as esqueueEvents } from './esqueue'; import { + EnqueueJobFn, ESQueueCreateJobFn, ImmediateCreateJobFn, Job, ServerFacade, RequestFacade, Logger, + ExportTypesRegistry, CaptureConfig, QueueConfig, ConditionalHeaders, @@ -26,13 +28,20 @@ interface ConfirmedJob { _primary_term: number; } -export function enqueueJobFactory(server: ServerFacade) { +interface EnqueueJobFactoryOpts { + exportTypesRegistry: ExportTypesRegistry; + esqueue: any; +} + +export function enqueueJobFactory( + server: ServerFacade, + { exportTypesRegistry, esqueue }: EnqueueJobFactoryOpts +): EnqueueJobFn { const config = server.config(); const captureConfig: CaptureConfig = config.get('xpack.reporting.capture'); const browserType = captureConfig.browser.type; const maxAttempts = captureConfig.maxAttempts; const queueConfig: QueueConfig = config.get('xpack.reporting.queue'); - const { exportTypesRegistry, queue: jobQueue } = server.plugins.reporting!; return async function enqueueJob( parentLogger: Logger, @@ -46,6 +55,12 @@ export function enqueueJobFactory(server: ServerFacade) { const logger = parentLogger.clone(['queue-job']); const exportType = exportTypesRegistry.getById(exportTypeId); + + if (exportType == null) { + throw new Error(`Export type ${exportTypeId} does not exist in the registry!`); + } + + // TODO: the createJobFn should be unwrapped in the register method of the export types registry const createJob = exportType.createJobFactory(server) as CreateJobFn; const payload = await createJob(jobParams, headers, request); @@ -57,7 +72,7 @@ export function enqueueJobFactory(server: ServerFacade) { }; return new Promise((resolve, reject) => { - const job = jobQueue.addJob(exportType.jobType, payload, options); + const job = esqueue.addJob(exportType.jobType, payload, options); job.on(esqueueEvents.EVENT_JOB_CREATED, (createdJob: ConfirmedJob) => { if (createdJob.id === job.id) { diff --git a/x-pack/legacy/plugins/reporting/server/lib/export_types_registry.ts b/x-pack/legacy/plugins/reporting/server/lib/export_types_registry.ts index af1457ab52fe2..d553cc07ae3ef 100644 --- a/x-pack/legacy/plugins/reporting/server/lib/export_types_registry.ts +++ b/x-pack/legacy/plugins/reporting/server/lib/export_types_registry.ts @@ -4,40 +4,110 @@ * you may not use this file except in compliance with the Elastic License. */ -import { resolve as pathResolve } from 'path'; -import glob from 'glob'; -import { ServerFacade } from '../../types'; -import { PLUGIN_ID } from '../../common/constants'; -import { oncePerServer } from './once_per_server'; -import { LevelLogger } from './level_logger'; -// @ts-ignore untype module TODO -import { ExportTypesRegistry } from '../../common/export_types_registry'; - -function scan(pattern: string) { - return new Promise((resolve, reject) => { - glob(pattern, {}, (err, files) => { - if (err) { - return reject(err); +import memoizeOne from 'memoize-one'; +import { isString } from 'lodash'; +import { getExportType as getTypeCsv } from '../../export_types/csv'; +import { getExportType as getTypeCsvFromSavedObject } from '../../export_types/csv_from_savedobject'; +import { getExportType as getTypePng } from '../../export_types/png'; +import { getExportType as getTypePrintablePdf } from '../../export_types/printable_pdf'; +import { ExportTypeDefinition } from '../../types'; + +type GetCallbackFn = ( + item: ExportTypeDefinition +) => boolean; +// => ExportTypeDefinition + +export class ExportTypesRegistry { + private _map: Map> = new Map(); + + constructor() {} + + register( + item: ExportTypeDefinition + ): void { + if (!isString(item.id)) { + throw new Error(`'item' must have a String 'id' property `); + } + + if (this._map.has(item.id)) { + throw new Error(`'item' with id ${item.id} has already been registered`); + } + + // TODO: Unwrap the execute function from the item's executeJobFactory + // Move that work out of server/lib/create_worker to reduce dependence on ESQueue + this._map.set(item.id, item); + } + + getAll() { + return Array.from(this._map.values()); + } + + getSize() { + return this._map.size; + } + + getById( + id: string + ): ExportTypeDefinition { + if (!this._map.has(id)) { + throw new Error(`Unknown id ${id}`); + } + + return this._map.get(id) as ExportTypeDefinition< + JobParamsType, + CreateJobFnType, + JobPayloadType, + ExecuteJobFnType + >; + } + + get( + findType: GetCallbackFn + ): ExportTypeDefinition { + let result; + for (const value of this._map.values()) { + if (!findType(value)) { + continue; // try next value } + const foundResult: ExportTypeDefinition< + JobParamsType, + CreateJobFnType, + JobPayloadType, + ExecuteJobFnType + > = value; - resolve(files); - }); - }); -} + if (result) { + throw new Error('Found multiple items matching predicate.'); + } + + result = foundResult; + } -const pattern = pathResolve(__dirname, '../../export_types/*/server/index.[jt]s'); -async function exportTypesRegistryFn(server: ServerFacade) { - const logger = LevelLogger.createForServer(server, [PLUGIN_ID, 'exportTypes']); - const exportTypesRegistry = new ExportTypesRegistry(); - const files: string[] = (await scan(pattern)) as string[]; + if (!result) { + throw new Error('Found no items matching predicate'); + } + + return result; + } +} - files.forEach(file => { - logger.debug(`Found exportType at ${file}`); +function getExportTypesRegistryFn(): ExportTypesRegistry { + const registry = new ExportTypesRegistry(); - const { register } = require(file); // eslint-disable-line @typescript-eslint/no-var-requires - register(exportTypesRegistry); + /* this replaces the previously async method of registering export types, + * where this would run a directory scan and types would be registered via + * discovery */ + const getTypeFns: Array<() => ExportTypeDefinition> = [ + getTypeCsv, + getTypeCsvFromSavedObject, + getTypePng, + getTypePrintablePdf, + ]; + getTypeFns.forEach(getType => { + registry.register(getType()); }); - return exportTypesRegistry; + return registry; } -export const exportTypesRegistryFactory = oncePerServer(exportTypesRegistryFn); +// FIXME: is this the best way to return a singleton? +export const getExportTypesRegistry = memoizeOne(getExportTypesRegistryFn); diff --git a/x-pack/legacy/plugins/reporting/server/lib/index.ts b/x-pack/legacy/plugins/reporting/server/lib/index.ts index b11f7bd95d9ef..50d1a276b6b5d 100644 --- a/x-pack/legacy/plugins/reporting/server/lib/index.ts +++ b/x-pack/legacy/plugins/reporting/server/lib/index.ts @@ -4,11 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -export { exportTypesRegistryFactory } from './export_types_registry'; +export { getExportTypesRegistry } from './export_types_registry'; // @ts-ignore untyped module export { checkLicenseFactory } from './check_license'; export { LevelLogger } from './level_logger'; -export { createQueueFactory } from './create_queue'; export { cryptoFactory } from './crypto'; export { oncePerServer } from './once_per_server'; export { runValidations } from './validate'; +export { createQueueFactory } from './create_queue'; +export { enqueueJobFactory } from './enqueue_job'; diff --git a/x-pack/legacy/plugins/reporting/server/routes/generate_from_savedobject_immediate.ts b/x-pack/legacy/plugins/reporting/server/routes/generate_from_savedobject_immediate.ts index 8b0dd1a6e7c4f..bc96c27f64c10 100644 --- a/x-pack/legacy/plugins/reporting/server/routes/generate_from_savedobject_immediate.ts +++ b/x-pack/legacy/plugins/reporting/server/routes/generate_from_savedobject_immediate.ts @@ -10,6 +10,7 @@ import { ServerFacade, RequestFacade, ResponseFacade, + HeadlessChromiumDriverFactory, ReportingResponseToolkit, Logger, JobDocOutputExecuted, @@ -45,8 +46,17 @@ export function registerGenerateCsvFromSavedObjectImmediate( handler: async (request: RequestFacade, h: ReportingResponseToolkit) => { const logger = parentLogger.clone(['savedobject-csv']); const jobParams = getJobParamsFromRequest(request, { isImmediate: true }); + + /* TODO these functions should be made available in the export types registry: + * + * const { createJobFn, executeJobFn } = exportTypesRegistry.getById(CSV_FROM_SAVEDOBJECT_JOB_TYPE) + * + * Calling an execute job factory requires passing a browserDriverFactory option, so we should not call the factory from here + */ const createJobFn = createJobFactory(server); - const executeJobFn = executeJobFactory(server); + const executeJobFn = executeJobFactory(server, { + browserDriverFactory: {} as HeadlessChromiumDriverFactory, + }); const jobDocPayload: JobDocPayloadPanelCsv = await createJobFn( jobParams, request.headers, diff --git a/x-pack/legacy/plugins/reporting/server/routes/generation.ts b/x-pack/legacy/plugins/reporting/server/routes/generation.ts new file mode 100644 index 0000000000000..7bed7bc5773e4 --- /dev/null +++ b/x-pack/legacy/plugins/reporting/server/routes/generation.ts @@ -0,0 +1,83 @@ +/* + * 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 boom from 'boom'; +import { API_BASE_URL } from '../../common/constants'; +import { + ServerFacade, + ExportTypesRegistry, + HeadlessChromiumDriverFactory, + RequestFacade, + ReportingResponseToolkit, + Logger, +} from '../../types'; +import { registerGenerateFromJobParams } from './generate_from_jobparams'; +import { registerGenerateCsvFromSavedObject } from './generate_from_savedobject'; +import { registerGenerateCsvFromSavedObjectImmediate } from './generate_from_savedobject_immediate'; +import { registerLegacy } from './legacy'; +import { createQueueFactory, enqueueJobFactory } from '../lib'; + +export function registerJobGenerationRoutes( + server: ServerFacade, + exportTypesRegistry: ExportTypesRegistry, + browserDriverFactory: HeadlessChromiumDriverFactory, + logger: Logger +) { + const config = server.config(); + const DOWNLOAD_BASE_URL = config.get('server.basePath') + `${API_BASE_URL}/jobs/download`; + // @ts-ignore TODO + const { errors: esErrors } = server.plugins.elasticsearch.getCluster('admin'); + + const esqueue = createQueueFactory(server, { exportTypesRegistry, browserDriverFactory }); + const enqueueJob = enqueueJobFactory(server, { exportTypesRegistry, esqueue }); + + /* + * Generates enqueued job details to use in responses + */ + async function handler( + exportTypeId: string, + jobParams: object, + request: RequestFacade, + h: ReportingResponseToolkit + ) { + const user = request.pre.user; + const headers = request.headers; + + const job = await enqueueJob(logger, exportTypeId, jobParams, user, headers, request); + + // return the queue's job information + const jobJson = job.toJSON(); + + return h + .response({ + path: `${DOWNLOAD_BASE_URL}/${jobJson.id}`, + job: jobJson, + }) + .type('application/json'); + } + + function handleError(exportTypeId: string, err: Error) { + if (err instanceof esErrors['401']) { + return boom.unauthorized(`Sorry, you aren't authenticated`); + } + if (err instanceof esErrors['403']) { + return boom.forbidden(`Sorry, you are not authorized to create ${exportTypeId} reports`); + } + if (err instanceof esErrors['404']) { + return boom.boomify(err, { statusCode: 404 }); + } + return err; + } + + registerGenerateFromJobParams(server, handler, handleError); + registerLegacy(server, handler, handleError); + + // Register beta panel-action download-related API's + if (config.get('xpack.reporting.csv.enablePanelActionDownload')) { + registerGenerateCsvFromSavedObject(server, handler, handleError); + registerGenerateCsvFromSavedObjectImmediate(server, logger); + } +} diff --git a/x-pack/legacy/plugins/reporting/server/routes/index.ts b/x-pack/legacy/plugins/reporting/server/routes/index.ts index c48a37a36812e..da664dcb91ae4 100644 --- a/x-pack/legacy/plugins/reporting/server/routes/index.ts +++ b/x-pack/legacy/plugins/reporting/server/routes/index.ts @@ -4,69 +4,21 @@ * you may not use this file except in compliance with the Elastic License. */ -import boom from 'boom'; -import { API_BASE_URL } from '../../common/constants'; -import { ServerFacade, RequestFacade, ReportingResponseToolkit, Logger } from '../../types'; -import { enqueueJobFactory } from '../lib/enqueue_job'; -import { registerGenerateFromJobParams } from './generate_from_jobparams'; -import { registerGenerateCsvFromSavedObject } from './generate_from_savedobject'; -import { registerGenerateCsvFromSavedObjectImmediate } from './generate_from_savedobject_immediate'; -import { registerJobs } from './jobs'; -import { registerLegacy } from './legacy'; - -export function registerRoutes(server: ServerFacade, logger: Logger) { - const config = server.config(); - const DOWNLOAD_BASE_URL = config.get('server.basePath') + `${API_BASE_URL}/jobs/download`; - // @ts-ignore TODO - const { errors: esErrors } = server.plugins.elasticsearch.getCluster('admin'); - const enqueueJob = enqueueJobFactory(server); - - /* - * Generates enqueued job details to use in responses - */ - async function handler( - exportTypeId: string, - jobParams: object, - request: RequestFacade, - h: ReportingResponseToolkit - ) { - const user = request.pre.user; - const headers = request.headers; - - const job = await enqueueJob(logger, exportTypeId, jobParams, user, headers, request); - - // return the queue's job information - const jobJson = job.toJSON(); - - return h - .response({ - path: `${DOWNLOAD_BASE_URL}/${jobJson.id}`, - job: jobJson, - }) - .type('application/json'); - } - - function handleError(exportTypeId: string, err: Error) { - if (err instanceof esErrors['401']) { - return boom.unauthorized(`Sorry, you aren't authenticated`); - } - if (err instanceof esErrors['403']) { - return boom.forbidden(`Sorry, you are not authorized to create ${exportTypeId} reports`); - } - if (err instanceof esErrors['404']) { - return boom.boomify(err, { statusCode: 404 }); - } - return err; - } - - registerGenerateFromJobParams(server, handler, handleError); - registerLegacy(server, handler, handleError); - - // Register beta panel-action download-related API's - if (config.get('xpack.reporting.csv.enablePanelActionDownload')) { - registerGenerateCsvFromSavedObject(server, handler, handleError); - registerGenerateCsvFromSavedObjectImmediate(server, logger); - } - - registerJobs(server); +import { + ServerFacade, + ExportTypesRegistry, + HeadlessChromiumDriverFactory, + Logger, +} from '../../types'; +import { registerJobGenerationRoutes } from './generation'; +import { registerJobInfoRoutes } from './jobs'; + +export function registerRoutes( + server: ServerFacade, + exportTypesRegistry: ExportTypesRegistry, + browserDriverFactory: HeadlessChromiumDriverFactory, + logger: Logger +) { + registerJobGenerationRoutes(server, exportTypesRegistry, browserDriverFactory, logger); + registerJobInfoRoutes(server, exportTypesRegistry, logger); } diff --git a/x-pack/legacy/plugins/reporting/server/routes/jobs.test.js b/x-pack/legacy/plugins/reporting/server/routes/jobs.test.js index 2d1f48dd790a0..c4d4f6e42c9cb 100644 --- a/x-pack/legacy/plugins/reporting/server/routes/jobs.test.js +++ b/x-pack/legacy/plugins/reporting/server/routes/jobs.test.js @@ -6,8 +6,8 @@ import Hapi from 'hapi'; import { difference, memoize } from 'lodash'; -import { registerJobs } from './jobs'; -import { ExportTypesRegistry } from '../../common/export_types_registry'; +import { registerJobInfoRoutes } from './jobs'; +import { ExportTypesRegistry } from '../lib/export_types_registry'; jest.mock('./lib/authorized_user_pre_routing', () => { return { authorizedUserPreRoutingFactory: () => () => ({}) @@ -19,13 +19,17 @@ jest.mock('./lib/reporting_feature_pre_routing', () => { }; }); - let mockServer; +let exportTypesRegistry; +const mockLogger = { + error: jest.fn(), + debug: jest.fn(), +}; beforeEach(() => { mockServer = new Hapi.Server({ debug: false, port: 8080, routes: { log: { collect: true } } }); mockServer.config = memoize(() => ({ get: jest.fn() })); - const exportTypesRegistry = new ExportTypesRegistry(); + exportTypesRegistry = new ExportTypesRegistry(); exportTypesRegistry.register({ id: 'unencoded', jobType: 'unencodedJobType', @@ -44,9 +48,6 @@ beforeEach(() => { callWithRequest: jest.fn(), callWithInternalUser: jest.fn(), })) - }, - reporting: { - exportTypesRegistry } }; }); @@ -63,7 +64,7 @@ test(`returns 404 if job not found`, async () => { mockServer.plugins.elasticsearch.getCluster('admin') .callWithInternalUser.mockReturnValue(Promise.resolve(getHits())); - registerJobs(mockServer); + registerJobInfoRoutes(mockServer, exportTypesRegistry, mockLogger); const request = { method: 'GET', @@ -79,7 +80,7 @@ test(`returns 401 if not valid job type`, async () => { mockServer.plugins.elasticsearch.getCluster('admin') .callWithInternalUser.mockReturnValue(Promise.resolve(getHits({ jobtype: 'invalidJobType' }))); - registerJobs(mockServer); + registerJobInfoRoutes(mockServer, exportTypesRegistry, mockLogger); const request = { method: 'GET', @@ -91,12 +92,11 @@ test(`returns 401 if not valid job type`, async () => { }); describe(`when job is incomplete`, () => { - const getIncompleteResponse = async () => { mockServer.plugins.elasticsearch.getCluster('admin') .callWithInternalUser.mockReturnValue(Promise.resolve(getHits({ jobtype: 'unencodedJobType', status: 'pending' }))); - registerJobs(mockServer); + registerJobInfoRoutes(mockServer, exportTypesRegistry, mockLogger); const request = { method: 'GET', @@ -133,7 +133,7 @@ describe(`when job is failed`, () => { mockServer.plugins.elasticsearch.getCluster('admin') .callWithInternalUser.mockReturnValue(Promise.resolve(hits)); - registerJobs(mockServer); + registerJobInfoRoutes(mockServer, exportTypesRegistry, mockLogger); const request = { method: 'GET', @@ -178,7 +178,7 @@ describe(`when job is completed`, () => { }); mockServer.plugins.elasticsearch.getCluster('admin').callWithInternalUser.mockReturnValue(Promise.resolve(hits)); - registerJobs(mockServer); + registerJobInfoRoutes(mockServer, exportTypesRegistry, mockLogger); const request = { method: 'GET', diff --git a/x-pack/legacy/plugins/reporting/server/routes/jobs.ts b/x-pack/legacy/plugins/reporting/server/routes/jobs.ts index 71d9f0d3ae13b..fd5014911d262 100644 --- a/x-pack/legacy/plugins/reporting/server/routes/jobs.ts +++ b/x-pack/legacy/plugins/reporting/server/routes/jobs.ts @@ -8,6 +8,8 @@ import boom from 'boom'; import { API_BASE_URL } from '../../common/constants'; import { ServerFacade, + ExportTypesRegistry, + Logger, RequestFacade, ReportingResponseToolkit, JobDocOutput, @@ -24,7 +26,11 @@ import { const MAIN_ENTRY = `${API_BASE_URL}/jobs`; -export function registerJobs(server: ServerFacade) { +export function registerJobInfoRoutes( + server: ServerFacade, + exportTypesRegistry: ExportTypesRegistry, + logger: Logger +) { const jobsQuery = jobsQueryFactory(server); const getRouteConfig = getRouteConfigFactoryManagementPre(server); const getRouteConfigDownload = getRouteConfigFactoryDownloadPre(server); @@ -119,7 +125,7 @@ export function registerJobs(server: ServerFacade) { }); // trigger a download of the output from a job - const jobResponseHandler = jobResponseHandlerFactory(server); + const jobResponseHandler = jobResponseHandlerFactory(server, exportTypesRegistry); server.route({ path: `${MAIN_ENTRY}/download/{docId}`, method: 'GET', @@ -136,13 +142,15 @@ export function registerJobs(server: ServerFacade) { const { statusCode } = response; if (statusCode !== 200) { - const logLevel = statusCode === 500 ? 'error' : 'debug'; - server.log( - [logLevel, 'reporting', 'download'], - `Report ${docId} has non-OK status: [${statusCode}] Reason: [${JSON.stringify( - response.source - )}]` - ); + if (statusCode === 500) { + logger.error(`Report ${docId} has failed: ${JSON.stringify(response.source)}`); + } else { + logger.debug( + `Report ${docId} has non-OK status: [${statusCode}] Reason: [${JSON.stringify( + response.source + )}]` + ); + } } if (!response.isBoom) { diff --git a/x-pack/legacy/plugins/reporting/server/routes/lib/get_document_payload.ts b/x-pack/legacy/plugins/reporting/server/routes/lib/get_document_payload.ts index a69c19c006b61..c3a30f9dda454 100644 --- a/x-pack/legacy/plugins/reporting/server/routes/lib/get_document_payload.ts +++ b/x-pack/legacy/plugins/reporting/server/routes/lib/get_document_payload.ts @@ -9,6 +9,7 @@ import * as _ from 'lodash'; import contentDisposition from 'content-disposition'; import { ServerFacade, + ExportTypesRegistry, ExportTypeDefinition, JobDocExecuted, JobDocOutputExecuted, @@ -40,9 +41,10 @@ const getReportingHeaders = (output: JobDocOutputExecuted, exportType: ExportTyp return metaDataHeaders; }; -export function getDocumentPayloadFactory(server: ServerFacade) { - const exportTypesRegistry = server.plugins.reporting!.exportTypesRegistry; - +export function getDocumentPayloadFactory( + server: ServerFacade, + exportTypesRegistry: ExportTypesRegistry +) { function encodeContent(content: string | null, exportType: ExportTypeType) { switch (exportType.jobContentEncoding) { case 'base64': diff --git a/x-pack/legacy/plugins/reporting/server/routes/lib/job_response_handler.js b/x-pack/legacy/plugins/reporting/server/routes/lib/job_response_handler.js index 758c50816c381..6bc370506a255 100644 --- a/x-pack/legacy/plugins/reporting/server/routes/lib/job_response_handler.js +++ b/x-pack/legacy/plugins/reporting/server/routes/lib/job_response_handler.js @@ -9,9 +9,9 @@ import { jobsQueryFactory } from '../../lib/jobs_query'; import { WHITELISTED_JOB_CONTENT_TYPES } from '../../../common/constants'; import { getDocumentPayloadFactory } from './get_document_payload'; -export function jobResponseHandlerFactory(server) { +export function jobResponseHandlerFactory(server, exportTypesRegistry) { const jobsQuery = jobsQueryFactory(server); - const getDocumentPayload = getDocumentPayloadFactory(server); + const getDocumentPayload = getDocumentPayloadFactory(server, exportTypesRegistry); return function jobResponseHandler(validJobTypes, user, h, params, opts = {}) { const { docId } = params; diff --git a/x-pack/legacy/plugins/reporting/server/usage/get_export_type_handler.js b/x-pack/legacy/plugins/reporting/server/usage/get_export_type_handler.ts similarity index 61% rename from x-pack/legacy/plugins/reporting/server/usage/get_export_type_handler.js rename to x-pack/legacy/plugins/reporting/server/usage/get_export_type_handler.ts index a1949b21aa086..f8913a0dcea6b 100644 --- a/x-pack/legacy/plugins/reporting/server/usage/get_export_type_handler.js +++ b/x-pack/legacy/plugins/reporting/server/usage/get_export_type_handler.ts @@ -4,17 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -import { exportTypesRegistryFactory } from '../lib/export_types_registry'; +import { XPackMainPlugin } from '../../../xpack_main/xpack_main'; +import { ExportTypesRegistry } from '../lib/export_types_registry'; /* * Gets a handle to the Reporting export types registry and returns a few * functions for examining them - * @param {Object} server: Kibana server * @return {Object} export type handler */ -export async function getExportTypesHandler(server) { - const exportTypesRegistry = await exportTypesRegistryFactory(server); - +export function getExportTypesHandler(exportTypesRegistry: ExportTypesRegistry) { return { /* * Based on the X-Pack license and which export types are available, @@ -23,12 +21,17 @@ export async function getExportTypesHandler(server) { * @param {Object} xpackInfo: xpack_main plugin info object * @return {Object} availability of each export type */ - getAvailability(xpackInfo) { - const exportTypesAvailability = {}; + getAvailability(xpackInfo: XPackMainPlugin['info']) { + const exportTypesAvailability: { [exportType: string]: boolean } = {}; const xpackInfoAvailable = xpackInfo && xpackInfo.isAvailable(); - const licenseType = xpackInfo.license.getType(); - for(const exportType of exportTypesRegistry.getAll()) { - exportTypesAvailability[exportType.jobType] = xpackInfoAvailable ? exportType.validLicenses.includes(licenseType) : false; + const licenseType: string | undefined = xpackInfo.license.getType(); + if (!licenseType) { + throw new Error('No license type returned from XPackMainPlugin#info!'); + } + for (const exportType of exportTypesRegistry.getAll()) { + exportTypesAvailability[exportType.jobType] = xpackInfoAvailable + ? exportType.validLicenses.includes(licenseType) + : false; } return exportTypesAvailability; @@ -39,6 +42,6 @@ export async function getExportTypesHandler(server) { */ getNumExportTypes() { return exportTypesRegistry.getSize(); - } + }, }; } diff --git a/x-pack/legacy/plugins/reporting/server/usage/get_reporting_usage.ts b/x-pack/legacy/plugins/reporting/server/usage/get_reporting_usage.ts index 0c85d39ae55d3..bd2d0cb835a79 100644 --- a/x-pack/legacy/plugins/reporting/server/usage/get_reporting_usage.ts +++ b/x-pack/legacy/plugins/reporting/server/usage/get_reporting_usage.ts @@ -5,7 +5,7 @@ */ import { get } from 'lodash'; -import { ServerFacade, ESCallCluster } from '../../types'; +import { ServerFacade, ExportTypesRegistry, ESCallCluster } from '../../types'; import { AggregationBuckets, AggregationResults, @@ -16,7 +16,6 @@ import { RangeStats, } from './types'; import { decorateRangeStats } from './decorate_range_stats'; -// @ts-ignore untyped module import { getExportTypesHandler } from './get_export_type_handler'; const JOB_TYPES_KEY = 'jobTypes'; @@ -101,7 +100,11 @@ async function handleResponse( }; } -export async function getReportingUsage(server: ServerFacade, callCluster: ESCallCluster) { +export async function getReportingUsage( + server: ServerFacade, + callCluster: ESCallCluster, + exportTypesRegistry: ExportTypesRegistry +) { const config = server.config(); const reportingIndex = config.get('xpack.reporting.index'); @@ -138,13 +141,13 @@ export async function getReportingUsage(server: ServerFacade, callCluster: ESCal return callCluster('search', params) .then((response: AggregationResults) => handleResponse(server, response)) - .then(async (usage: RangeStatSets) => { + .then((usage: RangeStatSets) => { // Allow this to explicitly throw an exception if/when this config is deprecated, // because we shouldn't collect browserType in that case! const browserType = config.get('xpack.reporting.capture.browser.type'); const xpackInfo = server.plugins.xpack_main.info; - const exportTypesHandler = await getExportTypesHandler(server); + const exportTypesHandler = getExportTypesHandler(exportTypesRegistry); const availability = exportTypesHandler.getAvailability(xpackInfo) as FeatureAvailabilityMap; const { lastDay, last7Days, ...all } = usage; diff --git a/x-pack/legacy/plugins/reporting/server/usage/reporting_usage_collector.test.js b/x-pack/legacy/plugins/reporting/server/usage/reporting_usage_collector.test.js index f23f679865146..f761f0d2d270b 100644 --- a/x-pack/legacy/plugins/reporting/server/usage/reporting_usage_collector.test.js +++ b/x-pack/legacy/plugins/reporting/server/usage/reporting_usage_collector.test.js @@ -4,8 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ import sinon from 'sinon'; +import { getExportTypesRegistry } from '../lib/export_types_registry'; import { getReportingUsageCollector } from './reporting_usage_collector'; +const exportTypesRegistry = getExportTypesRegistry(); + function getMockUsageCollection() { class MockUsageCollector { constructor(_server, { fetch }) { @@ -40,7 +43,6 @@ function getServerMock(customization) { }, }, }, - expose: () => {}, log: () => {}, config: () => ({ get: key => { @@ -67,8 +69,13 @@ describe('license checks', () => { .returns('basic'); const callClusterMock = jest.fn(() => Promise.resolve(getResponseMock())); const usageCollection = getMockUsageCollection(); - const { fetch: getReportingUsage } = getReportingUsageCollector(usageCollection, serverWithBasicLicenseMock); - usageStats = await getReportingUsage(callClusterMock); + const { fetch: getReportingUsage } = getReportingUsageCollector( + usageCollection, + serverWithBasicLicenseMock, + () => {}, + exportTypesRegistry + ); + usageStats = await getReportingUsage(callClusterMock, exportTypesRegistry); }); test('sets enables to true', async () => { @@ -93,8 +100,13 @@ describe('license checks', () => { .returns('none'); const callClusterMock = jest.fn(() => Promise.resolve(getResponseMock())); const usageCollection = getMockUsageCollection(); - const { fetch: getReportingUsage } = getReportingUsageCollector(usageCollection, serverWithNoLicenseMock); - usageStats = await getReportingUsage(callClusterMock); + const { fetch: getReportingUsage } = getReportingUsageCollector( + usageCollection, + serverWithNoLicenseMock, + () => {}, + exportTypesRegistry + ); + usageStats = await getReportingUsage(callClusterMock, exportTypesRegistry); }); test('sets enables to true', async () => { @@ -121,9 +133,11 @@ describe('license checks', () => { const usageCollection = getMockUsageCollection(); const { fetch: getReportingUsage } = getReportingUsageCollector( usageCollection, - serverWithPlatinumLicenseMock + serverWithPlatinumLicenseMock, + () => {}, + exportTypesRegistry ); - usageStats = await getReportingUsage(callClusterMock); + usageStats = await getReportingUsage(callClusterMock, exportTypesRegistry); }); test('sets enables to true', async () => { @@ -148,8 +162,13 @@ describe('license checks', () => { .returns('basic'); const callClusterMock = jest.fn(() => Promise.resolve({})); const usageCollection = getMockUsageCollection(); - const { fetch: getReportingUsage } = getReportingUsageCollector(usageCollection, serverWithBasicLicenseMock); - usageStats = await getReportingUsage(callClusterMock); + const { fetch: getReportingUsage } = getReportingUsageCollector( + usageCollection, + serverWithBasicLicenseMock, + () => {}, + exportTypesRegistry + ); + usageStats = await getReportingUsage(callClusterMock, exportTypesRegistry); }); test('sets enables to true', async () => { @@ -170,7 +189,12 @@ describe('data modeling', () => { serverWithPlatinumLicenseMock.plugins.xpack_main.info.license.getType = sinon .stub() .returns('platinum'); - ({ fetch: getReportingUsage } = getReportingUsageCollector(usageCollection, serverWithPlatinumLicenseMock)); + ({ fetch: getReportingUsage } = getReportingUsageCollector( + usageCollection, + serverWithPlatinumLicenseMock, + () => {}, + exportTypesRegistry + )); }); test('with normal looking usage data', async () => { @@ -295,6 +319,7 @@ describe('data modeling', () => { }) ) ); + const usageStats = await getReportingUsage(callClusterMock); expect(usageStats).toMatchInlineSnapshot(` Object { diff --git a/x-pack/legacy/plugins/reporting/server/usage/reporting_usage_collector.ts b/x-pack/legacy/plugins/reporting/server/usage/reporting_usage_collector.ts index 0a7ef0a194434..40cf315a78cbb 100644 --- a/x-pack/legacy/plugins/reporting/server/usage/reporting_usage_collector.ts +++ b/x-pack/legacy/plugins/reporting/server/usage/reporting_usage_collector.ts @@ -7,7 +7,7 @@ import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; // @ts-ignore untyped module import { KIBANA_STATS_TYPE_MONITORING } from '../../../monitoring/common/constants'; -import { ServerFacade, ESCallCluster } from '../../types'; +import { ServerFacade, ExportTypesRegistry, ESCallCluster } from '../../types'; import { KIBANA_REPORTING_TYPE } from '../../common/constants'; import { getReportingUsage } from './get_reporting_usage'; import { RangeStats } from './types'; @@ -19,12 +19,14 @@ import { RangeStats } from './types'; export function getReportingUsageCollector( usageCollection: UsageCollectionSetup, server: ServerFacade, - isReady: () => boolean + isReady: () => boolean, + exportTypesRegistry: ExportTypesRegistry ) { return usageCollection.makeUsageCollector({ type: KIBANA_REPORTING_TYPE, isReady, - fetch: (callCluster: ESCallCluster) => getReportingUsage(server, callCluster), + fetch: (callCluster: ESCallCluster) => + getReportingUsage(server, callCluster, exportTypesRegistry), /* * Format the response data into a model for internal upload @@ -49,8 +51,14 @@ export function getReportingUsageCollector( export function registerReportingUsageCollector( usageCollection: UsageCollectionSetup, server: ServerFacade, - isReady: () => boolean + isReady: () => boolean, + exportTypesRegistry: ExportTypesRegistry ) { - const collector = getReportingUsageCollector(usageCollection, server, isReady); + const collector = getReportingUsageCollector( + usageCollection, + server, + isReady, + exportTypesRegistry + ); usageCollection.registerCollector(collector); } diff --git a/x-pack/legacy/plugins/reporting/types.d.ts b/x-pack/legacy/plugins/reporting/types.d.ts index afba9f3e17838..597e9cafdc2a2 100644 --- a/x-pack/legacy/plugins/reporting/types.d.ts +++ b/x-pack/legacy/plugins/reporting/types.d.ts @@ -13,9 +13,12 @@ import { CallCluster, } from '../../../../src/legacy/core_plugins/elasticsearch'; import { CancellationToken } from './common/cancellation_token'; +import { LevelLogger } from './server/lib/level_logger'; import { HeadlessChromiumDriverFactory } from './server/browsers/chromium/driver_factory'; import { BrowserType } from './server/browsers/types'; +export type ReportingPlugin = object; // For Plugin contract + export type Job = EventEmitter & { id: string; toJSON: () => { @@ -23,21 +26,6 @@ export type Job = EventEmitter & { }; }; -export interface ReportingPlugin { - queue: { - addJob: (type: string, payload: PayloadType, options: object) => Job; - }; - // TODO: convert exportTypesRegistry to TS - exportTypesRegistry: { - getById: (id: string) => ExportTypeDefinition; - getAll: () => Array>; - get: ( - callback: (item: ExportTypeDefinition) => boolean - ) => ExportTypeDefinition; - }; - browserDriverFactory: HeadlessChromiumDriverFactory; -} - export interface ReportingConfigOptions { browser: BrowserConfig; poll: { @@ -88,7 +76,6 @@ export type ReportingPluginSpecOptions = Legacy.PluginSpecOptions; export type ServerFacade = Legacy.Server & { plugins: { - reporting?: ReportingPlugin; xpack_main?: XPackMainPlugin & { status?: any; }; @@ -107,6 +94,15 @@ interface ReportingRequest { }; } +export type EnqueueJobFn = ( + parentLogger: LevelLogger, + exportTypeId: string, + jobParams: JobParamsType, + user: string, + headers: Record, + request: RequestFacade +) => Promise; + export type RequestFacade = ReportingRequest & Legacy.Request; export type ResponseFacade = ResponseObject & { @@ -246,6 +242,10 @@ export interface JobDocOutputExecuted { size: number; } +export interface ESQueue { + addJob: (type: string, payload: object, options: object) => Job; +} + export interface ESQueueWorker { on: (event: string, handler: any) => void; } @@ -304,7 +304,12 @@ export interface ESQueueInstance { } export type CreateJobFactory = (server: ServerFacade) => CreateJobFnType; -export type ExecuteJobFactory = (server: ServerFacade) => ExecuteJobFnType; +export type ExecuteJobFactory = ( + server: ServerFacade, + opts: { + browserDriverFactory: HeadlessChromiumDriverFactory; + } +) => ExecuteJobFnType; export interface ExportTypeDefinition< JobParamsType, @@ -322,21 +327,13 @@ export interface ExportTypeDefinition< validLicenses: string[]; } -export interface ExportTypesRegistry { - register: ( - exportTypeDefinition: ExportTypeDefinition< - JobParamsType, - CreateJobFnType, - JobPayloadType, - ExecuteJobFnType - > - ) => void; -} - +export { ExportTypesRegistry } from './server/lib/export_types_registry'; +export { HeadlessChromiumDriver } from './server/browsers/chromium/driver'; +export { HeadlessChromiumDriverFactory } from './server/browsers/chromium/driver_factory'; export { CancellationToken } from './common/cancellation_token'; // Prefer to import this type using: `import { LevelLogger } from 'relative/path/server/lib';` -export { LevelLogger as Logger } from './server/lib/level_logger'; +export { LevelLogger as Logger }; export interface AbsoluteURLFactoryOptions { defaultBasePath: string; From 3bb48e67c046cb0e17808d8d12339a5ffa45b1e2 Mon Sep 17 00:00:00 2001 From: "Christiane (Tina) Heiligers" Date: Wed, 11 Dec 2019 12:18:37 -0700 Subject: [PATCH 20/79] Fixes the link to advanced settings in the telemetry opt-in notice banner (#52699) * Prepends base path to the link to advanced settings in the telemetry opt-in notice banner from all apps --- src/legacy/core_plugins/telemetry/common/constants.ts | 5 +++++ .../__snapshots__/opted_in_notice_banner.test.tsx.snap | 2 +- .../telemetry/public/components/opted_in_notice_banner.tsx | 7 ++++++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/legacy/core_plugins/telemetry/common/constants.ts b/src/legacy/core_plugins/telemetry/common/constants.ts index 7b0c62276f290..7e366676a8565 100644 --- a/src/legacy/core_plugins/telemetry/common/constants.ts +++ b/src/legacy/core_plugins/telemetry/common/constants.ts @@ -70,3 +70,8 @@ export const TELEMETRY_STATS_TYPE = 'telemetry'; * @type {string} */ export const UI_METRIC_USAGE_TYPE = 'ui_metric'; + +/** + * Link to Advanced Settings. + */ +export const PATH_TO_ADVANCED_SETTINGS = 'kibana#/management/kibana/settings'; diff --git a/src/legacy/core_plugins/telemetry/public/components/__snapshots__/opted_in_notice_banner.test.tsx.snap b/src/legacy/core_plugins/telemetry/public/components/__snapshots__/opted_in_notice_banner.test.tsx.snap index 9c26909dc68f1..193205cd394e2 100644 --- a/src/legacy/core_plugins/telemetry/public/components/__snapshots__/opted_in_notice_banner.test.tsx.snap +++ b/src/legacy/core_plugins/telemetry/public/components/__snapshots__/opted_in_notice_banner.test.tsx.snap @@ -10,7 +10,7 @@ exports[`OptInDetailsComponent renders as expected 1`] = ` values={ Object { "disableLink": any; @@ -57,7 +59,10 @@ export class OptedInBanner extends React.PureComponent { ), disableLink: ( - + Date: Wed, 11 Dec 2019 12:39:04 -0700 Subject: [PATCH 21/79] [Maps] fix tooltips for CCS (#52793) --- .../public/layers/sources/es_search_source/es_search_source.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js index 453a1851e47aa..61b0cad40a0a6 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js @@ -405,7 +405,7 @@ export class ESSearchSource extends AbstractESSource { searchSource.setField('size', 1); const query = { language: 'kuery', - query: `_id:"${docId}" and _index:${index}` + query: `_id:"${docId}" and _index:"${index}"` }; searchSource.setField('query', query); searchSource.setField('fields', this._getTooltipPropertyNames()); From 7ba47eebbfa2bd07acb28ea571ac5077181c4e4d Mon Sep 17 00:00:00 2001 From: Spencer Date: Wed, 11 Dec 2019 12:49:15 -0700 Subject: [PATCH 22/79] [euiUtils] fix unnecessary useEffect dep (#52782) --- .eslintrc.js | 6 ------ src/plugins/eui_utils/public/eui_utils.ts | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 367ac892107ab..8762c1dc02d2d 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -131,12 +131,6 @@ module.exports = { 'react-hooks/exhaustive-deps': 'off', }, }, - { - files: ['src/plugins/eui_utils/**/*.{js,ts,tsx}'], - rules: { - 'react-hooks/exhaustive-deps': 'off', - }, - }, { files: ['src/plugins/kibana_react/**/*.{js,ts,tsx}'], rules: { diff --git a/src/plugins/eui_utils/public/eui_utils.ts b/src/plugins/eui_utils/public/eui_utils.ts index 12249bf9eca90..d9c10c34dd4a8 100644 --- a/src/plugins/eui_utils/public/eui_utils.ts +++ b/src/plugins/eui_utils/public/eui_utils.ts @@ -42,7 +42,7 @@ export class EuiUtils { useEffect(() => { const s = getChartsTheme$().subscribe(update); return () => s.unsubscribe(); - }, [false]); + }, []); return value; }; From 9c203613db9c6f5ea85daebf1fa9074e5b853103 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 11 Dec 2019 13:19:20 -0700 Subject: [PATCH 23/79] [Maps] MapEmbeddable setLayerList (#52573) * [Maps] MapEmbeddable setLayerList * review feedback --- .../plugins/maps/public/embeddable/README.md | 98 +++++++++++++++++++ .../maps/public/embeddable/map_embeddable.js | 5 + 2 files changed, 103 insertions(+) diff --git a/x-pack/legacy/plugins/maps/public/embeddable/README.md b/x-pack/legacy/plugins/maps/public/embeddable/README.md index c2952de82c223..82f83f1bfcf4a 100644 --- a/x-pack/legacy/plugins/maps/public/embeddable/README.md +++ b/x-pack/legacy/plugins/maps/public/embeddable/README.md @@ -79,3 +79,101 @@ const eventHandlers = { const mapEmbeddable = await factory.createFromState(state, input, parent, renderTooltipContent, eventHandlers); ``` + + +#### Passing in geospatial data +You can pass geospatial data into the Map embeddable by configuring the layerList parameter with a layer with `GEOJSON_FILE` source. +Geojson sources will not update unless you modify `__featureCollection` property by calling the `setLayerList` method. + +``` +const factory = new MapEmbeddableFactory(); +const state = { + layerList: [ + { + 'id': 'gaxya', + 'label': 'My geospatial data', + 'minZoom': 0, + 'maxZoom': 24, + 'alpha': 1, + 'sourceDescriptor': { + 'id': 'b7486', + 'type': 'GEOJSON_FILE', + '__featureCollection': { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [0, 0], [10, 10], [10, 0], [0, 0] + ] + ] + }, + "properties": { + "name": "null island", + "another_prop": "something else interesting" + } + } + ] + } + }, + 'visible': true, + 'style': { + 'type': 'VECTOR', + 'properties': {} + }, + 'type': 'VECTOR' + } + ], + title: 'my map', +} +const input = { + hideFilterActions: true, + isLayerTOCOpen: false, + openTOCDetails: ['tfi3f', 'edh66'], + mapCenter: { lat: 0.0, lon: 0.0, zoom: 7 } +} +const mapEmbeddable = await factory.createFromState(state, input, parent); + +mapEmbeddable.setLayerList([ + { + 'id': 'gaxya', + 'label': 'My geospatial data', + 'minZoom': 0, + 'maxZoom': 24, + 'alpha': 1, + 'sourceDescriptor': { + 'id': 'b7486', + 'type': 'GEOJSON_FILE', + '__featureCollection': { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [35, 35], [45, 45], [45, 35], [35, 35] + ] + ] + }, + "properties": { + "name": "null island", + "another_prop": "something else interesting" + } + } + ] + } + }, + 'visible': true, + 'style': { + 'type': 'VECTOR', + 'properties': {} + }, + 'type': 'VECTOR' + } +]); +``` diff --git a/x-pack/legacy/plugins/maps/public/embeddable/map_embeddable.js b/x-pack/legacy/plugins/maps/public/embeddable/map_embeddable.js index 18c4c78b96974..2c203ffc8fc63 100644 --- a/x-pack/legacy/plugins/maps/public/embeddable/map_embeddable.js +++ b/x-pack/legacy/plugins/maps/public/embeddable/map_embeddable.js @@ -165,6 +165,11 @@ export class MapEmbeddable extends Embeddable { }); } + async setLayerList(layerList) { + this._layerList = layerList; + return await this._store.dispatch(replaceLayerList(this._layerList)); + } + addFilters = filters => { npStart.plugins.uiActions.executeTriggerActions(APPLY_FILTER_TRIGGER, { embeddable: this, From c6336c384b312e6bbd2894ee96fab4e05218b7ca Mon Sep 17 00:00:00 2001 From: patrykkopycinski Date: Wed, 11 Dec 2019 21:19:35 +0100 Subject: [PATCH 24/79] Bump react-router (#52445) --- package.json | 6 +- packages/kbn-analytics/package.json | 2 +- .../public/components/layouts/no_data.tsx | 38 +++--- .../components/navigation/connected_link.tsx | 24 ++-- .../public/containers/with_url_state.tsx | 28 ++-- .../public/app/app.js | 29 +++-- .../pages/link_to/redirect_to_logs.test.tsx | 3 - .../link_to/redirect_to_node_logs.test.tsx | 6 - .../plugins/remote_clusters/public/app/app.js | 27 ++-- .../plugins/rollup/public/crud_app/app.js | 24 ++-- .../monitor_page_link.test.tsx.snap | 2 - x-pack/package.json | 4 +- yarn.lock | 122 +++++++++--------- 13 files changed, 153 insertions(+), 162 deletions(-) diff --git a/package.json b/package.json index 8c4311a36767e..3403e9649f1b0 100644 --- a/package.json +++ b/package.json @@ -80,6 +80,7 @@ "resolutions": { "**/@types/node": "10.12.27", "**/@types/react": "^16.9.13", + "**/@types/react-router": "^5.1.3", "**/@types/hapi": "^17.0.18", "**/@types/angular": "^1.6.56", "**/typescript": "3.7.2", @@ -230,7 +231,7 @@ "react-monaco-editor": "~0.27.0", "react-redux": "^5.1.2", "react-resize-detector": "^4.2.0", - "react-router-dom": "^4.3.1", + "react-router-dom": "^5.1.2", "react-sizeme": "^2.3.6", "react-use": "^13.10.2", "reactcss": "1.2.3", @@ -344,7 +345,8 @@ "@types/react-dom": "^16.9.4", "@types/react-redux": "^6.0.6", "@types/react-resize-detector": "^4.0.1", - "@types/react-router-dom": "^4.3.1", + "@types/react-router": "^5.1.3", + "@types/react-router-dom": "^5.1.3", "@types/react-virtualized": "^9.18.7", "@types/redux": "^3.6.31", "@types/redux-actions": "^2.2.1", diff --git a/packages/kbn-analytics/package.json b/packages/kbn-analytics/package.json index f59fbf4720835..9eefa16aaca01 100644 --- a/packages/kbn-analytics/package.json +++ b/packages/kbn-analytics/package.json @@ -14,7 +14,7 @@ "kbn:watch": "node scripts/build --source-maps --watch" }, "devDependencies": { - "@babel/cli": "7.5.5", + "@babel/cli": "^7.5.5", "@kbn/dev-utils": "1.0.0", "@kbn/babel-preset": "1.0.0", "typescript": "3.7.2" diff --git a/x-pack/legacy/plugins/beats_management/public/components/layouts/no_data.tsx b/x-pack/legacy/plugins/beats_management/public/components/layouts/no_data.tsx index e525ea4be46e0..8d2edf9c29e9e 100644 --- a/x-pack/legacy/plugins/beats_management/public/components/layouts/no_data.tsx +++ b/x-pack/legacy/plugins/beats_management/public/components/layouts/no_data.tsx @@ -6,29 +6,25 @@ import { EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, EuiPageContent } from '@elastic/eui'; import React from 'react'; -import { withRouter } from 'react-router-dom'; +import { withRouter, RouteComponentProps } from 'react-router-dom'; -interface LayoutProps { +interface LayoutProps extends RouteComponentProps { + children: React.ReactNode; title: string | React.ReactNode; actionSection?: React.ReactNode; - modalClosePath?: string; } -export const NoDataLayout: React.FC = withRouter( - ({ actionSection, title, modalClosePath, children, history }) => { - return ( - - - - {title}} - body={children} - actions={actionSection} - /> - - - - ); - } -) as any; +export const NoDataLayout = withRouter(({ actionSection, title, children }: LayoutProps) => ( + + + + {title}} + body={children} + actions={actionSection} + /> + + + +)); diff --git a/x-pack/legacy/plugins/beats_management/public/components/navigation/connected_link.tsx b/x-pack/legacy/plugins/beats_management/public/components/navigation/connected_link.tsx index 30d12c9ce10de..947e22ee29089 100644 --- a/x-pack/legacy/plugins/beats_management/public/components/navigation/connected_link.tsx +++ b/x-pack/legacy/plugins/beats_management/public/components/navigation/connected_link.tsx @@ -6,22 +6,24 @@ import React from 'react'; import { EuiLink } from '@elastic/eui'; -import { Link, withRouter } from 'react-router-dom'; +import { Link, withRouter, RouteComponentProps } from 'react-router-dom'; -export function ConnectedLinkComponent({ +interface ConnectedLinkComponent extends RouteComponentProps { + location: any; + path: string; + disabled: boolean; + query: any; + [key: string]: any; +} + +export const ConnectedLinkComponent = ({ location, path, query, disabled, children, ...props -}: { - location: any; - path: string; - disabled: boolean; - query: any; - [key: string]: any; -}) { +}: ConnectedLinkComponent) => { if (disabled) { return ; } @@ -36,6 +38,6 @@ export function ConnectedLinkComponent({ className={`euiLink euiLink--primary ${props.className || ''}`} /> ); -} +}; -export const ConnectedLink = withRouter(ConnectedLinkComponent); +export const ConnectedLink = withRouter(ConnectedLinkComponent); diff --git a/x-pack/legacy/plugins/beats_management/public/containers/with_url_state.tsx b/x-pack/legacy/plugins/beats_management/public/containers/with_url_state.tsx index 29581508d2ad5..71e9163fe22e7 100644 --- a/x-pack/legacy/plugins/beats_management/public/containers/with_url_state.tsx +++ b/x-pack/legacy/plugins/beats_management/public/containers/with_url_state.tsx @@ -6,7 +6,7 @@ import { parse, stringify } from 'querystring'; import React from 'react'; -import { withRouter } from 'react-router-dom'; +import { withRouter, RouteComponentProps } from 'react-router-dom'; import { FlatObject } from '../frontend_types'; import { RendererFunction } from '../utils/typed_react'; @@ -22,9 +22,7 @@ export interface URLStateProps { ) => void; urlState: URLState; } -interface ComponentProps { - history: any; - match: any; +interface ComponentProps extends RouteComponentProps { children: RendererFunction>; } @@ -66,8 +64,8 @@ export class WithURLStateComponent extends React.Compon } const search: string = stringify({ - ...(pastState as any), - ...(newState as any), + ...pastState, + ...newState, }); const newLocation = { @@ -86,16 +84,12 @@ export class WithURLStateComponent extends React.Compon }); }; } -export const WithURLState = withRouter(WithURLStateComponent); +export const WithURLState = withRouter(WithURLStateComponent); -export function withUrlState( - UnwrappedComponent: React.ComponentType -): React.FC { - return (origProps: OP) => { - return ( - - {(URLProps: URLStateProps) => } - - ); - }; +export function withUrlState(UnwrappedComponent: React.ComponentType) { + return (origProps: OP) => ( + + {(URLProps: URLStateProps) => } + + ); } diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/app/app.js b/x-pack/legacy/plugins/cross_cluster_replication/public/app/app.js index 37d1305d667bf..5e893b7d9208c 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/public/app/app.js +++ b/x-pack/legacy/plugins/cross_cluster_replication/public/app/app.js @@ -6,7 +6,7 @@ import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; -import { Route, Switch, Redirect } from 'react-router-dom'; +import { Route, Switch, Redirect, withRouter } from 'react-router-dom'; import { fatalError } from 'ui/notify'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -34,15 +34,13 @@ import { FollowerIndexEdit, } from './sections'; -export class App extends Component { - static contextTypes = { - router: PropTypes.shape({ - history: PropTypes.shape({ - push: PropTypes.func.isRequired, - createHref: PropTypes.func.isRequired - }).isRequired - }).isRequired - } +class AppComponent extends Component { + static propTypes = { + history: PropTypes.shape({ + push: PropTypes.func.isRequired, + createHref: PropTypes.func.isRequired, + }).isRequired, + }; constructor(...args) { super(...args); @@ -99,8 +97,13 @@ export class App extends Component { } registerRouter() { - const { router } = this.context; - routing.reactRouter = router; + const { history, location } = this.props; + routing.reactRouter = { + history, + route: { + location, + }, + }; } render() { @@ -196,3 +199,5 @@ export class App extends Component { ); } } + +export const App = withRouter(AppComponent); diff --git a/x-pack/legacy/plugins/infra/public/pages/link_to/redirect_to_logs.test.tsx b/x-pack/legacy/plugins/infra/public/pages/link_to/redirect_to_logs.test.tsx index 0506cde60bb66..a800b6421c027 100644 --- a/x-pack/legacy/plugins/infra/public/pages/link_to/redirect_to_logs.test.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/link_to/redirect_to_logs.test.tsx @@ -19,7 +19,6 @@ describe('RedirectToLogs component', () => { expect(component).toMatchInlineSnapshot(` `); @@ -34,7 +33,6 @@ describe('RedirectToLogs component', () => { expect(component).toMatchInlineSnapshot(` `); @@ -47,7 +45,6 @@ describe('RedirectToLogs component', () => { expect(component).toMatchInlineSnapshot(` `); diff --git a/x-pack/legacy/plugins/infra/public/pages/link_to/redirect_to_node_logs.test.tsx b/x-pack/legacy/plugins/infra/public/pages/link_to/redirect_to_node_logs.test.tsx index 7a63406bb419a..5fa80c8efee73 100644 --- a/x-pack/legacy/plugins/infra/public/pages/link_to/redirect_to_node_logs.test.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/link_to/redirect_to_node_logs.test.tsx @@ -35,7 +35,6 @@ describe('RedirectToNodeLogs component', () => { expect(component).toMatchInlineSnapshot(` `); @@ -48,7 +47,6 @@ describe('RedirectToNodeLogs component', () => { expect(component).toMatchInlineSnapshot(` `); @@ -61,7 +59,6 @@ describe('RedirectToNodeLogs component', () => { expect(component).toMatchInlineSnapshot(` `); @@ -76,7 +73,6 @@ describe('RedirectToNodeLogs component', () => { expect(component).toMatchInlineSnapshot(` `); @@ -93,7 +89,6 @@ describe('RedirectToNodeLogs component', () => { expect(component).toMatchInlineSnapshot(` `); @@ -108,7 +103,6 @@ describe('RedirectToNodeLogs component', () => { expect(component).toMatchInlineSnapshot(` `); diff --git a/x-pack/legacy/plugins/remote_clusters/public/app/app.js b/x-pack/legacy/plugins/remote_clusters/public/app/app.js index 6fea66ad03c9c..483b2f5b97e27 100644 --- a/x-pack/legacy/plugins/remote_clusters/public/app/app.js +++ b/x-pack/legacy/plugins/remote_clusters/public/app/app.js @@ -6,21 +6,19 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import { Switch, Route, Redirect } from 'react-router-dom'; +import { Switch, Route, Redirect, withRouter } from 'react-router-dom'; import { CRUD_APP_BASE_PATH, UIM_APP_LOAD } from './constants'; import { registerRouter, setUserHasLeftApp, trackUiMetric, METRIC_TYPE } from './services'; import { RemoteClusterList, RemoteClusterAdd, RemoteClusterEdit } from './sections'; -export class App extends Component { - static contextTypes = { - router: PropTypes.shape({ - history: PropTypes.shape({ - push: PropTypes.func.isRequired, - createHref: PropTypes.func.isRequired - }).isRequired - }).isRequired - } +class AppComponent extends Component { + static propTypes = { + history: PropTypes.shape({ + push: PropTypes.func.isRequired, + createHref: PropTypes.func.isRequired, + }).isRequired, + }; constructor(...args) { super(...args); @@ -29,8 +27,11 @@ export class App extends Component { registerRouter() { // Share the router with the app without requiring React or context. - const { router } = this.context; - registerRouter(router); + const { history, location } = this.props; + registerRouter({ + history, + route: { location }, + }); } componentDidMount() { @@ -56,3 +57,5 @@ export class App extends Component { ); } } + +export const App = withRouter(AppComponent); diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/app.js b/x-pack/legacy/plugins/rollup/public/crud_app/app.js index 0e42194097492..c9f67afd830ec 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/app.js +++ b/x-pack/legacy/plugins/rollup/public/crud_app/app.js @@ -6,22 +6,20 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import { HashRouter, Switch, Route, Redirect } from 'react-router-dom'; +import { HashRouter, Switch, Route, Redirect, withRouter } from 'react-router-dom'; import { UIM_APP_LOAD } from '../../common'; import { CRUD_APP_BASE_PATH } from './constants'; import { registerRouter, setUserHasLeftApp, trackUiMetric, METRIC_TYPE } from './services'; import { JobList, JobCreate } from './sections'; -class ShareRouter extends Component { - static contextTypes = { - router: PropTypes.shape({ - history: PropTypes.shape({ - push: PropTypes.func.isRequired, - createHref: PropTypes.func.isRequired - }).isRequired - }).isRequired - } +class ShareRouterComponent extends Component { + static propTypes = { + history: PropTypes.shape({ + push: PropTypes.func.isRequired, + createHref: PropTypes.func.isRequired, + }).isRequired, + }; constructor(...args) { super(...args); @@ -30,8 +28,8 @@ class ShareRouter extends Component { registerRouter() { // Share the router with the app without requiring React or context. - const { router } = this.context; - registerRouter(router); + const { history } = this.props; + registerRouter({ history }); } render() { @@ -39,6 +37,8 @@ class ShareRouter extends Component { } } +const ShareRouter = withRouter(ShareRouterComponent); + export class App extends Component { // eslint-disable-line react/no-multi-comp componentDidMount() { trackUiMetric(METRIC_TYPE.LOADED, UIM_APP_LOAD); diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/__tests__/__snapshots__/monitor_page_link.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/__tests__/__snapshots__/monitor_page_link.test.tsx.snap index e52977749142d..376f1aa54f532 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/__tests__/__snapshots__/monitor_page_link.test.tsx.snap +++ b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_list/__tests__/__snapshots__/monitor_page_link.test.tsx.snap @@ -4,7 +4,6 @@ exports[`MonitorPageLink component renders a help link when link parameters pres @@ -14,7 +13,6 @@ exports[`MonitorPageLink component renders the link properly 1`] = ` diff --git a/x-pack/package.json b/x-pack/package.json index a92839eadefa4..4f806c6252f3f 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -91,7 +91,7 @@ "@types/react": "^16.9.11", "@types/react-dom": "^16.9.4", "@types/react-redux": "^6.0.6", - "@types/react-router-dom": "^4.3.1", + "@types/react-router-dom": "^5.1.3", "@types/react-sticky": "^6.0.3", "@types/react-test-renderer": "^16.9.1", "@types/recompose": "^0.30.6", @@ -302,7 +302,7 @@ "react-portal": "^3.2.0", "react-redux": "^5.1.2", "react-reverse-portal": "^1.0.4", - "react-router-dom": "^4.3.1", + "react-router-dom": "^5.1.2", "react-shortcuts": "^2.0.0", "react-sticky": "^6.0.3", "react-syntax-highlighter": "^5.7.0", diff --git a/yarn.lock b/yarn.lock index cfef1bec7e6a0..39551aeb5fb68 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,7 +2,7 @@ # yarn lockfile v1 -"@babel/cli@7.5.5", "@babel/cli@^7.5.5": +"@babel/cli@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.5.5.tgz#bdb6d9169e93e241a08f5f7b0265195bf38ef5ec" integrity sha512-UHI+7pHv/tk9g6WXQKYz+kmXTI77YtuY3vqC59KIqcoWEjsJJSG6rAxKaLsgj3LDyadsPrCB929gVOKM6Hui0w== @@ -1005,24 +1005,17 @@ dependencies: regenerator-runtime "^0.12.0" -"@babel/runtime@7.5.5", "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5": +"@babel/runtime@7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.5.5.tgz#74fba56d35efbeca444091c7850ccd494fd2f132" integrity sha512-28QvEGyQyNkB0/m2B4FU7IEZGK2NUrcMtT6BZEFALTguLk+AUT6ofsHtPk5QyjAdUkpMJ+/Em+quwz4HOt30AQ== dependencies: regenerator-runtime "^0.13.2" -"@babel/runtime@^7.4.4", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2": - version "7.7.2" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.7.2.tgz#111a78002a5c25fc8e3361bedc9529c696b85a6a" - integrity sha512-JONRbXbTXc9WQE2mAZd1p0Z3DZ/6vaQIkgYMSTP3KjRCyd7rCZCcfhCyX+YjwcKxcZ82UrxbRD358bpExNgrjw== - dependencies: - regenerator-runtime "^0.13.2" - -"@babel/runtime@^7.5.1", "@babel/runtime@^7.5.4", "@babel/runtime@^7.6.0", "@babel/runtime@^7.6.2": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.7.4.tgz#b23a856751e4bf099262f867767889c0e3fe175b" - integrity sha512-r24eVUUr0QqNZa+qrImUk8fn5SPhHq+IfYvIoIMg0do3GdK9sMdiLKP3GYVVaxpPKORgm8KRKaNTEhAjgIpLMw== +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.1", "@babel/runtime@^7.5.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.6.2", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2": + version "7.7.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.7.6.tgz#d18c511121aff1b4f2cd1d452f1bac9601dd830f" + integrity sha512-BWAJxpNVa0QlE5gZdWjSxXtemZyZ9RmrmVozxt3NUXeZhVIJ5ANyqmMc0JDrivBZyxUuQvFxlvH4OWWOogGfUw== dependencies: regenerator-runtime "^0.13.2" @@ -3859,19 +3852,19 @@ dependencies: "@types/react" "*" -"@types/react-router-dom@^4.3.1": - version "4.3.1" - resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-4.3.1.tgz#71fe2918f8f60474a891520def40a63997dafe04" - integrity sha512-GbztJAScOmQ/7RsQfO4cd55RuH1W4g6V1gDW3j4riLlt+8yxYLqqsiMzmyuXBLzdFmDtX/uU2Bpcm0cmudv44A== +"@types/react-router-dom@^5.1.3": + version "5.1.3" + resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.1.3.tgz#b5d28e7850bd274d944c0fbbe5d57e6b30d71196" + integrity sha512-pCq7AkOvjE65jkGS5fQwQhvUp4+4PVD9g39gXLZViP2UqFiFzsEpB3PKf0O6mdbKsewSK8N14/eegisa/0CwnA== dependencies: "@types/history" "*" "@types/react" "*" "@types/react-router" "*" -"@types/react-router@*": - version "4.0.32" - resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-4.0.32.tgz#501529e3d7aa7d5c738d339367e1a7dd5338b2a7" - integrity sha512-VLQSifCIKCTpfMFrJN/nO5a45LduB6qSMkO9ASbcGdCHiDwJnrLNzk91Q895yG0qWY7RqT2jR16giBRpRG1HQw== +"@types/react-router@*", "@types/react-router@^5.1.3": + version "5.1.3" + resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.3.tgz#7c7ca717399af64d8733d8cb338dd43641b96f2d" + integrity sha512-0gGhmerBqN8CzlnDmSgGNun3tuZFXerUclWkqEhozdLaJtfcJRUTGkKaEKk+/MpHd1KDS1+o2zb/3PkBUiv2qQ== dependencies: "@types/history" "*" "@types/react" "*" @@ -14855,17 +14848,6 @@ history@^3.0.0: query-string "^4.2.2" warning "^3.0.0" -history@^4.7.2: - version "4.7.2" - resolved "https://registry.yarnpkg.com/history/-/history-4.7.2.tgz#22b5c7f31633c5b8021c7f4a8a954ac139ee8d5b" - integrity sha512-1zkBRWW6XweO0NBcjiphtVJVsIQ+SXF29z9DVkceeaSLVMFXHool+fdCZD4spDCfZJCILPILc3bm7Bc+HRi0nA== - dependencies: - invariant "^2.2.1" - loose-envify "^1.2.0" - resolve-pathname "^2.2.0" - value-equal "^0.4.0" - warning "^3.0.0" - hjson@3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/hjson/-/hjson-3.2.0.tgz#76203ea69bc1c7c88422b48402cc34df8ff8de0e" @@ -14912,6 +14894,13 @@ hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.3.0: dependencies: react-is "^16.7.0" +hoist-non-react-statics@^3.1.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#101685d3aff3b23ea213163f6e8e12f4f111e19f" + integrity sha512-wbg3bpgA/ZqWrZuMOeJi8+SKMhr7X9TesL/rXMjTzh0p0JUBo3II8DHboYbuIXWRlttrUFxwcu/5kygrCw8fJw== + dependencies: + react-is "^16.7.0" + homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" @@ -19395,6 +19384,15 @@ min-indent@^1.0.0: resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.0.tgz#cfc45c37e9ec0d8f0a0ec3dd4ef7f7c3abe39256" integrity sha1-z8RcN+nsDY8KDsPdTvf3w6vjklY= +mini-create-react-context@^0.3.0: + version "0.3.2" + resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.3.2.tgz#79fc598f283dd623da8e088b05db8cddab250189" + integrity sha512-2v+OeetEyliMt5VHMXsBhABoJ0/M4RCe7fatd/fBy6SMiKazUSEt3gxxypfnk2SHMkdBYvorHRoQxuGoiwbzAw== + dependencies: + "@babel/runtime" "^7.4.0" + gud "^1.0.0" + tiny-warning "^1.0.2" + mini-css-extract-plugin@0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.8.0.tgz#81d41ec4fe58c713a96ad7c723cdb2d0bd4d70e1" @@ -23450,23 +23448,40 @@ react-reverse-portal@^1.0.4: resolved "https://registry.yarnpkg.com/react-reverse-portal/-/react-reverse-portal-1.0.4.tgz#d127d2c9147549b25c4959aba1802eca4b144cd4" integrity sha512-WESex/wSjxHwdG7M0uwPNkdQXaLauXNHi4INQiRybmFIXVzAqgf/Ak2OzJ4MLf4UuCD/IzEwJOkML2SxnnontA== -react-router-dom@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-4.3.1.tgz#4c2619fc24c4fa87c9fd18f4fb4a43fe63fbd5c6" - integrity sha512-c/MlywfxDdCp7EnB7YfPMOfMD3tOtIjrQlj/CKfNMBxdmpJP8xcz5P/UAFn3JbnQCNUxsHyVVqllF9LhgVyFCA== +react-router-dom@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.1.2.tgz#06701b834352f44d37fbb6311f870f84c76b9c18" + integrity sha512-7BPHAaIwWpZS074UKaw1FjVdZBSVWEk8IuDXdB+OkLb8vd/WRQIpA4ag9WQk61aEfQs47wHyjWUoUGGZxpQXew== dependencies: - history "^4.7.2" - invariant "^2.2.4" + "@babel/runtime" "^7.1.2" + history "^4.9.0" loose-envify "^1.3.1" - prop-types "^15.6.1" - react-router "^4.3.1" - warning "^4.0.1" + prop-types "^15.6.2" + react-router "5.1.2" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" react-router-redux@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/react-router-redux/-/react-router-redux-4.0.8.tgz#227403596b5151e182377dab835b5d45f0f8054e" integrity sha1-InQDWWtRUeGCN32rg1tdRfD4BU4= +react-router@5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.1.2.tgz#6ea51d789cb36a6be1ba5f7c0d48dd9e817d3418" + integrity sha512-yjEuMFy1ONK246B+rsa0cUam5OeAQ8pyclRDgpxuSCrAlJ1qN9uZ5IgyKC7gQg0w8OM50NXHEegPh/ks9YuR2A== + dependencies: + "@babel/runtime" "^7.1.2" + history "^4.9.0" + hoist-non-react-statics "^3.1.0" + loose-envify "^1.3.1" + mini-create-react-context "^0.3.0" + path-to-regexp "^1.7.0" + prop-types "^15.6.2" + react-is "^16.6.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + react-router@^3.2.0: version "3.2.1" resolved "https://registry.yarnpkg.com/react-router/-/react-router-3.2.1.tgz#b9a3279962bdfbe684c8bd0482b81ef288f0f244" @@ -23480,19 +23495,6 @@ react-router@^3.2.0: prop-types "^15.5.6" warning "^3.0.0" -react-router@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-4.3.1.tgz#aada4aef14c809cb2e686b05cee4742234506c4e" - integrity sha512-yrvL8AogDh2X42Dt9iknk4wF4V8bWREPirFfS9gLU1huk6qK41sg7Z/1S81jjTrGHxa3B8R3J6xIkDAA6CVarg== - dependencies: - history "^4.7.2" - hoist-non-react-statics "^2.5.0" - invariant "^2.2.4" - loose-envify "^1.3.1" - path-to-regexp "^1.7.0" - prop-types "^15.6.1" - warning "^4.0.1" - react-select@^3.0.0: version "3.0.8" resolved "https://registry.yarnpkg.com/react-select/-/react-select-3.0.8.tgz#06ff764e29db843bcec439ef13e196865242e0c1" @@ -27516,6 +27518,11 @@ tiny-warning@^1.0.0: resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.2.tgz#1dfae771ee1a04396bdfde27a3adcebc6b648b28" integrity sha512-rru86D9CpQRLvsFG5XFdy0KdLAvjdQDyZCsRcuu60WtzFylDM3eAWSxEVz5kzL2Gp544XiUvPbVKtOA/txLi9Q== +tiny-warning@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" + integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== + tinycolor2@1.4.1, tinycolor2@^1.0.0, tinycolor2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8" @@ -29817,13 +29824,6 @@ warning@^3.0.0: dependencies: loose-envify "^1.0.0" -warning@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.2.tgz#aa6876480872116fa3e11d434b0d0d8d91e44607" - integrity sha512-wbTp09q/9C+jJn4KKJfJfoS6VleK/Dti0yqWSm6KMvJ4MRCXFQNapHuJXutJIrWV0Cf4AhTdeIe4qdKHR1+Hug== - dependencies: - loose-envify "^1.0.0" - warning@^4.0.2: version "4.0.3" resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" From 7a1db7f23bec638ccd0034a7ff15be77b372b378 Mon Sep 17 00:00:00 2001 From: Melori Arellano Date: Wed, 11 Dec 2019 13:22:45 -0700 Subject: [PATCH 25/79] [DOCS]Clarify that by default server.host only allows local connections (#52802) * [DOCS]Clarify that by default server.host only allows local connections * Update docs/setup/access.asciidoc Co-Authored-By: gchaps <33642766+gchaps@users.noreply.github.com> * Update docs/setup/settings.asciidoc Co-Authored-By: gchaps <33642766+gchaps@users.noreply.github.com> * Update docs/setup/settings.asciidoc Co-Authored-By: gchaps <33642766+gchaps@users.noreply.github.com> --- docs/images/kibana-status-page-7_5_0.png | Bin 0 -> 95607 bytes docs/images/kibana-status-page.png | Bin 254446 -> 0 bytes docs/setup/access.asciidoc | 9 +++--- docs/setup/settings.asciidoc | 34 +++++++++++------------ 4 files changed, 21 insertions(+), 22 deletions(-) create mode 100644 docs/images/kibana-status-page-7_5_0.png delete mode 100644 docs/images/kibana-status-page.png diff --git a/docs/images/kibana-status-page-7_5_0.png b/docs/images/kibana-status-page-7_5_0.png new file mode 100644 index 0000000000000000000000000000000000000000..2dac4c3f94c351a0f95511c3e8248f7cea5c8a69 GIT binary patch literal 95607 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 XzONS{Sv>A=;E%L~{F72K!+`$-F|a-A literal 0 HcmV?d00001 diff --git a/docs/images/kibana-status-page.png b/docs/images/kibana-status-page.png deleted file mode 100644 index b269dbd3573039fbeb5ae269b604a07d5e57a004..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 254446 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

M1B&AN0s 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

a@u6z3}hK7gh;2Q!0|NB>c#j$w^2rQv2 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

FPw3O&8 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

BE7oQF`? z2F#VPSg1$nk&q&)0+$F@!~tU5QVf}O0JnA$?z*fGctIkkCBzKDP%`F2Z*cW*}1{0zyn8BGbcB2@vUC;7j>(d%$4mOE7PL z5A=^Th>XKj#Pm9}AbdyZB7@_$ z%8D9ldj(t#k>E|CF>L$T&+4j$FWO5DC}GK@i|k}u3|iR0$oG2fy_}oSTMq4ab#=`x z9PBk0f)5hsA=Q+ZBVTHRMOA=(=Jh*4jHLkK68~~BMxrjmvuOYrs00acpuMey-024F zb;51P`k-m+<7OKok4GcJ<%BOpa~6l%2)@CO04E%_`*s;={yD6ySzK>3 z3X5D%M;ov@r0J;R#T^D^eMU&(o`2@cW!`FG5z>Nn^?GC;0q!r|XzduLgoP9RJus)n z4b)KmJD_`Ws#!%_f2Iw`Q8Nw-dS>R)3C)kn$&RoMAf*;Kp=vs-S^gT*9rM@g=eeR} z9>xEVIu3x~Y{pzf0*@m?NbknGOClL*l$R8~rmc`=`wqqMd~&1d?4~7r0GCcUmSsHN zmh_1coN(c1@shx2wBl+K;WO$H&lXNd6gan@c@f9UIB+&tq}i?r!JTYl>;)16Kv~K( zpu$vwVRm5MpKx!ka?-!G0f80XLHoA#!W|kXE9ssQah%N{#;f=jM05)Uk7@RG0Bq%x z_#g!c*|4QOu%xS{sOVS4bA^$}??pt~ zV#4}yK9RW#cn}yr^#)tCOwQkvoB>~)uM$eEuh0a6F+k}KP6uY^`5T1H05gg$S$pB~ zTeba_IC3F(QR7mHRoMSaX-E{QIps<=%)M6>8t>vTvuurZQ$Ae*!mmYABFY63>0S@Y%D zz&Rv_O}N$jWk9CC*Yy_vJfV3^c2|Rdt}5vpK%N5BmgGf%x`>+AWb)sFWdT*&>hnMz zvGMqwPQY7*$S95H>lTr*ki$lrvNu^co=zBY0b>5f_X6_QIHI!kS0XhD^b%e5*RhU_ zU|foXI%vGZvQ|7A3*s7bS)T?D1_JZ`rJ>BFUiUd+YM%@#t#Rukr#6-&^V2Ai2k-J8 ziPsBKoI_w+Ws#4g7cnCY8+}_Xsm6)!nj~4sONRiL9m(Pl68aEBmkGfd1_kFZQJJE| zDeuEsqPJr(j|oc-IXKwpOcohLtpx@8AILp&R{9|q=-<3GFW2b(dhUWSgf#uQ zM}B`oHId6oux~?%&862GK&#?_Opvr#0B%EzPR9ptQSk%ti4Q|gEYm=8P;0QEnkACS zMYC~WVOao&;IzEn5GhlBW0+74Sh`3e2ca;krQ24C$?WT-zj5__yFDtjlm*T55SVP? z*&R1}N>=HLvqUNzKHu>UD zZtm_^XP331w+Le$+{lXmi|YL!)Ry}Gh#oobK;ENuga3syy5~fl649rVch~jVoCNIV z_PsXmucU{rDR749|8d@to&{v>ZI1(ee6EPm(9qb-^*Q6fnu4#L!Cb_W#Ns$DRG2I{ z9%aeA-z+?LO=&~oWOuc=*t z=`4j)4QGPfKER^85lQKoMfjirNO^%0Q3Ac$+2vH7&_;D@Yb_@v zu>!d&7eg#b4f@7G#y|-h2kn0xBtN9VrhUYgW^VsNGT-@-r9JObxU;FKJI~JDb%yRX z6YF6IO>xp-)zg0S$e~Y5x??q^&)MgWxOBVUKECz%##I+f73EXmwsqp{Mf0lQjfXWF zsjK)H*-y7+`Vh^=|HfKfhwJR z@1ll^3cuwK{@S8Pti}a!?CmFu^Af zhl}rh41)U_-PVSmiO^jcHmNkLa5UTmTg3|}Lf@ldEHYr=1%@qm{5XUOLnj_V%A>_c zwSFjY7w?so(B`~j?)Dwc{>@r&CKiL^;r2j!fW98acndUujL)NBj!RjWN+Bj)yHi13dhze1pwWfhRINi-2nvIhbKZ#Qy5PB$rJ>HFOH@^8)X!7y>zpj&dCwlVA!$t2R&emD(z zvhSe(K@3LTz~?BSHAMvxx*qazN?zU5#gc{yj6ziQKp0$J*LeXf0`1G`UNT@)Zn-4H z+`Tt?F8e#hynG%v?#JM07soR7MqOdMSNW&qVf%4e{pNb`^w`goGsWmL%5=nGaCH0@Hju$wH2i%43T!RDDjw@3ilqD3 z%RgC`p9QjoJ02b$Wka~iJ1~HSg$Al2w{PFRQN@17xXtx2gn<#yxRj#~lDOVeQ>U82 ziSs4j>izuL4chpRZ~~W)Z{EhIw-!}8kJG#zH2w|7)9y8f&+pNJ7hr z>yd(YE_X+uPgOrKv!Jp*Bg{9(0EBl=S5Xz%AkF>tV%PSEBI)W?l~1m>V0*dgG*3Z# zR>%3UOaa23{<8fdv!?*%yq?0)B#fI>72_7OQjq}}n*J`{3l3j+3OcCipR=Du4|dL+ z5C$3n6g#;(6X1%*Cv*J($xDKQf|&SJiU^3WXbx4y%GIlv*D2XSy(2-<++ES$p8xJ) zZluyBS@l&f%y)1OKis*(iqu!3&BzC{_&NRHCpQqcp~e zZueSEX3@Cpos?r`o7_5dWGwh~&HBckp@yxgEdi>Fqw+L5 zdtk^!%y*$Whe6*5_*ZOOjcVk!ff+N;*Y0I6k)L~XK2%SX*3t^8Cp{RY=w9+nq1@x9JaB}O$jk}qXwTrc= zJ?JsPElPo{#zcmlNqlJ1@HD1e$L0Cwn#%)+sbtxGz_+3fHr6@$`IqL;a|M=GRK&`) zo#-*TI2$Gh5W1oOr{e&_Bb?nFu?Z|&9Ru~VGD6LM6N5Cto9gl$jBU1 zx2okXD4`JipF^o~ph^=iZg_3=j*l_NBy>>#Bo7g`$rJ}nlf~ev*H9i%2Dyxh0f3x$ zx>#+*(VY>>@nt9JJa&oQ@nDEtS;DSGV!QvE@^2A z&`v%4BkRv$csNc9n|qV~fBv})G0rekeICW(DvFSZ2!@EpOCBx7ESxK+OH1BdJ{{lO ziziMu(9+nL{=xdpzr10gF~Z!xE7M0T;Z^rqemDA7>9;<{K6QBVmPOb>U}x(nvlKSK-f;0<(-1KO+@IF~ksDYbBIRSwbFa|X55YWSN{ zUJ~bA#5P~2pdzyXA0LHb9oY@Vx}a;;pt?cwvy6wa=-nfy4{Bc0``DKS`NDqbQ_({E z?8x5+Yd9V5FPB18LbaSB9xgkuWDV=3|O23`f z0cyoj??k4o(>EL-lQJprx7};nRlpXoZvFZ#lV}TI0G?2WNxK-$Z~;`rEp!M|to8)s znG)m2)nPk|l3{s4|C2V{pB~J~hGPtWoH>1(M^qbAS+7V#9H67>ok6L3;`FKR;+se~DHIrnO(Sy2 z7MLQ*0;W0M(ca$v^%j^JflHbg^FU^)O|6H;yYY=nz&^`XS1%p<{d{bQRV*F`p1}b4 z;6QRHJaqwo;{0hlqfVm@<6zT{Z7y7oGN5cupEN-a*cH~*6k`88`oW(iw#k+z@E|@H zrQ*KbyD7Ncf+EgH>I`b5Llk1^7?#0t%P6&%G?3oL(V9MRh>dL>&A_5oeUsy4m*;yP1(LYM${57f_i8b#utOu?_PwWS;*oO_P)7!t=J^>k|b=+{Z)MG z>U>ci5QAU1PH%LKA|>kJoLdneEd{ZK35`q{IZ61S`ee*^<}Ud5$76%hxzozZTVXPW zI>oIUU49y@v!C5aD25pW-OXo9FMiKYmC{~5l8ust5HtlYb{J=|@6e$QC?a~@uOGAB zRE*4WzgD!)J$=C0k0DM(;CO@q7!ZW$g13Eq#7yhYFKAs4$!WL2#xrb9+YfNG4!j4{ zzEp6DSW87!g3jKP);({AYI?D*$c-Rv zgg2tcK`wHx76Q&t52g&3jC=O&TY=1O8aaelO*<+OIb$2A@(8jIs+IYVoyrVESB@GRI~`j>VQ^IY0w|_%_frkD;-G$#c2SRv?k7jETXbqFKKzPuA6Kp$iNI@d^?n z-eED6Smk&OSo4H-Z8MhEYxt-UkA4urE1=d|2F%)pSk3ESZ;IK&eCouB%P4ut{e`0q zsB>2pZO6>FV+{D7&yy3C<9Sg&Mp(oBGmHc+4!VV>bHBy(m8vRPOz#a3ONUcSp;HJ# zVz<`t^eHNpC4`*g5XoS+gbn2-j*)lDX4q-js`eOR;v0USdZ2k}cj)8C_dx0bVWNki zrm)PB-N^ZjXejC|xUI&x=+%H4y#a3-kH+BOU=Jo{b^(EA){Q!bP(lu(d#Oynv$NBy zYXt?5>QqqH)3mr*Mf4ne%EMO18s+*32NDW}_=kcP;}1gOs0;W+n&CDD^V*jIp^?Tp zjr0N{HLvA29DrwRb+2CTg6_H%?EbRGqJn~35u)}VtvPjV3t8W|iZI+-X6A?BUl5T} zB;BJ~hYQ(8(|5~kh6x861?@1V3WHCBOd1h`h@5lX%OQ@FYNQh%L&HuhE}Mp+*o%GR zAn;XYtf2WXI3M+*iDy?_tLScmJ1P8oy+w5U?NuLV613jyN zU_ftF}*&Q7SydC9Q=noH>_ zxezf%a(lHU63qu=Vy?Mje@8!2A#A&y%}gKk;d=)IOB#NUM5tF$xqy)?B{pqWi_Y-3F4r**B$UWo`XJXq#3O zK=`ZhJlv9#lUuC|&Qso@* zH>YkdM+hSmdHiLbnp;|y0@B|Xf^D+{ARPuN@QdncVyqOHpmChY&q3N?6oOOaPnBIA zfJ-pTIaNseLg*^-OP4Mgx2CNk%{HypnB%hxyWTZFKfi1N*iFQ{%y2}|UP#;yw+q5? zI~ArWUE1AZOl1J@ps0aWgBt3YSBl!=( zOBlChtiwpp)SQP8hJVMg%Kk)>k|lN|<#1L+{iLmEKtbhwR23*GH*MK+2Ot9Rd4-YZ z+v;jp$#9p%#6$2DCbnP)^uM9}gS8SF8MBFxO=DTP{PE+%DSef{EEen|48%mn=$DfxXJvI5yw$2>42SD!Hz>8ja+W0N zDC6<9PolpOP|l^e{;}?2T4cUtR0Q^eePmXWws(3uKQ0IZ(B%P|?d=Y2$XF)@4t5)| zl!`hswdT1(pwnYPaZJ1eMx$QfqWov*s?yr85G-K07HyQmx+6!juXN{QzwA4Ba1G=J zoLRk(dIrkc+VVQQN$nWIjNZU9bnIaUCk0;|-#|!Mn7*~PvZCU+w6vRQIYM6VqvDf^ z`!L}MWhKVfnBTa;HZgZj>GwzFpZ%ty)^E+1O1sTCTFFFZ3TvasSJ1!-*(|sQaPl-1 zAW`?qPy*+Re!!ee-0i#SiRB16?3_HG5G7LEyn4iDWd-ml-UUpS&8817%FDYDXKoiR zp)1#f4p=G~JuvzB{(RPbiD6;h?D@Wo@2BjYcV(U>bAZu?^b$w%H#BYC-}4fB)#{ot z;9#Ua6P*a1y80?*WN=BGb!dEt@=DgRtm9bY{wknLWD7mfOjE}GI7;me!~k<|9T$Cm zwEr{QVQ}bb^~G<4bX2Zur7#FA`>lPZ`XL;`ltCwrt3!)RGa!CnKQaaJb{k{SD#U;c zaD4Bq!oyL8YiotPqT(V7w9A)wBgJ{-^mHk_@y9P;s?P5t;BEcIrh%)!!7_v0XBq+wJflzj z9mC2e68=Hz{{{D6@E_0UznU-|K%ULNy_A@!ssHT<7$k{eB&Yeem!keW)7<#QOo;@ZfBQN4gQ6?XfB*3JyYjz%Llp17 ztOH!LiH`0rM7BV{C9LP7>kR=_v~K?^j>eRbF*PWJF;uA>SUhs(m%ft!@g1hPuWHiM z@clp4y?I!Vd)xN?Gh1O9BO+6gBqU@WB1$NgLPh2x8c3nRP*D*n$&`>(lqsdr)SyTq zAxV-VQ;E{}e7+XfdhX}Bw|Cp#f8OnW+pgsl+n;XJ?RG3>{F>^nUgqdt5d(=#)- zAzTVZFZ`|n>9H2^WV$}hSN^(AxGn1@Hg!L&1fb5qG}|&7IeT|{Eap}sHojyJt#mXry=ZDLa(-vRsPJcNaw<3ns zl6{&jm|elz?MZ>SlNXoe{OPsA#r-zeGVGh`%1O?d~_a0)fi5+@EBPiC!>dpwDWDHb?S;tM`%;i=zW57)@E2uK!2eHy8;If9JrZUIs6dH?qH?CTyafv zW{<7exWPlN9eME0cUXGcp+wMgO`=gZ`dAArIMStY`xz`ruSz%9E@m_drU%Cn+E8<` z?Bno>;T7GTW|+q}F65Dkj#u=I6&bzZ9Pfywqw#PAkHI;{}-;Gdt}Qp z3bLv-R5Ee1#=V?k%yOHxZZG319E{?;Y(zUt&LJUhP&;l!{$sVsTX1vs?A^PAT80+; zG6Q%xWcNSTg5P+F>f?LBs$<9Dv^mIi>9P}4z2XL!aX6OD&2bgyTn@kxiYjnuMJ>DZ zI|t6%)I$xMM$rPHkI_=niN^}Qk~yDSB0Qr8j2~ZnxrHuIPt(G`n(B8JMya%xm^`TI zW7=ze%D2t66Dw;0?{*1sgO)oE z1Omq@DbLcJkmseKSsf(Hn4)(3tT=~3-)UcOa5UMBQxi(m2;dM{ji_4Gl{7^G7p9VtOc%{+LuiK_iFAOhWdaz$JbJBhYJpFzlbfu+h zx^-{v3d+1^YDdWhBr)z9x?fv73@;3&lbA#23FjwY`67fYZXpmP^~)BI%YMJLkY;o@ zH=bR!G-~_)c46^-9Zyih`^w*X@uJt$r%wqa!l0Vbbp`AL&!0GBFMS{0-v7GNfPXWp zq4Rtv3r{{%5xc(Ac#ef(9FfJGh+roq6?HKAzzAimI9r8qM>`jVwm@=cKOvNMyE|T%}^??qb z06sNo{kd0sBkwH3MTs8Zo$B@MMcB6hTHO_W$fr;Hi2Qfb(n8ZW3*$bRmg?JnD07ubDE%p9pM>p#@ho%! zmLHkZbn?rK=yqZnm-eB&yd89gGmg04WV4}sXtNkw(Pj!GRcKv?Z(->56+pHaeOGmxH!Z2qMccMK4?twt(?T=`&J;bX0#G5WSqo56 zl+?-#7ZIJp!|%JfRqZ!f>Ur*SvrE1iW4vD_ySRwC3ZAkc>etkRrUy@@k3@Vzz}u3W z5Y9YKojSF=&Y9of%S;2TR8>{QBy|^sd=X>=4d4R&iFOSLNGA6|2iOg3m4sAYlDrm33YIeN-k*I{D$|0lIG_1+0jpupR>3&Uw=@pZ?$`_p+IU!Otx2%D!`7 zo?mUl>krE0G;8l(*PczdU}|q+0~{LUEJbvLk=U!1d;3s}=*0+$KK~fU49Si3&>DuR z1}rQ+hXJ&;Ecv#PoIQ7LIfQSA(i2pFein%i2|;bC0<D{R~n$Jh0TO14OLyCTkZir?By0CF)b6c)HllyhOEf7+q`)uy~SN;9y?{z zxNg8n*PnG~Fh`}eQgxDoLaU|QD_TiTabF<>bbV}VXD4jlp%pwkpNK70Fk6)nhs47# z%yPW@Ob`>7J^S~k^03wnfIUMbmSb{xT`~fIQo)8cRc^1%8R8k2j=#hcX59B@L?L@-enlHUipm(J%7!b z@MRf`o2y$CAHMDcmV9ApvK)`(=)cBu6!?NNoO*&inDuGBpop)N;ezau@}VkPwe0sa zoWGO}seWQ4V{2_Kk*t4}uqfdj4qNbn1qTEI_JErl?j1XKHt*a;@j-2~ZjNae%*#%H z^{FX+7&KO@9oqA~ckI~VKmh<8-hX;)iEvb61*bRHtV=!v`d)t8A@?pVaeoY)KHLoC zb2?941$+_a!^Zz^b?%kf2o*JfwfaFLLI)gN* zKPe-3!RYMAsm5uiNB*arGak#C|bnz9UpZD}eg?kVHKAGc0Y)9Nj~h zmi9mB`{;`X)bqCO-ap)ijSnv+?`~d4?mQ3}xR-H&Y@YymEzKS~saDanYC*0MW>=Jh z5?7>Y>fy69s5+aoP1rNqn6YC5Ub<2kgE5iN>@N>SMZ7!B@OXJ0SAsfDO=_cXUgCP* zCj0J%3fn>g+oOYIP;mc-153ES=uvkm7p1!xzKn?#c0)j0XLt?LNh?V|7WJ<+h-k%~ z(#&+&w(Sn&7oDbIkJhTiqWrMdhnlW?>FE0Qg9Zt$Q@gn{>TWtp|DL?Sd78?Fi|gm8MX4xXOMkOz!m(au&p#freg04!7TqyM=4%Nw zV)Eediq)3{6cja`-hd9ip&j`(Vybmk4QvlVTlGW4hX@}rq?h(+QNSOD_L= z!uOn1dFpTFK}Z;B{d#J}K(WgvtT!t(>WHAfs4x5X@0Y$ZrB-U}R(MV+L!%M~oQ$!` z@6N`25C5%9h?cCBIi<+QB?QcZb(OLXVB^l3ASZXe5Ue5yV!g?dWUeCMFKNB5+m z=h#U@L)0E;31?}RCexVud`0WEstz|qOFIccZ`&uK==$^EcR<2e3$AQWEYp2`<8EPnp z?DjEPt#82Nj;Hk=%xk;8vTyo@x7|zU*9?w(b}4&mVTg6~MqQPhH`h>V?3|Am-(x0qsNfJXhlEk)I)^9IRp z_xBu?`nJtl`T}up7!ayTWDG;X#O0+-XmzTc3A%E(*2WQ7?x>uY=va9$MiAW3TsqKL zgHnKL=K~q(>8=YSMjw^y(`O&U{}seoa?;f!hmRc_D%YlE%OedHO;kIh!uy>KP2M#g zBH!9=gF1X{($Ex-+9DVF_pfZxd3|&E_HOQ(_ne#6eFLHit}SW`tu5Vl_2X!-Wr}%k z#3rB2w6r#y-9Z}e)F>UH=y!ieF);V=Mb0I&+!i!LhZ+#`7>L=yUy|5=XsRh{PHw#= zN7QXj-`mE<$zI`uDWS_3g-Igsj|yu2P8Hf$J_He9OxzohnEfj-@*+SHi8w4 zadXO<2qCU>Q5BPqGtLK+k`t|qntn_{gy8JPZL*q5fLFEQI+g zwuUjW7fe(hhlIcK{_QW(=>`s-UGB*J)La+50bi+BkvRld9PKu&4~oj*2=RC_Dav@9jF% zM=nO%(^UdwJ2aa;V@B0R>(`Ig%#PdgvMl;o^?dWvpB?8;M|!aP;-u~4*jpA8b4FiP zL@Ao?RN}?3cY#w}l5#p-=UNDTrm}cEIrBcoHPqMNt#*St;HNavBysEJiPbOd!2COX zr}Yvh9VdOD;43PxeAYx%2}*HZMP=-;K_%Up1}|qU3(*pmK(jReH99u<%iw5#m_I!s zA1Ke;2-c1NXt1uLHR~q3Jv@#zOiQ@%{KbpgP+6qhrq}B(W%1rJtaPfs!X?=k(xCr3O@} zo|D{!VDp>HHy$3MC8;QGil4g1Vav9K3lFzVgFD!sak6UMu0Gj@D^yM33CPjrdHDPL zw_X0Tre;t7XxAn;Up5@97FdOyIyLp}e{WWa)=(BHc|In~ZmpsD;mX`cfaQ9{8`Pak#wF++~b| zv*dM_rCZ1LyE9>3W<$%xONwEAiGCe;)0LSUnRvF2D7@dKc%|4i=<0}NcdqoEwK9Lt3C*>fITK-@WZOPUIuA!A zh}=`6G3Z{A;nkrk1qJKuYaeVIeEHk$O%8F_W`2xTIGjAePs5li^EccIN-KB9#r9ub z4V(T#Z1QaTHnph#TuSi8AMKx5M&Gkepwj+BRo?BKuNwIAVBMVmmU}G$oVo1M>Lj^YZ z;e*o7@$Qd<{0N#wV0|Kd3qlWcB1xQitT5xae{^&^L48zjZ!~i}IQgrs<-^Y85yx|q zoVE$nh;B^`FP{s(i{Rtn&rFqenhH|P%b=or^E}C#?iN~s2Myy`!8#Zixae&XTEWL! z7D%q4is%$*GusR=*~^374Pj_1H{>QPS90(GL{RI!Z*Nl!mE+_P(^POh!mb(cs0 z1%0SwrVl#QUqxkJRmq*(w==FyAM!8i!6L>tuiWcqh+OoOXw8^r5D8eve+0?peaYzc z23m+Qbc7F*0*$$ugaL*i5_-R53UG_gU(WH!waUmW{1x<-jW0=PdhT+wzOp3YX+=yC zR5F^@VHLFiwIeovFtBMB3@Rgfi+i1x!icJY9}?s_hFmFFRKWYM3HajiV=a3~R+H?; zgdIy=8l(xxK8eHjY3jcnVgD{`@F`hmu}}BrJDKViW&DP^Kdlo_{n1IOY{m<>aqyj1 z5<%rzD@SJrpX(HF+`W1YEQUeBA->m(xY;nt_nIeG6&;~&oW{)h+Y;vSVy|2|==kyW zph)nVcD0!~S|~yr%&ueXkiv2xVEK~)9#YNvWewA<3|}tVWgmDs8wFzbal3#Bf%7Df zm3~3ktyQ)5n?0Cv>+`p!%QC&LoK3hr{atM_tfHGlh0fB_tw=EQC;x0Y=dki+nR=^N z3FF|$8-;&qA(~3_VDV)}jL1IU@pR5wYY?9S9#a>F8NjQEt}zW)hb3P2Dsch=aMthc z_k<~R2c{g@f9HlYK$^=H|Ds!l0~Y#Qtnre10F30>_a1V425%&KS`l{LjG`6c_fM1? zvtEY5_egqM@$5Z|-!dGbk4EDy-xqcx1h$tMApu>Q$@-eZB#vOOedq3$-+S;Ng_5-Yc4X9=zd`+1b}?3&xIK_+Q};|xw?(<5 zn6Rfi9g_cxL%Q6QN>T$19@w*)WNlt#AH=I3xX<}dmtnBi;ONi?zc}8D<+d&(V*kVO z9)4QZeVB5?Gc(RB$9j=T8p;hL7&uAdEGJUeYwGHDVgR#~&ZYYVwOfzVpFZslyd+&` zM)7^syzd;1Q4ovT0W!Hp#vQnE$!}rAu!>6y-0$f5r)^uS1#4sk2caV2Y>|&IoXmif zY}6Fj%uu}h6)IYF;qsGouz^nV$qP2X)dQvsc-5|S-pjbn5e8}bWVwn(jl4`sIm5H%>OMqLl)r;rni>Ul|E=vfp@he7#&k+; zn2D!v`+{A-x>y*To6`Qv@w|?OYd+Tt&bX^e%d=BHzoCG*MSpqRG zfajSt|5{ux=75e$e|X=|od58?y?5qAQg`@6{MK|y^U_z}O*3m{p9Bth^rDKqRu@(l zT1@RxIS#j^6f0C}yprM-AT^#YbgC-T6I_)y?)&+!?nnMjiAsUm-y`5<*&RH5cy(nh zDNH=%62_$pDjvhNe9zB2y)fePe>mV}pI_bnf5!puwjrl)G4ShsGn4cBq5IqBnItn@E7N=h&^e#Ycu z;%0|VX{xo-oH?_ICv8w^H8i8{rGj&=X&wUuhRxW%Fs0#ApUn9QFxN6v?5)(64LlTX z27;LeEH42xdOy55QLbT$zr0%2+1t~%venS7nK^O&7bW~l{QpG>Kcnqko77cu)#*7b zI2}5vH?{4Pdkiy)?Zi-hb=^t6&yXML>|!E}(pn-&jnjtAnw2)dYZ+N#H%kQlgA#B;v-h+)aqYHO-jQJA1;yO)gFAAp|Y6}!2-JJ7#az#6$x>&{w* z(JbTg>3cKo*QDtbBOS3(^X)UOCHtM8KRXN^&2+mnWsC+xYNk5YsFk3i-jN#Sdh8@E z-)ywOC2{Q*6QjCXT|=-y3=BJST~O&QW{xrHudN;ACK|Vo7fbS--&Tw!Zo+%E<|s4U zTLEWGX8a~aL2hSA-PEvR#VR+5na#4@E>TxlTwBU7+#xn1Bk3y8RT_iapvx_$8l5O( ztls%CYXWTt4-QprN?>0MXi$V8xbh4jaw~}RX75?9T)US;U z9Dcza5za5U-sW)wp4m7!2k5d32bnIbeEsVCY9x|#r- z6knR+s#u{8*#IPD8h3%?d5Q5u0)}uios-#Un}PV`vmXo$y`KuMDRb1oi@GcKJDa-m z*r$BG@t+(t!@%(mCw)~@2inVJ#L$_4=jf|Tii(SOK}i%{jl>o5<&ldEilGi%?&Tw| zHAus*XI4bhw8f5W%;7Q|Q`^gX}08sRr-8;@O=9q!@$hRLqdIMz0 z^!Y+ZFr%gn*>bidx;%!$=!P!t^544#64RRgW5zsPSs-p9|NQ<2+UB@2q#&PV0kWp3 z0o$)Hh?7v|?AD91#bWeA;82*nkrgvdczHVSpp)EzEb}0F8T_tQW&anoy{cj1 zKFwXk71k{k$TbJ#|6(Y1oBbw=#{QC2x6IJa!G*o+7!z8-NycreOVLMy8f5VJ}!TVCb zYJSp~7y7UP2sl$rVUPy7V8gZhXkG*_2)p~^`(r7O{hmh`9!YxR1C=$W+}&`8#B{WL z;(xOF;_p;}3OnE8N z!>ZdlPS{koY>Z!UDFb@uzP(5UBQ2)*WaQ*@7952cGj>0B`kWWlSL}~w?JK%GkKsCC z>gv3Fq{ak~Uf`*QC#y7;ixD2$a|S>4l>EhR6S6nMUszH)=VbR_i-Y#YOG_4A>|5}> zhsiBv);kh;Brs9grd>oTmSXingsm9qGmWTm@WctLD{|D(gln;LBG5FZsd9BMmsoyz z$0$PbCPX*vLR11FVqsp1$KS20V}7j^>GgFx>-Gc5EPfzhY{20lBW-vCLV* zrJUBDe{gkR&NcfjEu(AVUf!AR?y`~mvcYCDS4d7yrM5L}`&gWbj%--B&g%~kKE?XV z{}T;fv3AS5+U^XeM07+cMN= z#Suz(@7}!yBbF3OAn3N}qE?e!0gxSd#x6EV0nVRSzoDxTgg)r`iHS}JOLHGJu42}> zdC7~IM@b%T0T1rq-~FqZ?!)UHKXGF2^x-}O$B*wt!hw*G#&#n#;tp%odeI8qgw_K? zcPjgDbFMuEBAq>VF0VQXvNCG!{dcZ-CsG?iH>@`JibBXM_z+Vruc9cCIFQa;^wLAj zRpLwGZ}Zvjx3*|6_$6n2Cg0{fTUN!v!9jR(52&R`-Na4RqmfZ&h9@~O2ag0oEQSZRPgZ&S)t~7kJt2%HgaG|xmy*n!naIwPbN@^RGPen+O zigQT{{x|U`d{zG$SgAW?jsalNX`+n8v+v~dYS_*jZ`4xs*A|tDWCYTdUgrI$ZrO4v z$=8#C;(z$|Etf7WTwZEpYuns)L93PUQb_UoAGe2$i%R*lbdk6{qu0-$89gj|vFV%F znvlMrJSm$=1bnl6fyIlf(b3U*Dd*oDZ%Y30c}mi|xTfNoZ|m(=-&vVD=%?NQ&4GTp zSFUJje;YU|vcIYPS;dR7WpTAdYmAcLD(Nr%@J=cqXyy!s>2GJbd#!g?3tS(#Yn;9&nCq0_Ci6bL0j8MN!cDl3-*F%XB=DoMcdF`yByYou-9b$V@RKIwli2mOzmcguoE++ClAIJ zUSM2s?lp?ivA1X=Cq%FV0Lfva6D{u-*ENb$_1oE;hU`W2vr@m?KNMUPwR)28oh}H zbv$CbzGve<$3@(ai6Z-k#66bdJ@e9FII6L@R9wN(HB#MaAZ zKa6N8#mjfljtJCMQq`7%wd7JUd516Z6@KA_8N2Le63Ijzd;9CcmzcL2igOY)qfv*^ zI*R}d+|=dwM>AMfGC3Mmw~SBMQCI<<(k5Egg4)SzQT%Jqo^2iPOz;zB`niD-uj%OV z{ywuH@#&)IS-x;=qRQ>_!t`emTZE)4T8MsN`UZ({$I(<|zJ8kg1gLNG&*xzvVgLE% z`!0h5&QcN6-|3nD5s+4jwe2f|3zJwv5qdecKSQqFTlolPS16kM78H#LkgA=#kdcug zT+oDJ0&W2d(7k-^{mpvIOB)Xsy@#=8g^Ipeb@j#<*TRyT8n-n-HxRBc06jx7xuT0h zv7bLQ8&x!PlKz_3pX<=^U3qzg7{&mw=+B$CpNg#;hlzABzRmB;)YwwzZ;v~Ahc}L} zd)%Pn6O`!EHSv$$ z^-PK1Z~o6G=WiVTF070mXYhY~f%MH$Bc7l+w3Qj>zdv%t0dt!ajq)|z{{Q&>|3A1% z4l|aOfl}(?K-LYpU7ntR_)nSl?qTEB@c2hEo>Z6|ouXU%Ak0E+ZEZKqmMwAP!Kaj~ zDHMmYWI7MGP;};(g#35Lg9jn{zwf~7`B`aQ?JGe_z!!aa5E->)=@WX)wGxGE6+^^f5!OuMm+{O1S&GQmAxrRKh&dkbs3TfW|`0)#% z_Gqi7qn*HGq)TIk-ekdoppDGogt5^|G{K<=njI>(rI`@EI6%yLJXFH7h88TGf&$H; zBEx8q+Ys8owLHz*T3QF?g_9lcrbp?EO77jI*a^G_WY(a*JnS?7md{*N+Jp@NE;y$d zj2f0*oVCp zgo{hB#I~C>bm$zGMD-y1A|Lqb)hm>U_sKcF?Tj3Cs>5W$y^u`I4c2JGknxM>ryzuy zp%1j$Imu|-4vV7OZYox<*+!#H5{)u+KZ^PH#lQ-Sk zM|v9ue^iGIj@olchrc=r-B@2CMBQ%{Ll=ADXahEJ9^k3&==BqUfkLR1ZF9o~uUbWN zrj!s*<(8=UJAxr^=2$fpHZ=r2Wwj8YTd1ti-)0Ks$^0L9rKwrJzPawzU}l$(Xdk@O z#6^P3tDr^d&SiKe%+s}f&&@j#j;Qxk!~m7->x5n?WsCd}C>{(X7jnuJw76QrQl4x& z7>`xjWed~+j-SVZ;;)YlPGMu@9F2T8y{*!8D{S;#{KWCXlTX}z131pA&8Lw=MQI~^ zKX_s(l)P(5&b6emyM37N1vv{p!`{1X!!( z%Yha6&_HGR62tAaU=RD=KM`VsXvWSnkVuqb>&^Rze(5+rZ^x6|kPVO5k0F)_yG!T= z92-nnFVo0w^fr{YfEgwonW4L3gUaAPhuh(Z?NakHSjSHQUL$#!-$%xOUI5)Pso}>G zVG77I8z3(<@EPYXWc6TgK4J#(0;)$BSc}d9=bkzht$FjF(()>3aduC29+Ccqr?3_? z$M2v5IErMVD9M!B2m;6)nNnuOOdk$0GZB6`tZ`t?2LO_=?C!IL}@cHw52zpd2FJ9MGDl91VjTwyO%ZmR}Se_Ox3LDU%VnL@4_y zA9ph<#u%g-gW)aUzf~yWpqyS7o)yTvx!h}bQZ`@SkQX@PgJ1Kaa69>A&iIg#BlUc} zR~R4h_HIviGtZZ5Y7$JMtdbkxsom9AqfsryxA)tSK*UEQCMgkLctW2Hi+Q==bs}8d zC_bguBcW|d@g;3Mm|(NOtR%R;^e4wySkMr-b zxCdTl{ zTO(lQijHPLVXB+s{;Bs?k|-AvO}&o0+Y>J^ z#hQIE=#O24q-55OzuS{xgtR=s^Fk7LRUt;82qY+8dIheohC0r`bY0&cr4NpUGUv?1 zNPD4vz(H5WbB)8q@rMf#8lxgvRI^!Lu z4pG37%tT>=8!c5&_wmEl^SHfv^TyjUfSWyV1l7&2pAwTB2!~^Z_^Z+ME`?(YOMEPy zuqcc;48CWv+9LROKl13j`lmTcmHQU~RWxmWv1;iXYK%e!W%m91;q#_6YLq?(z6YHf zf38`vh+;<=c~X?5J3M3=CDSsx`;pU1O;?0+^Ft;S#>`8EO##Mm69=|cg>C`Y^tQsL zw-8aTEX}I6Uf9vM^4u}sN~MH}mFWXDxBZN$fKy%$b1=1-D0${X4l!z<(oC_#@Hw&C zEWj%L3r*CR+JWlo#y%4(_lR4`2F96vq;N|@=hn9eXL&mH?(???6O;4MUmrO{GU4Fp z9t1+aNU+lO?fi6z72!HSg_syag)o{iwUDO&^kli{ONC@nT2^)DQt81>j&H5iv9ejS z+YQD|Zp_A|^!XpaBZO8jw!z{bvRD>Sz4-ESH=BAhr|*Wv4ngeJkk>b~m<_137*fxM z8ztREAL)zmz?9xNNnC|bicyYR)8MGc3G^7ZGx*YH)wLfs(R<>;;*E$ z_}y-t5qtzhKTB0|&oWwR^5mqOV_@z-KYx2IcF0Vxrl)1Y?jCbnkmPNbT>jH#>n7D0 zTz6P3T@$<(+xl>Pw=ff#nWOI@X2Q35Zj~U?9K__lVTexTs02J znejSkTy4rT-Qxctk?Si`Am!LChYi?q!V*1-LbLpkDBBzW`i)h@H6J=@@9$q?i~rUV zvhr0VRbj^Y;YD-=IMrxE?4+M>4{a#S$KVlEg#>bl&cx*Q3`j0#M}7*FZy@NowRS%) zRJlPeWb=FCUBs7ue_~6eN@YStsw|MfmghfCi-ikKV_^cvrhxTdd)_8T2-P<6ZkL-6 z4v0X7Mrcqo)&TXLmt0@zmG9I5lT3KqYAql#7&1B;kUxo{ZDfcsX<#%WKLJy72w~r; zoRmnasLouisHc_kZjhVkaLFcb3%Bp&)(=AlDvPSPEXt)J0(fLIl<{Kq(vA~=DD;uQ z0z%2A!P;u->;mot)vnQ^?xjuRywbOC%OE(X)E0;(!hLC~)pQZhRw|!g=#TXT>a7#=cp1j=nywNkAR<&c54}B8Za-W6n zl51;=RQI##m4~#o&-5w7@1~~y^0xm+!WtcmGS#Gnqc*V*R@;Sr9LJi(J~-*ml1MXg z-nWMLU;)X%L6}cS0}R?rl?uN0lxm2@>9T*YEJ=xmTkW7NB7G#e3a3Z{g79(D^3Amz zeJ(amj%Sa=JaEWx8CziV8_E9kyck?%6@HhQ z(JSwDxyZ5*H%R4D!)IsvP!eY^u)@rlQl*nq@7|Tkzl5a<$Y!?}S=1#o&c(L9=MFjq zo96;BQ?dF6Kp*1iH%Mj)nRFjErk(Ujy>iv+%XMbu}n3vTc18w6U}be zhU9-2?l;Ay$@L|}joJsTT(zp_6hygV6Fb=vfIhJAWB)z|<2;!ycBRQ*ukrp=EORoB zjkkgp9uB1fGO+-PNK`ipVrZna9&s(bg}wgK??b>OM7Dxv*Th!^YSmtq2TXZKn>6T+AF}#U_~q6$m!pluXJ>IEva8lu;!s7b~xeRF;!N`b}AUG0?4 zWb(y&Hrw}To*gDEhN6u8bcL15FtHJu^c1%PD(DTNtz#E%X<7)1DGIN%3Gdr^E_i0J zBEZ82O(w7Jub64SpnR7X2D20ho8w=t@R_u_{`izr`U^0f9tdx@)TS^QlK?a5bjOKucqea;SVi0an1gXzOd*$nHS zkT?Xp1t3EoAVV093v(3Jr-9=)hr{jssQP(vg2UyJSsz$F%fF6X-U{#GqehJ?a6YH_ zUj1c}wcr4Zl

2vfA?kn{;5=;hVP0b?v%hq8ZNHJ2vw$tT2eCH3{WIr)psd|LaG3 zs#~D%{rvnT0yo&?NF|NanIa8BUzd74$QrRKhBH}$mS(@iD`ok1J(n9WpNi*HJ&G&d zKOy66^EnobffSLQqtVMHD$$$+y`DkuTidrHY66#Q!>&2=VhZe!vG?Y8@}$|v;v+7L zBgCtV-Avsg0pTo(Y5a2gu_#~HW}jNn>YRY6k+Q|jSASuIA#4DfFlB!%=UY0;@th2J zxFi&Wy#P@5MS|m19&}XFqBvG-88mS!{PR6Ee5+{dX8S@5Fr=s{b}V%kwpl`~J_-il z=-Z>1Qw+(T@9R0b#As2yinKtqGS*K}iFyQX9~so!!_;G*OR4?yjca1oR*Lcf8{lbv@(ra^n)K-L zyg${@zwY}EmTh{Wc(rO^6;qJ4gqqayEuUVjdimF6d=9=7kEhn8|2*mDc1_fq{kr)d zJ!+{l*9JmMu_Jz@24et&9*mBdym_Fhk43ITax=QvN;Sgffrp=i<%#@~C}e1o4;~ji z&zL??pV(A&A*4^fXvZ1(9)+WesW37H;mk9%9Hj@~T)sqW0n>G<-8p|i@sfatK{lbD z;nw=y>G-0T-D)mMw&*;w$J{MZ!GTZ;7ZFkQR!)~8{140B#*%5hduw$%?(Zy`$4<JTnAm-YJbWXON!c z23ZcFP^RGW6PCB8#2-cbW1LT6v;+(CG^NK3s#1Tyu_vCApGVUH5wqqJONM@Zk$J~3 z>zC#=lMmCZ6NN5K1vNKtT~2+-5isi0dT52q)SsU(4fm2-oE1Jt;l^zH#HJ<=RHR(o zzQ=z-!N*Yycm5Eef7&jgFJ#fk3gNd0ca$tE}vjwT3#s zPx92C`sPVFSe-L-;y~NQ*J~~;yisy^Nfo?nBI-0>F$zqilu{{&RyChRzv*G2T6Xhp zY##WL*DD#2g3^SztpOHYK%$YPbsst}adk|7W|cZiFAIR8HU(DiMTP`6=P7`L=b!AY zo?n?M?7Vma^b*(LhN80L_!~>oGdhjIEWUoAJ9;^a*c_6_borIK^UqM@p>se6Qw?^`oZGe3TKyVU zD3KSg@-_nV|( z?;s5g4X;TJx{Vesr0TA)b!tTEG5p%T`}cM5)iPXQ*6Ik$Cwfk`ReC@aSRuy@oi|t4 zEcRHJ3{2(d4N{BYpvO9W0s@INHa)MNHqzxtNNn0=&?L=PCxE-(QxoTfB#YA~Yz2K` z+4UC*1CgLz^1^am#oRxlh@m6TQqNL7S|jg%hMcv1&IoFssi2j5A)~(%_Px@WF$=|W z!~~P7sPTK03wF`ETnCnPo&eAF)8dhSoH;ysdx4TYbJj4XE57o;)!?Raro)E}(SnKL zdzS6>Zbx=r96>vhIx~S{q1UvC%!d{1In2&zM-yCdG?}u*uZ6;29SZhbI^fsitB_x= za9|@}bM`D>(bbUN=J4U z;x@&SGo`#l{)j8nKJTKy!wD(@52cuvQf&@24VyMs?6{%gDD7GlgMRJJZ7DmrV{S&EOot+E>jA zViY6WV=)iF9JPWO05c-*vMR0-qM({(5BT+fa}`0ZrhIwgpuz3CUU|IU=tM6%po`NBl`yiZd9yg9U03xMT~ZD< z%_~3@do2hjxV5m%hR=N#2*QG?`2c41DQ#U4J`K^_jfgnDrz+OMvhh z0}EE9IYBz+#-N6LcFvkhp9Q;k!f>@qv>nPV$SbYodP0be+Qk1AAcEk>3oJ;qj+!!I zl;N5(_m~yXzz6tk$*ZN}-#3PEDh#beU(2JJi^9)$UZU5IBarSsu&bhWmSTfR?iRji*g1~yk($VV4v;?U6%=F<;89%5?NFqo7p zm@bs#L$riVUB0#kIo)lc>&QTzR_A7CBu9R0_miyg;N+ww0^npIrdu{fIyzCo^dbEd z@piOQKhsFcu&poztI#Z%oe^>F8k_T4j^@In>3y(=+ycU@7+-_j3EXyVC?{0Z_nWkb zl>QiZN6S7w@ow7X^GR*nw$0|-_Z?__h;E9|6K|SV@MK*`Ny1|RD5cu*QFWObYUjR! z$a?{)jvLt}Oq23xY2Q_v0Mx^e87K%#WY+OpJ|8#RUNKW}Qep}-Pw#)=pEV7OH~fS| z9%0)smU3rK`rsy;I;J}%#l^LSPyK7-NDEt$?(vTQGNtb0sDKGgC)kUyFfid_mUxX) zySBBd&~N+dh_jWQyJt*s-skBl%soZ-$Ien2Xi@+hyf_pJ6;T#Y=h5#Skaxl`P1tM} zT=!3YQ<}T~4o6dfqQWLS4bJJcePRwr+|YDL9wDZ!K_}$Jga5AOZ$g!;)cM;6GGc}{ zh64zZDc*E4=57sjg-!O`wnU8T_vX_l2snABSyMJ2itnd2d-fil?GRjThq9CwGD(Xm zzaH0TUu7e+k0-d(M0FmhDXNgIY$kpOLW@m!M`ZSUuzJ+1!W$nev-R{cRg45Q?u)!m z=C=T&IihZrO89}#XAawbdaoTRdLfyMR+gM$K)NnS+QP6v7)=_)g@K&}=hOKqi*oV2 zqP}mj@w3VA3S+=AKHwUrbS;Qf8_wN0Pd$?N@#S{3tW5Vu*&S8gQt4p|3t?rw3DYyw zZxXUc9D+yzMq9-MOu9@KrV%?nveJintFsK&2-k+=0jqahr&y$li=;mZXJ${pni}>a z|Hg0(k5?^yd198)_%=>XPPCz_VrP3pK6*8e2vyyB_cmD>RQvPijY(7FwwCo5mvy1B zvGI;o+zZiM3a9mNJt&!MDVgFz8xL77j*qClR&NyO;a2H0%2R5{G5A|DBX7(2U>v1I z%-GzsTr6yCr6lrx*e#%)l$3BB%#F2K5m24X157C>X1(IiSjkdHJ!V42yfJoqetL3H z$4ONODq@K_aiqI((|Z8yBRI&Gi!~D5UWcyEues)YaOZb#%~Q}0_i<`L5L^NtQf)wZd-cB zqO29)u-GwWnKU}{o9HM3_|MU(3%Eu2`!1S{06Skd(&YHAtQA`T>wnhOF=0_+JnNb3 zD-s~bvFv*OhWOIJvVBtoxgEUgne%4Xqa{<;4Po(ozWD{r1b3D8PrI+%b6Qqt1oQ*49R&#W(*O zYn~Y;DnDeM{vKbK=V;b#OVgYy9e>u5ab9a8WV3MZQoCWPMZ85g2<6_iz%{HPIiMx4_H1-~eOCZAbn=!Gdxg#(SQ z(Q#G2^sgUX=gu;5QpACU4C6*~VmJlNh=hsi0?f)e+k=4n#B`V~5|yZ9Y8GAmO*3{7 zhAj{#wN>w}F#cW1jkr#{nDsD(WY@vx4>wDUV>?Ia`>YV2$HXt~!N0HH)K&{W>kl1s z?BdG}$DmGfl>Lq!ix7B*uit?KqBD;v--1CdY!LJDS1N5Q>uSUiJu{FuaLokzwt(oF z+U@>4Dl=x(XMVl2_$CI{C6h-8MkL@#7~5GTm2)h}Vi>B8eLk5iSJnfT~(ABfl#VeGYMEU=uOQR!^Ux#Ov%&QO23-!RV-s0c$Q`2?CIBnIw`a|x& z+?1SIyyi>cjHv&RW%&0uSNO%$d-w48GdTVAhraf1>Hh0){`^nJ>C67iy8iive*Y7H z;f-Bl;a664Lh^p!x?i95^|N9tep1KQ9M>{ fgf76Y`YB<_SLL>Lth_5eu-43ZGa{!i+xfo$o^1ep diff --git a/docs/setup/access.asciidoc b/docs/setup/access.asciidoc index 538b42781b127..a7374a37ddaec 100644 --- a/docs/setup/access.asciidoc +++ b/docs/setup/access.asciidoc @@ -2,8 +2,8 @@ == Accessing Kibana Kibana is a web application that you access through port 5601. All you need to do is point your web browser at the -machine where Kibana is running and specify the port number. For example, `localhost:5601` or -`http://YOURDOMAIN.com:5601`. +machine where Kibana is running and specify the port number. For example, `localhost:5601` or `http://YOURDOMAIN.com:5601`. +If you want to allow remote users to connect, set the parameter `server.host` in `kibana.yml` to a non-loopback address. When you access Kibana, the <> page loads by default with the default index pattern selected. The time filter is set to the last 15 minutes and the search query is set to match-all (\*). @@ -15,9 +15,10 @@ If you still don't see any results, it's possible that you don't *have* any docu [[status]] === Checking Kibana Status -You can reach the Kibana server's status page by navigating to `localhost:5601/status`. The status page displays +You can reach the Kibana server's status page by navigating to the status endpoint, for example, `localhost:5601/status`. The status page displays information about the server's resource usage and lists the installed plugins. -image::images/kibana-status-page.png[] +[role="screenshot"] +image::images/kibana-status-page-7_5_0.png[] NOTE: For JSON-formatted server status details, use the API endpoint at `localhost:5601/api/status` diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc index 5cda7b2b214f0..414d4ef34db55 100644 --- a/docs/setup/settings.asciidoc +++ b/docs/setup/settings.asciidoc @@ -7,9 +7,7 @@ if you installed {kib} from an archive distribution (`.tar.gz` or `.zip`), by default it is in `$KIBANA_HOME/config`. By default, with package distributions (Debian or RPM), it is in `/etc/kibana`. -The default settings configure Kibana to run on `localhost:5601`. To change the -host or port number, or connect to Elasticsearch running on a different machine, -you'll need to update your `kibana.yml` file. You can also enable SSL and set a +The default host and port settings configure {kib} to run on `localhost:5601`. To change this behavior and allow remote users to connect, you'll need to update your `kibana.yml` file. You can also enable SSL and set a variety of other options. Finally, environment variables can be injected into configuration using `${MY_ENV_VAR}` syntax. @@ -32,7 +30,7 @@ strongly recommend that you keep the default CSP rules that ship with Kibana. `csp.strict:`:: *Default: `true`* Blocks access to Kibana to any browser that does not enforce even rudimentary CSP rules. In practice, this will disable -support for older, less safe browsers like Internet Explorer. +support for older, less safe browsers like Internet Explorer. See <> for more information. `csp.warnLegacyBrowsers:`:: *Default: `true`* Shows a warning message after @@ -65,7 +63,7 @@ connects to this Kibana instance. `elasticsearch.requestHeadersWhitelist:`:: *Default: `[ 'authorization' ]`* List of Kibana client-side headers to send to Elasticsearch. To send *no* client-side headers, set this value to [] (an empty list). -Removing the `authorization` header from being whitelisted means that you cannot +Removing the `authorization` header from being whitelisted means that you cannot use <> in Kibana. `elasticsearch.requestTimeout:`:: *Default: 30000* Time in milliseconds to wait @@ -164,19 +162,19 @@ The following example shows a valid logging rotate configuration: enable log rotation. If you do not have a `logging.dest` set that is different from `stdout` that feature would not take any effect. -`logging.rotate.everyBytes:`:: [experimental] *Default: 10485760* The maximum size of a log file (that is `not an exact` limit). After the +`logging.rotate.everyBytes:`:: [experimental] *Default: 10485760* The maximum size of a log file (that is `not an exact` limit). After the limit is reached, a new log file is generated. The default size limit is 10485760 (10 MB) and this option should be at least greater than 1024. -`logging.rotate.keepFiles:`:: [experimental] *Default: 7* The number of most recent rotated log files to keep -on disk. Older files are deleted during log rotation. The default value is 7. The `logging.rotate.keepFiles` +`logging.rotate.keepFiles:`:: [experimental] *Default: 7* The number of most recent rotated log files to keep +on disk. Older files are deleted during log rotation. The default value is 7. The `logging.rotate.keepFiles` option has to be in the range of 2 to 1024 files. -`logging.rotate.pollingInterval:`:: [experimental] *Default: 10000* The number of milliseconds for the polling strategy in case +`logging.rotate.pollingInterval:`:: [experimental] *Default: 10000* The number of milliseconds for the polling strategy in case the `logging.rotate.usePolling` is enabled. That option has to be in the range of 5000 to 3600000 milliseconds. -`logging.rotate.usePolling:`:: [experimental] *Default: false* By default we try to understand the best way to monitoring -the log file. However, there is some systems where it could not be always accurate. In those cases, if needed, +`logging.rotate.usePolling:`:: [experimental] *Default: false* By default we try to understand the best way to monitoring +the log file. However, there is some systems where it could not be always accurate. In those cases, if needed, the `polling` method could be used enabling that option. `logging.silent:`:: *Default: false* Set the value of this setting to `true` to @@ -304,7 +302,7 @@ This setting may not be used when `server.compression.enabled` is set to `false` send on all responses to the client from the Kibana server. `server.host:`:: *Default: "localhost"* This setting specifies the host of the -back end server. +back end server. To allow remote users to connect, set the value to the IP address or DNS name of the {kib} server. `server.keepaliveTimeout:`:: *Default: "120000"* The number of milliseconds to wait for additional data before restarting the `server.socketTimeout` counter. @@ -358,15 +356,15 @@ supported protocols with versions. Valid protocols: `TLSv1`, `TLSv1.1`, `TLSv1.2 setting this to `true` enables unauthenticated users to access the Kibana server status API and status page. -`telemetry.allowChangingOptInStatus`:: *Default: true*. If `true`, -users are able to change the telemetry setting at a later time in -<>. If `false`, -{kib} looks at the value of `telemetry.optIn` to determine whether to send +`telemetry.allowChangingOptInStatus`:: *Default: true*. If `true`, +users are able to change the telemetry setting at a later time in +<>. If `false`, +{kib} looks at the value of `telemetry.optIn` to determine whether to send telemetry data or not. `telemetry.allowChangingOptInStatus` and `telemetry.optIn` cannot be `false` at the same time. -`telemetry.optIn`:: *Default: true* If `true`, telemetry data is sent to Elastic. - If `false`, collection of telemetry data is disabled. +`telemetry.optIn`:: *Default: true* If `true`, telemetry data is sent to Elastic. + If `false`, collection of telemetry data is disabled. To enable telemetry and prevent users from disabling it, set `telemetry.allowChangingOptInStatus` to `false` and `telemetry.optIn` to `true`. From e0f155be31bc9eda9941535558693ab2aa1e82de Mon Sep 17 00:00:00 2001 From: Nathan L Smith Date: Wed, 11 Dec 2019 14:49:51 -0600 Subject: [PATCH 26/79] [APM] Refactor core and plugin context (#52353) * [APM] Refactor core and plugin context Change the plugin to use a context that exposes: ``` export interface ApmPluginContextValue { config: ConfigSchema; core: AppMountContext['core']; packageInfo: PackageInfo; plugins: ApmPluginSetupDeps; } ``` This replaces the `PluginContext` and `usePlugins` that were added with the NP shim, and the `KibanaCoraContext` and `useKibanaCore` from the observability plugin. Remove the observability plugin since it's not being used anywhere else. --- .../public/components/app/Home/Home.test.tsx | 10 +- .../app/Home/__snapshots__/Home.test.tsx.snap | 56 +++++++++-- .../apm/public/components/app/Home/index.tsx | 7 +- ...mbs.test.js => UpdateBreadcrumbs.test.tsx} | 66 +++++++------ .../components/app/Main/UpdateBreadcrumbs.tsx | 9 +- .../UpdateBreadcrumbs.test.tsx.snap} | 0 .../app/ServiceDetails/ServiceDetailTabs.tsx | 5 +- .../MachineLearningFlyout/index.tsx | 12 +-- .../MachineLearningFlyout/view.tsx | 4 +- .../ServiceIntegrations/WatcherFlyout.tsx | 25 +++-- .../ServiceIntegrations/index.tsx | 8 +- .../app/ServiceNodeMetrics/index.test.tsx | 9 +- .../__test__/ServiceOverview.test.tsx | 87 +++++++++-------- .../components/app/ServiceOverview/index.tsx | 4 +- .../AddEditFlyout/DeleteButton.tsx | 7 +- .../AddEditFlyout/index.tsx | 6 +- .../app/Settings/ApmIndices/index.tsx | 6 +- .../app/TraceLink/__test__/TraceLink.test.tsx | 29 +++--- .../__jest__/TransactionOverview.test.tsx | 11 +-- .../app/TransactionOverview/index.tsx | 4 +- .../components/shared/KueryBar/index.tsx | 4 +- .../Links/DiscoverLinks/DiscoverLink.tsx | 4 +- .../DiscoverLinks.integration.test.tsx | 23 ----- .../shared/Links/ElasticDocsLink.tsx | 7 +- .../shared/Links/InfraLink.test.tsx | 12 --- .../components/shared/Links/InfraLink.tsx | 4 +- .../shared/Links/KibanaLink.test.tsx | 18 ---- .../components/shared/Links/KibanaLink.tsx | 4 +- .../MachineLearningLinks/MLJobLink.test.tsx | 17 ---- .../MachineLearningLinks/MLLink.test.tsx | 20 ---- .../Links/MachineLearningLinks/MLLink.tsx | 4 +- .../__test__/ErrorMetadata.test.tsx | 4 +- .../__test__/SpanMetadata.test.tsx | 4 +- .../__test__/TransactionMetadata.test.tsx | 4 +- .../__test__/MetadataTable.test.tsx | 4 +- .../TransactionActionMenu.tsx | 4 +- .../__test__/TransactionActionMenu.test.tsx | 22 +---- .../BrowserLineChart.test.tsx | 9 +- .../apm/public/context/ApmPluginContext.tsx | 18 ++++ .../InvalidLicenseNotification.tsx | 4 +- .../public/context/LicenseContext/index.tsx | 4 +- .../useApmPluginContext.ts} | 7 +- .../plugins/apm/public/hooks/useCallApi.ts | 4 +- .../plugins/apm/public/hooks/useCallApmApi.ts | 4 +- .../hooks/useFetcher.integration.test.tsx | 21 +--- .../apm/public/hooks/useFetcher.test.tsx | 21 +--- .../plugins/apm/public/hooks/useFetcher.tsx | 4 +- x-pack/legacy/plugins/apm/public/index.tsx | 8 +- .../apm/public/new-platform/plugin.tsx | 97 ++++++++----------- .../plugins/apm/public/utils/testHelpers.tsx | 78 ++++++++++----- x-pack/legacy/plugins/observability/README.md | 19 ---- .../components/example_shared_component.tsx | 15 --- .../public/context/kibana_core.tsx | 25 ----- .../plugins/observability/public/index.tsx | 9 -- 54 files changed, 388 insertions(+), 483 deletions(-) rename x-pack/legacy/plugins/apm/public/components/app/Main/{__test__/UpdateBreadcrumbs.test.js => UpdateBreadcrumbs.test.tsx} (50%) rename x-pack/legacy/plugins/apm/public/components/app/Main/{__test__/__snapshots__/UpdateBreadcrumbs.test.js.snap => __snapshots__/UpdateBreadcrumbs.test.tsx.snap} (100%) create mode 100644 x-pack/legacy/plugins/apm/public/context/ApmPluginContext.tsx rename x-pack/legacy/plugins/apm/public/{new-platform/stackVersionFromLegacyMetadata.ts => hooks/useApmPluginContext.ts} (57%) delete mode 100644 x-pack/legacy/plugins/observability/README.md delete mode 100644 x-pack/legacy/plugins/observability/public/components/example_shared_component.tsx delete mode 100644 x-pack/legacy/plugins/observability/public/context/kibana_core.tsx delete mode 100644 x-pack/legacy/plugins/observability/public/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/Home/Home.test.tsx b/x-pack/legacy/plugins/apm/public/components/app/Home/Home.test.tsx index 272e2561b7fd7..711290942cea1 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Home/Home.test.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/Home/Home.test.tsx @@ -7,15 +7,15 @@ import { shallow } from 'enzyme'; import React from 'react'; import { Home } from '../Home'; -import { MockPluginContextWrapper } from '../../../utils/testHelpers'; +import { MockApmPluginContextWrapper } from '../../../utils/testHelpers'; describe('Home component', () => { it('should render services', () => { expect( shallow( - + - + ) ).toMatchSnapshot(); }); @@ -23,9 +23,9 @@ describe('Home component', () => { it('should render traces', () => { expect( shallow( - + - + ) ).toMatchSnapshot(); }); diff --git a/x-pack/legacy/plugins/apm/public/components/app/Home/__snapshots__/Home.test.tsx.snap b/x-pack/legacy/plugins/apm/public/components/app/Home/__snapshots__/Home.test.tsx.snap index 664a71c934a4e..7809734dbf2ad 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Home/__snapshots__/Home.test.tsx.snap +++ b/x-pack/legacy/plugins/apm/public/components/app/Home/__snapshots__/Home.test.tsx.snap @@ -4,10 +4,32 @@ exports[`Home component should render services 1`] = ` @@ -21,10 +43,32 @@ exports[`Home component should render traces 1`] = ` diff --git a/x-pack/legacy/plugins/apm/public/components/app/Home/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/Home/index.tsx index 2b3f1368f6fa0..4c98618d7de8a 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Home/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/Home/index.tsx @@ -25,7 +25,7 @@ import { EuiTabLink } from '../../shared/EuiTabLink'; import { SettingsLink } from '../../shared/Links/apm/SettingsLink'; import { ServiceMapLink } from '../../shared/Links/apm/ServiceMapLink'; import { ServiceMap } from '../ServiceMap'; -import { usePlugins } from '../../../new-platform/plugin'; +import { useApmPluginContext } from '../../../hooks/useApmPluginContext'; function getHomeTabs({ serviceMapEnabled = false @@ -82,9 +82,8 @@ interface Props { } export function Home({ tab }: Props) { - const { apm } = usePlugins(); - const { serviceMapEnabled } = apm.config; - const homeTabs = getHomeTabs({ serviceMapEnabled }); + const { config } = useApmPluginContext(); + const homeTabs = getHomeTabs(config); const selectedTab = homeTabs.find( homeTab => homeTab.name === tab ) as $ElementType; diff --git a/x-pack/legacy/plugins/apm/public/components/app/Main/__test__/UpdateBreadcrumbs.test.js b/x-pack/legacy/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.test.tsx similarity index 50% rename from x-pack/legacy/plugins/apm/public/components/app/Main/__test__/UpdateBreadcrumbs.test.js rename to x-pack/legacy/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.test.tsx index c2009cd0ae3a1..97f8c941911b6 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Main/__test__/UpdateBreadcrumbs.test.js +++ b/x-pack/legacy/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.test.tsx @@ -7,67 +7,79 @@ import { mount } from 'enzyme'; import React from 'react'; import { MemoryRouter } from 'react-router-dom'; -import { UpdateBreadcrumbs } from '../UpdateBreadcrumbs'; -import * as kibanaCore from '../../../../../../observability/public/context/kibana_core'; -import { getRoutes } from '../route_config'; - -const coreMock = { - chrome: { - setBreadcrumbs: jest.fn() - } -}; - -jest.spyOn(kibanaCore, 'useKibanaCore').mockReturnValue(coreMock); +import { UpdateBreadcrumbs } from './UpdateBreadcrumbs'; +import { getRoutes } from './route_config'; +import { + MockApmPluginContextWrapper, + mockApmPluginContextValue +} from '../../../utils/testHelpers'; +import { ApmPluginContextValue } from '../../../context/ApmPluginContext'; const routes = getRoutes({ serviceMapEnabled: true }); +const setBreadcrumbs = jest.fn(); -function expectBreadcrumbToMatchSnapshot(route, params = '') { +function expectBreadcrumbToMatchSnapshot(route: string, params = '') { mount( - - - + + + + + ); - expect(coreMock.chrome.setBreadcrumbs).toHaveBeenCalledTimes(1); - expect(coreMock.chrome.setBreadcrumbs.mock.calls[0][0]).toMatchSnapshot(); + expect(setBreadcrumbs).toHaveBeenCalledTimes(1); + expect(setBreadcrumbs.mock.calls[0][0]).toMatchSnapshot(); } describe('UpdateBreadcrumbs', () => { - let realDoc; + let realDoc: Document; beforeEach(() => { - realDoc = global.document; - global.document = { + realDoc = window.document; + (window.document as any) = { title: 'Kibana' }; - coreMock.chrome.setBreadcrumbs.mockReset(); + setBreadcrumbs.mockReset(); }); afterEach(() => { - global.document = realDoc; + (window.document as any) = realDoc; }); it('Homepage', () => { expectBreadcrumbToMatchSnapshot('/'); - expect(global.document.title).toMatchInlineSnapshot(`"APM"`); + expect(window.document.title).toMatchInlineSnapshot(`"APM"`); }); it('/services/:serviceName/errors/:groupId', () => { expectBreadcrumbToMatchSnapshot('/services/opbeans-node/errors/myGroupId'); - expect(global.document.title).toMatchInlineSnapshot( + expect(window.document.title).toMatchInlineSnapshot( `"myGroupId | Errors | opbeans-node | Services | APM"` ); }); it('/services/:serviceName/errors', () => { expectBreadcrumbToMatchSnapshot('/services/opbeans-node/errors'); - expect(global.document.title).toMatchInlineSnapshot( + expect(window.document.title).toMatchInlineSnapshot( `"Errors | opbeans-node | Services | APM"` ); }); it('/services/:serviceName/transactions', () => { expectBreadcrumbToMatchSnapshot('/services/opbeans-node/transactions'); - expect(global.document.title).toMatchInlineSnapshot( + expect(window.document.title).toMatchInlineSnapshot( `"Transactions | opbeans-node | Services | APM"` ); }); @@ -77,7 +89,7 @@ describe('UpdateBreadcrumbs', () => { '/services/opbeans-node/transactions/view', 'transactionName=my-transaction-name' ); - expect(global.document.title).toMatchInlineSnapshot( + expect(window.document.title).toMatchInlineSnapshot( `"my-transaction-name | Transactions | opbeans-node | Services | APM"` ); }); diff --git a/x-pack/legacy/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.tsx b/x-pack/legacy/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.tsx index 6568c9151bfd9..8960af0f21fd2 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.tsx @@ -6,19 +6,19 @@ import { Location } from 'history'; import React from 'react'; -import { LegacyCoreStart } from 'src/core/public'; -import { useKibanaCore } from '../../../../../observability/public'; +import { AppMountContext } from 'src/core/public'; import { getAPMHref } from '../../shared/Links/apm/APMLink'; import { Breadcrumb, ProvideBreadcrumbs, BreadcrumbRoute } from './ProvideBreadcrumbs'; +import { useApmPluginContext } from '../../../hooks/useApmPluginContext'; interface Props { location: Location; breadcrumbs: Breadcrumb[]; - core: LegacyCoreStart; + core: AppMountContext['core']; } function getTitleFromBreadCrumbs(breadcrumbs: Breadcrumb[]) { @@ -57,7 +57,8 @@ interface UpdateBreadcrumbsProps { } export function UpdateBreadcrumbs({ routes }: UpdateBreadcrumbsProps) { - const core = useKibanaCore(); + const { core } = useApmPluginContext(); + return ( { - static contextType = KibanaCoreContext; + static contextType = ApmPluginContext; public state: State = { isCreatingJob: false @@ -37,7 +37,7 @@ export class MachineLearningFlyout extends Component { }) => { this.setState({ isCreatingJob: true }); try { - const { http } = this.context; + const { http } = this.context.core; const { serviceName } = this.props.urlParams; if (!serviceName) { throw new Error('Service name is required to create this ML job'); @@ -91,7 +91,7 @@ export class MachineLearningFlyout extends Component { }: { transactionType: string; }) => { - const core = this.context; + const { core } = this.context; const { urlParams } = this.props; const { serviceName } = urlParams; @@ -119,7 +119,7 @@ export class MachineLearningFlyout extends Component { } } )}{' '} - + { } )} - +

) }); diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/MachineLearningFlyout/view.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/MachineLearningFlyout/view.tsx index c3d1c8ba1f5b1..31fc4db8f1a2f 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/MachineLearningFlyout/view.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/MachineLearningFlyout/view.tsx @@ -22,7 +22,6 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { useState, useEffect } from 'react'; import { isEmpty } from 'lodash'; -import { useKibanaCore } from '../../../../../../../observability/public'; import { FETCH_STATUS, useFetcher } from '../../../../../hooks/useFetcher'; import { getHasMLJob } from '../../../../../services/rest/ml'; import { MLJobLink } from '../../../../shared/Links/MachineLearningLinks/MLJobLink'; @@ -30,6 +29,7 @@ import { MLLink } from '../../../../shared/Links/MachineLearningLinks/MLLink'; import { TransactionSelect } from './TransactionSelect'; import { IUrlParams } from '../../../../../context/UrlParamsContext/types'; import { useServiceTransactionTypes } from '../../../../../hooks/useServiceTransactionTypes'; +import { useApmPluginContext } from '../../../../../hooks/useApmPluginContext'; interface Props { isCreatingJob: boolean; @@ -51,7 +51,7 @@ export function MachineLearningFlyoutView({ string | undefined >(undefined); - const { http } = useKibanaCore(); + const { http } = useApmPluginContext().core; const { data: hasMLJob = false, status } = useFetcher(() => { if (serviceName && selectedTransactionType) { diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/WatcherFlyout.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/WatcherFlyout.tsx index 3625fb430ff29..85254bee12e13 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/WatcherFlyout.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/WatcherFlyout.tsx @@ -31,12 +31,11 @@ import moment from 'moment-timezone'; import React, { Component } from 'react'; import styled from 'styled-components'; import { toMountPoint } from '../../../../../../../../../src/plugins/kibana_react/public'; -import { KibanaCoreContext } from '../../../../../../observability/public'; import { IUrlParams } from '../../../../context/UrlParamsContext/types'; import { KibanaLink } from '../../../shared/Links/KibanaLink'; import { createErrorGroupWatch, Schedule } from './createErrorGroupWatch'; import { ElasticDocsLink } from '../../../shared/Links/ElasticDocsLink'; -import { PluginsContext } from '../../../../new-platform/plugin'; +import { ApmPluginContext } from '../../../../context/ApmPluginContext'; type ScheduleKey = keyof Schedule; @@ -77,8 +76,8 @@ export class WatcherFlyout extends Component< WatcherFlyoutProps, WatcherFlyoutState > { - static contextType = KibanaCoreContext; - context!: React.ContextType; + static contextType = ApmPluginContext; + context!: React.ContextType; public state: WatcherFlyoutState = { schedule: 'daily', threshold: 10, @@ -156,7 +155,7 @@ export class WatcherFlyout extends Component< indexPatternTitle: string; }) => () => { const { serviceName } = this.props.urlParams; - const core = this.context; + const { core } = this.context; if (!serviceName) { return; @@ -213,7 +212,7 @@ export class WatcherFlyout extends Component< }; public addErrorToast = () => { - const core = this.context; + const { core } = this.context; core.notifications.toasts.addWarning({ title: i18n.translate( @@ -237,7 +236,7 @@ export class WatcherFlyout extends Component< }; public addSuccessToast = (id: string) => { - const core = this.context; + const { core } = this.context; core.notifications.toasts.addSuccess({ title: i18n.translate( @@ -258,7 +257,7 @@ export class WatcherFlyout extends Component< } } )}{' '} - + @@ -269,7 +268,7 @@ export class WatcherFlyout extends Component< } )} - +

) }); @@ -614,11 +613,11 @@ export class WatcherFlyout extends Component< - - {({ apm }) => { + + {({ config }) => { return ( ); }} - + diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/index.tsx index 8903900a625c1..4158bb877e459 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/index.tsx @@ -13,11 +13,11 @@ import { import { i18n } from '@kbn/i18n'; import { memoize } from 'lodash'; import React, { Fragment } from 'react'; -import { KibanaCoreContext } from '../../../../../../observability/public'; import { IUrlParams } from '../../../../context/UrlParamsContext/types'; import { LicenseContext } from '../../../../context/LicenseContext'; import { MachineLearningFlyout } from './MachineLearningFlyout'; import { WatcherFlyout } from './WatcherFlyout'; +import { ApmPluginContext } from '../../../../context/ApmPluginContext'; interface Props { urlParams: IUrlParams; @@ -29,8 +29,8 @@ interface State { type FlyoutName = null | 'ML' | 'Watcher'; export class ServiceIntegrations extends React.Component { - static contextType = KibanaCoreContext; - context!: React.ContextType; + static contextType = ApmPluginContext; + context!: React.ContextType; public state: State = { isPopoverOpen: false, activeFlyout: null }; @@ -67,7 +67,7 @@ export class ServiceIntegrations extends React.Component { }; public getWatcherPanelItems = () => { - const core = this.context; + const { core } = this.context; return [ { diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceNodeMetrics/index.test.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceNodeMetrics/index.test.tsx index 21a39e19657a1..0ec9e90a31659 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceNodeMetrics/index.test.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceNodeMetrics/index.test.tsx @@ -7,11 +7,18 @@ import React from 'react'; import { shallow } from 'enzyme'; import { ServiceNodeMetrics } from '.'; +import { MockApmPluginContextWrapper } from '../../../utils/testHelpers'; describe('ServiceNodeMetrics', () => { describe('render', () => { it('renders', () => { - expect(() => shallow()).not.toThrowError(); + expect(() => + shallow( + + + + ) + ).not.toThrowError(); }); }); }); diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/__test__/ServiceOverview.test.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/__test__/ServiceOverview.test.tsx index 9f48880090369..e5406e59004fb 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/__test__/ServiceOverview.test.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/__test__/ServiceOverview.test.tsx @@ -4,42 +4,58 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; +import React, { ReactChild, FunctionComponent } from 'react'; import { render, wait, waitForElement } from '@testing-library/react'; import { ServiceOverview } from '..'; import * as urlParamsHooks from '../../../../hooks/useUrlParams'; -import * as kibanaCore from '../../../../../../observability/public/context/kibana_core'; -import { LegacyCoreStart } from 'src/core/public'; import * as useLocalUIFilters from '../../../../hooks/useLocalUIFilters'; import { FETCH_STATUS } from '../../../../hooks/useFetcher'; import { SessionStorageMock } from '../../../../services/__test__/SessionStorageMock'; +import { + MockApmPluginContextWrapper, + mockApmPluginContextValue +} from '../../../../utils/testHelpers'; +import { ApmPluginContextValue } from '../../../../context/ApmPluginContext'; + +function wrapper({ children }: { children: ReactChild }) { + return ( + + {children} + + ); +} function renderServiceOverview() { - return render(); + return render(, { wrapper } as { + wrapper: FunctionComponent<{}>; + }); } -const coreMock = ({ - http: { - basePath: { - prepend: (path: string) => `/basepath${path}` - }, - get: jest.fn() - }, - notifications: { - toasts: { - addWarning: () => {} - } - } -} as unknown) as LegacyCoreStart & { - http: { get: jest.Mock }; -}; +const addWarning = jest.fn(); +const httpGet = jest.fn(); describe('Service Overview -> View', () => { beforeEach(() => { // @ts-ignore global.sessionStorage = new SessionStorageMock(); - spyOn(kibanaCore, 'useKibanaCore').and.returnValue(coreMock); // mock urlParams spyOn(urlParamsHooks, 'useUrlParams').and.returnValue({ urlParams: { @@ -62,7 +78,7 @@ describe('Service Overview -> View', () => { it('should render services, when list is not empty', async () => { // mock rest requests - coreMock.http.get.mockResolvedValueOnce({ + httpGet.mockResolvedValueOnce({ hasLegacyData: false, hasHistoricalData: true, items: [ @@ -88,14 +104,14 @@ describe('Service Overview -> View', () => { const { container, getByText } = renderServiceOverview(); // wait for requests to be made - await wait(() => expect(coreMock.http.get).toHaveBeenCalledTimes(1)); + await wait(() => expect(httpGet).toHaveBeenCalledTimes(1)); await waitForElement(() => getByText('My Python Service')); expect(container.querySelectorAll('.euiTableRow')).toMatchSnapshot(); }); it('should render getting started message, when list is empty and no historical data is found', async () => { - coreMock.http.get.mockResolvedValueOnce({ + httpGet.mockResolvedValueOnce({ hasLegacyData: false, hasHistoricalData: false, items: [] @@ -104,7 +120,7 @@ describe('Service Overview -> View', () => { const { container, getByText } = renderServiceOverview(); // wait for requests to be made - await wait(() => expect(coreMock.http.get).toHaveBeenCalledTimes(1)); + await wait(() => expect(httpGet).toHaveBeenCalledTimes(1)); // wait for elements to be rendered await waitForElement(() => @@ -117,7 +133,7 @@ describe('Service Overview -> View', () => { }); it('should render empty message, when list is empty and historical data is found', async () => { - coreMock.http.get.mockResolvedValueOnce({ + httpGet.mockResolvedValueOnce({ hasLegacyData: false, hasHistoricalData: true, items: [] @@ -126,7 +142,7 @@ describe('Service Overview -> View', () => { const { container, getByText } = renderServiceOverview(); // wait for requests to be made - await wait(() => expect(coreMock.http.get).toHaveBeenCalledTimes(1)); + await wait(() => expect(httpGet).toHaveBeenCalledTimes(1)); await waitForElement(() => getByText('No services found')); expect(container.querySelectorAll('.euiTableRow')).toMatchSnapshot(); @@ -134,13 +150,7 @@ describe('Service Overview -> View', () => { describe('when legacy data is found', () => { it('renders an upgrade migration notification', async () => { - // create spies - const addWarning = jest.spyOn( - coreMock.notifications.toasts, - 'addWarning' - ); - - coreMock.http.get.mockResolvedValueOnce({ + httpGet.mockResolvedValueOnce({ hasLegacyData: true, hasHistoricalData: true, items: [] @@ -149,7 +159,7 @@ describe('Service Overview -> View', () => { renderServiceOverview(); // wait for requests to be made - await wait(() => expect(coreMock.http.get).toHaveBeenCalledTimes(1)); + await wait(() => expect(httpGet).toHaveBeenCalledTimes(1)); expect(addWarning).toHaveBeenLastCalledWith( expect.objectContaining({ @@ -161,12 +171,7 @@ describe('Service Overview -> View', () => { describe('when legacy data is not found', () => { it('does not render an upgrade migration notification', async () => { - // create spies - const addWarning = jest.spyOn( - coreMock.notifications.toasts, - 'addWarning' - ); - coreMock.http.get.mockResolvedValueOnce({ + httpGet.mockResolvedValueOnce({ hasLegacyData: false, hasHistoricalData: true, items: [] @@ -175,7 +180,7 @@ describe('Service Overview -> View', () => { renderServiceOverview(); // wait for requests to be made - await wait(() => expect(coreMock.http.get).toHaveBeenCalledTimes(1)); + await wait(() => expect(httpGet).toHaveBeenCalledTimes(1)); expect(addWarning).not.toHaveBeenCalled(); }); diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/index.tsx index 0702e092a714f..05ccc691ecdba 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/index.tsx @@ -15,9 +15,9 @@ import { NoServicesMessage } from './NoServicesMessage'; import { ServiceList } from './ServiceList'; import { useUrlParams } from '../../../hooks/useUrlParams'; import { useTrackPageview } from '../../../../../infra/public'; -import { useKibanaCore } from '../../../../../observability/public'; import { PROJECTION } from '../../../../common/projections/typings'; import { LocalUIFilters } from '../../shared/LocalUIFilters'; +import { useApmPluginContext } from '../../../hooks/useApmPluginContext'; const initalData = { items: [], @@ -28,7 +28,7 @@ const initalData = { let hasDisplayedToast = false; export function ServiceOverview() { - const core = useKibanaCore(); + const { core } = useApmPluginContext(); const { urlParams: { start, end }, uiFilters diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AddEditFlyout/DeleteButton.tsx b/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AddEditFlyout/DeleteButton.tsx index 8f5d4f4f600d3..b5a59aea3286d 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AddEditFlyout/DeleteButton.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AddEditFlyout/DeleteButton.tsx @@ -11,8 +11,8 @@ import { i18n } from '@kbn/i18n'; import { useCallApmApi } from '../../../../../hooks/useCallApmApi'; import { Config } from '../index'; import { getOptionLabel } from '../../../../../../common/agent_configuration_constants'; -import { useKibanaCore } from '../../../../../../../observability/public'; import { APMClient } from '../../../../../services/rest/createCallApmApi'; +import { useApmPluginContext } from '../../../../../hooks/useApmPluginContext'; interface Props { onDeleted: () => void; @@ -21,10 +21,7 @@ interface Props { export function DeleteButton({ onDeleted, selectedConfig }: Props) { const [isDeleting, setIsDeleting] = useState(false); - const { - notifications: { toasts } - } = useKibanaCore(); - + const { toasts } = useApmPluginContext().core.notifications; const callApmApi = useCallApmApi(); return ( diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AddEditFlyout/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AddEditFlyout/index.tsx index 853ce26d324fb..e1cb07be3d378 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AddEditFlyout/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AddEditFlyout/index.tsx @@ -33,7 +33,7 @@ import { useFetcher } from '../../../../../hooks/useFetcher'; import { isRumAgentName } from '../../../../../../common/agent_name'; import { ALL_OPTION_VALUE } from '../../../../../../common/agent_configuration_constants'; import { saveConfig } from './saveConfig'; -import { useKibanaCore } from '../../../../../../../observability/public'; +import { useApmPluginContext } from '../../../../../hooks/useApmPluginContext'; const defaultSettings = { TRANSACTION_SAMPLE_RATE: '1.0', @@ -54,9 +54,7 @@ export function AddEditFlyout({ onDeleted, selectedConfig }: Props) { - const { - notifications: { toasts } - } = useKibanaCore(); + const { toasts } = useApmPluginContext().core.notifications; const [isSaving, setIsSaving] = useState(false); const callApmApiFromHook = useCallApmApi(); diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/ApmIndices/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/Settings/ApmIndices/index.tsx index 7ced0b6fdd566..ba68e1726d2b4 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/ApmIndices/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/Settings/ApmIndices/index.tsx @@ -23,7 +23,7 @@ import { useFetcher } from '../../../../hooks/useFetcher'; import { useCallApmApi } from '../../../../hooks/useCallApmApi'; import { APMClient } from '../../../../services/rest/createCallApmApi'; import { clearCache } from '../../../../services/rest/callApi'; -import { useKibanaCore } from '../../../../../../observability/public'; +import { useApmPluginContext } from '../../../../hooks/useApmPluginContext'; const APM_INDEX_LABELS = [ { @@ -86,9 +86,7 @@ async function saveApmIndices({ } export function ApmIndices() { - const { - notifications: { toasts } - } = useKibanaCore(); + const { toasts } = useApmPluginContext().core.notifications; const [apmIndices, setApmIndices] = useState>({}); const [isSaving, setIsSaving] = useState(false); diff --git a/x-pack/legacy/plugins/apm/public/components/app/TraceLink/__test__/TraceLink.test.tsx b/x-pack/legacy/plugins/apm/public/components/app/TraceLink/__test__/TraceLink.test.tsx index b77524fca050d..d1254e1e1e2ad 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TraceLink/__test__/TraceLink.test.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/TraceLink/__test__/TraceLink.test.tsx @@ -9,26 +9,29 @@ import { shallow } from 'enzyme'; import * as urlParamsHooks from '../../../../hooks/useUrlParams'; import * as hooks from '../../../../hooks/useFetcher'; import { TraceLink } from '../'; +import { MockApmPluginContextWrapper } from '../../../../utils/testHelpers'; +import * as routeConfig from '../../Main/route_config'; +import { BreadcrumbRoute } from '../../Main/ProvideBreadcrumbs'; -jest.mock('../../Main/route_config/index.tsx', () => ({ - routes: [ - { - path: '/services/:serviceName/transactions/view', - name: 'transaction_name' - }, - { - path: '/traces', - name: 'traces' - } - ] -})); +const renderOptions = { wrapper: MockApmPluginContextWrapper }; + +jest.spyOn(routeConfig, 'getRoutes').mockReturnValue([ + { + path: '/services/:serviceName/transactions/view', + name: 'transaction_name' + }, + { + path: '/traces', + name: 'traces' + } +] as BreadcrumbRoute[]); describe('TraceLink', () => { afterAll(() => { jest.clearAllMocks(); }); it('renders transition page', () => { - const component = render(); + const component = render(, renderOptions); expect(component.getByText('Fetching trace...')).toBeDefined(); }); diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/__jest__/TransactionOverview.test.tsx b/x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/__jest__/TransactionOverview.test.tsx index 91e0ae11a652e..a6f0d26a32e78 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/__jest__/TransactionOverview.test.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/__jest__/TransactionOverview.test.tsx @@ -22,16 +22,11 @@ import * as useFetcherHook from '../../../../hooks/useFetcher'; import { fromQuery } from '../../../shared/Links/url_helpers'; import { Router } from 'react-router-dom'; import { UrlParamsProvider } from '../../../../context/UrlParamsContext'; -import { KibanaCoreContext } from '../../../../../../observability/public'; -import { LegacyCoreStart } from 'kibana/public'; +import { MockApmPluginContextWrapper } from '../../../../utils/testHelpers'; jest.spyOn(history, 'push'); jest.spyOn(history, 'replace'); -const coreMock = ({ - notifications: { toasts: { addWarning: () => {} } } -} as unknown) as LegacyCoreStart; - function setup({ urlParams, serviceTransactionTypes @@ -55,13 +50,13 @@ function setup({ jest.spyOn(useFetcherHook, 'useFetcher').mockReturnValue({} as any); return render( - + - + ); } diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/index.tsx index f016052df56a2..de356b5812e9a 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/index.tsx @@ -15,7 +15,6 @@ import { import { Location } from 'history'; import { first } from 'lodash'; import React, { useMemo } from 'react'; -import { useKibanaCore } from '../../../../../observability/public'; import { useTransactionList } from '../../../hooks/useTransactionList'; import { useTransactionCharts } from '../../../hooks/useTransactionCharts'; import { IUrlParams } from '../../../context/UrlParamsContext/types'; @@ -35,6 +34,7 @@ import { PROJECTION } from '../../../../common/projections/typings'; import { useUrlParams } from '../../../hooks/useUrlParams'; import { useServiceTransactionTypes } from '../../../hooks/useServiceTransactionTypes'; import { TransactionTypeFilter } from '../../shared/LocalUIFilters/TransactionTypeFilter'; +import { useApmPluginContext } from '../../../hooks/useApmPluginContext'; function getRedirectLocation({ urlParams, @@ -86,7 +86,7 @@ export function TransactionOverview() { status: transactionListStatus } = useTransactionList(urlParams); - const { http } = useKibanaCore(); + const { http } = useApmPluginContext().core; const { data: hasMLJob = false } = useFetcher(() => { if (serviceName && transactionType) { diff --git a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx b/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx index 32fbe46ac560c..67bff86c8ccdf 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx @@ -15,7 +15,7 @@ import { getBoolFilter } from './get_bool_filter'; import { useLocation } from '../../../hooks/useLocation'; import { useUrlParams } from '../../../hooks/useUrlParams'; import { history } from '../../../utils/history'; -import { usePlugins } from '../../../new-platform/plugin'; +import { useApmPluginContext } from '../../../hooks/useApmPluginContext'; import { useDynamicIndexPattern } from '../../../hooks/useDynamicIndexPattern'; import { AutocompleteProvider, @@ -71,7 +71,7 @@ export function KueryBar() { }); const { urlParams } = useUrlParams(); const location = useLocation(); - const { data } = usePlugins(); + const { data } = useApmPluginContext().plugins; const autocompleteProvider = data.autocomplete.getProvider('kuery'); let currentRequestCheck; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx b/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx index 5d25dc7de4e13..51d8b43dac0ea 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx @@ -10,8 +10,8 @@ import url from 'url'; import rison, { RisonValue } from 'rison-node'; import { useLocation } from '../../../../hooks/useLocation'; import { getTimepickerRisonData } from '../rison_helpers'; -import { useKibanaCore } from '../../../../../../observability/public'; import { APM_STATIC_INDEX_PATTERN_ID } from '../../../../../common/index_pattern_constants'; +import { useApmPluginContext } from '../../../../hooks/useApmPluginContext'; interface Props { query: { @@ -31,7 +31,7 @@ interface Props { } export function DiscoverLink({ query = {}, ...rest }: Props) { - const core = useKibanaCore(); + const { core } = useApmPluginContext(); const location = useLocation(); const risonQuery = { diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverLinks.integration.test.tsx b/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverLinks.integration.test.tsx index 839efbbdf60f1..2f49e476ef610 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverLinks.integration.test.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverLinks.integration.test.tsx @@ -13,31 +13,8 @@ import { getRenderedHref } from '../../../../../utils/testHelpers'; import { DiscoverErrorLink } from '../DiscoverErrorLink'; import { DiscoverSpanLink } from '../DiscoverSpanLink'; import { DiscoverTransactionLink } from '../DiscoverTransactionLink'; -import * as kibanaCore from '../../../../../../../observability/public/context/kibana_core'; -import { LegacyCoreStart } from 'src/core/public'; describe('DiscoverLinks', () => { - beforeAll(() => { - jest.spyOn(console, 'error').mockImplementation(() => null); - - const coreMock = ({ - http: { - notifications: { - toasts: {} - }, - basePath: { - prepend: (path: string) => `/basepath${path}` - } - } - } as unknown) as LegacyCoreStart; - - spyOn(kibanaCore, 'useKibanaCore').and.returnValue(coreMock); - }); - - afterAll(() => { - jest.restoreAllMocks(); - }); - it('produces the correct URL for a transaction', async () => { const transaction = { transaction: { diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/ElasticDocsLink.tsx b/x-pack/legacy/plugins/apm/public/components/shared/Links/ElasticDocsLink.tsx index 1888e1d04c2cb..efae8982c2235 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/ElasticDocsLink.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/Links/ElasticDocsLink.tsx @@ -6,7 +6,7 @@ import React from 'react'; import { EuiLink, EuiLinkAnchorProps } from '@elastic/eui'; -import { usePlugins } from '../../../new-platform/plugin'; +import { useApmPluginContext } from '../../../hooks/useApmPluginContext'; // union type constisting of valid guide sections that we link to type DocsSection = '/apm/get-started' | '/x-pack' | '/apm/server'; @@ -17,8 +17,7 @@ interface Props extends EuiLinkAnchorProps { } export function ElasticDocsLink({ section, path, ...rest }: Props) { - const { apm } = usePlugins(); - const { stackVersion } = apm; - const href = `https://www.elastic.co/guide/en${section}/${stackVersion}${path}`; + const { version } = useApmPluginContext().packageInfo; + const href = `https://www.elastic.co/guide/en${section}/${version}${path}`; return ; } diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/InfraLink.test.tsx b/x-pack/legacy/plugins/apm/public/components/shared/Links/InfraLink.test.tsx index 4f96f529c471c..42022a3741495 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/InfraLink.test.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/Links/InfraLink.test.tsx @@ -8,18 +8,6 @@ import { Location } from 'history'; import React from 'react'; import { getRenderedHref } from '../../../utils/testHelpers'; import { InfraLink } from './InfraLink'; -import * as kibanaCore from '../../../../../observability/public/context/kibana_core'; -import { LegacyCoreStart } from 'src/core/public'; - -const coreMock = ({ - http: { - basePath: { - prepend: (path: string) => `/basepath${path}` - } - } -} as unknown) as LegacyCoreStart; - -jest.spyOn(kibanaCore, 'useKibanaCore').mockReturnValue(coreMock); test('InfraLink produces the correct URL', async () => { const href = await getRenderedHref( diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/InfraLink.tsx b/x-pack/legacy/plugins/apm/public/components/shared/Links/InfraLink.tsx index 192fafadba4c0..8ff5e3010d6cc 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/InfraLink.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/Links/InfraLink.tsx @@ -9,7 +9,7 @@ import { compact } from 'lodash'; import React from 'react'; import url from 'url'; import { fromQuery } from './url_helpers'; -import { useKibanaCore } from '../../../../../observability/public'; +import { useApmPluginContext } from '../../../hooks/useApmPluginContext'; interface InfraQueryParams { time?: number; @@ -24,7 +24,7 @@ interface Props extends EuiLinkAnchorProps { } export function InfraLink({ path, query = {}, ...rest }: Props) { - const core = useKibanaCore(); + const { core } = useApmPluginContext(); const nextSearch = fromQuery(query); const href = url.format({ pathname: core.http.basePath.prepend('/app/infra'), diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/KibanaLink.test.tsx b/x-pack/legacy/plugins/apm/public/components/shared/Links/KibanaLink.test.tsx index 521d62205311d..fad534e11f645 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/KibanaLink.test.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/Links/KibanaLink.test.tsx @@ -8,26 +8,8 @@ import { Location } from 'history'; import React from 'react'; import { getRenderedHref } from '../../../utils/testHelpers'; import { KibanaLink } from './KibanaLink'; -import * as kibanaCore from '../../../../../observability/public/context/kibana_core'; -import { LegacyCoreStart } from 'src/core/public'; describe('KibanaLink', () => { - beforeEach(() => { - const coreMock = ({ - http: { - basePath: { - prepend: (path: string) => `/basepath${path}` - } - } - } as unknown) as LegacyCoreStart; - - jest.spyOn(kibanaCore, 'useKibanaCore').mockReturnValue(coreMock); - }); - - afterEach(() => { - jest.resetAllMocks(); - }); - it('produces the correct URL', async () => { const href = await getRenderedHref(() => , { search: '?rangeFrom=now-5h&rangeTo=now-2h' diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/KibanaLink.tsx b/x-pack/legacy/plugins/apm/public/components/shared/Links/KibanaLink.tsx index de62d5e46070a..37e2c06d2f701 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/KibanaLink.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/Links/KibanaLink.tsx @@ -7,7 +7,7 @@ import { EuiLink, EuiLinkAnchorProps } from '@elastic/eui'; import React from 'react'; import url from 'url'; -import { useKibanaCore } from '../../../../../observability/public'; +import { useApmPluginContext } from '../../../hooks/useApmPluginContext'; interface Props extends EuiLinkAnchorProps { path?: string; @@ -15,7 +15,7 @@ interface Props extends EuiLinkAnchorProps { } export function KibanaLink({ path, ...rest }: Props) { - const core = useKibanaCore(); + const { core } = useApmPluginContext(); const href = url.format({ pathname: core.http.basePath.prepend('/app/kibana'), hash: path diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLJobLink.test.tsx b/x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLJobLink.test.tsx index aaf27e75ce93b..75a247a1aae40 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLJobLink.test.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLJobLink.test.tsx @@ -8,25 +8,8 @@ import { Location } from 'history'; import React from 'react'; import { getRenderedHref } from '../../../../utils/testHelpers'; import { MLJobLink } from './MLJobLink'; -import * as kibanaCore from '../../../../../../observability/public/context/kibana_core'; -import { LegacyCoreStart } from 'src/core/public'; describe('MLJobLink', () => { - beforeEach(() => { - const coreMock = ({ - http: { - basePath: { - prepend: (path: string) => `/basepath${path}` - } - } - } as unknown) as LegacyCoreStart; - - spyOn(kibanaCore, 'useKibanaCore').and.returnValue(coreMock); - }); - - afterEach(() => { - jest.resetAllMocks(); - }); it('should produce the correct URL', async () => { const href = await getRenderedHref( () => ( diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.test.tsx b/x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.test.tsx index 0db30e136b6ec..d38d61fede37a 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.test.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.test.tsx @@ -8,26 +8,6 @@ import { Location } from 'history'; import React from 'react'; import { getRenderedHref } from '../../../../utils/testHelpers'; import { MLLink } from './MLLink'; -import * as kibanaCore from '../../../../../../observability/public/context/kibana_core'; -import { LegacyCoreStart } from 'src/core/public'; - -const coreMock = ({ - http: { - basePath: { - prepend: (path: string) => `/basepath${path}` - } - } -} as unknown) as LegacyCoreStart; - -jest.spyOn(kibanaCore, 'useKibanaCore').mockReturnValue(coreMock); - -beforeAll(() => { - jest.spyOn(console, 'error').mockImplementation(() => null); -}); - -afterAll(() => { - jest.restoreAllMocks(); -}); test('MLLink produces the correct URL', async () => { const href = await getRenderedHref( diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.tsx b/x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.tsx index 0fe80b729f010..3671a0089fd6e 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.tsx @@ -10,7 +10,7 @@ import url from 'url'; import rison, { RisonValue } from 'rison-node'; import { useLocation } from '../../../../hooks/useLocation'; import { getTimepickerRisonData, TimepickerRisonData } from '../rison_helpers'; -import { useKibanaCore } from '../../../../../../observability/public'; +import { useApmPluginContext } from '../../../../hooks/useApmPluginContext'; interface MlRisonData { ml?: { @@ -25,7 +25,7 @@ interface Props { } export function MLLink({ children, path = '', query = {} }: Props) { - const core = useKibanaCore(); + const { core } = useApmPluginContext(); const location = useLocation(); const risonQuery: MlRisonData & TimepickerRisonData = getTimepickerRisonData( diff --git a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/__test__/ErrorMetadata.test.tsx b/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/__test__/ErrorMetadata.test.tsx index c3913e43cbd62..5bbc194e35992 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/__test__/ErrorMetadata.test.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/__test__/ErrorMetadata.test.tsx @@ -11,11 +11,11 @@ import { APMError } from '../../../../../../typings/es_schemas/ui/APMError'; import { expectTextsInDocument, expectTextsNotInDocument, - MockPluginContextWrapper + MockApmPluginContextWrapper } from '../../../../../utils/testHelpers'; const renderOptions = { - wrapper: MockPluginContextWrapper + wrapper: MockApmPluginContextWrapper }; function getError() { diff --git a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/__test__/SpanMetadata.test.tsx b/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/__test__/SpanMetadata.test.tsx index 438fe57218cc9..4b6355034f16a 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/__test__/SpanMetadata.test.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/__test__/SpanMetadata.test.tsx @@ -11,11 +11,11 @@ import { Span } from '../../../../../../typings/es_schemas/ui/Span'; import { expectTextsInDocument, expectTextsNotInDocument, - MockPluginContextWrapper + MockApmPluginContextWrapper } from '../../../../../utils/testHelpers'; const renderOptions = { - wrapper: MockPluginContextWrapper + wrapper: MockApmPluginContextWrapper }; describe('SpanMetadata', () => { diff --git a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/__test__/TransactionMetadata.test.tsx b/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/__test__/TransactionMetadata.test.tsx index 1ea20ecd64562..1fcb093fa0354 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/__test__/TransactionMetadata.test.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/__test__/TransactionMetadata.test.tsx @@ -11,11 +11,11 @@ import { Transaction } from '../../../../../../typings/es_schemas/ui/Transaction import { expectTextsInDocument, expectTextsNotInDocument, - MockPluginContextWrapper + MockApmPluginContextWrapper } from '../../../../../utils/testHelpers'; const renderOptions = { - wrapper: MockPluginContextWrapper + wrapper: MockApmPluginContextWrapper }; function getTransaction() { diff --git a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/__test__/MetadataTable.test.tsx b/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/__test__/MetadataTable.test.tsx index bed25fcc64012..979b9118a7534 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/__test__/MetadataTable.test.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/__test__/MetadataTable.test.tsx @@ -9,12 +9,12 @@ import { render } from '@testing-library/react'; import { MetadataTable } from '..'; import { expectTextsInDocument, - MockPluginContextWrapper + MockApmPluginContextWrapper } from '../../../../utils/testHelpers'; import { SectionsWithRows } from '../helper'; const renderOptions = { - wrapper: MockPluginContextWrapper + wrapper: MockApmPluginContextWrapper }; describe('MetadataTable', () => { diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx b/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx index 4a3b77b699c5f..040d29aaa56dd 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx @@ -23,7 +23,7 @@ import { DiscoverTransactionLink } from '../Links/DiscoverLinks/DiscoverTransact import { InfraLink } from '../Links/InfraLink'; import { useUrlParams } from '../../../hooks/useUrlParams'; import { fromQuery } from '../Links/url_helpers'; -import { useKibanaCore } from '../../../../../observability/public'; +import { useApmPluginContext } from '../../../hooks/useApmPluginContext'; function getInfraMetricsQuery(transaction: Transaction) { const plus5 = new Date(transaction['@timestamp']); @@ -65,7 +65,7 @@ export const TransactionActionMenu: FunctionComponent = ( ) => { const { transaction } = props; - const core = useKibanaCore(); + const { core } = useApmPluginContext(); const [isOpen, setIsOpen] = useState(false); diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/__test__/TransactionActionMenu.test.tsx b/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/__test__/TransactionActionMenu.test.tsx index 4bb018c760f1f..2bfa5cf1274fa 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/__test__/TransactionActionMenu.test.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/__test__/TransactionActionMenu.test.tsx @@ -9,12 +9,12 @@ import { render, fireEvent } from '@testing-library/react'; import { TransactionActionMenu } from '../TransactionActionMenu'; import { Transaction } from '../../../../../typings/es_schemas/ui/Transaction'; import * as Transactions from './mockData'; -import * as kibanaCore from '../../../../../../observability/public/context/kibana_core'; -import { LegacyCoreStart } from 'src/core/public'; +import { MockApmPluginContextWrapper } from '../../../../utils/testHelpers'; const renderTransaction = async (transaction: Record) => { const rendered = render( - + , + { wrapper: MockApmPluginContextWrapper } ); fireEvent.click(rendered.getByText('Actions')); @@ -23,22 +23,6 @@ const renderTransaction = async (transaction: Record) => { }; describe('TransactionActionMenu component', () => { - beforeEach(() => { - const coreMock = ({ - http: { - basePath: { - prepend: (path: string) => `/basepath${path}` - } - } - } as unknown) as LegacyCoreStart; - - jest.spyOn(kibanaCore, 'useKibanaCore').mockReturnValue(coreMock); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - it('should always render the discover link', async () => { const { queryByText } = await renderTransaction( Transactions.transactionWithMinimalData diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/TransactionCharts/BrowserLineChart.test.tsx b/x-pack/legacy/plugins/apm/public/components/shared/charts/TransactionCharts/BrowserLineChart.test.tsx index e95f733fb4bc8..6d3e29ec09985 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/charts/TransactionCharts/BrowserLineChart.test.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/charts/TransactionCharts/BrowserLineChart.test.tsx @@ -7,11 +7,18 @@ import React from 'react'; import { shallow } from 'enzyme'; import { BrowserLineChart } from './BrowserLineChart'; +import { MockApmPluginContextWrapper } from '../../../../utils/testHelpers'; describe('BrowserLineChart', () => { describe('render', () => { it('renders', () => { - expect(() => shallow()).not.toThrowError(); + expect(() => + shallow( + + + + ) + ).not.toThrowError(); }); }); }); diff --git a/x-pack/legacy/plugins/apm/public/context/ApmPluginContext.tsx b/x-pack/legacy/plugins/apm/public/context/ApmPluginContext.tsx new file mode 100644 index 0000000000000..86efd9b31974e --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/context/ApmPluginContext.tsx @@ -0,0 +1,18 @@ +/* + * 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 { createContext } from 'react'; +import { AppMountContext, PackageInfo } from 'kibana/public'; +import { ApmPluginSetupDeps, ConfigSchema } from '../new-platform/plugin'; + +export interface ApmPluginContextValue { + config: ConfigSchema; + core: AppMountContext['core']; + packageInfo: PackageInfo; + plugins: ApmPluginSetupDeps; +} + +export const ApmPluginContext = createContext({} as ApmPluginContextValue); diff --git a/x-pack/legacy/plugins/apm/public/context/LicenseContext/InvalidLicenseNotification.tsx b/x-pack/legacy/plugins/apm/public/context/LicenseContext/InvalidLicenseNotification.tsx index 1c340f4b4f3c7..36e780f50c3ae 100644 --- a/x-pack/legacy/plugins/apm/public/context/LicenseContext/InvalidLicenseNotification.tsx +++ b/x-pack/legacy/plugins/apm/public/context/LicenseContext/InvalidLicenseNotification.tsx @@ -6,10 +6,10 @@ import { EuiButton, EuiEmptyPrompt } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; -import { useKibanaCore } from '../../../../observability/public'; +import { useApmPluginContext } from '../../hooks/useApmPluginContext'; export function InvalidLicenseNotification() { - const core = useKibanaCore(); + const { core } = useApmPluginContext(); const manageLicenseURL = core.http.basePath.prepend( '/app/kibana#/management/elasticsearch/license_management' ); diff --git a/x-pack/legacy/plugins/apm/public/context/LicenseContext/index.tsx b/x-pack/legacy/plugins/apm/public/context/LicenseContext/index.tsx index 38a402fd72ed2..4bb246a2a745b 100644 --- a/x-pack/legacy/plugins/apm/public/context/LicenseContext/index.tsx +++ b/x-pack/legacy/plugins/apm/public/context/LicenseContext/index.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { FETCH_STATUS, useFetcher } from '../../hooks/useFetcher'; import { loadLicense, LicenseApiResponse } from '../../services/rest/xpack'; import { InvalidLicenseNotification } from './InvalidLicenseNotification'; -import { useKibanaCore } from '../../../../observability/public'; +import { useApmPluginContext } from '../../hooks/useApmPluginContext'; const initialLicense: LicenseApiResponse = { features: {}, @@ -18,7 +18,7 @@ const initialLicense: LicenseApiResponse = { export const LicenseContext = React.createContext(initialLicense); export const LicenseProvider: React.FC = ({ children }) => { - const { http } = useKibanaCore(); + const { http } = useApmPluginContext().core; const { data = initialLicense, status } = useFetcher( () => loadLicense(http), [http] diff --git a/x-pack/legacy/plugins/apm/public/new-platform/stackVersionFromLegacyMetadata.ts b/x-pack/legacy/plugins/apm/public/hooks/useApmPluginContext.ts similarity index 57% rename from x-pack/legacy/plugins/apm/public/new-platform/stackVersionFromLegacyMetadata.ts rename to x-pack/legacy/plugins/apm/public/hooks/useApmPluginContext.ts index 3d43b8e39a122..80a04edbca858 100644 --- a/x-pack/legacy/plugins/apm/public/new-platform/stackVersionFromLegacyMetadata.ts +++ b/x-pack/legacy/plugins/apm/public/hooks/useApmPluginContext.ts @@ -4,6 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { metadata } from 'ui/metadata'; +import { useContext } from 'react'; +import { ApmPluginContext } from '../context/ApmPluginContext'; -export const stackVersionFromLegacyMetadata = metadata.branch; +export function useApmPluginContext() { + return useContext(ApmPluginContext); +} diff --git a/x-pack/legacy/plugins/apm/public/hooks/useCallApi.ts b/x-pack/legacy/plugins/apm/public/hooks/useCallApi.ts index 6b12fd04d0916..415e6172ae81e 100644 --- a/x-pack/legacy/plugins/apm/public/hooks/useCallApi.ts +++ b/x-pack/legacy/plugins/apm/public/hooks/useCallApi.ts @@ -5,11 +5,11 @@ */ import { useMemo } from 'react'; -import { useKibanaCore } from '../../../observability/public'; import { callApi, FetchOptions } from '../services/rest/callApi'; +import { useApmPluginContext } from './useApmPluginContext'; export function useCallApi() { - const { http } = useKibanaCore(); + const { http } = useApmPluginContext().core; return useMemo(() => { return (options: FetchOptions) => callApi(http, options); diff --git a/x-pack/legacy/plugins/apm/public/hooks/useCallApmApi.ts b/x-pack/legacy/plugins/apm/public/hooks/useCallApmApi.ts index b201b396e05c3..b28b295d8189e 100644 --- a/x-pack/legacy/plugins/apm/public/hooks/useCallApmApi.ts +++ b/x-pack/legacy/plugins/apm/public/hooks/useCallApmApi.ts @@ -5,11 +5,11 @@ */ import { useMemo } from 'react'; -import { useKibanaCore } from '../../../observability/public'; import { createCallApmApi } from '../services/rest/createCallApmApi'; +import { useApmPluginContext } from './useApmPluginContext'; export function useCallApmApi() { - const { http } = useKibanaCore(); + const { http } = useApmPluginContext().core; return useMemo(() => { return createCallApmApi(http); diff --git a/x-pack/legacy/plugins/apm/public/hooks/useFetcher.integration.test.tsx b/x-pack/legacy/plugins/apm/public/hooks/useFetcher.integration.test.tsx index 743cf4e01e555..8d8716e6e5cd7 100644 --- a/x-pack/legacy/plugins/apm/public/hooks/useFetcher.integration.test.tsx +++ b/x-pack/legacy/plugins/apm/public/hooks/useFetcher.integration.test.tsx @@ -4,25 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; import { render, wait } from '@testing-library/react'; -import { delay } from '../utils/testHelpers'; +import React from 'react'; +import { delay, MockApmPluginContextWrapper } from '../utils/testHelpers'; import { useFetcher } from './useFetcher'; -import { KibanaCoreContext } from '../../../observability/public/context/kibana_core'; -import { LegacyCoreStart } from 'kibana/public'; - -// Wrap the hook with a provider so it can useKibanaCore -const wrapper = ({ children }: { children?: React.ReactNode }) => ( - {} } } - } as unknown) as LegacyCoreStart - } - > - {children} - -); + +const wrapper = MockApmPluginContextWrapper; async function asyncFn(name: string, ms: number) { await delay(ms); diff --git a/x-pack/legacy/plugins/apm/public/hooks/useFetcher.test.tsx b/x-pack/legacy/plugins/apm/public/hooks/useFetcher.test.tsx index 92246499c6229..e3ef1d44c8b03 100644 --- a/x-pack/legacy/plugins/apm/public/hooks/useFetcher.test.tsx +++ b/x-pack/legacy/plugins/apm/public/hooks/useFetcher.test.tsx @@ -5,24 +5,11 @@ */ import { renderHook } from '@testing-library/react-hooks'; -import { delay } from '../utils/testHelpers'; +import { delay, MockApmPluginContextWrapper } from '../utils/testHelpers'; import { useFetcher } from './useFetcher'; -import { KibanaCoreContext } from '../../../observability/public/context/kibana_core'; -import { LegacyCoreStart } from 'kibana/public'; -import React from 'react'; - -// Wrap the hook with a provider so it can useKibanaCore -const wrapper = ({ children }: { children?: React.ReactNode }) => ( - {} } } - } as unknown) as LegacyCoreStart - } - > - {children} - -); + +// Wrap the hook with a provider so it can useApmPluginContext +const wrapper = MockApmPluginContextWrapper; describe('useFetcher', () => { describe('when resolving after 500ms', () => { diff --git a/x-pack/legacy/plugins/apm/public/hooks/useFetcher.tsx b/x-pack/legacy/plugins/apm/public/hooks/useFetcher.tsx index 2d60273c1896a..ac8f40a29d93a 100644 --- a/x-pack/legacy/plugins/apm/public/hooks/useFetcher.tsx +++ b/x-pack/legacy/plugins/apm/public/hooks/useFetcher.tsx @@ -10,9 +10,9 @@ import { IHttpFetchError } from 'src/core/public'; import { toMountPoint } from '../../../../../../src/plugins/kibana_react/public'; import { LoadingIndicatorContext } from '../context/LoadingIndicatorContext'; import { useComponentId } from './useComponentId'; -import { useKibanaCore } from '../../../observability/public'; import { APMClient } from '../services/rest/createCallApmApi'; import { useCallApmApi } from './useCallApmApi'; +import { useApmPluginContext } from './useApmPluginContext'; export enum FETCH_STATUS { LOADING = 'loading', @@ -42,7 +42,7 @@ export function useFetcher( preservePreviousData?: boolean; } = {} ): Result> & { refetch: () => void } { - const { notifications } = useKibanaCore(); + const { notifications } = useApmPluginContext().core; const { preservePreviousData = true } = options; const id = useComponentId(); diff --git a/x-pack/legacy/plugins/apm/public/index.tsx b/x-pack/legacy/plugins/apm/public/index.tsx index db14e1c520020..59b2fedaafba6 100644 --- a/x-pack/legacy/plugins/apm/public/index.tsx +++ b/x-pack/legacy/plugins/apm/public/index.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { npStart } from 'ui/new_platform'; +import { npSetup, npStart } from 'ui/new_platform'; import 'react-vis/dist/style.css'; import { PluginInitializerContext } from 'kibana/public'; import 'ui/autoload/all'; @@ -14,8 +14,6 @@ import { REACT_APP_ROOT_ID } from './new-platform/plugin'; import './style/global_overrides.css'; import template from './templates/index.html'; -const { core, plugins } = npStart; - // This will be moved to core.application.register when the new platform // migration is complete. // @ts-ignore @@ -32,5 +30,7 @@ const checkForRoot = () => { }); }; checkForRoot().then(() => { - plugin({} as PluginInitializerContext).start(core, plugins); + const pluginInstance = plugin({} as PluginInitializerContext); + pluginInstance.setup(npSetup.core, npSetup.plugins); + pluginInstance.start(npStart.core, npStart.plugins); }); diff --git a/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx b/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx index 8277707e538ac..38dc82f01b386 100644 --- a/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx +++ b/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx @@ -4,20 +4,20 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useContext, createContext } from 'react'; +import React from 'react'; import ReactDOM from 'react-dom'; import { Router, Route, Switch } from 'react-router-dom'; import styled from 'styled-components'; +import { metadata } from 'ui/metadata'; import { HomePublicPluginSetup } from '../../../../../../src/plugins/home/public'; import { CoreStart, - LegacyCoreStart, Plugin, CoreSetup, - PluginInitializerContext + PluginInitializerContext, + PackageInfo } from '../../../../../../src/core/public'; -import { DataPublicPluginStart } from '../../../../../../src/plugins/data/public'; -import { KibanaCoreContextProvider } from '../../../observability/public'; +import { DataPublicPluginSetup } from '../../../../../../src/plugins/data/public'; import { history } from '../utils/history'; import { LocationProvider } from '../context/LocationContext'; import { UrlParamsProvider } from '../context/UrlParamsContext'; @@ -35,7 +35,7 @@ import { featureCatalogueEntry } from './featureCatalogueEntry'; import { getConfigFromInjectedMetadata } from './getConfigFromInjectedMetadata'; import { toggleAppLinkInNav } from './toggleAppLinkInNav'; import { BreadcrumbRoute } from '../components/app/Main/ProvideBreadcrumbs'; -import { stackVersionFromLegacyMetadata } from './stackVersionFromLegacyMetadata'; +import { ApmPluginContext } from '../context/ApmPluginContext'; export const REACT_APP_ROOT_ID = 'react-apm-root'; @@ -63,13 +63,10 @@ export type ApmPluginSetup = void; export type ApmPluginStart = void; export interface ApmPluginSetupDeps { + data: DataPublicPluginSetup; home: HomePublicPluginSetup; } -export interface ApmPluginStartDeps { - data: DataPublicPluginStart; -} - export interface ConfigSchema { indexPatternTitle: string; serviceMapEnabled: boolean; @@ -78,27 +75,14 @@ export interface ConfigSchema { }; } -// These are to be used until we switch over all our context handling to -// kibana_react -export const PluginsContext = createContext< - ApmPluginStartDeps & { apm: { config: ConfigSchema; stackVersion: string } } ->( - {} as ApmPluginStartDeps & { - apm: { config: ConfigSchema; stackVersion: string }; - } -); -export function usePlugins() { - return useContext(PluginsContext); -} - export class ApmPlugin - implements - Plugin< - ApmPluginSetup, - ApmPluginStart, - ApmPluginSetupDeps, - ApmPluginStartDeps - > { + implements Plugin { + // When we switch over from the old platform to new platform the plugins will + // be coming from setup instead of start, since that's where we do + // `core.application.register`. During the transitions we put plugins on an + // instance property so we can use it in start. + setupPlugins: ApmPluginSetupDeps = {} as ApmPluginSetupDeps; + constructor( // @ts-ignore Not using initializerContext now, but will be once NP // migration is complete. @@ -108,10 +92,12 @@ export class ApmPlugin // Take the DOM element as the constructor, so we can mount the app. public setup(_core: CoreSetup, plugins: ApmPluginSetupDeps) { plugins.home.featureCatalogue.register(featureCatalogueEntry); + this.setupPlugins = plugins; } - public start(core: CoreStart, plugins: ApmPluginStartDeps) { + public start(core: CoreStart) { const i18nCore = core.i18n; + const plugins = this.setupPlugins; // Once we're actually an NP plugin we'll get the config from the // initializerContext like: @@ -124,12 +110,10 @@ export class ApmPlugin // Once we're actually an NP plugin we'll get the package info from the // initializerContext like: // - // const stackVersion = this.initializerContext.env.packageInfo.branch + // const packageInfo = this.initializerContext.env.packageInfo // // Until then we use a shim to get it from legacy metadata: - const stackVersion = stackVersionFromLegacyMetadata; - - const pluginsForContext = { ...plugins, apm: { config, stackVersion } }; + const packageInfo = metadata as PackageInfo; const routes = getRoutes(config); @@ -138,26 +122,31 @@ export class ApmPlugin setReadonlyBadge(core); toggleAppLinkInNav(core, config); + const apmPluginContextValue = { + config, + core, + packageInfo, + plugins + }; + ReactDOM.render( - - - - - - - - - - - - - - - - - - - , + + + + + + + + + + + + + + + + + , document.getElementById(REACT_APP_ROOT_ID) ); diff --git a/x-pack/legacy/plugins/apm/public/utils/testHelpers.tsx b/x-pack/legacy/plugins/apm/public/utils/testHelpers.tsx index 9e3c486715a1f..4e0a0209926bf 100644 --- a/x-pack/legacy/plugins/apm/public/utils/testHelpers.tsx +++ b/x-pack/legacy/plugins/apm/public/utils/testHelpers.tsx @@ -11,7 +11,7 @@ import enzymeToJson from 'enzyme-to-json'; import { Location } from 'history'; import moment from 'moment'; import { Moment } from 'moment-timezone'; -import React, { FunctionComponent, ReactNode } from 'react'; +import React, { ReactNode } from 'react'; import { render, waitForElement } from '@testing-library/react'; import '@testing-library/jest-dom/extend-expect'; import { MemoryRouter } from 'react-router-dom'; @@ -20,10 +20,10 @@ import { LocationProvider } from '../context/LocationContext'; import { PromiseReturnType } from '../../typings/common'; import { ESFilter } from '../../typings/elasticsearch'; import { - PluginsContext, - ConfigSchema, - ApmPluginStartDeps -} from '../new-platform/plugin'; + ApmPluginContext, + ApmPluginContextValue +} from '../context/ApmPluginContext'; +import { ConfigSchema } from '../new-platform/plugin'; export function toJson(wrapper: ReactWrapper) { return enzymeToJson(wrapper, { @@ -51,11 +51,13 @@ export function mockMoment() { // Useful for getting the rendered href from any kind of link component export async function getRenderedHref(Component: React.FC, location: Location) { const el = render( - - - - - + + + + + + + ); await waitForElement(() => el.container.querySelector('a')); @@ -181,22 +183,52 @@ export async function inspectSearchParams( export type SearchParamsMock = PromiseReturnType; -export const MockPluginContextWrapper: FunctionComponent<{}> = ({ - children +const mockCore = { + chrome: { + setBreadcrumbs: () => {} + }, + http: { + basePath: { + prepend: (path: string) => `/basepath${path}` + } + }, + notifications: { + toasts: { + addWarning: () => {} + } + } +}; + +const mockConfig: ConfigSchema = { + indexPatternTitle: 'apm-*', + serviceMapEnabled: false, + ui: { + enabled: false + } +}; + +export const mockApmPluginContextValue = { + config: mockConfig, + core: mockCore, + packageInfo: { version: '0' }, + plugins: {} +}; + +export function MockApmPluginContextWrapper({ + children, + value = {} as ApmPluginContextValue }: { children?: ReactNode; -}) => { + value?: ApmPluginContextValue; +}) { return ( - {children} - + ); -}; +} diff --git a/x-pack/legacy/plugins/observability/README.md b/x-pack/legacy/plugins/observability/README.md deleted file mode 100644 index f7d8365fe6c80..0000000000000 --- a/x-pack/legacy/plugins/observability/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Observability Shared Resources - -This "faux" plugin serves as a place to statically share resources, helpers, and components across observability plugins. There is some discussion still happening about the best way to do this, but this is one suggested method that will work for now and has the benefit of adopting our pre-defined build and compile tooling out of the box. - -Files found here can be imported from any other x-pack plugin, with the caveat that these shared components should all be exposed from either `public/index` or `server/index` so that the platform can attempt to monitor breaking changes in this shared API. - -# for a file found at `x-pack/legacy/plugins/infra/public/components/Example.tsx` - -```ts -import { ExampleSharedComponent } from '../../../observability/public'; -``` - -### Plugin registration and config - -There is no plugin registration code or config in this folder because it's a "faux" plugin only being used to share code between other plugins. Plugins using this code do not need to register a dependency on this plugin unless this plugin ever exports functionality that relies on Kibana core itself (rather than being static DI components and utilities only, as it is now). - -### Directory structure - -Code meant to be shared by the UI should live in `public/` and be explicity exported from `public/index` while server helpers etc should live in `server/` and be explicitly exported from `server/index`. Code that needs to be shared across client and server should be exported from both places (not put in `common`, etc). diff --git a/x-pack/legacy/plugins/observability/public/components/example_shared_component.tsx b/x-pack/legacy/plugins/observability/public/components/example_shared_component.tsx deleted file mode 100644 index e7cac9e3d7015..0000000000000 --- a/x-pack/legacy/plugins/observability/public/components/example_shared_component.tsx +++ /dev/null @@ -1,15 +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'; - -interface Props { - message?: string; -} - -export function ExampleSharedComponent({ message = 'See how it loads.' }: Props) { - return

This is an example of an observability shared component. {message}

; -} diff --git a/x-pack/legacy/plugins/observability/public/context/kibana_core.tsx b/x-pack/legacy/plugins/observability/public/context/kibana_core.tsx deleted file mode 100644 index ab936ed689edf..0000000000000 --- a/x-pack/legacy/plugins/observability/public/context/kibana_core.tsx +++ /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 React, { createContext, useContext } from 'react'; -import { LegacyCoreStart } from '../../../../../../src/core/public'; - -interface AppMountContext { - core: LegacyCoreStart; -} - -// TODO: Replace CoreStart/CoreSetup with AppMountContext -// see: https://github.com/elastic/kibana/pull/41007 - -export const KibanaCoreContext = createContext({} as AppMountContext['core']); - -export const KibanaCoreContextProvider: React.FC<{ core: AppMountContext['core'] }> = props => ( - -); - -export function useKibanaCore() { - return useContext(KibanaCoreContext); -} diff --git a/x-pack/legacy/plugins/observability/public/index.tsx b/x-pack/legacy/plugins/observability/public/index.tsx deleted file mode 100644 index 49e5a6d787a55..0000000000000 --- a/x-pack/legacy/plugins/observability/public/index.tsx +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -import { KibanaCoreContext, KibanaCoreContextProvider, useKibanaCore } from './context/kibana_core'; -import { ExampleSharedComponent } from './components/example_shared_component'; - -export { ExampleSharedComponent, KibanaCoreContext, KibanaCoreContextProvider, useKibanaCore }; From e3f3dd15ba274803c406e6e9fd1014016d2a174c Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Wed, 11 Dec 2019 23:51:37 +0300 Subject: [PATCH 27/79] Fix ts types for AggType folder (#50049) --- src/legacy/ui/public/agg_types/agg_config.ts | 17 ++++++----- src/legacy/ui/public/agg_types/agg_configs.ts | 7 +++-- .../ui/public/agg_types/agg_params.test.ts | 11 +++---- src/legacy/ui/public/agg_types/agg_params.ts | 28 +++++++++--------- src/legacy/ui/public/agg_types/agg_type.ts | 17 ++++++----- .../agg_types/buckets/_bucket_agg_type.ts | 26 ++++++++++------- .../buckets/create_filter/date_range.test.ts | 3 +- .../buckets/create_filter/filters.test.ts | 3 +- .../buckets/create_filter/histogram.test.ts | 3 +- .../buckets/create_filter/ip_range.test.ts | 5 ++-- .../buckets/create_filter/range.test.ts | 6 +++- .../buckets/create_filter/terms.test.ts | 27 ++++++++++++----- .../agg_types/buckets/date_histogram.ts | 29 +++++++++++-------- .../ui/public/agg_types/buckets/date_range.ts | 2 +- .../ui/public/agg_types/buckets/filters.ts | 4 +-- .../ui/public/agg_types/buckets/geo_hash.ts | 2 +- .../ui/public/agg_types/buckets/geo_tile.ts | 7 +++-- .../ui/public/agg_types/buckets/histogram.ts | 10 +++---- .../ui/public/agg_types/buckets/ip_range.ts | 4 +-- .../buckets/migrate_include_exclude_format.ts | 7 +++-- .../ui/public/agg_types/buckets/range.ts | 3 +- .../buckets/significant_terms.test.ts | 3 +- .../agg_types/buckets/significant_terms.ts | 6 ++-- .../ui/public/agg_types/buckets/terms.ts | 25 +++++++++------- .../metrics/lib/nested_agg_helpers.ts | 2 +- .../metrics/lib/parent_pipeline_agg_helper.ts | 6 ++-- .../lib/sibling_pipeline_agg_helper.ts | 4 +-- .../ui/public/agg_types/metrics/median.ts | 4 +-- .../agg_types/metrics/metric_agg_type.ts | 24 ++++++++------- .../agg_types/metrics/parent_pipeline.test.ts | 2 +- .../agg_types/metrics/percentile_ranks.ts | 4 +-- .../public/agg_types/metrics/percentiles.ts | 4 +-- .../metrics/sibling_pipeline.test.ts | 2 +- .../public/agg_types/metrics/top_hit.test.ts | 2 +- .../ui/public/agg_types/metrics/top_hit.ts | 6 ++-- .../ui/public/agg_types/param_types/agg.ts | 12 ++++---- .../ui/public/agg_types/param_types/base.ts | 17 +++++------ 37 files changed, 195 insertions(+), 149 deletions(-) diff --git a/src/legacy/ui/public/agg_types/agg_config.ts b/src/legacy/ui/public/agg_types/agg_config.ts index d4ef203721456..9306ffcaff9fd 100644 --- a/src/legacy/ui/public/agg_types/agg_config.ts +++ b/src/legacy/ui/public/agg_types/agg_config.ts @@ -29,7 +29,6 @@ import { i18n } from '@kbn/i18n'; import { npStart } from 'ui/new_platform'; import { SearchSourceContract, FetchOptions } from '../courier/types'; import { AggType } from './agg_type'; -import { FieldParamType } from './param_types/field'; import { AggGroupNames } from '../vis/editors/default/agg_groups'; import { writeParams } from './agg_params'; import { AggConfigs } from './agg_configs'; @@ -204,7 +203,7 @@ export class AggConfig { } write(aggs?: AggConfigs) { - return writeParams(this.type.params, this, aggs); + return writeParams(this.type.params, this, aggs); } isFilterable() { @@ -425,13 +424,15 @@ export class AggConfig { } this.__type = type; + let availableFields = []; + + const fieldParam = this.type && this.type.params.find((p: any) => p.type === 'field'); + + if (fieldParam) { + // @ts-ignore + availableFields = fieldParam.getAvailableFields(this.getIndexPattern().fields); + } - const fieldParam = - this.type && (this.type.params.find((p: any) => p.type === 'field') as FieldParamType); - // @ts-ignore - const availableFields = fieldParam - ? fieldParam.getAvailableFields(this.getIndexPattern().fields) - : []; // clear out the previous params except for a few special ones this.setParams({ // split row/columns is "outside" of the agg, so don't reset it diff --git a/src/legacy/ui/public/agg_types/agg_configs.ts b/src/legacy/ui/public/agg_types/agg_configs.ts index b4ea0ec8bc465..b5a7474c99b0e 100644 --- a/src/legacy/ui/public/agg_types/agg_configs.ts +++ b/src/legacy/ui/public/agg_types/agg_configs.ts @@ -126,7 +126,10 @@ export class AggConfigs { return aggConfigs; } - createAggConfig(params: AggConfig | AggConfigOptions, { addToAggConfigs = true } = {}) { + createAggConfig( + params: AggConfig | AggConfigOptions, + { addToAggConfigs = true } = {} + ) { let aggConfig; if (params instanceof AggConfig) { aggConfig = params; @@ -137,7 +140,7 @@ export class AggConfigs { if (addToAggConfigs) { this.aggs.push(aggConfig); } - return aggConfig; + return aggConfig as T; } /** diff --git a/src/legacy/ui/public/agg_types/agg_params.test.ts b/src/legacy/ui/public/agg_types/agg_params.test.ts index 28d852c7f2567..25e62e06d52d7 100644 --- a/src/legacy/ui/public/agg_types/agg_params.test.ts +++ b/src/legacy/ui/public/agg_types/agg_params.test.ts @@ -17,17 +17,18 @@ * under the License. */ -import { AggParam, initParams } from './agg_params'; +import { initParams } from './agg_params'; import { BaseParamType } from './param_types/base'; import { FieldParamType } from './param_types/field'; import { OptionedParamType } from './param_types/optioned'; +import { AggParamType } from '../agg_types/param_types/agg'; jest.mock('ui/new_platform'); describe('AggParams class', () => { describe('constructor args', () => { it('accepts an array of param defs', () => { - const params = [{ name: 'one' }, { name: 'two' }] as AggParam[]; + const params = [{ name: 'one' }, { name: 'two' }] as AggParamType[]; const aggParams = initParams(params); expect(aggParams).toHaveLength(params.length); @@ -37,7 +38,7 @@ describe('AggParams class', () => { describe('AggParam creation', () => { it('Uses the FieldParamType class for params with the name "field"', () => { - const params = [{ name: 'field', type: 'field' }] as AggParam[]; + const params = [{ name: 'field', type: 'field' }] as AggParamType[]; const aggParams = initParams(params); expect(aggParams).toHaveLength(params.length); @@ -50,7 +51,7 @@ describe('AggParams class', () => { name: 'order', type: 'optioned', }, - ]; + ] as AggParamType[]; const aggParams = initParams(params); expect(aggParams).toHaveLength(params.length); @@ -71,7 +72,7 @@ describe('AggParams class', () => { name: 'waist', displayName: 'waist', }, - ] as AggParam[]; + ] as AggParamType[]; const aggParams = initParams(params); diff --git a/src/legacy/ui/public/agg_types/agg_params.ts b/src/legacy/ui/public/agg_types/agg_params.ts index 8925bf9e3d46c..262a57f4a5aa3 100644 --- a/src/legacy/ui/public/agg_types/agg_params.ts +++ b/src/legacy/ui/public/agg_types/agg_params.ts @@ -44,17 +44,10 @@ export interface AggParamOption { enabled?(agg: AggConfig): boolean; } -export interface AggParamConfig { - type: string; -} - -export const initParams = < - TAggParam extends AggParam = AggParam, - TAggParamConfig extends AggParamConfig = AggParamConfig ->( - params: TAggParamConfig[] +export const initParams = ( + params: TAggParam[] ): TAggParam[] => - params.map((config: TAggParamConfig) => { + params.map((config: TAggParam) => { const Class = paramTypeMap[config.type] || paramTypeMap._default; return new Class(config); @@ -74,20 +67,25 @@ export const initParams = < * output object which is used to create the agg dsl for the search request. All other properties * are dependent on the AggParam#write methods which should be studied for each AggType. */ -export const writeParams = ( - params: AggParam[], - aggConfig: AggConfig, +export const writeParams = < + TAggConfig extends AggConfig = AggConfig, + TAggParam extends AggParamType = AggParamType +>( + params: Array> = [], + aggConfig: TAggConfig, aggs?: AggConfigs, locals?: Record ) => { const output = { params: {} as Record }; locals = locals || {}; - params.forEach(function(param) { + params.forEach(param => { if (param.write) { param.write(aggConfig, output, aggs, locals); } else { - output.params[param.name] = aggConfig.params[param.name]; + if (param && param.name) { + output.params[param.name] = aggConfig.params[param.name]; + } } }); diff --git a/src/legacy/ui/public/agg_types/agg_type.ts b/src/legacy/ui/public/agg_types/agg_type.ts index 5216affb3e52d..ff4c6875ec6c0 100644 --- a/src/legacy/ui/public/agg_types/agg_type.ts +++ b/src/legacy/ui/public/agg_types/agg_type.ts @@ -20,19 +20,19 @@ import { constant, noop, identity } from 'lodash'; import { i18n } from '@kbn/i18n'; import { npStart } from 'ui/new_platform'; -import { AggParam, initParams } from './agg_params'; +import { initParams } from './agg_params'; import { AggConfig } from '../vis'; import { AggConfigs } from './agg_configs'; import { SearchSource } from '../courier'; import { Adapters } from '../inspector'; import { BaseParamType } from './param_types/base'; - +import { AggParamType } from '../agg_types/param_types/agg'; import { KBN_FIELD_TYPES, FieldFormat } from '../../../../plugins/data/public'; export interface AggTypeConfig< TAggConfig extends AggConfig = AggConfig, - TParam extends AggParam = AggParam + TParam extends AggParamType = AggParamType > { name: string; title: string; @@ -46,7 +46,7 @@ export interface AggTypeConfig< getRequestAggs?: ((aggConfig: TAggConfig) => TAggConfig[]) | (() => TAggConfig[] | void); getResponseAggs?: ((aggConfig: TAggConfig) => TAggConfig[]) | (() => TAggConfig[] | void); customLabels?: boolean; - decorateAggConfig?: () => Record; + decorateAggConfig?: () => any; postFlightRequest?: ( resp: any, aggConfigs: AggConfigs, @@ -67,7 +67,10 @@ const getFormat = (agg: AggConfig) => { return field ? field.format : fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.STRING); }; -export class AggType { +export class AggType< + TAggConfig extends AggConfig = AggConfig, + TParam extends AggParamType = AggParamType +> { /** * the unique, unchanging, name that we have assigned this aggType * @@ -162,7 +165,7 @@ export class AggType Record; + decorateAggConfig: () => any; /** * A function that needs to be called after the main request has been made * and should return an updated response @@ -196,7 +199,7 @@ export class AggType any; paramByName = (name: string) => { - return this.params.find((p: AggParam) => p.name === name); + return this.params.find((p: TParam) => p.name === name); }; /** diff --git a/src/legacy/ui/public/agg_types/buckets/_bucket_agg_type.ts b/src/legacy/ui/public/agg_types/buckets/_bucket_agg_type.ts index c151f9101d090..ed332ea420bcc 100644 --- a/src/legacy/ui/public/agg_types/buckets/_bucket_agg_type.ts +++ b/src/legacy/ui/public/agg_types/buckets/_bucket_agg_type.ts @@ -17,29 +17,33 @@ * under the License. */ -import { AggParamType } from '../param_types/agg'; import { AggConfig } from '../../vis'; import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; import { AggType, AggTypeConfig } from '../agg_type'; +import { AggParamType } from '../param_types/agg'; -export type IBucketAggConfig = AggConfig; +export interface IBucketAggConfig extends AggConfig { + type: InstanceType; +} -export interface BucketAggParam extends AggParamType { +export interface BucketAggParam + extends AggParamType { scriptable?: boolean; filterFieldTypes?: KBN_FIELD_TYPES | KBN_FIELD_TYPES[] | '*'; } -export interface BucketAggTypeConfig - extends AggTypeConfig { +const bucketType = 'buckets'; + +interface BucketAggTypeConfig + extends AggTypeConfig> { getKey?: (bucket: any, key: any, agg: AggConfig) => any; } -const bucketType = 'buckets'; - -export class BucketAggType< - TBucketAggConfig extends IBucketAggConfig = IBucketAggConfig -> extends AggType { - getKey: (bucket: any, key: any, agg: IBucketAggConfig) => any; +export class BucketAggType extends AggType< + TBucketAggConfig, + BucketAggParam +> { + getKey: (bucket: any, key: any, agg: TBucketAggConfig) => any; type = bucketType; constructor(config: BucketAggTypeConfig) { diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/date_range.test.ts b/src/legacy/ui/public/agg_types/buckets/create_filter/date_range.test.ts index 0399e8d382320..ddb4102563a7c 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/date_range.test.ts +++ b/src/legacy/ui/public/agg_types/buckets/create_filter/date_range.test.ts @@ -22,6 +22,7 @@ import { createFilterDateRange } from './date_range'; import { DateFormat } from '../../../../../../plugins/data/public'; import { AggConfigs } from '../../agg_configs'; import { BUCKET_TYPES } from '../bucket_agg_types'; +import { IBucketAggConfig } from '../_bucket_agg_type'; jest.mock('ui/new_platform'); @@ -61,7 +62,7 @@ describe('AggConfig Filters', () => { const aggConfigs = getAggConfigs(); const from = new Date('1 Feb 2015'); const to = new Date('7 Feb 2015'); - const filter = createFilterDateRange(aggConfigs.aggs[0], { + const filter = createFilterDateRange(aggConfigs.aggs[0] as IBucketAggConfig, { from: from.valueOf(), to: to.valueOf(), }); diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/filters.test.ts b/src/legacy/ui/public/agg_types/buckets/create_filter/filters.test.ts index 125532fe070ba..34cf996826865 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/filters.test.ts +++ b/src/legacy/ui/public/agg_types/buckets/create_filter/filters.test.ts @@ -18,6 +18,7 @@ */ import { createFilterFilters } from './filters'; import { AggConfigs } from '../../agg_configs'; +import { IBucketAggConfig } from '../_bucket_agg_type'; jest.mock('ui/new_platform'); @@ -56,7 +57,7 @@ describe('AggConfig Filters', () => { }; it('should return a filters filter', () => { const aggConfigs = getAggConfigs(); - const filter = createFilterFilters(aggConfigs.aggs[0], 'type:nginx'); + const filter = createFilterFilters(aggConfigs.aggs[0] as IBucketAggConfig, 'type:nginx'); expect(filter!.query.bool.must[0].query_string.query).toBe('type:nginx'); expect(filter!.meta).toHaveProperty('index', '1234'); diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/histogram.test.ts b/src/legacy/ui/public/agg_types/buckets/create_filter/histogram.test.ts index ac8e55f096fb4..d07cf84aef4d9 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/histogram.test.ts +++ b/src/legacy/ui/public/agg_types/buckets/create_filter/histogram.test.ts @@ -19,6 +19,7 @@ import { createFilterHistogram } from './histogram'; import { AggConfigs } from '../../agg_configs'; import { BUCKET_TYPES } from '../bucket_agg_types'; +import { IBucketAggConfig } from '../_bucket_agg_type'; import { BytesFormat } from '../../../../../../plugins/data/public'; jest.mock('ui/new_platform'); @@ -59,7 +60,7 @@ describe('AggConfig Filters', () => { it('should return an range filter for histogram', () => { const aggConfigs = getAggConfigs(); - const filter = createFilterHistogram(aggConfigs.aggs[0], '2048'); + const filter = createFilterHistogram(aggConfigs.aggs[0] as IBucketAggConfig, '2048'); expect(filter).toHaveProperty('meta'); expect(filter.meta).toHaveProperty('index', '1234'); diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.test.ts b/src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.test.ts index 569735a60298d..bf6b437f17cf2 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.test.ts +++ b/src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.test.ts @@ -21,6 +21,7 @@ import { createFilterIpRange } from './ip_range'; import { AggConfigs } from '../../agg_configs'; import { IpFormat } from '../../../../../../plugins/data/public'; import { BUCKET_TYPES } from '../bucket_agg_types'; +import { IBucketAggConfig } from '../_bucket_agg_type'; jest.mock('ui/new_platform'); @@ -59,7 +60,7 @@ describe('AggConfig Filters', () => { }, ]); - const filter = createFilterIpRange(aggConfigs.aggs[0], { + const filter = createFilterIpRange(aggConfigs.aggs[0] as IBucketAggConfig, { type: 'range', from: '0.0.0.0', to: '1.1.1.1', @@ -88,7 +89,7 @@ describe('AggConfig Filters', () => { }, ]); - const filter = createFilterIpRange(aggConfigs.aggs[0], { + const filter = createFilterIpRange(aggConfigs.aggs[0] as IBucketAggConfig, { type: 'mask', mask: '67.129.65.201/27', }); diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/range.test.ts b/src/legacy/ui/public/agg_types/buckets/create_filter/range.test.ts index e7344f16ba0b1..dc02b773edc42 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/range.test.ts +++ b/src/legacy/ui/public/agg_types/buckets/create_filter/range.test.ts @@ -21,6 +21,7 @@ import { createFilterRange } from './range'; import { BytesFormat } from '../../../../../../plugins/data/public'; import { AggConfigs } from '../../agg_configs'; import { BUCKET_TYPES } from '../bucket_agg_types'; +import { IBucketAggConfig } from '../_bucket_agg_type'; jest.mock('ui/new_platform'); @@ -60,7 +61,10 @@ describe('AggConfig Filters', () => { it('should return a range filter for range agg', () => { const aggConfigs = getAggConfigs(); - const filter = createFilterRange(aggConfigs.aggs[0], { gte: 1024, lt: 2048.0 }); + const filter = createFilterRange(aggConfigs.aggs[0] as IBucketAggConfig, { + gte: 1024, + lt: 2048.0, + }); expect(filter).toHaveProperty('range'); expect(filter).toHaveProperty('meta'); diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/terms.test.ts b/src/legacy/ui/public/agg_types/buckets/create_filter/terms.test.ts index 42f8349d5a2a3..86c0aa24f529a 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/terms.test.ts +++ b/src/legacy/ui/public/agg_types/buckets/create_filter/terms.test.ts @@ -20,6 +20,7 @@ import { createFilterTerms } from './terms'; import { AggConfigs } from '../../agg_configs'; import { BUCKET_TYPES } from '../bucket_agg_types'; +import { IBucketAggConfig } from '../_bucket_agg_type'; import { esFilters } from '../../../../../../plugins/data/public'; jest.mock('ui/new_platform'); @@ -49,7 +50,11 @@ describe('AggConfig Filters', () => { { type: BUCKET_TYPES.TERMS, schema: 'segment', params: { field: 'field' } }, ]); - const filter = createFilterTerms(aggConfigs.aggs[0], 'apache', {}) as esFilters.Filter; + const filter = createFilterTerms( + aggConfigs.aggs[0] as IBucketAggConfig, + 'apache', + {} + ) as esFilters.Filter; expect(filter).toHaveProperty('query'); expect(filter.query).toHaveProperty('match_phrase'); @@ -64,27 +69,35 @@ describe('AggConfig Filters', () => { { type: BUCKET_TYPES.TERMS, schema: 'segment', params: { field: 'field' } }, ]); - const filterFalse = createFilterTerms(aggConfigs.aggs[0], '', {}) as esFilters.Filter; + const filterFalse = createFilterTerms( + aggConfigs.aggs[0] as IBucketAggConfig, + '', + {} + ) as esFilters.Filter; expect(filterFalse).toHaveProperty('query'); expect(filterFalse.query).toHaveProperty('match_phrase'); expect(filterFalse.query.match_phrase).toHaveProperty('field'); expect(filterFalse.query.match_phrase.field).toBeFalsy(); - const filterTrue = createFilterTerms(aggConfigs.aggs[0], '1', {}) as esFilters.Filter; + const filterTrue = createFilterTerms( + aggConfigs.aggs[0] as IBucketAggConfig, + '1', + {} + ) as esFilters.Filter; expect(filterTrue).toHaveProperty('query'); expect(filterTrue.query).toHaveProperty('match_phrase'); expect(filterTrue.query.match_phrase).toHaveProperty('field'); expect(filterTrue.query.match_phrase.field).toBeTruthy(); }); - // + it('should generate correct __missing__ filter', () => { const aggConfigs = getAggConfigs([ { type: BUCKET_TYPES.TERMS, schema: 'segment', params: { field: 'field' } }, ]); const filter = createFilterTerms( - aggConfigs.aggs[0], + aggConfigs.aggs[0] as IBucketAggConfig, '__missing__', {} ) as esFilters.ExistsFilter; @@ -95,13 +108,13 @@ describe('AggConfig Filters', () => { expect(filter.meta).toHaveProperty('index', '1234'); expect(filter.meta).toHaveProperty('negate', true); }); - // + it('should generate correct __other__ filter', () => { const aggConfigs = getAggConfigs([ { type: BUCKET_TYPES.TERMS, schema: 'segment', params: { field: 'field' } }, ]); - const [filter] = createFilterTerms(aggConfigs.aggs[0], '__other__', { + const [filter] = createFilterTerms(aggConfigs.aggs[0] as IBucketAggConfig, '__other__', { terms: ['apache'], }) as esFilters.Filter[]; diff --git a/src/legacy/ui/public/agg_types/buckets/date_histogram.ts b/src/legacy/ui/public/agg_types/buckets/date_histogram.ts index 6a87b2e88ac4c..45122a24c8184 100644 --- a/src/legacy/ui/public/agg_types/buckets/date_histogram.ts +++ b/src/legacy/ui/public/agg_types/buckets/date_histogram.ts @@ -20,9 +20,10 @@ import _ from 'lodash'; import moment from 'moment-timezone'; import { i18n } from '@kbn/i18n'; -import { BUCKET_TYPES } from 'ui/agg_types/buckets/bucket_agg_types'; + import { npStart } from 'ui/new_platform'; -import { BucketAggParam, BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; +import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; +import { BUCKET_TYPES } from './bucket_agg_types'; import { createFilterDateHistogram } from './create_filter/date_histogram'; import { intervalOptions } from './_interval_options'; import { TimeIntervalParamEditor } from '../../vis/editors/default/controls/time_interval'; @@ -31,7 +32,6 @@ import { DropPartialsParamEditor } from '../../vis/editors/default/controls/drop import { ScaleMetricsParamEditor } from '../../vis/editors/default/controls/scale_metrics'; import { dateHistogramInterval } from '../../../../core_plugins/data/public'; import { writeParams } from '../agg_params'; -import { AggConfigs } from '../agg_configs'; import { isMetricAggType } from '../metrics/metric_agg_type'; import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; @@ -77,7 +77,12 @@ export const dateHistogramBucketAgg = new BucketAggType = writeParams(this.params as BucketAggParam[], agg); + let output: Record = {}; + + if (this.params) { + output = writeParams(this.params, agg); + } + const field = agg.getFieldDisplayName(); return i18n.translate('common.ui.aggTypes.buckets.dateHistogramLabel', { defaultMessage: '{fieldName} per {intervalDescription}', @@ -102,7 +107,7 @@ export const dateHistogramBucketAgg = new BucketAggType, aggs: AggConfigs) { + write(agg, output, aggs) { setBounds(agg, true); agg.buckets.setInterval(getInterval(agg)); const { useNormalizedEsInterval, scaleMetricValues } = agg.params; @@ -200,7 +205,7 @@ export const dateHistogramBucketAgg = new BucketAggType) { + write(agg, output) { // If a time_zone has been set explicitly always prefer this. let tz = agg.params.time_zone; if (!tz && agg.params.field) { @@ -230,7 +235,7 @@ export const dateHistogramBucketAgg = new BucketAggType) { + write(agg, output) { const val = agg.params.extended_bounds; if (val.min != null || val.max != null) { @@ -263,6 +268,6 @@ export const dateHistogramBucketAgg = new BucketAggType undefined, - write: (agg: IBucketAggConfig, output: Record) => { + write: (agg, output) => { const field = agg.getParam('field'); let tz = agg.getParam('time_zone'); diff --git a/src/legacy/ui/public/agg_types/buckets/filters.ts b/src/legacy/ui/public/agg_types/buckets/filters.ts index caebf2d7d974e..6e7f4e27b9e90 100644 --- a/src/legacy/ui/public/agg_types/buckets/filters.ts +++ b/src/legacy/ui/public/agg_types/buckets/filters.ts @@ -25,7 +25,7 @@ import { i18n } from '@kbn/i18n'; import chrome from 'ui/chrome'; import { FiltersParamEditor, FilterValue } from '../../vis/editors/default/controls/filters'; import { createFilterFilters } from './create_filter/filters'; -import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; +import { BucketAggType } from './_bucket_agg_type'; import { Storage } from '../../../../../plugins/kibana_utils/public'; import { getQueryLog, esQuery } from '../../../../../plugins/data/public'; @@ -48,7 +48,7 @@ export const filtersBucketAgg = new BucketAggType({ name: 'filters', editorComponent: FiltersParamEditor, default: [{ input: { query: '', language: config.get('search:queryLanguage') }, label: '' }], - write(aggConfig: IBucketAggConfig, output: Record) { + write(aggConfig, output) { const inFilters: FilterValue[] = aggConfig.params.filters; if (!_.size(inFilters)) return; diff --git a/src/legacy/ui/public/agg_types/buckets/geo_hash.ts b/src/legacy/ui/public/agg_types/buckets/geo_hash.ts index 546e51c1492e8..8e39a464b9adf 100644 --- a/src/legacy/ui/public/agg_types/buckets/geo_hash.ts +++ b/src/legacy/ui/public/agg_types/buckets/geo_hash.ts @@ -141,7 +141,7 @@ export const geoHashBucketAgg = new BucketAggType({ }, ], getRequestAggs(agg) { - const aggs: IBucketAggConfig[] = []; + const aggs = []; const params = agg.params; if (params.isFilteredByCollar && agg.getField()) { diff --git a/src/legacy/ui/public/agg_types/buckets/geo_tile.ts b/src/legacy/ui/public/agg_types/buckets/geo_tile.ts index 3afb35a035690..ef71e3947566a 100644 --- a/src/legacy/ui/public/agg_types/buckets/geo_tile.ts +++ b/src/legacy/ui/public/agg_types/buckets/geo_tile.ts @@ -19,12 +19,13 @@ import { i18n } from '@kbn/i18n'; import { noop } from 'lodash'; -import { METRIC_TYPES } from 'ui/agg_types/metrics/metric_agg_types'; -import { AggConfigOptions } from 'ui/agg_types/agg_config'; +import { AggConfigOptions } from '../agg_config'; import { BucketAggType } from './_bucket_agg_type'; import { BUCKET_TYPES } from './bucket_agg_types'; import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { IBucketAggConfig } from './_bucket_agg_type'; +import { METRIC_TYPES } from '../metrics/metric_agg_types'; const geotileGridTitle = i18n.translate('common.ui.aggTypes.buckets.geotileGridTitle', { defaultMessage: 'Geotile', @@ -67,6 +68,6 @@ export const geoTileBucketAgg = new BucketAggType({ aggs.push(agg.aggConfigs.createAggConfig(aggConfig, { addToAggConfigs: false })); } - return aggs; + return aggs as IBucketAggConfig[]; }, }); diff --git a/src/legacy/ui/public/agg_types/buckets/histogram.ts b/src/legacy/ui/public/agg_types/buckets/histogram.ts index 7bd3d565003be..d287cbddb7834 100644 --- a/src/legacy/ui/public/agg_types/buckets/histogram.ts +++ b/src/legacy/ui/public/agg_types/buckets/histogram.ts @@ -22,7 +22,7 @@ import { i18n } from '@kbn/i18n'; import { toastNotifications } from 'ui/notify'; import { npStart } from 'ui/new_platform'; -import { BucketAggType, IBucketAggConfig, BucketAggParam } from './_bucket_agg_type'; +import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; import { createFilterHistogram } from './create_filter/histogram'; import { NumberIntervalParamEditor } from '../../vis/editors/default/controls/number_interval'; import { MinDocCountParamEditor } from '../../vis/editors/default/controls/min_doc_count'; @@ -130,7 +130,7 @@ export const histogramBucketAgg = new BucketAggType({ ); }); }, - write(aggConfig: IBucketHistogramAggConfig, output: Record) { + write(aggConfig, output) { let interval = parseFloat(aggConfig.params.interval); if (interval <= 0) { interval = 1; @@ -171,12 +171,12 @@ export const histogramBucketAgg = new BucketAggType({ output.params.interval = interval; }, - } as BucketAggParam, + }, { name: 'min_doc_count', default: false, editorComponent: MinDocCountParamEditor, - write(aggConfig: IBucketAggConfig, output: Record) { + write(aggConfig, output) { if (aggConfig.params.min_doc_count) { output.params.min_doc_count = 0; } else { @@ -197,7 +197,7 @@ export const histogramBucketAgg = new BucketAggType({ max: '', }, editorComponent: ExtendedBoundsParamEditor, - write(aggConfig: IBucketAggConfig, output: Record) { + write(aggConfig, output) { const { min, max } = aggConfig.params.extended_bounds; if (aggConfig.params.has_extended_bounds && (min || min === 0) && (max || max === 0)) { diff --git a/src/legacy/ui/public/agg_types/buckets/ip_range.ts b/src/legacy/ui/public/agg_types/buckets/ip_range.ts index fefe69cbf8e79..609cd8adb5c39 100644 --- a/src/legacy/ui/public/agg_types/buckets/ip_range.ts +++ b/src/legacy/ui/public/agg_types/buckets/ip_range.ts @@ -20,7 +20,7 @@ import { noop, map, omit, isNull } from 'lodash'; import { i18n } from '@kbn/i18n'; import { npStart } from 'ui/new_platform'; -import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; +import { BucketAggType } from './_bucket_agg_type'; import { IpRangeTypeParamEditor } from '../../vis/editors/default/controls/ip_range_type'; import { IpRangesParamEditor } from '../../vis/editors/default/controls/ip_ranges'; import { BUCKET_TYPES } from './bucket_agg_types'; @@ -92,7 +92,7 @@ export const ipRangeBucketAgg = new BucketAggType({ mask: [{ mask: '0.0.0.0/1' }, { mask: '128.0.0.0/2' }], }, editorComponent: IpRangesParamEditor, - write(aggConfig: IBucketAggConfig, output: Record) { + write(aggConfig, output) { const ipRangeType = aggConfig.params.ipRangeType; let ranges = aggConfig.params.ranges[ipRangeType]; diff --git a/src/legacy/ui/public/agg_types/buckets/migrate_include_exclude_format.ts b/src/legacy/ui/public/agg_types/buckets/migrate_include_exclude_format.ts index e4527ff87f48c..77e84e044de55 100644 --- a/src/legacy/ui/public/agg_types/buckets/migrate_include_exclude_format.ts +++ b/src/legacy/ui/public/agg_types/buckets/migrate_include_exclude_format.ts @@ -19,9 +19,10 @@ import { isString, isObject } from 'lodash'; import { IBucketAggConfig, BucketAggType, BucketAggParam } from './_bucket_agg_type'; +import { AggConfig } from '../agg_config'; export const isType = (type: string) => { - return (agg: IBucketAggConfig): boolean => { + return (agg: AggConfig): boolean => { const field = agg.params.field; return field && field.type === type; @@ -31,7 +32,7 @@ export const isType = (type: string) => { export const isStringType = isType('string'); export const migrateIncludeExcludeFormat = { - serialize(this: BucketAggParam, value: any, agg: IBucketAggConfig) { + serialize(this: BucketAggParam, value: any, agg: IBucketAggConfig) { if (this.shouldShow && !this.shouldShow(agg)) return; if (!value || isString(value)) return value; else return value.pattern; @@ -49,4 +50,4 @@ export const migrateIncludeExcludeFormat = { output.params[this.name] = value; } }, -}; +} as Partial>; diff --git a/src/legacy/ui/public/agg_types/buckets/range.ts b/src/legacy/ui/public/agg_types/buckets/range.ts index 89529442b24a6..24757a607e005 100644 --- a/src/legacy/ui/public/agg_types/buckets/range.ts +++ b/src/legacy/ui/public/agg_types/buckets/range.ts @@ -18,7 +18,6 @@ */ import { i18n } from '@kbn/i18n'; -import { IBucketAggConfig } from './_bucket_agg_type'; import { BucketAggType } from './_bucket_agg_type'; import { FieldFormat, KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; import { RangeKey } from './range_key'; @@ -102,7 +101,7 @@ export const rangeBucketAgg = new BucketAggType({ { from: 1000, to: 2000 }, ], editorComponent: RangesEditor, - write(aggConfig: IBucketAggConfig, output: Record) { + write(aggConfig, output) { output.params.ranges = aggConfig.params.ranges; output.params.keyed = true; }, diff --git a/src/legacy/ui/public/agg_types/buckets/significant_terms.test.ts b/src/legacy/ui/public/agg_types/buckets/significant_terms.test.ts index 454f1bf70a790..8db9226e41eec 100644 --- a/src/legacy/ui/public/agg_types/buckets/significant_terms.test.ts +++ b/src/legacy/ui/public/agg_types/buckets/significant_terms.test.ts @@ -20,6 +20,7 @@ import { AggConfigs } from '../index'; import { BUCKET_TYPES } from './bucket_agg_types'; import { significantTermsBucketAgg } from './significant_terms'; +import { IBucketAggConfig } from './_bucket_agg_type'; jest.mock('ui/new_platform'); @@ -71,7 +72,7 @@ describe('Significant Terms Agg', () => { name: 'FIELD', }, }); - const label = significantTermsBucketAgg.makeLabel(aggConfigs.aggs[0]); + const label = significantTermsBucketAgg.makeLabel(aggConfigs.aggs[0] as IBucketAggConfig); expect(label).toBe('Top SIZE unusual terms in FIELD'); }); diff --git a/src/legacy/ui/public/agg_types/buckets/significant_terms.ts b/src/legacy/ui/public/agg_types/buckets/significant_terms.ts index 65c73e5f9b7dd..128fd9e83e6fd 100644 --- a/src/legacy/ui/public/agg_types/buckets/significant_terms.ts +++ b/src/legacy/ui/public/agg_types/buckets/significant_terms.ts @@ -19,7 +19,7 @@ import { i18n } from '@kbn/i18n'; import { SizeParamEditor } from '../../vis/editors/default/controls/size'; -import { BucketAggType, BucketAggParam } from './_bucket_agg_type'; +import { BucketAggType } from './_bucket_agg_type'; import { createFilterTerms } from './create_filter/terms'; import { isStringType, migrateIncludeExcludeFormat } from './migrate_include_exclude_format'; import { BUCKET_TYPES } from './bucket_agg_types'; @@ -63,7 +63,7 @@ export const significantTermsBucketAgg = new BucketAggType({ advanced: true, shouldShow: isStringType, ...migrateIncludeExcludeFormat, - } as BucketAggParam, + }, { name: 'include', displayName: i18n.translate('common.ui.aggTypes.buckets.significantTerms.includeLabel', { @@ -73,6 +73,6 @@ export const significantTermsBucketAgg = new BucketAggType({ advanced: true, shouldShow: isStringType, ...migrateIncludeExcludeFormat, - } as BucketAggParam, + }, ], }); diff --git a/src/legacy/ui/public/agg_types/buckets/terms.ts b/src/legacy/ui/public/agg_types/buckets/terms.ts index 6ce0b9ce38ad3..e38f7ca4cc038 100644 --- a/src/legacy/ui/public/agg_types/buckets/terms.ts +++ b/src/legacy/ui/public/agg_types/buckets/terms.ts @@ -21,9 +21,8 @@ import chrome from 'ui/chrome'; import { noop } from 'lodash'; import { i18n } from '@kbn/i18n'; import { SearchSource, getRequestInspectorStats, getResponseInspectorStats } from '../../courier'; -import { BucketAggType, BucketAggParam } from './_bucket_agg_type'; +import { BucketAggType } from './_bucket_agg_type'; import { BUCKET_TYPES } from './bucket_agg_types'; -import { AggConfigOptions } from '../agg_config'; import { IBucketAggConfig } from './_bucket_agg_type'; import { createFilterTerms } from './create_filter/terms'; import { wrapWithInlineComp } from './inline_comp_wrapper'; @@ -158,18 +157,21 @@ export const termsBucketAgg = new BucketAggType({ type: 'agg', default: null, editorComponent: OrderAggParamEditor, - makeAgg(termsAgg: IBucketAggConfig, state: AggConfigOptions) { + makeAgg(termsAgg, state) { state = state || {}; state.schema = orderAggSchema; - const orderAgg = termsAgg.aggConfigs.createAggConfig(state, { addToAggConfigs: false }); + const orderAgg = termsAgg.aggConfigs.createAggConfig(state, { + addToAggConfigs: false, + }); orderAgg.id = termsAgg.id + '-orderAgg'; + return orderAgg; }, - write(agg: IBucketAggConfig, output: Record, aggs: AggConfigs) { + write(agg, output, aggs) { const dir = agg.params.order.value; const order: Record = (output.params.order = {}); - let orderAgg = agg.params.orderAgg || aggs.getResponseAggById(agg.params.orderBy); + let orderAgg = agg.params.orderAgg || aggs!.getResponseAggById(agg.params.orderBy); // TODO: This works around an Elasticsearch bug the always casts terms agg scripts to strings // thus causing issues with filtering. This probably causes other issues since float might not @@ -194,7 +196,8 @@ export const termsBucketAgg = new BucketAggType({ } const orderAggId = orderAgg.id; - if (orderAgg.parentId) { + + if (orderAgg.parentId && aggs) { orderAgg = aggs.byId(orderAgg.parentId); } @@ -243,9 +246,9 @@ export const termsBucketAgg = new BucketAggType({ displayName: i18n.translate('common.ui.aggTypes.otherBucket.labelForOtherBucketLabel', { defaultMessage: 'Label for other bucket', }), - shouldShow: (agg: IBucketAggConfig) => agg.getParam('otherBucket'), + shouldShow: agg => agg.getParam('otherBucket'), write: noop, - } as BucketAggParam, + }, { name: 'missingBucket', default: false, @@ -263,7 +266,7 @@ export const termsBucketAgg = new BucketAggType({ displayName: i18n.translate('common.ui.aggTypes.otherBucket.labelForMissingValuesLabel', { defaultMessage: 'Label for missing values', }), - shouldShow: (agg: IBucketAggConfig) => agg.getParam('missingBucket'), + shouldShow: agg => agg.getParam('missingBucket'), write: noop, }, { @@ -286,5 +289,5 @@ export const termsBucketAgg = new BucketAggType({ shouldShow: isStringType, ...migrateIncludeExcludeFormat, }, - ] as BucketAggParam[], + ], }); diff --git a/src/legacy/ui/public/agg_types/metrics/lib/nested_agg_helpers.ts b/src/legacy/ui/public/agg_types/metrics/lib/nested_agg_helpers.ts index dac36ac8a89ca..a7bfb7b82b97f 100644 --- a/src/legacy/ui/public/agg_types/metrics/lib/nested_agg_helpers.ts +++ b/src/legacy/ui/public/agg_types/metrics/lib/nested_agg_helpers.ts @@ -44,7 +44,7 @@ export const forwardModifyAggConfigOnSearchRequestStart = (paramName: string) => const nestedAggConfig = aggConfig.getParam(paramName); if (nestedAggConfig && nestedAggConfig.type && nestedAggConfig.type.params) { - nestedAggConfig.type.params.forEach((param: MetricAggParam) => { + nestedAggConfig.type.params.forEach((param: MetricAggParam) => { // Check if this parameter of the nested aggConfig has a modifyAggConfigOnSearchRequestStart // function, that needs to be called. if (param.modifyAggConfigOnSearchRequestStart) { diff --git a/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_helper.ts b/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_helper.ts index e4726c62428cb..d177a62649d13 100644 --- a/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_helper.ts +++ b/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_helper.ts @@ -22,7 +22,7 @@ import { noop } from 'lodash'; import { MetricAggParamEditor } from '../../../vis/editors/default/controls/metric_agg'; import { SubAggParamEditor } from '../../../vis/editors/default/controls/sub_agg'; import { forwardModifyAggConfigOnSearchRequestStart } from './nested_agg_helpers'; -import { IMetricAggConfig } from '../metric_agg_type'; +import { IMetricAggConfig, MetricAggParam } from '../metric_agg_type'; import { parentPipelineAggWriter } from './parent_pipeline_agg_writer'; // @ts-ignore @@ -74,7 +74,7 @@ export const parentPipelineAggHelper = { name: 'customMetric', editorComponent: SubAggParamEditor, type: 'agg', - makeAgg(termsAgg: IMetricAggConfig, state: any) { + makeAgg(termsAgg, state: any) { state = state || { type: 'count' }; state.schema = metricAggSchema; @@ -93,7 +93,7 @@ export const parentPipelineAggHelper = { name: 'buckets_path', write: noop, }, - ]; + ] as Array>; }, getFormat(agg: IMetricAggConfig) { diff --git a/src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_helper.ts b/src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_helper.ts index 1df771727f6cc..e75ebf366a27e 100644 --- a/src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_helper.ts +++ b/src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_helper.ts @@ -22,7 +22,7 @@ import { siblingPipelineAggWriter } from './sibling_pipeline_agg_writer'; import { SubMetricParamEditor } from '../../../vis/editors/default/controls/sub_metric'; import { forwardModifyAggConfigOnSearchRequestStart } from './nested_agg_helpers'; -import { IMetricAggConfig } from '../metric_agg_type'; +import { IMetricAggConfig, MetricAggParam } from '../metric_agg_type'; // @ts-ignore import { Schemas } from '../../../vis/editors/default/schemas'; @@ -110,7 +110,7 @@ const siblingPipelineAggHelper = { ), write: siblingPipelineAggWriter, }, - ]; + ] as Array>; }, getFormat(agg: IMetricAggConfig) { diff --git a/src/legacy/ui/public/agg_types/metrics/median.ts b/src/legacy/ui/public/agg_types/metrics/median.ts index 8797bed5105c5..5792d4a7c2ba3 100644 --- a/src/legacy/ui/public/agg_types/metrics/median.ts +++ b/src/legacy/ui/public/agg_types/metrics/median.ts @@ -17,7 +17,7 @@ * under the License. */ import { i18n } from '@kbn/i18n'; -import { IMetricAggConfig, MetricAggType } from './metric_agg_type'; +import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; // @ts-ignore @@ -49,7 +49,7 @@ export const medianMetricAgg = new MetricAggType({ default: [50], }, { - write(agg: IMetricAggConfig, output: Record) { + write(agg, output) { output.params.keyed = false; }, }, diff --git a/src/legacy/ui/public/agg_types/metrics/metric_agg_type.ts b/src/legacy/ui/public/agg_types/metrics/metric_agg_type.ts index c24dda180ea94..29499c5be84b8 100644 --- a/src/legacy/ui/public/agg_types/metrics/metric_agg_type.ts +++ b/src/legacy/ui/public/agg_types/metrics/metric_agg_type.ts @@ -25,24 +25,28 @@ import { AggConfig } from '../agg_config'; import { METRIC_TYPES } from './metric_agg_types'; import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; -export type IMetricAggConfig = AggConfig; - -export interface MetricAggTypeConfig - extends AggTypeConfig { - isScalable?: () => boolean; - subtype?: string; +export interface IMetricAggConfig extends AggConfig { + type: InstanceType; } -export interface MetricAggParam extends AggParamType { +export interface MetricAggParam + extends AggParamType { filterFieldTypes?: KBN_FIELD_TYPES | KBN_FIELD_TYPES[] | '*'; onlyAggregatable?: boolean; } const metricType = 'metrics'; -export class MetricAggType< - TMetricAggConfig extends IMetricAggConfig = IMetricAggConfig -> extends AggType { +interface MetricAggTypeConfig + extends AggTypeConfig> { + isScalable?: () => boolean; + subtype?: string; +} + +export class MetricAggType extends AggType< + TMetricAggConfig, + MetricAggParam +> { subtype: string; isScalable: () => boolean; type = metricType; diff --git a/src/legacy/ui/public/agg_types/metrics/parent_pipeline.test.ts b/src/legacy/ui/public/agg_types/metrics/parent_pipeline.test.ts index 7c7a2a68cd7c5..0adf41a0420a0 100644 --- a/src/legacy/ui/public/agg_types/metrics/parent_pipeline.test.ts +++ b/src/legacy/ui/public/agg_types/metrics/parent_pipeline.test.ts @@ -111,7 +111,7 @@ describe('parent pipeline aggs', function() { // Grab the aggConfig off the vis (we don't actually use the vis for anything else) metricAgg = metric.provider; - aggConfig = aggConfigs.aggs[1]; + aggConfig = aggConfigs.aggs[1] as IMetricAggConfig; aggDsl = aggConfig.toDsl(aggConfigs); }; diff --git a/src/legacy/ui/public/agg_types/metrics/percentile_ranks.ts b/src/legacy/ui/public/agg_types/metrics/percentile_ranks.ts index ead5122278b5a..1a1d5bf04309f 100644 --- a/src/legacy/ui/public/agg_types/metrics/percentile_ranks.ts +++ b/src/legacy/ui/public/agg_types/metrics/percentile_ranks.ts @@ -20,7 +20,7 @@ import { i18n } from '@kbn/i18n'; import { npStart } from 'ui/new_platform'; import { PercentileRanksEditor } from '../../vis/editors/default/controls/percentile_ranks'; -import { IMetricAggConfig, MetricAggType } from './metric_agg_type'; +import { MetricAggType } from './metric_agg_type'; import { getResponseAggConfigClass, IResponseAggConfig } from './lib/get_response_agg_config_class'; import { getPercentileValue } from './percentiles_get_value'; @@ -72,7 +72,7 @@ export const percentileRanksMetricAgg = new MetricAggType) { + write(agg, output) { output.params.keyed = false; }, }, diff --git a/src/legacy/ui/public/agg_types/metrics/percentiles.ts b/src/legacy/ui/public/agg_types/metrics/percentiles.ts index 60946b6162b3b..9b8205425b4a4 100644 --- a/src/legacy/ui/public/agg_types/metrics/percentiles.ts +++ b/src/legacy/ui/public/agg_types/metrics/percentiles.ts @@ -19,7 +19,7 @@ import { i18n } from '@kbn/i18n'; -import { IMetricAggConfig, MetricAggType } from './metric_agg_type'; +import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; @@ -67,7 +67,7 @@ export const percentilesMetricAgg = new MetricAggType({ default: [1, 5, 25, 50, 75, 95, 99], }, { - write(agg: IMetricAggConfig, output: Record) { + write(agg, output) { output.params.keyed = false; }, }, diff --git a/src/legacy/ui/public/agg_types/metrics/sibling_pipeline.test.ts b/src/legacy/ui/public/agg_types/metrics/sibling_pipeline.test.ts index e038936de07d2..60165790da545 100644 --- a/src/legacy/ui/public/agg_types/metrics/sibling_pipeline.test.ts +++ b/src/legacy/ui/public/agg_types/metrics/sibling_pipeline.test.ts @@ -107,7 +107,7 @@ describe('sibling pipeline aggs', () => { // Grab the aggConfig off the vis (we don't actually use the vis for anything else) metricAgg = metric.provider; - aggConfig = aggConfigs.aggs[1]; + aggConfig = aggConfigs.aggs[1] as IMetricAggConfig; aggDsl = aggConfig.toDsl(aggConfigs); }; diff --git a/src/legacy/ui/public/agg_types/metrics/top_hit.test.ts b/src/legacy/ui/public/agg_types/metrics/top_hit.test.ts index 051174c388c1b..3e861c052d367 100644 --- a/src/legacy/ui/public/agg_types/metrics/top_hit.test.ts +++ b/src/legacy/ui/public/agg_types/metrics/top_hit.test.ts @@ -85,7 +85,7 @@ describe('Top hit metric', () => { ); // Grab the aggConfig off the vis (we don't actually use the vis for anything else) - aggConfig = aggConfigs.aggs[0]; + aggConfig = aggConfigs.aggs[0] as IMetricAggConfig; aggDsl = aggConfig.toDsl(aggConfigs); }; diff --git a/src/legacy/ui/public/agg_types/metrics/top_hit.ts b/src/legacy/ui/public/agg_types/metrics/top_hit.ts index 49c4a7951fab9..4b07c997f11e0 100644 --- a/src/legacy/ui/public/agg_types/metrics/top_hit.ts +++ b/src/legacy/ui/public/agg_types/metrics/top_hit.ts @@ -38,7 +38,7 @@ const isNumericFieldSelected = (agg: IMetricAggConfig) => { return field && field.type && field.type === KBN_FIELD_TYPES.NUMBER; }; -aggTypeFieldFilters.addFilter((field, aggConfig: IMetricAggConfig) => { +aggTypeFieldFilters.addFilter((field, aggConfig) => { if ( aggConfig.type.name !== METRIC_TYPES.TOP_HITS || _.get(aggConfig.schema, 'aggSettings.top_hits.allowStrings', false) @@ -82,7 +82,7 @@ export const topHitMetricAgg = new MetricAggType({ editorComponent: TopFieldParamEditor, onlyAggregatable: false, filterFieldTypes: '*', - write(agg: IMetricAggConfig, output: Record) { + write(agg, output) { const field = agg.getParam('field'); output.params = {}; @@ -196,7 +196,7 @@ export const topHitMetricAgg = new MetricAggType({ value: 'asc', }, ], - write(agg: IMetricAggConfig, output: Record) { + write(agg, output) { const sortField = agg.params.sortField; const sortOrder = agg.params.sortOrder; diff --git a/src/legacy/ui/public/agg_types/param_types/agg.ts b/src/legacy/ui/public/agg_types/param_types/agg.ts index 71b2d41bdb773..0a83805c8c44c 100644 --- a/src/legacy/ui/public/agg_types/param_types/agg.ts +++ b/src/legacy/ui/public/agg_types/param_types/agg.ts @@ -20,26 +20,28 @@ import { AggConfig } from '../agg_config'; import { BaseParamType } from './base'; -export class AggParamType extends BaseParamType { - makeAgg: (agg: AggConfig, state?: any) => AggConfig; +export class AggParamType extends BaseParamType< + TAggConfig +> { + makeAgg: (agg: TAggConfig, state?: any) => TAggConfig; constructor(config: Record) { super(config); if (!config.write) { - this.write = (aggConfig: AggConfig, output: Record) => { + this.write = (aggConfig: TAggConfig, output: Record) => { if (aggConfig.params[this.name] && aggConfig.params[this.name].length) { output.params[this.name] = aggConfig.params[this.name]; } }; } if (!config.serialize) { - this.serialize = (agg: AggConfig) => { + this.serialize = (agg: TAggConfig) => { return agg.toJSON(); }; } if (!config.deserialize) { - this.deserialize = (state: unknown, agg?: AggConfig): AggConfig => { + this.deserialize = (state: unknown, agg?: TAggConfig): TAggConfig => { if (!agg) { throw new Error('aggConfig was not provided to AggParamType deserialize function'); } diff --git a/src/legacy/ui/public/agg_types/param_types/base.ts b/src/legacy/ui/public/agg_types/param_types/base.ts index 61ef73fb62e8a..bc8fd30e6324e 100644 --- a/src/legacy/ui/public/agg_types/param_types/base.ts +++ b/src/legacy/ui/public/agg_types/param_types/base.ts @@ -17,12 +17,11 @@ * under the License. */ -import { AggParam } from '../'; import { AggConfigs } from '../agg_configs'; import { AggConfig } from '../../vis'; import { SearchSourceContract, FetchOptions } from '../../courier/types'; -export class BaseParamType implements AggParam { +export class BaseParamType { name: string; type: string; displayName: string; @@ -31,18 +30,18 @@ export class BaseParamType implements AggParam { editorComponent: any = null; default: any; write: ( - aggConfig: AggConfig, + aggConfig: TAggConfig, output: Record, aggConfigs?: AggConfigs, locals?: Record ) => void; - serialize: (value: any, aggConfig?: AggConfig) => any; - deserialize: (value: any, aggConfig?: AggConfig) => any; + serialize: (value: any, aggConfig?: TAggConfig) => any; + deserialize: (value: any, aggConfig?: TAggConfig) => any; options: any[]; valueType?: any; - onChange?(agg: AggConfig): void; - shouldShow?(agg: AggConfig): boolean; + onChange?(agg: TAggConfig): void; + shouldShow?(agg: TAggConfig): boolean; /** * A function that will be called before an aggConfig is serialized and sent to ES. @@ -54,7 +53,7 @@ export class BaseParamType implements AggParam { * @returns {Promise|undefined} */ modifyAggConfigOnSearchRequestStart: ( - aggConfig: AggConfig, + aggConfig: TAggConfig, searchSource?: SearchSourceContract, options?: FetchOptions ) => void; @@ -70,7 +69,7 @@ export class BaseParamType implements AggParam { this.default = config.default; this.editorComponent = config.editorComponent; - const defaultWrite = (aggConfig: AggConfig, output: Record) => { + const defaultWrite = (aggConfig: TAggConfig, output: Record) => { if (aggConfig.params[this.name]) { output.params[this.name] = aggConfig.params[this.name] || this.default; } From eb8c0e33dd8640a41ea0ed5f09cdedaf1f465f12 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 11 Dec 2019 13:53:58 -0700 Subject: [PATCH 28/79] [Maps] clean up source settings (#52644) * [Maps] clean up source settings * update es_search_source editor * geo grid source * pew pew source * fix i18n * doc updates for changing UI * docs re-wording * use correct image name * update snapshot * review feedback --- docs/maps/images/top_hits.png | Bin 0 -> 642730 bytes .../indexing-geojson-data-tutorial.asciidoc | 5 - docs/maps/maps-aggregations.asciidoc | 15 +- docs/maps/search.asciidoc | 2 +- .../tooltip_selector.test.js.snap | 14 - .../components/global_filter_checkbox.js | 9 +- .../public/components/tooltip_selector.js | 9 - .../__snapshots__/view.test.js.snap | 4 +- .../filter_editor/filter_editor.js | 41 +- .../layer_panel/filter_editor/index.js | 5 +- .../connected_components/layer_panel/index.js | 6 +- .../layer_panel/join_editor/resources/join.js | 2 +- .../source_settings.test.js.snap | 30 - .../layer_panel/source_settings/index.js | 25 - .../source_settings/source_settings.js | 44 -- .../source_settings/source_settings.test.js | 42 -- .../connected_components/layer_panel/view.js | 7 +- .../layer_panel/view.test.js | 8 +- .../ems_file_source/update_source_editor.js | 32 +- .../es_geo_grid_source/es_geo_grid_source.js | 1 - .../update_source_editor.js | 36 +- .../es_pew_pew_source/update_source_editor.js | 42 +- .../update_source_editor.test.js.snap | 640 ++++++++++-------- .../es_search_source/es_search_source.js | 6 +- .../es_search_source/update_source_editor.js | 191 +++--- .../public/layers/sources/vector_source.js | 4 + .../translations/translations/ja-JP.json | 3 - .../translations/translations/zh-CN.json | 3 - 28 files changed, 594 insertions(+), 632 deletions(-) create mode 100644 docs/maps/images/top_hits.png delete mode 100644 x-pack/legacy/plugins/maps/public/connected_components/layer_panel/source_settings/__snapshots__/source_settings.test.js.snap delete mode 100644 x-pack/legacy/plugins/maps/public/connected_components/layer_panel/source_settings/index.js delete mode 100644 x-pack/legacy/plugins/maps/public/connected_components/layer_panel/source_settings/source_settings.js delete mode 100644 x-pack/legacy/plugins/maps/public/connected_components/layer_panel/source_settings/source_settings.test.js diff --git a/docs/maps/images/top_hits.png b/docs/maps/images/top_hits.png new file mode 100644 index 0000000000000000000000000000000000000000..45bbf575f10dd5faff45674daa345e0e310e1591 GIT binary patch literal 642730 zcmZ^~1yCKqvo{I^g1fuB`@!Ai;O_434#C~sAy{yCm*5)Q4z59i%S-H&qDil(00suvXe}nD zBqJt9qU7ReVQps)1|}VqmI1AXeu_1ACGYb^lmtRW)G_3quIH;#A`+LVC@f{Tuu=nk z41GJ6ns|Nn30Y)F92wVeh`nS*U)_!kYf}2ogX5Hqj zD(5?&pLHg1$&Jro(m110A$9>&qhk$LpcqOXFaU#aph&z|s2r zwQ;Nh+GnNW#EuQsgzc>ttqW0ChH{dB*xDY#cJZex&qo^@d+Gkl+)zk99W26_B&XeU z)xt6Kq;@KR+$}dOWd6A%mku!&&oZDD_y&OY>K)i;P)NANv&=W!(=$fmcFCo@8#??W zfy*v>@F%6+MRDRG2IttUNXRqyPKDfblt&Xsz%;jMkvxR@=;`Mjnss~ku~}5#8xeaG zwa@+?Rc%@d9xh;Bth$?6B)P7DpE){t7W>$1(l(lXkm_X?Ch@q*mHgoN$cT9rP<|6K zNOcxEz5*>u0tP^V!cF{wwi_%2BLXSIBLgqBZGD}^Y(RlpR(j;rU9X=q42phAR|Rls zEYE%R<@r{d#Dg71WNq5u!l5lUju`ck+A?evUcNHn%SKmR^Lu!bEV+=^H!kO3O zKZs%ygp|y|l=x@eWKW5=D#WHp@=270Z!5u0B1Q@Nxo=iqe2{v=w?(?FYe;q=34yL3)1?G}3Yzp-lJAK@Nxfx}JL1l>^En8c9@gLgODPv%eVPi%gez2Jf1 zf$%$V#KVEqEHK%St|9Qja*>p!C|D?PFqEOPq5>c?5K>Xbb+9x=W7Md)lnDuIe5RzH zyq?siOf`8c3SXqaFezG8sUjP7N0O)vzY0=iP;;JJqFefs%o(LW+2T)LGyFy&o_q$f zIH;oyz2u)=OziDmILN z$o{bYA&iq;Ea6$SSO{&#Y*tw}UN_g_zGT7Zh+IIRQN7^m?+ydQCQVjm1om@Ci=_e*J72v9l=KAw7F$HcYQ+R zRb!w0LiPbCt@XmXOiKzcwZB?U^-*PdsYZoHxrfwc46oD{P(a^5#i!&29kDw+Yg9fC z3a^WU$)-EInr+RUEzkvYP?ADyQ=Dy)4a$z;e6%rGAy`;ghMPmPwO`?_`y-oEb6J^J z)+6y6`w)aAH>NLD(IjzPJp&(4Hx`pJKzpdSi*ROh_VrBG{qdyr9O)eQT;jB5;m4wH zG4Pk?0&sb!c&AFps?d~W%P2}DZa_>dx+ulC3dA+UHIyJZD#$1tmtj3PetY@Ng?WHCz z3vs7x^Qe_^XnDt@!#?E_pU<_6qD$Z7@lyL?@p5IgZ9UM{$t@AE#ESsH15g2eJ9QtI z?qM7?&zv^053Fr?cihn)&oUt~@i0m0f4H?cDR>I(t_w|j=`1w+FZyiWZ+bcSZgy_+ z{D%E4)aB`Y;&aVU$Di+g<_pJ9FYwwe-?Pw-<36l4aJ z5Iie2p&P*r>lkAs zF%<(qxglNPa}hfzp-G{!RPNsD4Wm z9K2q)-5A30L+L_(k#Ue2k?|jQ7#|sbr*)vsQT?hSpdzPY2{cm8x<`(gI3dJ1g(Gk(6o4X|5nNorSazWGg+ zprAf7wb#9uKfTD!Z3nWW-MkGr@2=65y^!^AEOAJ2IHyCTwO@Cr_uqf0Gp{uFoamW6 z_pth{)wRE`I50D#pWkKUX?w}E{(fi)ntgnPys)ldsiIkv+sx^DeC|E*x9%5hh6Tge+4QvYot3DjRn_J3Hx#NxQ^%(TRnk}4?VT7A+PVqY((AOnXgVy^U-6WV`0G5{8av5emXZfr;hIWNc!bn{#|uK zFAkK?axxL+;pTn0Km_PW#9ot#EYArBG53snYIy4SzK6coRDbrA=lLiZ2yL#i83kte|6-u)?o{EQm&yRRSs zvuQ9M#(QoCBN!dDf(k08?vIp+zK2{|)*$*+@@TA?)?(y6;(#qMYxL9sE42u6M9Z@C zDwlt-Ctkkz5|m!e>L^HNf5B&rgW_ScDpb&}S01p~vP z{C9%Os8C%0^>4pgt7*AuDaiAhI@&WCn>m`8GkMuN{pAJ&m@+;9}eEX*Z+!{$w>ag;$|yArlp`nBIf8~PQuB=!Nfu)2uDIf!tY{c!K)%J`QPxr zcLHQqZf;Jz%*>vio=l$XOpY#=%&a^-Jj^U?%xr9oe>oUky&c?)y%-%_$^Wa7|F<1+ zb5~OrYbQ5rM+cIB?HZdny1NOGk^SrF{~Z4%r@5E)|McYG`rpI)J3!`tHO#C`EX@C3 zFgI(9{~y@Dn*W0RXI%f)9sj?^c$KWZ%pwD$O>R(W7g zARIsQ|FQAk8y3krFfd^-8F3LcFYt>V=pcP5ckTd>o!&-A-+5VGiW;95#_`qkE@vot zPDYAmNEiwbIcXRqOK2z>2`uH3lHgMWiq1MVZ)@->26n7-TD5`30@kJMhT+E6=auKt zjPGNQf7ffP^g0{)W!K|OE)Tn_#nIGM7Q1Ei=q_Y!(`$1qW}Iv@$KdSEOwjXN%yq4@ ze}L+&QA66~=;(@2Q4!KEJX|?h7mCV{6wrZ^fr?&8A4)&qD=)V{T+mfB44} zXj$P&?Y3t!nK&wQHA$s{3hdk0Vpf?_+0u3|wLwa7SPZBnbxq5~x;iMFZ~X2R*rovu z7<~DiVDwHN+DwC+4rUybLzSeou&H2c5PCm?5~d?{X|MM6JjKy6udpz&WvsQ8qQ4w; z9fx29lzu#}{Q^P7)o>7q;ls%}D@Ub%9fMT0JH~>7!m^Suk*D7y!-~JtJSKqpFKVRi zU(4_O05Rdpd&pUn#YO?cPtS9%HUuHwB9g`9^t|v7Cf4zipg74eCH)` zaf6+{N*G$XVl&Fsi_ds?j?bH3y8KbkIDxb?b8{O=Grwu;mXZBA3LQMBMMwJu_$fT7 z&{Yb+NuF1O`13QWB_1J##7QJfMfg=-CMp-;A^*GQ5j83`{BRVXIR$g_oFYql;%3{Q zO(iu|i6kV9^F`TU7-cW^dnuV3`Je9!ID-wW$;2# zgF{JY5l+TC8Nc=>C1ny^c2CSy!(Hz2H0ZFK~(1z`r&C z@;B{h;ULX9mYKi22GD%}Q757c1|%c}=85d<5SVGJd?yhy(ocww|CtqRnoJN=Ipc-ONuxPCJ7-t1d*cJu;xC6)k*|iGToY z256OKvWYj^x4^K6v$dcss43iJn=O6giXRz|E~tnv3u$PN9O~TwaMfY;As&0yP9o-9 zY=qxf=LywBy}3+U-Dr8m%nmBtD|o>VdB%(lE;=%8>h06>0|{25S<7h`yb%GAd_0>S z=aXT_(;~cZfWI__4Oa^Fn*igYk72oHik;oaNw_@2yez#V8-f%iTbDqU4TNxGOi@+s zWQZf;I(T~MIc&RNDcHDgu}~_>2%>_s`~a{#vA*8fak$)t*#-PQx7J#p zAL~Yk&C5vQPz-EmPT^^0ea>On#2z&p9hpUH^Ij;on8Zc`#v#>JT3IfV!tGy(&;4LG ztNY8?U$ds>iHdwYwqk1D!inOS#Ec4lJxq|q97V002c?o%$O+;vD+tt3*s;X zv##Z}SeyM!hGeX(4M`PR=tNI{bO}+rhcvQ+@;CoY1mXnWt*YM#xC|dHw(6NpNoW?YLI=<-CVM;v`xw6ch`z(eAQ#m zZ*8uYhrvw~bWijjnBT_IjZ!)&f}D~3Lrn8diP=RAya?FqW~X`+Ht!BrtLC;O=#0Wh#x& zk14V$I(3G2BrD>{#8*3ovKpXz?6BX!9)fVh0DX;v?@zchP|Vl9jSy+fC{WH``xryd zGy9R@MLA$ORPVI5bKSH)A7;na2;Sod0(^q+3V_8wXovV|UxTCJU33+{6h&q7n;Rs7 zhrbXg;jZHfF+v;2xGF#iS+Cy-2m`|LEEmMtVD^nhO*2oGUQpM6;P*mjX1W^y?l_LJ zo_0%Dc=t*dpJ2+3q)x56n-)SZNgZ7-p!NpdP^4HPC8r`8bHeH^Br>T$Z=kp3TQBS6 z2Py*aeARW|KY39FgtdqBaTueIVW`l8oCHbk6IbvnM)t^5#BUEt;fAOD>;+Vt%W%EB z=1xbWZE?oQ9trK>Fe~xIyyT26Eof1pOU>eC_BJl?XHw_T5_NTT={x+Lz$&^)v&(g? zRQlh4G#3M~)QZwoEVP4Bz~akHlKFcK2jj3ygl=;1+Iv0vQmtHwCbDI}r*dZm5vT5^ z!n9LB{&v33SH@gVcAaNlnJ*ah7|j1IMEWPGjJ6r%%G!R#0X5eG(;!k$wDaqd`iLZIV`R^Oz?F|~Z0}$M? zi*|=e=nKmmG{5F`Dr5U8zW;LJreO81e?H3i+&Y@O8uRRo+RK@%415PrhcH2oj!r}8 z%+3zJ7IZju>;$a(U3FZi__N2(0EPD1FAckvbNNk*Y%8PK-I$K=TM>@g;>J(+MG612 z-W@?hEkHb~xrp!GK!yh5&`b8`vN|d4Myt-80kVoLuvTIKh?RpjikVM}<*}GM7-}{E z``dvmC;1YT0%OTScw_GCx!G{^bYrtAy$G{G@B^Nfy9iHoMSyA7OzAM-XnM3fG2?0! zv&b&;oA~LNOMULt7sACBYa0M$V|@rXNhmEVLcpFGg)S2F(yr3F6(mD5YvqGgNwEA7 zJoOgM8zE&L=z@7sbKN_{Jk$Tz9EW|66Wl_U;WF+%Tkf+6M{3+*KeQg2g-oXAM+w-< zvSs0LsQ^TrY)UIFe%J+rE0|lUObRM<;IM@6ro1c0m|#mhcttbIQgExRuyY(4ur;@o z(KhskLt!r7dfmkaasdK0`ip5Yq{EA{R(`>QLAw+*<{P`~Fu2eWw#+HhyD3zv&f!_ zv9$w<;3hL>+V_Qe1S*Q;B{GZELH8*kYhi`Q zbb&M4^doZ)z+Az>cyNU&i)PE_$+z7ZPb8ZDfPoJ-xKYfYW#VT>Le9-EIH}`eYvrSS z*Vu3PP(!B|wkc)Nf6x%sE4*A772gRVN6rDCkC zwRwY@Mw;9h$XIV?aI!a=LXVa1@Q>+&tDjmrx4N8mvpkZ(RuM)qSVQyIj9QI^@hq++ zPFrU^tWTuNb0uTuup;vo(|$gxo^n~U%T7rc>=YNTzzEdQve8lk^zhpWmIdMz&U1V- zD;6dxBoE;YW-#O73XW#+(#B#HMWWNR7W@o3Ag~~p-$Qapiln;Gu$}@&cXg}L#y`$2 z|15pGwsaujp4-krt>|JLT|i|+g+hRkH7YNR1b0vei37it<5WV>o|?C`%v%11*STXB zjHy*6*gnZl{7K1Bew~l^dnYWmSSz_7$`>3iGMZ~fTLP@jFiItkR4Xx+J^e#3DXp{Be*bsy5)Xe6u$_T&IKW_t?J~5>Qd` zluZ6oufJ|s8}cH~MtaW8DGNYJ8r|D4+}CVIe$% z^t_EWS#59e*I|>)%z6Y2B8}h(C-$Qc==`9lEEP^pu{cj6>M~rY!RrJE)>K{i#>7B3 zlh}YSB96trLd|~MgQfDTun{xHdF#E&K|LP457@UHaAcwbk!lj>>Lj392yf_5b|&si zpCSo;bZt_4+huEhp=#d(Dk$MaRs@}qfqL<5&xz|BXi|zW58mFzu2$7Tvv;F|{vN=4 zeP6+X0t&gBWs9>I57{JL6)QGQ8V;9sTxB6`V&`s{9JswIEp8N|Gzxy^x;M6iwcd=S z3^-h2dy*_v>VO(CQ!m3e4>tSES+pAh$w&CTBP7Ol;^kyIJ0N*W*wJEdPQP8dTj&k* z+Wcq)aF<=1qZWw@z5wjd`&M#>MJN*T$M-4>i>jq&d0`!69V#A^Wr<^2a;7W@S{7yB z#t*-;EjK&^jbV;(XIIIl-U*3ZLhZh8MedbzR%*A|r8r;Lf75~w1`Pzd8jK_AY@yCV*6sv-}bG}s)JbX zvD8cz5RT3qhQO8Ej`+b!knv3z3w;hU^cI2I4wj?I8ksW~if*WqHYc=yEj&WB{gNol zh@e*$XBxH!(UJg*E6fQlP#Z~|E|~ZxVhAPzi_2LBKR?6_eMW25Nw|F){qn*iSAceF z=u%5Q!`2V(7wl|bG1^i!d7bk zi_%a7c#t*^=O``z3;@P4>1Z{w2=z2meCvCj1DsJ&0tfA!alXp9yq~X+F+vLGsQGB& zk_|y}*;l|~=pONUa1=M3mOG4PKxNwaL-DgX*xldFhvTxqo!JSPA6mMWjkMxpUUH0X z?eK8J*LA!hpUUKX#p}j8_ivpgC5buhTHL9N*||QKP{ZbVx`+YfW1Kqd-KnYe!Coy6 z^Ixs$_2mlh@6YhfLEjb0Wx{h>#Yi@YGEHEPh|r?cww-LwUB5+^OSpv${50@ueMMtv zl%@{HkKhktx*Jb=3Lzr-C<^otC+TFb?u>9w!OZy z26e2SnKj85SRB4lBNYEkkyY2ps9H_Gleh5u`2|c}DWRE}}lDEJw24X@99A z(*p^=h8G*?QF*ok)Q35kO7ak z-V`44b9dTFpxE@oRYYVQqoSf#jW1`K;4LUtIsj3!u)29v$mI*Z+iEMf*hJ$TbFa>9 zSftP$Uv}8VdGQE2@~zTGgZm*7 zON}{Tz7Wu=p;LITfjWAsQcI5QIB=}VnH#Yw|BG_e+&CKM`8YyV+{AWrrDD#wGIc0M zbN9B)mz~PNvhcJ?t(-A&*UFeKX!YcqjC*(MBBKpBY9KU; z$Wk~Jsb%*EJ2Iz`B62Z9EaB{9NO5LIXJNHztm0?yMDvtzK*LevU&280oYDNs*My-Y zk?Vu^`5r%wE!5yRUW1xXJ=P9k}p74YBW&*`{+-%`+aWyX8F=PGmyn>2x{!&Q~1}!2U(fa z^*h1i@8gZAfz}-O!RwMz`8bN$p+;JH8PGY@%s9SJy*Y!MkQ55!-GZ@O;LE$G~~&>uxF=LQ}!F6zkBu z>QZ_hzZPVPav9AO2#8Mk^_v}CV{iiyJKL&`$7w&g*8~cGm}t5>ge02G3aWL<1df78Dqv!nq4hQnGc1hq2ZK**&*(CGaH5KnR%-iZeYqqA-L;o;zD^jb{^vd$uuTQoPk z+sle{?KZCv0TJcYOBLzF+~*P*p!r72NIyCR*|A#`j_kQ?$r<^~uTP0(s~i{=qd^eA z4(bItjJ__*}5m5SyH<9P)g-Snp@H)zam9~kL{2Of4* zq||OrAwX&6kge+fih4BoGQ@TjO1EUKJBdBOB}y`J4{R>tuzLwZ@lI*Fu^1|eH08Rv zvzYS!?@*HKzfcm!lQC^YjBoXtfE1|O|52bwzq$$BOT?P`GF5*+!d7l_7#?=kq*r|J zJMh!lMVfgtRN0g#kKX`CdfL+F1fTCfyU3snFt0vW-9FVcU#bZzXC}sq2>(Wc5P{Te zbFiR>#L2Fvl>j(>E8V{fn<>%mvCf6iW?ZScoZdCs>RRr zgT8ID@fORorT`qWkl3o0M0Z#i#vr#HLvCSxT$lX{36(}q2VtMgL;KP~`uMf{nf z{{UnWB8Dylo-ieb<7sXC(#=%Nc)TsdzJ_TF+oIEy?iu^ffI-4)%@^Y^&@UEf_ z%Px;H=z2k@h+t$VW6VkjImH0qX%8$*=iSo;tn=H}ghhEdUw-6oh>uVo04aBuK>F6BI zRX3(VnQky{TxS*V{cRKCFHA-X2KA+B<%6L{Reid9)PaoOYgXtI%)1swod#Tv(0c1J zSaM26R{8bSyOe>f+8+U=ci-^?b021ZD%2aO>Fq}0^i8e*fGJPhUo|2M;gr{-h)p39 zsg|n__w|999GBY0bwQenZ4{6x9iLA?HYYl@El4R;gjRs!QwN|T4s2R5v}hu^Ys#2= z<#1@aPJzN%b3d-l;Vjt&Q8O8Tn>|qtv1+f1TPq$45$1;V>)^cR()kCrkB)2VB4qxI zL%uV;PVt#wcnKO+M~frHolI5N^w-qm3mWz8{90{LY#Ou6*1ngkE*sbaA4Sx;7r0(@Mc;0)xOD#)@JC|ETE+5zi;*~S!$+xqHv9P5lF9?Tm{HhtE zh06R0)`tAPFD}gv!{&Z`*HpLm+|rwMtOg2LH|w!fD%~j?Y&;PgQx@q^E|WcR}AVgt&_|&)JbZ5E?n!ZW!C&XGX@ZqXrqO6{sJ_ z+f%+<4&8w)aq>p2cYdJ@eKen1It+PbX^(2(Wd$EIz54h^Om9Ci!Y3CTzaN0vZPF<$zg=_&B~_DeE+cNp!e4 zl}qCXQ{lOlD%$*@YIq`2!eA!>G@5TD#WL8~cl$7xdqsDC%u#*F8;eNyCC}yV=Q^RS zTRf<~K0C^}LDI7N`kauzm$%>jn70O}3m$-WrBtt-W*87#CsmWm$ZO>+SPrK%`ZF@z zeNC4+I+I5Ne4B$VGDCbSin+Xu32#1i@m+_9${iQD8*U{sKt+*6L6obsU1=2TVy=oc zoNTrqy4#^~6D-ZeDR{GG*3MnW1S&y4lmxVu7|iQI`4_sBL-xpWw-?4y9KREd6yVXs z2*oO@@HGII!goSLGOPCG&pcQ6;L{aQBzDBnQl&yfsYlrkQD3>_D1S3Lo9+@UuXKxq zaRryDLVk}eBJWEi%Vdq^(2qrw=T4u_q3hhmWu-PY(vu*gG*8CC?KR?=ARH@8Ns8Kc zN&R-jJKA7XA&S=^LZHGoOBTlov(BHVMqo#ZVO7NlIWYi$lUD$LI2ZTRO1{a=A7p2X z=f7La<+)zUY$DB!&l$2<9QOY=y)X#=n_MO&@2*v_vJjG}I0lnCuv^iEpc;y#vk(w- zF*o7quY=`5eZ(n!TI>S%JKfeTxtD~At*uDf4aG=0#po>MVZd;2Wr$x6 z;8E!MuO#Anh)uYdl7Le1JF*yT4s?$T@QtxOk`zq1$XXq?Z?)9;Gau1&mz>n|2IS`QcTo73YXk{5TO#(*0R^ z2hrcY4m84eVkd%M(d`GSFjZ6na)yD#si6JGeHYMI7!~Fu;bypuL{nopV?LmhGyC_( zW{r)|8Kfly-3GS@k!!WA)T3xBPHI!G76Qkdoak&Jt)J9hXdD4AFjM2XskaKVY`1Xn zrnR#(1<{>zJjQ%Q&n%g_c=GrAgL12nV|{n07pq(;9Cu^W2#NeXvF!7W-JR-Tm!Xfd zuNKK=G3=~Rt1fIy1voQde{CoM{-8SHr!rnzYV=T98oEce(aFXi?MQHSJz0RuGlp#; z&V@a$+^=i|u1vz{R1m3|jH;tMp(i|-2Y)1O&mu2CS|4OD2Vi@RqOy?R89bT95Lyf? zfY9e%g z-VLT!Q%x21G+;Q5&|QM$DG2-05M#A&eH|N%;4ba96<65TGq>w!VfIlraue0setO|g zh|#KAAMkKdmWpAYEFxl)|dFwyzUJ9+X|u_MN}u@2^<+et+rPOCJzmzYJ@^#x1|q1YfiT@=X2G-%kf*yK|g+#$1hJVM-Sap+pK zXjNHUpi;8N7aG3|KA9XoW=+1iz7qlwzcHa?@2K}iF__XAnd#GNbXR`X5qs;@_Bl{9=^&mS?U?Z!kE1)5L4r-AZ@p3~ZPQS; zQ>Z8qCyw)!!$%es8Doa05X@VNbFO*6?5Vw4pPmg;mI30FRaI#ZF%KJ|A67Rud<#(_ z2W&&|WA>vW`Fcu{l0V74I>(T&~M$Gg2QEz{U>?L?NeXg+}%726Y3|ql}Z&s$b)nt0abb7 zAyH8lZ9M*QHftv5vOJv8ib_^HRb8jYPy%fEIKkVqB6a>No4L!u_P@je3q|k^O{w{U zwXn6eOMPDic2K(1T6q$PMIFCyjzC^BUzNrH`uIOvYZhXfMAY`zBLg!(4^as!IgvM- zc-8Z+qwM_j0SoLQ;tT}Mc`}o55zC?1z6ze7;!c^{a)ze#KgFkfspNgAoZp_!ilPg{ z04V1}P*y#2qI&V*Q6Wih9OKblW`gqgMP&@!6kN+!K^DH>;Wp+wg=wXJP%dIvC@E#1 z7D~QWrN#YoyLo)72}8zPY#dC#p6I1U(Fm6z#cj?*av?(l2lz)1iAqoV&?R)?J_xA2 zVq1UwkP5h&lv4Ln?Cb2L)A!2d_tqI}aRR`Q`r!;dROFtqV1K5kNtD83gXhQvN~P{- zN1vfzB<$-$=1AMFG=m}c{#j_Z>jliWw_%(JIZj$Z8Kb1eiLhv>bjZ`S@=HZOya~T_ z0e@Nz=~Q@(y7dmnr6nbqoDx-}R#_$7gCJ!}+hu{w?Wz=at>Kmhtj$RWYh1MP%cqBn zgDE+!TT?_`L-mm~{j8Khh}k}N9-c^qLd=w=+3fCX&g}bX#ls1RV=b63isp>}$pXQ` zgPMv>6ZLR_TR^CW`?fm2Hp`l?jFb!lV=z35@iXeY)12fh!*?uFUOrs;_i~*olaM<- zPB`Ea;g*AbY;JKNtc1@C?W_;5X$du{J)DE5IN!CuiN}LDEPfKIGpWIwZ*y%$UFX9G z!o_AWaVnoo&ABnD=y(BSGE4~a%8UfSHZCV+bDU{0>;~pzV;>zsX%mM}qDny?TWyZI z)c)^cRT6qSylvQAhLLR3bsVg;NAGX~uZ7Vue7r_zrt)E8=y#{jX`iks_hq?xZ55d_es4v<%haS0}s@+?I*8uj~_H#jbx|DNZm}@*lJOq3S z#Km&%W7(_VvA~hgFlXYL*OjCJJGcMVOdmGYh+ge~ecBvV{cDxu&2h!dev$F(pS*vN zg{&?3h$3EaNO_WAAkhe2cKbze@rXhQj}oh`?bCk!(5$TALN4#`B~}>PUwN4$jwB-hj-{Bp4So5LX9H)%K&l#rDBlBE`1NP6>a>Fqad@Hql@w-??biakpN&J(YyFz@Ok+^ytbPTP*ejrE|`o!1u?`pF;k71&7CvTWMd{8vWbe zZgLE%>%2xLi*7WFM4SEOqrIY^%2_Wt;&9nRkf`e31mnCtn6tMLP+c0a5i{ff+R@x? zUKR?8R7+Db1GWCXSIX9vt3mL4MvGWGimQTMt(|J7u6tsPrrDRP?Z#;o#ugSBIwN87 zk?C~PWvULp9Il3;3IS#pTvw${ z7A;3ytQdy~0drJ`*ZZf>G@*AtG-`vG1$Xsy)!7(+6X&0Z?!YeBCRY{fQf#&Wlc^tM z7`$~RZ0Vh>cQu-c^RY_pE!u9nweY`fiOb~kP*Jj=it>H_7K|Oy*>Kfmau^JYk)u?? z7>*vyB+Z$`a6{x43(acJS_2=Gao-+{WqBLBVL}87Aw^q{JtD+6d*)+zNmA5qvNpp= z71|q`s=-fs!aMG-QV+c`tq5`FhqZh>YzPoS9q~cg3B3tsBYq=~qb|E!Vi8Pj@-g?;rmsw0E6l}Y z!(RJ05$j<5gxTc83)?(046h8a7oF=LF%h)Pg2i3R=)GsY9p&ydXtnDTt?dGFb+|m5 z-yWp+9$e3(-`Z6U^x;zRnh?b7J0cuJ;gK@LRN3gESZU z!qJyXRehH|@p7gk-E92QHb*a$+M_RDUKgsK9D(Wi?rhM|MO5eZ2U*yL`LrkcC zVM8NMO)65P)%X7Un+w}x?w*U|!ac9;`_ zQlITv+4#oH*o`o(5hXcbk&|`^kh|zC;Qe%MOv}uiaX6Vl&-AHx<)xd0aF1+sVgCy~ z@%8a4BYHyC+QDYwsT^1^x+S!wVrU4h8tR`(KZ*%`)7IQfTDGrw@N}9Ba)#r4h-CCpD z^4iK9zQ!roRTw#rF&l(Off4SzgcQKT&qqwL)S8xDiHW85>S*uS6Xwo7F62?%Mf{38 zL@k_F4(0i{z&(lr*t=SH157VCJUu@b+qqI7=n5l4E`rdc^pdc)ragM3P90lXUf#_w zgHEO1bQ(g;oRz|unRR7Ais>sqMv#|5k`)vCc1yDG6B!7gPaSh1W$qOT}W;3jQ zRV{Y{Vozx3>i+n{hM&t+`!93so+h#7v%ETGGdUi}0yMaglq}9Dvk`tk#{Ie_hAdD$ z_^^@x4pCWGqf+!jZ}<$iRv%Df!1Wk{-7CNS+57lY-*cYF1+r(x7-b z!uTwdTjwdoNjJt$2e`+1NJEniCBgOc>C#ff8JiM?wqK@genQ*OH>$d7t8ma`A?-`~ z-<7rLI~Zp)KK{9SPCI&QqqR*q|4_%NY7jvS4N7?ZJ4-$(tOhr;_oc@zT`RT0>ZHu` z$2WVMguKVEe-*D$+wRwO(QDGB=W_FPEgIghZqq+WO(XTR^kqR`_weioQ_>{!4pk0! zOR?xwCfnMe(M!vb$y6Ym5y1f=O#Qf@MYSl|d2RB9Q_s&VuFa$%i9@skMyL7T1-3U^ zPq=}L(9?VQ?lquHWE%qF>KPf3V;&~V>QnlZ^(Jq5E{?&Cu33{876{@@&5$pCBccct zFTwZ}ne#psQYc4Bw}NW5L%EA;I+qzs8FAlyvN`2o5l^|uEKe_qHO2#9VoEsF(>Uix zGi28u1@LyPuZPVw^IMxVq}_S_cw9VfNLW-3`iKa;wul|jJ<#m)(Sowsd3pRyOh2-~ zY(za`41Cjge(n2&&irPpTJ*eJqxkodB)RxtJD2<`_W&R%T9~=^KG_Z@lDmp{7&-iZyel`Sj!>v{KAY5LEZ$ z2mBE-U&9(lwYCtPu^)2iEr#MoZ(5uD$s%3O_~~S4t)-`=SEr*F`u2Sr_ltS&*k3>9 zPk)Kj;rWiQ{KxC>atbV<46P!E)F9={1##qL;Kzx~^XMaSMnnN1_(PBrnHGF%KS7Ae zR!4K3GUNAX)S|_^?%D!H%@559=71ZyEjQCAcTn_3}2QV7uJC-%*J0Nm1yw;v#HV1w+u%^Fxf;-x5Qc**%_pLOvM^FABzQ_(@bRi zPf7ccL!rlz7}wfPdQ^y(IBC-fH@Y@`)hQ-bM^>1ikR>a2j!$Q0lBu6_)6Gojc!c`i z)a76ssL%3*Tz9RGy7UQe76p2qmx{l{Eri@I?Oa}-#b`t6m|%b8fu1U*O5LUrZ4#U@ z@KEIDH=&*d38#xOO-*$4&{E$cHq>+S0%~d$e4c670u(qEIc^H##Vio&A7QHvwo1KL ziMA*!WTPn`hth`;@vCu-#{{T;*g9uBj!?3>U4X+bH&;ZV!tKw`r{mZInCa7%O63*g zDV*mSUiD>Avb$FS<^{5%yAmmGltqQ5M)@qTHA~4PTwjWUC$3Ph%TYK2)$x(<@dxzL zqrCJ^acJX;ukaWFOn&>UQU5E z5rXliIl5|tO8hL-`pdriGoL8VOCFk98`t8?RHKrzTDvfUb6*`ga?VVR*?8b;gT03~ zhxc{3%(n@PNmVZ;kI{IEKrlA_L0f_s>=V0B^4_B(Nvq!Q(UHwIM`FnRPvHAi@2f+{ zQTC6+xW3P?-j7|shk5UbU+1BVf4Q8 z-J$l}epY;**Y_N^Z`-ERH1uzI+m{lgy7D{DgL&2M`22W1%y<+c8QMjhw{p`H%#HZB z)_}dDyc(*imV79rO4XM4z8wapad(3}NfQPnt|Coe3xtryq!u&c2&AV!Oyb1?Z>bj_ z5#_Uy!Gdpz?oB6$TyE|*;9iOS8ucC4w&;)r15|n+ddAE*I(=~Csf}B?X^^ij6Gvaz z)*4$40&Y%V*BX9JHDysN%ob?xbd@DsJ$_E-b#`El=>@xn;=J5RVB2fPIfgU^F5XXJ z3x4wa{rMv3FFG>@l9`ECd7x85Mnh^6K0VJlA1IZbbUA-PO9*QBmO|&WuRn9zXRk{c zBMO8&qCRh6QbKt*{>c2j2oys6aBU*sSr7kX&&f1Rq#73p!OFN-W|}X}4EOpz;|LJ} zu;v=Ql9aSYT6}W)Mu{}QM`)}qY3mU|4PQ3sSl@2=FD9R*MABvHgR?rmhWm#&|Ki59 zy*>5wmgjdaA;1YnMA>_z;6so~wjL_h%iZ1mc73H=<#+r3v(MX=tKn1h=I5?sXN8VeI)>4)bi&t(c3M{Ch(a8_reA!~)*I zqX%8cGrylBuI_a?b*Rhx`;R2PZ6@vlA6342s3HW`9Xeef=Clqw@p$;*9l zlhZ#vS+ppf>(CaTDnd58k-Mz>tIm4lklTA}iTj-2;C z21=J!IOM9E6!*&W6Rpl2U~>I`)Ou@%xMq;T%@PmE{JfRTG+u94gxcMj>-T*+?o%sz zac|qA^MCKTz3aM4o~-Lq#M7)vT_hyDo%9VL%g_tRs@7@4x(TF&ez*t*tCsiB_fK15 zWcQ@W1uRn`Z+Q}TUPS8oOmjBc*#AEO0zv)0E9zksu>0hxM;?LTJ}5h{+%3x?grMt$ zxu^&4yH|z>24%TXXget8BifD5;GgcLji+pHi@oX9<5Cg7`gq_dpmGmfLTCj+#~I@9$TW6EsajS5;LdzxDE$${+l}o79}lrO&uj ze*X<`P+>dEG$X#CnB9+~!1<$qZL8G0K62!!&O@?T0Xi$?DdBJ!>!_6c(?5M${_3y( zT>F=eo0VI1LdrL^Pg4%WzQB&jd9dxE$^g6%zSHp&f8<}L@0fYAH+@zRi-0&OP)=f9 zS5{gg(bAxzk4AzLjo=b;jOz?1K8xN%FyVtT8oDbkzXF?WmoTcvwa=5MIyBt!6+UTh zg|4KeSWmY;_Shadc<`XgvUcv=sr-a+J1)5>%?}b-7ySB>M^$i6K6J??mq=A*xg0on zSRQ!be#Q6TgAV}TFiy&D(KJX;=5O!Q`*BL=R|@kp%wNuI-zJ+jZIVZxd`#&~b6O8R z_@MHj8^G&G$H$)93)}~_EE_g#z)749Dmdo`3h$aaak3qzoS#&U`IW0y!TjoGsfLM5 z(wL@nN?^W+e3=^pr+d!IqrdqL%<5F=h9vpy6MOdwH#LcGGve}(W#+fzfm&7W$5CKL z6fhi#Q7sqKCz+~cg$UCRvZ?%z9hsdG`+8DcT?PAK^-JPLv##WPcX~v(SW^;rwL2mpxzp%$&+>O#SQ!KahP-J^|}GGzT^+QP^ny z*|+~k_CE5kM9Rt`2tO$=eATPvkzaD5S}afg`Vo2l@BEIOJbnxvEFky%=YL5T?5++C z4a(=<_dbxZNP159$Om5Y8VC>~QVpBUfA^YKOWRQh8bYP=%OBq(hxR-L&9-9sr?>qj z=AUsrdGO&s`a{)fZ(6-dKK$xe%6@3WMxez?9yw!&{3Xwxlw#cL6DX}R8!MJU%owSQ zxKt>>af8Y$VO+GkvSye1DAO4VBan<$m;uqh6`^UZvVc2GQ4S2^-U@D>?ny%Mf zdo48HKcd>Itee@=R5Rj!90kr31=!Ack3lzVjZ?GP{+)r4mBM)1AE$EUQEXOInPeho z`ZH|~*uL$_Up&UZ{?9*3;R#FGh&u1V_k4ZF^eLmfc;jWO<#Ye+h@kd#QWkGzo>$A zYNu1U|LISEMlRj8LtggVZ;+dAyj9-*_IJoLF1=3v^{Zdi2mwzu{6io75a6zp-+sl* z<@)Qck$?Dye?WedYSQM9-|}YJdFkcymbboLKJ%H+>ik2MMZqk|+wQ&hUU}y`{z@*p z;!2?j=5OKT4Hb9(?Q37tv|sa@*UB9)dVzfV+uu=hS^xNt{|J+o+vS5F{IJ~l?)S(= z+qcTszy1xCzfpir)6Ok88AOfwkA3_Ta@Fq3!*c}_HZ81Fkho8{p^P0lGXD+3Rpy@&cz8Khy!MCqa?`M3bN9@!@43S{|1oh; z6yRbk5)MHla!@BO{60VZePL402-_j#O2%Yx z|J^Weu|`T;p!G45AfpHST-u6Rd3E_8TO`TkH?RC&phn;&k_RTl#zCunMJ|z7RuAMk^NZxeSmDm_F z$F(C6&~Lo>VyVXI$-BS&C5^M^(MM(VrO%Mtf9vJ=E|RCAvGwSK56SBF8)3pGEE@p7 z4q94YfA~S|%7>u66|Sh17ryd$Bp5E0wj)R6q5r*Cw&0lgj7@5x(rLRt)q7lmb!%aw z3n%}U*r_3{4EHlT3V?U84@6;>u|EL~)X~JW+a%-9#`&ZB-*r(4#5(u)Hm0&>4FJ}( z`P6>^&bcHy3x0}BhG6=IW~AtbVV~kGA2#uR2OE6v zf~lE}&>a0O@D!S>S+Qb;md)}qMecqa1?C|I*hbk8r!pzSOGSTq|AX?5xBt0nT{F&v z?Hm0V!HSoCoBi6r>zDEbas~u={(OToUP>j4pLpzYgYSgAXj7xyw5vyUUyRF(Avhi! zN?=pI7=qqWDUXKanU}Z9^17&OTHBzPs!o_sO)2|_8sxkrnSyj(H$q;u`-&^T2eP>l zFA}}%@~ian!_O-9o3rt`7k~`$#Uq7mw zexwsO1nFM&s#n77&zIEX&qQNemS%sCGZ#pMGZ_<(%&GoREpu=|S3 zpuBbhxLzfH2VwhL-}+Xq$1i{R%djthAJTgfPW{w^ewr=!<0#-LFaru?3Eau}GW?ND z)nbHi&cul!ma+3l{tee(D}O8RlFN2oBb_Uu(GFX;VF<)pTAHMxd7E5?%jW+3KffW* zdG=qa7QDrr{j}+TnInMA81fH~Ig^ol0(Os28pdxh7zXSGWHO$OzQ8X#FiZ|UCP8S6 z252ADqub>0i!0R9es%R0wK++FUSV`wTy$`yIsX)3U#I5MiWT*0Tl?^l6WG;Xt`jJp ze3{N^mjk|8QBL7vOoCz7o`m5YzSYCquS&NbQM_KwnGDU zrt=rZ9~IQaz42fiA@u6ytMnH)THSU&ur56E42-6fm0 zTr8jd)Tc03SIRB7+@c!luYK*S^|I6czJ7TMr&a7p6>g%_{n4A>f>V*}qzyu=4}b6j zs7?MJYgtaD$LQE=Uql9rV%uqVD;4#V8cO*h^kt*xsk9s5lGHif2y$n;V6b0c)m zgcvaq;mIc`#o;?%C?YY=1bQFl!Qf5=^0?qVSN>k%<^?UAfpQ{3QUQkO%AwC_=Rh3~aK|ATzv7TseondsTLWkTG%n5Ek3? zp4s@u$E6Lf3S4S5JlgNsZ%vSuj@R;aB>(!(+1MN-iV zq!>JYO)aP+hfm^|Tnd^>t$JK|fn@*uWRpA-n}TByY7Oqc2j&hcU`P5gd_!~0GB|)slA!5cT->9ZG`vXZ8M`(^Bc##uCokvmetY@ph0D83 zd0|q3!ewf?*Lqs+J^j>jFO@JZP>rAbjS6MC35G_dbDD)&$^vt3CUMGccroe`ToSf% z>sGxSwWhX2P8~UH%vu2*1?4qZ6t3UCU0!#~t@4$7|5r8Bh6atD<)r2`Yo2wRgrVj2<4=83{^Dz2*UX*4!uP6|yi{HZyUgs*W6&60 zyK$p@@lW3h8}84O6)i3DKOg(3ybj00i?F!on4*`g7FaZbnVDZP%*h;=Ky;Y|LbwL@@8aP1KQZ-^&`r8m|s_2o@E$1a3A9MWg!*qSlZ_v0}Q+_ZC_zXzEG z%Xmh>Zg8j#_hMh9DKbaCNf*MV-2316H>zdI?-b@Q4a=4Z&BojT6EGCE)7^B_P4bhU z{3Ly9n)cbRz4jU%#~Ds7-=F{d7vLdrZ#<`>1_ep4Q{f|FUiQ+LN^5JYYL&kG-S2`% z=xx&8-hsQvUI@F!yHs&(s`Vi8IOixZpC~}V@!7Mz*hKQgJm_2;f7$-&F1h$3eNNf7 z(W$i`L)cx6zHEf<8G$$B^N)PP&l5QB&K0_w*j8xIp(lr@ZS zegsFsH2)}sPa%#Sbv1B;A0)5td*A=Q?7H;Q^kt!xJ4GPaK6^GJ{5FtKqQoXV1?k;A z-E!UaH>vG(nwMeuX#f1hFMYY1g(1AnTLh=*C=loASgSRkgc1)O>p-8_JfzD<>oiOf z^BK?4wm!}M(BvhB^rR()?DySwpM2vR-&E@nPwqb^vEGv!gL&qO1v(1K>9|S3&6X=J ze};b31ZzDM6W;UgJN5gy&wGK|izk`lSU*!!|C`_X5Aeem%f~+YkFsOuWjNvUGSzOU zu%8zZN3v$qq;+LTz^1tEvK1ddpk> z4lr%<!3N}=cfLp7{6}wuwm`K`e8vge0ZGC-dn087)Yb-uIB()H#ty;HU)>~(lgW{Rk%piYHd$MB94EvbEd^+q465AdGHr$;K551(W8+k z{z0$?KTY441-)cZ;eDP{WYCVc+z{vGgSl=ME&-%7>5i%3{e~NENc(NXW}0<`p^%Kq zV7ZR>iqTn^n<2Qjj^-EqjxaV~et-AwC@>!>z_!XZ+t|25|MKP0wrTs!2b1<=x2Jt} zJlLmsD379b#VW9M85klayhv|6fo*+X*DLHuHkZj$$B@+Q}CXT_$H7T8?ft7Rd4w;Eu8b+-p7$|O4P!La^UtElh z2H0G`>+YY*?a#hV-u14(hS{s%hQ|APT*~@@3do7W;;{mJ=7D}RA49=CN!1IX{Bv%9 zK1|*`AEvTiFQ5JFKg-+R_7`bIBbv53-gZ(ifZc=3>Hp80|4{zwFaK7K9DPbwuWC`j zyiI4K@;HA-0Y`!S6z~b$4Wm%TNm!2~dA|89%A_%}WAkFL3fP8v^PB$w$NX-RC!Tmx zFXiA(*gUpJ`+2;yflPSP4vTb^wWqlu89SLHevpp$(Cjgj%%5fK{7^V%pWMY1BAw6a zz8Jj3Gl82VXo46E(wp@`VLNHs-rFX%;T2LAsz9A{$8+L=WI-0zWqQF-fbEf*1ho*x zY~H+DwU-+jYSAY1Zw@Y)g3VP%F1E7;JCtz zjL5e+@zu#P*b^@a;$_`oOybMSqwuFrHOGAi??vo4jDT5V+q!_;&RPO)rMYd{V`vK^J1>6VPpBq8*k9Q zX6J!#de=J@oPBQf+BLFzO{?;$*ZtXBIgyjAZ@N+Ego)UoJR90q?5DB8J{7j}J(Y~h zW!GFO7heW5S@@hK-w)*oFawSm@t9n6=?>X+k+JDa+tAd2UDXCZnp#<>c2Y0@X0#j0eZEyr_s60|7+g4m52TngG@#GLL zQ!Pykcew7MP-gC&!NvZQb{_h4D(Nt`di=w;h1Pgpxcc#(5%FhX(s&De;hK_t$~u4F z%`Lv;g0}T5+b>b&7>j$Nr!AWmKywX1KduXCx&^Q5?4_#QoCK zxMDZtayR4B)P8y43ts>;JFind_og?#L3Zr8M4tED=fDnqyWD^O{jz)aZZ$P@(~UPs zYip~9b#`{Dz+Dq?KaK*90yCn3PvDOD>B$WR*=9mTtjafi%rjp~WIlGHvU&3+y@)0k zj*P`FvU0=hx1GYJ)2E=<2J(pyn-2Z6vNg`bi@?VWolPq%Iua!l9E|tNFebv$P`TzQ z3uY00aAME;=;%ErmBD&kkh)bjSm-ymlm10SG*^`KLIL)}1T+C!S2sz2-4Kof_DTh8 zZ^L_OJDn8MluSb6?N3Ok;S!jWiK-^%ViWF>M{``E(7Xrr&r=U&uzNUG6p-#A94l{L zAsg4X;G(r-upbTExG+PsZQD9&ZEez{rJNM!Or3YB&2ME|i<5DYPqT~^By!V_3s`<@zvBnoC^jV2F)W3-1>mT$ zt_xxW*?!Kab!IU-Dl|DmZFiDzc(9)nG@YZ3(CmysuYQcj_=M*In@7}#hq!1p@D^`j zPYULk#}S-ZcuIoRt6`cRd`Hu?i57;*K{*QeDZqA}!iG^4iY?n#TrQ`FPf2WK&^u9U zAbA?tI=gPN-!pxtyO!5{Gp(3!T=+Xt6_2;z%d{ zS*PFj1JB%WUr_or7sleV&orQWaTHiU6qvL2%Pvd>7W8L~cKVNf+Q@v^$2_8>yE^3p zbcP?K!#yzju;V#TmL@QFf7SCYk$WFHEMNWM)3R$roealQ5)GHgFP`d@7hk_twr^M= z-}=#$hNl1t<4;yb3eV{>0&S!5t)BQ{e7ZQy*wN7r`Y(R|zY2f-_1DRDH{2x8y6qNu z*Sp`NVRzs26NTd(hK}n_I+G85O{c|sq3FtRx{mInxZL!PJMK^uSX2nGf_R2SqXy<9 zANh!yZ@K!KYh(zg?PzPAj`*qJzGlrD{r;DK`Tx|^)q@W{C~y6fx2PZUzJ2>v`Rn)m zEzD*8t_%ze$Tldse(h^tlmGk0&#SF=&X0cjle^{So6TvSSG?jCLLAS3-tF?}V^8R5 zpqIS(MRLXNt8sbsdo_qS9P=1^9f7j(%hgmXQ%Jo&BCl*xuKB76PIXJ^rGw9;Z(4BoZ0?EPv;x zGJSf0cPh9q(4R*S6{Aes`SIAuB{=@mHE>e;<2}&!t_0<1bIg~x1zZGA9bz%yR)&_z z>e`JEZt+N$IeN7Sisy>3z$rlf!aiC80m|c#A5dW{HJMYG$mQ$13%s}mXTJ!%JaPJn zj0|*2=_+1~13GbzIU8nJaO&p|kaf)Q;;B6cFDZ}J;(cT`5ca( zmxu6u27*PPH?*~3@K{_XjSRfSS!76i+Hg0Yf1OX9LzRF_jD9+6qsieAP*WE8pNjb5KO-rGcV*j zWDX3o$~(olbD{_*z3AwVAM*}C{ieVA_+Jbx=k5oNcFO~gpOCh$0eRJPw#t<|R>{WJ zdbw!R3R$zFT<(7GnCv-xT9(&FWy|^o9^m0y9(A>WZKN%f8Zdr$#0d`)>SZhRSjF{yI>pr-{o}I zX}R&nXX+_iyY2wdUV6*)da^S#z`Q)emS$_1RyW|;{?vyY7 z-_PR|@LJr<$op+j_s%&AI10>&0!3gxI+g0g&BW9=iogU6FN46+gp`n;G zuWZrXI7Z23ax+RjC(`j_M|FZ$ic2VX{I`g9r|>TTrlcJm6FGi+yj=6Zd}smqlji7n zS5L#xnT(CY_vyOava=JwzDUY1$s&m#u4LkIT$P(sUaym0wO zXkJ2-V>XO%))_lD2*~y^m6o6W{4qIs^f)d~46D8NQEcAwGA6-dAR2|{Dd;gg99IqZ zTW{TslMqoon!4oL$GNEnhcyoc*cCC2krQXfFm{e%!y1=sLJ-9ZQ&auj5^H-1-)nY&-{Wx{EV$_HW8-3}2x10R3GxeM|{0zaRkT-u$C5mnL6m z5;9sELVUA1&oFMJ4-IpZ5$57>I<*95`Ep&pIXvT0%bl9t`2@u*AI;4$j4*^{9GXEM zgogM@2%%T5Tq)&crJ7uC-+*k{dI@Zw|1Rz%yb~tqQW~EEc$>aWQ%}!JtRy_#-qZLQLuJeF|8OI&oly?qK3jYhEcCsur? zkNTS+dYu!eN$Zc9kSUJ_Z)Mv2Q(yHo;ge><6u`s-BbtrVwDaIl;lIh1_dA6l^$!^HC)X|~OPK=fo}9GQ)>g`)Lnq|$k&|-iuFdHG zOK+l}{TEts@veQ^B*JyA86n;xY$Q51;nYoOO{0{YI0eonQdNV~SeSec4#1W(v{KIW z^yy@tlgNv93~Jwez;m_t&$G(O4^robSk-?r@XPA_~V>3m3 zdtNGX*F5GClz3oy^T_-YlQNCG5YsLgnSNzyt;A(eFAq&;a@v^YTLee3kA#JiyF+U0Yvl6Fw&{hbefzOLWceltY+EGO@w5ycxJOE= zS|!rBO#+b$oXUWmP}&T2TGQvJ!U{-*f<@mMl9@&p*gY! z3X-kMH)r>!XW=MRro1{IyoIs0)CptWA@GOp{+2CURp=0s+37rbOyKnK&nO0& zN!sxp+*z3iUcm49kq#y^NHcGE<5SC^0A7G)>gh5z7)3Uc0s%Sm-j!e8t>KB6=^MkbC~?RKuum$ ztlI5QtKdCUyGjLn-ZXh$gtxjSVRK27?yrL-Df3*W0DOGwb}+a zh;SmzqpFZtYCr0%`gaXqbqkw zs3Bgt;zfO6I~< z%F;-g8$De43?=)qiI)IRf%c}FaF|K?4Il9>r6xqev69Ym9?mhWV~~dP1-yxQBwQBW z40u{dWaGQ1qkyBp{G`Cdf>z53_{1MNyX6BDO;5~xd-8H-((^G4FG?nCavc89LgM&g z%)419Q0x1an{SleyLYR372>6N72XYI&9nI9PL=LNur^+9ctO z6E}?9&wa>ld{aUOWknn3QBdZ_r&Cb01qQ_3=3F2IJ4#(-FFwII9BZa^ZRTz|v8SQr1g)YKf6Dq7*WCgeU zn8Nel{ARE0!-5NsZ5-5u*IysKq{pzmjN`l&`;D61}G+cH$99_8gE%^E03U-;9kj*rXYU zU_O<4Y2>8{8=AwY8*Y+tLqzK(t5TN+9b75TGX=mV^nL*Flrw`}YQvqTA4gQ%-SC&` zjB!GNC%5OjRS$eZ}aEPVeoCV+zoSJ7@c2O>#-Hn?{mgT8)hlM`2M)ozwjs1&%>w+N1%|* z1GT*IANJ3qde;*J$jbcYS*D5BfjbH~3M_F7WC`3!3nQuqXEFbke_2L*u4!e{A=~7i zb;^jLnP^-#o1TbCXF=g(A~>7Iw4TTunQ{VJO$pfT3uh(E{E!Zwe9vAc_Z%gR&J0(d$Ve}>yb#yN(#cZuz-rNK^E^i zpk`!frechCpciR*c|lNTXOFa<=z{&jDEKiZ$+4JfxN~BB0{&aJti{Et*fjJB-4|Ak zy4)^E3Sc_G`>Rg%!agZxSyiPu+U>c8@)o1EzlN%tVB@{P*mpm2pNz(L;9^zWN#TU< zxs*F^-<(4hV*@ia&@IXCeNwjWMr?2vDnQGIHS0sJr_7ql962^|GGP?V85p~cBzp_sCl5+rf_$~< z&2&9A-T3+7>1Wf=7oL;ltWO))KC=Sxk?UUw{@gfzoHi`?nGc437S12;e`h$IEkECL zoI{&4?$p|JVja{Y3@{psYs6PC_T594EgrwaGO+IN5Y`QCH= z7%w;dTo@Z}{q2)+{qOuP(9wJhqr$OobNn-Z*jXFHRjBOG_(%T3U#6q?IKbbFrg81h zgff_M*&F9!QB3+IZ?XBE6tI9mmW__)T9|J-`dNSVa6gU$jslJX)1W}Mz}@mW@E6Oz zEwh;h&RKyfZ}Sq*WuWvXYp3%wZ~LxF@rX1L)3tDlU7aLw8TFba(g4`gJWZ`(-XoT2ysCUn;`oBQFKWU8o!qY( znckJ*c*|^w>*5zi0gAPX(FP&#!aAt9D4^}Ju(%e=@**<_vc3~N?O2-|p7FPfMnC{1 zv63};KU}cE&-5MBPfYr`_{M)13O7Ec@tJP?T==QJCrX$8Hm-fBnRJa-aEN{C*R?TRanmTmO7;xqi9dHts~vso4W8B>DTt9!feYekCSbi7o*njD?Tl0w*-JsKs&NNJTI*;%-J`_+R*at$s;U6#4 zIrLz1!x4L0Znp7r6JuWe`OOV?-;M%~0*(TOQXpI4o@Simqg$3bK4gx4EC*I*?#Im> zAkcecg%H+TsQUdq9&WrWUj51n@kg1~JDI!EWp2<-EA6=f<^;Y-&Bk=}9h0h1gH%WA zaSR>{dN?=G%ng+tmh(>mwp|_ztf(l1mh&1pa`*&HBaO$#zu!#bA~Fbj>I;Z7MT zPRO!KoM6*2QCA@|ODJny-CVmm`2=Mz{75?u!Iyn{0p4d8UItkl9+-JBu`Hxnq3**`z)`?a zV4+bUkLqKF$&oRV7pf2WUjdGB%k|5&c}(|z*j zQ%50?j7teFI9j!G1)6G+#N!F&@!>FR*Mly3`Sn6>)GqJyh5~k;V%nLVH&;Jjzv5N#o5g!~nz zWJY5B5^sMDHuW!);$T?q?k^_(x)7^ospOfwrWpNwC^;Ylsk2fVEJN3)raS)%b!ILw z<(Qb}Dc;<{d-zskNRXah0F$?Id|v9!wHy}|o?ArI5nCkpbQDy7!MnM@Fh7n=njRxZ9#lcX@?AU$V?W1XVPH-uVd<-G;tvZ^@RJt+l}D;1Ha37f zjUv?vb5$_T^9#tj3dm5RPeMge*|>bC1Op*x0mC$on-!nms&J{DGYU{(wQt{12xON_ z>)Mra7Uo9w>^Us^amnUI+t*2LZI$vi%e&55M$R!}3fyB|Pe~CL;z8Jdrr8OWeX%(5 zr0(vsu*=>FlQDhzHwydo)MT%%t(1la-Z=q2?C~zzY`5==g$Ax1^NRvB>A+#1V?Tvq z6fAN44VU{+?_hogX_zy+g#?ZaRKIKjtWpPpZX zFZo#m#W3Vac1@L!E!Z$y9EI@#Dt^Z|EP341QNU4P5l|po;En>3S&|v*3%~U*^F2|S z{S5T@@iuw->3uTr|FicU0CF8g+O=tBHt%ZlD(xy~%h-~024@_w4F_k^9pUW5q~l0F z4s+ariFYO#2jC2M1mBOr;Do^m<7~@OmSp9y(gtmgGaLW!tA0K2&Fsu3?Ml1WYiahq z?yj!xuGd}NU0q$>)hVH1NER+!Ad43*QenFnZWt~yZs%uaktSa)4w!KYUq)cUHkM!` zO+wu=csTs9!i*L$B$f6z6d(^s zh184YMfjsOdmpr)L!p42bmAJ>z59S{cyWuYSW&Io(c}sJ{nQroOeAMQZMC9lG7#xh z?e@(1CqoVdE%5Q$u$V@5<+t#cvTm_HdK5h8tx`$y#j2=Sfx3knCw5l1;UP zvZOQ>8`_5|bnlh4P_E=GyHL8e{ziEKf%G&ZmG+foV+v+s%1b-tazbdc6&| z^KVzyGRCSAfx|iyWHLr1KG;-KVBFtzste@f_bD&~C=eC68y;slU6PVBI)SsDFC2-; zZ+`Pz`NlVYARAwODhiobyiC4w{k8J`_g^iAg@tNzW+YAbXhOU&OUuNg;RypxEZIJ_ z&Aih*%fl7IdPcwz%_qqV^N0>Ucpp~2Bdlf!7r%(R+J7mE7j zn0^#6f^*t&rff=WMmGbitDzYVzQBuB>FlI&`qeGA zMAUAN)Nhs4P@!bxmmA^R3>Ca_EaBLYmWB;L2-RtK-(|4aZ+5LNWEkQa-^rXOD|AQ!zINfxfK#jM|-3hJyfi^ zI92vE4ayt!gR;Ebn496Y-b6-Pj@yH<;hq-Af~NcV(zX2&{2rIgdFwQcbR5Day6+~5 z0{GV4yc~o!d-%Wx30ADt4UfV8Fvf;A&*`B_qLz^Com3NW-Dt~daasSwFdn{Cw!EX|NI1H&)XNJq zR{W#o@5lQTc(YT$T{U=ln)e+PFxuM*I40t3XQN>2$G87f-h1_XpiP=4r=4-GoPOr{ zc%COK7FWurKJ{_=_y72Ybar;CK*e_M;RI$rhLgKY-atjunCRh2oscM89E3NVLUZFr zK^BKYy-rdJsg1VN1aKt6dll0YTG$f4%_Vz1Wo&LC#f&XO}g_!+uFKD31g!q9fEgiuJb!BsGhBxCw+bWQdwCl zRr6=7uzjZ1HwhX1;Au_)YL#|HIwXt>O}X$0K)_yJFi&z}VlF38AQ{kzw(|lsRcN}W zN(lG&HgpW3J)?4V>M?($#DANJ_W`?0j^Itu6h4)l48Ra7B7`lnI|HWCRt9{fjw27aDC1*Q`PT!DMcgv#M~=vcdFNju zvkLRIBa$f-MJ5DW7r*@q`R;eVA%FbipQ1<-F@PA;EYbX>$jQC-)FS%z_Rm11>0fFufI>j8OI+tiF`MGD8Mn(jGJ7Fa=tO7 zn(l2q&Cx>IUdT^Zo|hsm-9vhrD($=DvrpV{Qw{eQq+qixd%>yroe8riA?exmi1c?g zLr9E+i-(lK#EbT(NeTL;;-b{Pj)O4OwM8=L9*=PY(`BWr{jzVG+WHllW)$FDoysw3 zd^$fCkz+f@f{e5wSyfRYfz*82)5uf9xJM$X&^@lbI^MX@VH7Z2&8}<+?Mb1L_~QwR zBJhS0gs|guOwvD*bm*U4*N{g1*|`Cq_BYyCYT?FN5#(TqUIzGMOgiGca$F(fiQ*CYS^4Q}~N_Tg+`s49iJbc>qhYgF*llfE7-qFz^ z-~8rxaW~plU4uRH=;L_yD1L7l`R+TP0zL&?3U~zW2t*(D?qh;m7#^#AJC36g9Pu0g z*ts8i_)&xu%F{2rArJleUU~en2j%g<;D_g<58p5M-t&-@R<4kH?|V?%+dDL!TMYY_ zjIkm-hQBx-L1==TH!mjoWeLl~>=8t+>!O zD=R2__SVbmn|4Oy@~P#%V75-|_8&Ni(+F*ureAL+ELcl;z({WPb8an=6%9fAC` zYJ*3bct<3EGbhq<(-}G`c&7=OY}jqj%PhdW2n!7xhvxv=cMdL2g<=#;(a_&PY4zVEZ-OW~yWdFqbdO#Cs8h?$~SxpGhusAB6-=oW$8&ZFCgW z6QSdhMi7q|7v4Q^7Du9|cWnF9UmubG{N4@n`i^Z1>Wxd3)`pQUbFE{wHI+{zl27{^ zNsE&uw{RAx_sOw2QCV1Zjq?H@!uv>NI0UqQ(rH2g+e1d`8dMMpz!YXzcdxW|^h5=` ztb(>vJ}sidQm@#|sA^ye;Dl>sxUuCeS9}fQ{jmj)k4@CqVpAmd*|hBMci;Vc*}QqH zZd`CqJr>9QoB;vzrcImW{U7)!1kLSIU0p2?Kxy=|pZ%h=w6sUpAJlrcKf7LJALd4h z^)pZF=evdHli|#d!hLTz>tKK0@MIeHgyqIUD2P+qm}f?yICk^Rx8pv=F7-3si-)vf z81uj9o_po>*I(E7M0wIID?pV$78Mo2v}Yz{dF}F}TYjPfcc4P~T{;9%FXHi?PXV6- zh5}I=?k+*d^4w0s#iY6sI!-tomhIbj0xT#u{@bTz{``5mTSkV%4#$q#*widP`q5A2 zx#wSzj?NC42*}kq!VGtwFcw9lk&-eiBctX-X zD^xCp1*KT{2c@4Ha`6P3@%8j8;8Vb*0BwNh;!@28&|V*D;J5vN6S1t!pd5GH3TbX` zQ$%lU-Ge@pE2YqaAAn$HcZFibH8qL}EJ{r!^@c8kD0;DHtNzGF*6PcA=CVkyuHOXdZY$hPoN{x4%i@+2( zlfev)fs2Qkklz`<2m2!^R|@WLm?PoZS7i_vxTZk6Nd@x$7(af}LeQQ9g@kb38#2__ zBcX~F*w=6_r5!&uKZQ?$F;jq>JTy_&8E%z>JvCCCQ=z7-(o+L6H)An)5VbV>r5kgR z_AoYt`qHq;mnO|!1+uqMWKK~%G~&4_7`xiBwza3p%7u%OCt|_NM#4szKFka3$z7r+Zw>?km@n`ipA4Li z>xL3WtIVEVsX}?C;m?kfd~)8%^-+N1tWzk46V3|jITqV@o8I2*K!3cm=`E}+8=nk| z52v;%9m{O-*)n?JZI}Z4e`X8?Mry~b!~lftnL)@+TD#@;KWvmtnCX4jTbD{jagIcA z>Qmd(5vi@=1KKfodnz28yRDDuE>5S3E1%&?7SfIMw*6?R%_bT!{ukTlsFl5H)k^vC zkMEF=ee55kx@w-%(DvU%m{}&qvnGG|!+r9R4}SpPKp?+B-uK>jE9l85pA1>ntx{iK z4{Hv23bzgNuU)%#>m7wFRxDR@r9I(ZtY`K}d3m|YyJ!k?%NskfW+_H|mh9ZQS28oR zR8yQVt5zvq|_dk@xC#lo`E+$zH!eDEPzwrq)H zXH&7MS_Sia_U=a=w(I(gu*Jo*Q07cI{q$2|*0Vwm9y}-&<)um&ezK;fCal@E=sJaE zEGsLCDWd}Ve|!oYr4;b!TCuwrE=ML~e}*pfC3j@F?Ce<IN<$Z!o$f683P9r zMV<&<6i=c^PZ*0CW$`AQ%zR8v%Q-Chn38&dm|I3#K!2=|7Rd`RE#5hiMfpOFY6^LKdLq&c zZHAt3L?L9B1`T)$7r7|r<_OcwbT`&I5Y7tSIo|S}KhleB)*cCse-g%bheiPk z(kbrYskVNcYUAk{j{o=yQN+}&9Dp#)I};(Fpk{kbGcN#!K&$|F65u(R%~r>F+{Hpo zckH^!K(}L7CR#H8Wy}l* z>g8C8sBMJJF)^_Sz;~Qj=Q#vn9ADLI<6;oF9v#cL$>juvuwD#>vLvf$A^M)#Tvp+j zGv=AKW^8);I0oK)%Wd)x*L+;Azy1dK(1-s~zW;+CsriSSzIU@~s&0AX4f((?*KrKeWQTb2~d`@jE` z)HcGD3ACWK9VDqX<3{}@Nt-N~5)N%@+T2V}bz2_aTpw}7wo9jH10*&)ac-6m#KtBL zjfHW2HXrsu3Z<7rkbKQGAC~WZ|7Mtn*`vZ_bI*>O#{0%}#KByPie|}cuWiH{uubQ1 z1^GGhxzGI*1ld(u>p%VJ&+_39U#Gm`)?0rpH{SS7U3U(GC-C0F0|#ocX5l8vp#1QM zx2RyA=72u_iO&Mh_43CD|Ey+O4mLK+CqD5{a^HOqC@;CtXlRP zU*9CZ{oUQ*VPAr9y9LTerY*3n6t*8YP>)T8PpR-W>Pabe8@=4 z5H@MEVM^veZ6~xha-ca;EKfZ3if(i~{^Tn-VbCYxu1>J96j`%oF|;!lD*vA-4?ldh z8#yQ2e#TM{!dgK);S)KFk8yYOAKD;NFxWX~1t~1uw6f0>yJhIv}ZmEZpT#EPZXY z&~~pFdnJ8Hmja+AdsXD;tlZpO2!k?kH_yv*@<}JivB$2J zfBwuTqKXqVxzO6$hLdxJsvV!5oh2PGldvB`GRDycGEZZ3joSq~$lw3LEwXgUBKgpV zKB&rNwg@|R?39zv`CED7Pd}IAk3UXLEa>J*Z$$brm!!~+<3&TmK{ZoYSXij_W_pG< zHa4mjDZ}Y@?cNPR;cR{97~b66jB@0uwmvoVd8)jmq$Fyt!aL?`BLB~fqyUAoS)qU& zZ0VBk-1)M+@2!g@FFPpDY^;@kyJCg>-@{ww{THr~T!c}OJj|gFjI}Lz=P$$X#0Ri* z!SSI#@BqsO^l73^D$Yj~cI>i-k;*bsoXK$HzoZ9G1uR-vE&uS*56c~Q{2cxF?_}P* z*-FEa=tcd|OD}!9`~Vww?|c7;<&4u$Rvxl$-SMiBRkOcVzV`L+%J;wbEjf1WYH91} zg24Ne^28HQ${A;zj&+Q4pCO7!s^sP8X`iLi5Z9$2`tS$koU=~X3Xr!@!~Aof`)BZP zkwuFZNiBrn)Re#N_MgZNU;cuee%i^(R{sNn{6`;sOs=}}a-=1l&HRL>b5^ZdE}#GW zXBEf)`_0|*jcM{73->1 z^44?C#JDnq)8V=D>TCDO>QyV$f9*ehLbcaVIAOia0>4bvwHGR)Cz-?2+> zy6HP=is!7eaJLYScCu-VL}Nwb|M4ks6i{Hez};c2rtWs9G%+REiO39TPwMQm&y+8J z`Fc6+gi~<@W-%C(aX_*by%kk+wQMJh_XsBBcj4SEBbceC9QdI+U_XDw@`X6E*dm)?Rwg~IOD|AO z$HZ>!F-v60;`v%)(*Cf}eG2JAtv8y~8H5(Cz1TNVc5Kgdw!Ze643_cynFWj6_EnHV zRG_&PbR@!Yw1<&y)NJqW?SMw;IIfIZx}1n z^FO$AF9tN(I_o8S@j0L>=;!p6qn$i{{imJ+-qgD>Hf zO+<<)j92}cH1MQi?cy0}5bh2JaT#NVA>wQXCZZp#Z&dGKYqGCLw=B{@>oe80T-Kaa}O zl_$vjmFwl$CCg<#Od)Vh8ShxXEC|e3uU?50azIdk{vsCt9JbT4?HAmRv{;JUXefC`!LK% zJSX$!&y|ZWx=@Qi!TfLTx?8e?L-JqW`;mP0D_@drFvIZM-~K_hOE0_ZA~_Snx9|Sv z_oN;Icaro<2+A&b`$f{(*(KD9efpW_bT0Y6tN%u>xZ-kEN~3U&?xvf5AnhHU@`cZT zMxJ{583@gO4z`XvL$b5wi(mL>si-K|3p6Rj^WDs)0Ox+0Fr!FeJ2l%WY%k2ulw1F> zQLek<7^#DHdjRH9tcH7hO|?Iv3GCfhgL!k4&M9^72S6KVy6ccEUbH~lkC_{ezuhRF zXfiX4WSA!?rg(%f^G*Uqp<-Z$c?iaWPtbYm#yK_x*Grcyl()U@9GHo@N3Mf;nUNgl z&J-q>!z{{|zI45sR@uCHv)p>yPvm#M`-6PzTVGeRGAFD*R!!FQ;pk$1Zng@+d7P8r7T;zM2pbT*#m{H9WY(`&D+$x%yDnQ-DUX4`dYVo^(wXL{=dJtQ#S-RZ`l^z;IlCNKIFyZu?rR~ zgbAB`(CP-%{bX!B9uL|Tt4SP|(RV%tj&=$R7r1N3AeSR^u;fuzX*~&_?AYJ__J7J} zKJzJAf8trHt*DEA;Gs~8!uD&hn|9%a=WBW|GfapOfeOROVSP206ORQ~!aQQo#CQ^d zdjnnCctfYhJ2wK_dYT|?@5ZG{>tX*b3k!WCAebH{^h@DWU}`Bq-optj&B2tEz@9PO zM8(rRbE~M8-2N$e6+$AXjp3YH()}63kzZTgr;aF%!kHH3REOgze&>b=Sg}N zE@|wC*_??~ZoK(U1w3fWqmYA`Iquw3kNZ7(urP)eA1*}YMYe0!EKzelHTw_3mVS<` zU$;``;)KCrrT0|SI}Rr=R^pEnUMqO#H}wvEjOW6En+$f7Ck{=t4SHdTlYTneMvdkP zh|fiUj`es)X0bWOV?Vn5%0nOk>wq?CG44qSro+S${ATP2y{rS>C;*{}nc29wl=hZY zGZo)&Ukms~UaI70qR&DH!BGmbDJSiz3tF0$!CelKx;|W{+#(ryr7{S<7TH2o6@*)legYwg#{7g2k-zW{RFMQf*r^@liy#+!a*hEL=+uGXXwT+upKy=5? z{#P~EfBB35mJJ(Tgy#FFPK3ZcTe`b@ai zR$5(h1nux6DB^AU#!WdG1KU|v?++|b%fZ^vX7@*tjBxC3i;WhG>CecA?o^h5Hexk_sa z&TU<|X1MLPAIl3byd>{@=R0KS(#5i8?>=3hc)usV5l;}YOcmuNa`O*wLYfzJbMpH? zxK+M!<5!^|waOQ|^CSE2sHebifjdcp9?VWW7RSy<=0Ik0%{3pDeC}}F@Sjpw^O`4l zxqR(w--Mm359+Zvc6{5hJwW;zoy0j2hLOiZ(LXkp>}6a@Q?agI9!0>BoWtO{BJI#7 z>5{CVxd3*gB!?@G_2semyud7}%3lGkiyU9rez=J5=QFJ+z`ihleubJRp~;eoIy+yC z;6g4Q1Drj(RLz{!z+6p7R<}-MLOAZs3$8eU@=i!5nrEVPtPgFP_O&-a!@XW|mYfUT zJMnrY%Hwc`u|A|{LqoG{e0_&LIq-xbnJl6Z9^*t7CYmRnuo{~i^->12KqVzO`t6*a znkqUUP8!7LMZq|Kobd8T8qsllwL){&o3vq^rGb67>1{a2Sxx7RZxq&07~B=XhQ?qR z!r=_b3(kU2hB%QQHG0Q27;5p}bbmPSNP|$TCEOrA{T(pn5WqOfzRjw-lLaoI_=&iH z&C7(@0RBUt(LVvoe`Q(%%lVGI~~y z65p=Bvq4Ssq~LVJ5H6&3KKc1?Q`H@&j>kW5l9bXay%QQIX zC*Dj%tCH1?)Cv5;ZF2nDMew)F<}Gi?=Rf;Ny=;-@WPbh2JAfO4FO>a* zANUy3wyACCe3+Bryyu%={j^Zyw7I24-tv}XVJ2gt;`jf|Tnf;hcL*1x);D#^O?SNt zVf$ieN{8gOdtR4MUb$BGLD>G_^LynQ2-|5&hUQTyU}ZY5v;B!$#+)~E4#@e4&QUy1 zrU^huN@wSZ>KWmWn-ku+v1aAsAI9aWxX2Xc{qsYQs$$Wpr=6nl%xm58$141bFrCHI*SrvxriHj32w_8E z?%X-@2sZnUJ$8+Lj}03(Ky!X4=J%<3S!*QHCrg*%@?BhXN=iQQ#M9aaNLk)L(G9a% zbUk=~;ExZ<*T4Q1IR+<&csii9^>*hY=D5y3@2&cyIW7v{ zDRB3lPXV6-SjP_|0vTo^mnD-CRHqNkkwrvNcaiPJW(jIPw)*2?cp?omBBdtM>L62H50uvg6 zVzt@Mdik2|o@I$NGY zMmR+X%pAqgr8RsIwCA{L`d{)ahoHq?1TA;)8r0L8lfiljcHE&|q~9%h>dA<)Z6iIe zQhFQTfc$+WS4NmtQQH3|?=Xi-KoXDr4FdMT9$Zd2s~Q;j)hSHyX?LjP_0x||0rJJR za1;1(r-U-HR45aliemxcylv8Ky0eWAN?}d|HvYJ&O3lUy1oV9pNz0SQj#BXZHpGF~ zBmE%adAX_)fiV}F&mx~P+LA-2XRtUX2J3D0#Oundd(%T$}GXhOZ zo}xZs{W=@0+LzS&H9{iOtNA_vfmIhwy3qCY^{Rb!L)R1tyo}Z+g=Rdx#0_sc3eqWD zigyv%YG-Y!bV0|m5WjW*_y6v~MTQT<1k7ikurV7Nps$(lh&qIU(>e;gsNK$W+sCf^ zJB;b+a^L-bl#gF`EpVqph<^plM4X@+^MCiD>*PQF?Td2mxo@?}{pSp$0OuMR=y*-7 zJ@T^$Hp^9~RZCt@NN&IPbu}YX)6gytJO^R>Woslq2j-%nj1tvmj;kwiv2X9(wMT!P zKifH%c0}#FP^kdi$tSK;^B*=%9I6? z8>UDA$7u@VJuV>*Py8sa%!iu(EfA3N!cq#`&%qrJH2-4qON@Z!;QBEL6F=l9fB)f6 zs!10Ly?=Ap?;+4$Eh|^90ME*Xz4TAWbszsHdEa~At*2MAaN_xtQ%=^?jF(^bb_kz8 zAph~TkE0AYUGwr2jv|eK-!w+Q539|-ecg5cq$gX7v1xeI_kSWkzU{xT$wIl>2jso) zzeYas@egVIXFl^^vf+i_ML&U#3)ls@{PN4Nad@5H@xZb^1fhL#QK59>V$*qZXUluu zeWhG^)z$LRk9<&G-?SMgdtQ1Bgf%d;_4bQDBES0ecW@Hta=G$~OXXYN{H~mL z-rLl6`yGJ$@Q43S%gnMm8UXTlUT^#@OMtR@Kpez$zfD2Uli+5hZL3|wjaXH6;SllszQFap>8t?O_^^Ozq zaO3rlku>8)J8pP>H(t`#)r-r2LS-s!H%H$`6B3L&D?foxfoV?xJISIsnN6E^Vsf+; zLidnPbcRjn##tMio@|nWbqYdPu3P|ZsROXD`6@1to-Iq3%-2crWD4GypK7XO^&|FGuCcd2f(pmbe=S}{H zb+v+YTUAcX=`7!if54UK-(_a*SZxO#CfWXZNpok#oZBZk+PwAQl3^N z=@?5O=GSxv`}qGdUo9NUYl@r#QwW@H;Cs%1cFWC)rp`KSsy9nf4(uhPJkqck zHG~D_Sibpac>Q>v0;5rY?TmcmAns)uN*j=@08XYRP~!3Od5)31V}f@zQRrTnT>^g7 zgAG2TrAS`OjlNkB!e{p7No!XDPUL0+t_6ble()slc?io=fQL6xMEX;ZwpX>{`vl(G+Xd4u+4#{>yZzBeAD5FMxGRAcy`@bcBOpypt!l2~l1ttWVbqXn#cLw` z*|l@GUOu=88t?bt_kjHFx4)L#Z~K9oySeIppOg(x{$6To_RGI~>1*=4yZ%>gyHhxL z!3F24Ig6_K^W?2>JsTG^eoNkQ`6Y4|l-ln2`LCoFcIbUK^C)0@1iME7+RQKGo}yrS ziY%I6BzN5VntbdXYh*u!?e{+eGcxZuMsl+PF~aslHMad>)yieil3tbwWLTI@Gb|!e zfcE9s2n|v`F@_n2!y95TjMq1IBwilz``_Oq>((8o!gkt6ryEP%sZhoH9sc~_UGmy% z8}(x4Fa68sVCr(Ut|=+Fzx=XGVPM9Y2m{93ATxheBF<&=}uzX?Ke zuABDmc>?!TR7AD(Sr^ue7r|11&if{)!1V2J->CeI%CH;@uDa? zw3?aeMT->@48v_k`!Rq^AUd!IU_>~*3$3@UZx)J%cfB&*R zdAaJ2oiC_xo@M;*cfWxX=5w|DW1;nUTY?YoQ(&f1AV%OmtnhI>R2R|1fMNqERQEDE z##;Y`Ivq!*XgOSu5hKuVoXx}f$NU^S{~m^tlVoZLqJo|>4g;Ig0Dcpi1!(VSmhNzu zROPKe2>zi=6QcK&mexn^Q()>Tz;;hQ#0dw5;nWOL4FH5srnC7___=&pwUn05(#t+u zT3~7_98o{DD=2uUJCy#&wA8c;*Fn3zXtAV)a#b7iP;gErEyjz>e2Ek+EW7o@0P9gz zH5+!?^KhIothBOqv(NG7@ur6d%|>d`90!abXGog5Yo%+TO-l3UK-hxKClz{goWMnM z5bp3tp>lIiofKzM{DJnS8jvI9ketH2NR-D|DSFXS8X2{89fYQ0tCZ!=#R(CfI!S({ zH#z31jd4n=bnEWzRC~!vWGssGnIwCr(@kzuTSM2NNDJgNeU5^;P7@|Z&Lp`e2nLTx z!S_wYg;;}q-Pk-SP5|Tw#Z!RaF9jzV`f0yC0K2RZ_<_NaX~%>5exCx9N&&V#@=Kbm ziVSqaEDTR`xoew|GNWLl11D{nc2-Uq<_NsNnQfLoVkTb_31+l|_rnxI*DPqeSHcWt z7O z1!VW)rT|Lmz)~PiHG+DWJ~$9qAWfJ@sRP^qcpDwHDHF{JsQG*9DJSAmQzMioZRiMl z_F1PwSOjw~$mi^{PE(=PyWjmz6?pyS@h72_ag6-q$36uGfNq6T7|iSF7D9Q90xP=9 zFS|tk?W$7t{wHvy;lkA~sOg6}(1NFF5SID*=U%(BIiVO@FujG#00cj}3EunuhFXqzP1lIK#nQJmY<{Jc8>l zUO-w{SO7k0sAl6v!bupGohDo6Lm1AVbw)^T)^!Zy#mfBAk>A=iAJ>M*u3e+y_7Br? zJxX|%hss3cBh06?v{=qN_Z$nV0(H`!%0~+qRO!z~Qo!!52j7XK9Oh!kCtQa+uaFPR z#C*JEB{i6aj;DA|0FR-gkUta($?2z^tbY54bz@m5TxUH~Xw?L%)zcTfzYAH%(H zUVud5JF)A=qkUOfutS;#?LJJPXorv5W;_C@N2&OZ5>t@C7iUhTsL4#UGK^OS@8;;u zkM9a+qZNMa?46TXweQ+Ic&9o8r64}m`?+?_pbvb=O1%mNgsFvVNn!&)Ri zGoJ!Sm;&TG6m++>b;8t37i@OIUY%icQ&KXEo0BW%+Xzjk9Xo1ZUvrMy@iQiE%*1LU z{gT>isSr^1w$w<^-e)Ce*#)>*4AMLv>5FG{Q&PjpM{2*(tFLawG0ZohWsxgqow-gm zLpTAQ2%RRslrtYA$A^}1J;ten5UTJfJjQkkWs|g<=B|2~pTAs6b7w>N5}q&tC;;jo zgw0@#(F1sP^>s*N*8yqntd(UY>!lnQ{u-O;aRc>)bDX?{)Eeam_LhbhWL9pOZcun_ zCVO+@TtJ0osAG4yQx+8;qwu`Ya0r60tqp@RuaM??aO8H%yDMikq-TnB?fi>m6jV#F zWWmh7RM|`HDS9V=O~Ks;LwynH+;YDJ%a4&@=_1J6dz1E)DJqJO_9&!)Sx=-(cW(!H z&Ia(DQlrR&lNP2w8=}~Gh9wdG8R-Ez(7YRIJ7rM4f(_Y9ep-Gp+qVx0rw(SX@FC2JwhAxd4G`4l-0Uv2mR z;`q)>&?z79f{B!DTtK{j%_-WKSXWa%TZ`D|fyRUK`$r#?oK5%1;y|Z7g;Q76r@lkZ zU4Jr8W*MP(Y>HT)9oyo^Hyci9mXB-2=bn23c8Oc%%rnoB0|ySs`4|6<{NFEcQ|(o+ zc0AM4F%2E(Ck(UZV~Ee@M-zC2v#>Ut>4=k>t6bmG5r>7Nl0h2gjseFcjV-TDZ%_Df zj!Bb-TqkE|!*)NMH-8QA|4e%dP@}k|vse3GCN4{T=9Rs2-lv}sS&}7RIeiW;_)M2~ zp0iX6V9VWWM#ft)Zd3))W(snKn>g~qP4wNitNOZn;V&1a9l0Tvjy6a=L&`wtmsIp8 zTqvK$H3`Z@XXG`ezo?(ggL6(qo2jP*=gdQGJ6BjIjPD9%Kta82z0@hNbWQy{A09>c=G7uDH7_&F(~ow{uN z)4r!2$^s;(qV1^h5Z-WhN=_&^kudhjh?fjHHkA`PEIbOuf`K7S#F?Z_J9?dnpHQ^3 znA&G9&mj{!yv|UA7c8YohAb^T9%ce?p&$euhrcX`x8{CsJ_Saj0JVjhp=n-Q+X&lr zWx8=VTAGQ*+x|u##$P@rrpLWyxoT>^uwgTfFK5Co`2w{EIFSoKx#>vr29f%W5-3?F zX+iK{3PTY-6CHU!`8=QP9bH)H4?)nLrJEDpabYIbZ90{if{mKi?W)-G<`TDqh3dB&r%;)p73RS^~9A&J1H$5$&ygezOLPIufnHuddVUgYeK^=J%$6#aj ziem7zlrAaDqlSI4G{EM2M>t!`@*5y9k3_ZI-6A6`|51`pBh zbwdWo8x(zypO_Fu3=fY&j^~9GFoogM?CFgs{lsBuZ zKjoW^0_J2+7A{QX#DOer1oki~mA4ZZyUWiDw~kq}7#B$IlE3_AgREY&2)DzRpe%#Y zBZoFk(gL91DbQl;ZQ2dhs$OWUE`;!%hpv+_!K8?$M+CnE7mum058(9jRf56K%UMTqc5I=r=98DbQwA=%QlNUJ zcQK}+PFH{j2ZGR^g|o29@Wrq5ESxvoz8`bU8u{r@ek4uJ&Cn(giy!J!z^B0B zqrh;1J10{5V}V26oj7VChWl}weMY|8+a)9? z-Y!m?lmGN7aP(53CyWcgpjBl0#W?!+A(D*wF*n*==jAykp0G;x?W@OyJNz)+0e`mU<~4g zdN?|dU&6MTr0yJxI9?G)MP8NEv~N?B0%q}L+IeK42X=-joH0UbGtwnNc({Vm)mTpo zyLvFDt4;ecjj2X(#SL$6Brv^F7k}8bsYyzcGJBc_K?feeHsMp&eaU!Gf>eBa8G!v` zb~@h;r+~whXiBDg_j58BX_K5K=PJL2njss*@HBpiPk||*00mLH**DMyAvZSrz_oHwRvaIs?_f0+;#lDA`R*OmjD@CLWZSu;xbhij_B zyx4jt1RNnS*;wTbx9_A^5Q6;53f@^_oEfKL`@V&@F!6pH&ZmvjF)bENG|mfe-)*|F z_~T)1nwj!sOO7MWOey-Lm6PUjGcXwlV+Wq^w2MuXC)RQJ;di#Q^7ekxj$NIIsgEGC^CIAI(_Xa<4yz4*?7h6~jIj`rn2 zFqMuo*a`zM_r(k>%4ks%o?ujk3F11E4h8M#X_15N`yp`8mHf6Mq&n(gfKFP!ddsA1P3OY!`oL~VoPRt~fnug6?4G^|> zNk&RY=9Vu};k++wkCM`V@hJe-!3peu%&shfCbcnF#eR4=o#uve&~7KoGZ$uUsKK>+ zPpuqmfJRkjwO;1R3tf4cO|pq(3NA#B)Nhi(UR-R33onPjcV~(tKjU(Mr>~9uY6uoU zgE#heNG2{JTef(%JoD^E*ir3-HZgfW1qd;$f2LG*T9uP@q|iGv145GQ+0xzLj>R2L zdhj2{U)|v4NRR&UC{PbXi9QyA0G{y5 zhI9ev<`@5_{K^T8uNB9Y$#iDE!S$MJre?D9n9TAXZd?=sCv^M_hJ~8wct1lEg&~-7 z1fRwnl2c$Z24;bHsX7Gh^e1ZGw#D10A-LHW&cqm>$sPT};bIC9-!n~fNIKQ9ZDDw_ zn7(&7s^RD1Q^2QyPk|#vfhe~oFLcLH%OTCU$-#gFB?aQy5R_0jLLm_a?z|iaToY;e zkIu!SUe6yc;Q5au3x)2~Y)ped%-W=*Uk77?c+y#q=0Nn$$dqV+@+KSeyIb8cC1DvU z{4UFzE3>l7Gz~ROD7;WQfF5}n#VRx>IcQIs@me=P_XT>TC^S2o7mwM~wk;j;76eLE zV8V$YwO6?Kr=veFqXfbV*wTlPpK-phT}k8r@hK2P0UpyNf8vFuN76<6JdTI*y|SWM ze=V>t|N5p~xY4~5!uWFS+vKU_X_^LoJq2bh`ny{sQum5vRi6QY5QJ#ZcDFc>WWC0c zH-+s~+KKcIVKXun<3_q{ua8I|w?K|xS|DMZK(OX_XimoPb7k;jLGQziKmjuj4N3*f z$u#%WiE5Q&Y@r~X!gpSHWlvZ1L&#W^RjDRa^rBNh={P+C{?Vd1R&hKm$}X3>u00Ua z^y=8gjeuTgxXVC_%qduW$oY&`jyhs!KMziEv_a_Mr%qVHB}qu zJh>TNRFETCnE^H(&F{@g&CzQ`g~R-8Zu07E4Ybf+=TOBGorI&ae&ge55dAjBdszN* z+@y=yGh>jaXaqsgqK;AOb-sTzLPI?X-H60*!_p@P^Fw_K_!RIdFkLAS6}S&8AQ>kE z@rM%foq245gZ*JWhzQS%pPrfzJeHqQ*C`GfWtG9DD{Rg!oW@q#!08nw}KC zd(EwA{uYV#pj>45mdRV@Zlf*u#GfAIqaX>S2O&t$bcPPr+XyOHrd*r`uytlQHCU|6 z2n19c-uhMJkRufwFF>M+8tY=yrbsB8`I!kikLCN5MN29F=~KY)BJwH<+;{IfAk`3P zXQR&ysAl-&af$KL+S^b0URanXixoR;#qNcS#Qx-;u_>(mf|Ay^zNDLIs!$2Yxf(O&$g8 z;w>#DLyEIztHyaNPF?M9+W{fUfNs`i2lG@YUXndW3PL5(%)M#`3xUJ-7}*Bv5*g^0 z?!FGm3BYbW$7dwx$exB5$QU5Z7&E#ZV*&HOJsLu&y3Kz_*+c{!m1^xM(^Yl z6;wQSeUykAiBZSq=k=+!I}oO)b?FHnrsr~oFkJVsth8*Q8t*v1LtF3z`ZR07loWsC zFVT0Hc47Rm7`MB+BD$8HQ(lN~$*-K;>G(zvz9euO&v3wSec#^MBdzT)*@nR|NsDiK^i9qQEFJK*r%;~yx)c&h9|N%&A`YwG)Jd6rgdHQZ@pMzw#i@fNPz3R5!e zlC$6xEO2L#DH*Uo3fo({24PlfNS2qS$SXTjq-N_rS-r4ZmMxi!4b}|V)zF3G=+wBz zn1IEY@1}wR#xxAIwo7v$SkHt#-f)|AL|XM!6}7mnMm9#C=omFwC80oOR;XO^1I3s> zP+Jlg=JI|MIBJwnD+iuIp%+iC4WaFh=kyrsspfKU`fN}07Fk;I7R+g&WsZ3O=Q`AA zk3jBJmg~-mrmpVbf3)Ea(>>%HDKuqA37Iqhn7VwYH)a*KLm=7LRxjPV9+j-BGq90a zAwzv(j2APL|8T71T_HN)S@LuI!(4qjjd`|c{xdlR_$_I6(p-S*tRF_0=W~w3r3O#X zat+4Qu>nE9H%p`B86}88a>o%VT-5J)spSMgI)e$T?aoB$I|FqcsH-1^(pdB6;B?^q z$MmKE$FczCq2wQF+Q=rayg`^j>FmbcBEFk}6o}&u-fqo~p2V5;7=ZCV`mV4LfaJR()FH6A$ivus&n*K2GS|K?s4(kM81>cxxaj8PK zsk`BfvUr@d^cp-AITI&+Oo69~Pys%L@9~QSE2Jh40u$W);fr-BsiHISlRQVTnIw23 zKP^zSWD29DaKaNLGPOt&KT_Jnbx)LoALdiw=%fHAYH8RM?CA;1erS$U!=1g8!j^d6 za-=9^%MpPDj%8i3VxbD=Hf`RitZm8CYDs||>4Af68oKcD!tS@nxw^Pmy5GEL_IckGm^|q^sAQbUISsLZXyT3bNx*HQUMSnqC2<}oaK^wvjz3y)?d(#xA zD9`DQ)(G1JFwxa2UEBXGA@J2e(L4y-A^e%a!gg+4^28(=F7HvIsYZV2zTRGJ;Evt= z7~8C-M`PufhvjwQ0I70+TO&lEnzGi}QM; z#`GRdkG7@nCV$IL3?J80k$WaVnJhdBxF39kC}2M}$0+m7yn;{r&28ayGud-8k+5`j zerw_Qw0KlO%^TsrPk##NXEooJg>~O1r|7nAOb)i;Sf(2P@ErXRp8`GwdI`m3A`wg$ zu|S}fBZC|W#b@n>>0&qztqW-)Z2k<7pLY&R>Ie7~@G0=7qySIf&^|a#wNzDACR_ka zhl;bDT!7ex%aX}XbvI0$*D67Rbyqkt7|Q?Q1^|2lNqFlOp~ zpX@?#o)BGV>-f&x>?l9kxlJ4&%b5-nJng+r5Vm(=e!@06#^ojJgFn&3KmPI0vU>F@S-Nzw zS+lck#t(3ge^|K9#(z#*3YhNewgVPa`#gjA8*l%%&5Vd9;B}m4ZnUIug39JYU^==HeH?NPvn7A z7D@|cOJ3tH$qn?$i!}kMlC83E;anAf(7yY0o@^@X1uGtesj)3vcT418t#oFVOHpy5 z6c-m@W3>;$_mC`rX_IXYg91yhda)V>2)xU~cT-OR+uo)=r`Q~hRKBsLNbY05qF{@5 z?rXbtOI9#DIdFm)&Xl;Bkp&YyB{`Mo1Kij!j5$=5U>ZJ zB_C9!8k#{O+yLm63Z5K*_Ix_ha6;W14r@5^WoBlG?tNbieT4szMtZs?EmKM}=i}1mZVC5wV~orIPsxS$I=%@maPEw>fw$mp44hQr z$sxL;%t|TFtdPc@14a<9{oU>Hp4HL#YKerJ)kVJ%R+Dp;_BL?QI_>%nh+H zwu)|y4Y5z31z1Y>PoDxl1&$^PxB_=@K@O63HpJt|_I6S(*mzWW)~w>Fu-(AMk&3Iy zm_!t(~kZ3jARfZW%4k^fqbh3(C&zd!-$h zjRu3T?TQVAbkxac7aHC=tttfmoDS{w{ml`nt!tKZPhADRJ_`#moM3_mrEc8f*2uJ! z0m%)f%kD;wF~-KVui-wezT{C=7;0?NoL&E5pS*GKCETHq17TJGLayHE{9`Nxp+KxC zs~i`i=b8&s!E-p%q2g~C3dFOr(92_|K4U>UJ{V;rm?x=83goY*sK$q4xkdfB>do3{6rD_6*@!UCK) zYE=H*iZloIACP6smq}^yETwH{SGT?k1$rm_Ml*xlhozL{L!m&H%ndHmcJAG@>&FHW;~R(S zq_w9(1@9a)=N2rM{9uu^MVe4X?ffH_H4*!9*Jp{-GfgzcivaKJM(RvAOTyl`1~grf zu+cOorT=%DP=M`AH)riPO;9ej70%+&N@S?tE=RgHLK+}cl{1?(;+$b z*kcl;^aMHh{dVA?$uxX*`)suLqm=GD+lxB(eY_~V384=^wkD6G$4TM|9sBE{rXPDw zKBP|pp8`GwCY=J1YH&+_Smp^zsb{FoC=*s z-Y(|B&-BI_IKG?wonSmnd0l_}8{vKDQ^2Rd(Le!QPzWAUI4d7VT&t82>b@xwo0JlI2pv{mIb+)a@=vtB_}6KHf`D|b@ffU*x|*h6u3+$zD5p96JZg^ zvg+Fh<&@(W!Sq-TghEDW$uYn>Zm8yFrbmdAKORWuX-| zl;+HpNN*1WN#&gPnY?52jJ!4Jxg9Xq56g0!!F?M7*B@01>xWxMsZALAL89Xof*ukZXnXuD%9 z+VY0{;upV^?5r%g_ul*D`3*0rR{Pg){D%C`|NgJi|E{}!EB8O}plZ&OvOZrQTl->L zr*PdBwwu12j{cmH8kEZXDp^s!PF7W%D2t1Z#YwnX3Y&(zCb($`N{^h;DA8`>#DIxI z-Bey)6XiPk!Zjq@fmuuX&*?{pv2;>9kJ|<_R;QnSs#I53X@BQQn0H)$sT{;f_3rL& zUGwuBTNiB$PJsXYr{DJ<_Dz!V66b5OKidziFHv7?Q*wjt*SD#nPj6d^2Kp~P1$+wl z6nGO+AgbZ+%!#55lp5~l)_F69(s$1QIvNcu1GNM6Xz+|5P)$_6QSd^cz7g!};s{LJ z9kj{8T_00eo^JB9KE{mK9ZK5q=H-K#>T<;$vJE+9jC)%LE#C&!f8 z6ak^E=^3fA^8mEl_w1IHCsw0U6n42L1<2E>9mVhi`}Rp&%?=en@)SZaNc*#_#}t*% zN9$8yL<$%!_o||0QXHv}j=mO&3|KqvoL``A#?3im(LwkLP2M!vfVVRUc35=70TDw*U7$pH4xfIV57N1PCexm6{LOY z)1Q_zPCrBb`q#h8(q&8K#1l_c8_vJ_)vvL+y;MTMpj>#t1sJQ2k?N`{`RRY(As3u~ zE>1nA>zFl}bRV56GZ(_nRSeHDLTbChQT_owMDtg)?`|$=PLZD8F6j)nNnYkG4Lg+D zGv6o=8v&7lVY`n9Vt|SDMzM=H-6V?Nn=%F#5iS-lRN`=NT0)!LW7E;+#TlPwIJ6sL z@!9k?tqr%h`DB=dv*9)@KHiHbQ5u_`&+#~$pZCf1-u#C72@JyKAH zM}EWpO+Ls|Fz258R(&V5ZO44K-(BDN$DxqLZnL!IQxNA*JdBM?M6X2YEqtOpY#3p@ z_^jWioygPTws=P?+gRY@%MnkTk@AR7OTRb0H-9a=tw5rLF)b-JS36GIcBGfLD=r5P z@5*5~5pwc~zS>05ui=(TK@rb(#XQv6Xdu#X1{y#%Kz-MT!V?%Sn#OoX{2LGJMd1`7 zDLx0*)-jq-e0Y2wEF!{e6>Ykhurc6>DVH}7@4H3L=UBrn9G`TS4#qdU?D25k^l@n& z6bZ}1`qSCZs~(Gsp7?i$4a3g>2ay9mjIQx%Jb0t94hqHZiFeBYBnr$zBycuOvZqbr z&4*zl!CP3u**aMGxU|t=TTH^+K>K8xc;}6?@Am0|jaJ=@*AuU=Hl2Mk(EIMdM``Z( zV_+=2eMUcs0Unmt;ur}IxD=hkGh%Sqd`5dR9}B}*yc1ni;2teU6bdYn#1eCnY4iiS zfJxst_)-It&N4>t;F~NV^V3Bw1vQ$t{sA~k%T%m^>nvk;LnioUvzcIWKbcPfp90f^ z0^|v)IP%`q+@=D6l9Ixx2ITZ8VS-YC8&fbHX~gAsIb~qZcEi!|J8pJ{AdqHwdD$%4 z`1%g{%U@oU<;$z2tgHy(j@g_9sHZB(@@HFCUI^I{9+HkoiY%R*3s#LX0m#eu6&BjQ z8#nKeS6`)B1AqZ;?b;=hpARz}zP;b6`dmKVQ7HgnIR2p{N^U40c9V0Y9cCI@BaIMl z!E6csabDwX&juyhIOa$LNY~cgEEU<+F|!m-gW92F4hu@KyDWMFgzbK69VRs36)9-} z8H{uyt0~WLN~=SfQ>a7!pqE0%)rax++t}}8d5NB!0Urv$o_Y7q$7L|wA*rDpY-D01 z0_hILQM;b`(y@I|h+t5{hZoL)?ekFb87(dIWd6*{)SqKuDmI-vvUBua5RRAR)2mjl#NNb!^hd%lKU1s%@}{O{6{z2P@4eF2-Yyqk ze6cpArp6`-_k`unJMV-I`4*U!I8(n(aY+f%&O&hq^?T*QtPJU6PA`pC3qL-d0{o_~ zGw(LU@G28a{=>^wY4bfltH@061|T#j5rg)dh;5~ zyTxIj@p$9?gky71c*DpNW@C5^Vcq$iJ#jf2zq9R^X>HRRseHBoUYJB-Hr_rhOrmEp znE3E`eq?-!4YiZtZ&8jnAw z9nj~r5!;^h9zMnsgNf%G)AOH~>zH=t!f5Vnb4;h{nUaOHFgDPJx&ByOZny^#k$IfO zVTs_)!<4}-t2d4)Y+75gSRAIF7LG8ix9c|{#A4HFqzBIU&0h->Uj_>^Jl;UsaKa@@ zYvUOg>nyYzYGF-?`yJi1CXInh6z}3n^k(rhWjtNnJmOOtScWpag>!LP_~CFCh7hso z+_HP)_-@m9;qALOK5;sO*M5muTyFW8Hko6ZMEQBcnAX5~aeCilv0I$BJj}t{M=fp} zZ!wwgWOFk(y)ZV$rni0r>DI%faq~3rHWv$Ro`khAE?ygw7?z<1HXhFShv#p@-7*;* zHry=(-z=>RJ%}wv;Lb#*-S7=R$BsL6hjdcT=#d-;Q92I3oM>}F5`@+Z9sLX+$&tZO zTSuK1#*~9-nbPuX`;5osRx3Wn_-*+N^Gyunhx!!oDKK*>z`jkBGV|wEsD?Y=r*nTN zPfCTRT7Orw3`N={FmJshRC2!ox!?e7pVQ^%=Ro6dt?b&hA2xFjN=|MTY}Kc$7Chq( zj{_%E{>hNZcg%y6YhI4m4W{r(4^2#d^ zwqt^w0h{#e*R6nU;R^j`lV4IFqfddcQ^3q0V3q{JSn`a*%rXeEdSoBWJeB0m)=LVl zMybWhxe4uvcTs54@p;K2$!+)LT8)Wozu7>lkmp;QU3IN zn8&GmRf1*9)szY*S5uVXB$Rm+6r4NqXNBDHJUx-0yooM74RcS}#!iL(@j-mgv{0^@ z=8lr*NYPfS-kYy&KTOB@E`M}1x8Q}-z$y5{JPiLwp3pY^{U7cHe_bc**00yxo_y*V z*|}?{eBldUl#cc`dHCUnHJs%hLRra^EsZm9IwB`0M;0$$EPwOv_e4v}jbYOD^wUp+ zR=mN>$PNhP`=D8G>dcc(ST%T#b4=lI6fN7)^kUnZ5z3egpSc-jzyG1pf}Crt&Tu;N zIsJK((I0h;heyljH-;!#rqhdUJA7K+H4@*7kBj$v>t^Sp+}u+WwQLKA%!R!<`0tZV zf%xykcH!;PHa~uMnjedFntPhqy&1;w#PoVR*#OjQIhS`TV&*Fbz+z=Q6Syv#H(pF! zG{gl;@)nOP378-3Q^2QyPk||;K#ag$a{&(<0;4mmj7*XN_^-1k6Pl66IGLj6L}7_h6yLafG~%lGZ*q|K8JKiG?wwkGG+_{S}c||3EsG1Z&~A_ ze6LRdp8_+O0^~syPVd;cU*^s&)5}IF9I?D7L>)z%)lA2W_X_MTfD>%$DD7 zAXHb+ma3{sX>IL*w)l2gzN|`$iwl&;8ck4_A5UhT$ve|w8l%0tPd4p3D47t-48Z1f zdrPa-H+4!`7VIStmO(fBit&Lxr@}y18p!92mV7iiOW*6 zi7!>Q)DKE^QK}T;@>DaofnXLdX8yuOi@+i8$tE1yae< zTYjA^ezL>ap1N?sDa(}}%$BWhY>{g}_Hp^q55F&uJ@zQZ!nsmjUM`P4`lvknECla6 zcd8wC-lx&u-v_ftXtUTr<$|Ce?>#*|a>5DgA(Vee{_oCTV{9qL<=0_352k6ZxZ)jh z#~nYDwzf94*F10jd|9|~AvEW^&7>VTSf1{15B?fQf8sA^A^hh=DL~q$<1|YeHo0R& zVq+mVVTd4^8!1lHxB%Mitk*t0crBl^PfwKpIt?g*(F|kWkYt7e($vx+`|Dey>+q3^ zm#7IP3+uyxn3K&-X~X_U!t2K!SqkVkLJ?dxf;R-Ze)|m>#tm`&1ruO=3f^_RrcVPn z=P`34@*8J}j#e=7*zUkPP|8yHhbZF_L@_0MiN%!+$`AJ`;8Vb-z*JEn1&aseW3>nB zaLTq1cG$3>#6O+5F$RmvJ_xM3yTUSO&K$|g&ep|}m*EkG_5T4{HQ`7EnlTHd_CT#v zR#wU*kNid6_rAZyq`gRmE6IfJd-v>xu&hrqVSkbf0mE4#e8*yyj2wkAOkHQsJKy+|gl4}5rVr-8>~aLGDfww2>}ZjW+TF4Of_@4hn-4Z&b0Zxl zZi*!@4?=j4cDv1&--q_->l#|+FMoYm1@#oRpLXi8j+Xm0{Z6(5{`07!0Ou9xJ(2-o z*52mr(iGkg;d!aHcS{Hhlbb$E@2t zS6AO4^XAS$yE8WSu3qYD>m(QRdY)|MSegQ*8_HzVj0~14 zX}BjPEhD7k9NP?kM$ThpL+JZxS1H3x%8(4;VNMz^=P_-MJjvxohTVAAG;Um?d5uYJ z=5g*I%uqU}P4pfgN56F@KaP8DS#24I&w}EvJj$O=G@=h4y0bzI)+KxWUVJlh(!UP3L`&#X%pP z&Dr{s)!T)0@pxg~_{4ZeFQ1z(QCUoS8{^H*zOycFTQb<(zZS}3aAWv3yiO)R7s{L7 zeK+Z>-(qr88T!V5E5^sCq2H9vEsGmwFdDy`=Sc82t$i8{E^gy@{}PTa9;X{>`?r_I z7N33E`kGX+e_a@t-Z3MeDFQzt(10=0j-NU_n7J*Y7cH5x9h84_*YBjWqf@TF`rSH- z&&tfg1bvAvtZupGcDd%7kEo4DYT+bYTrm&eqXYki&-rk)Cx~E%@n@aM*C`bro;V9* zpSFzFucyh2skr#Gc^`NeCbGGuC@&T{ zBQY{mM%f$~78kVSYk7HQ6O_-5ukXZ#c#X0Qg7BQ2Oy#GOpwy}Sm%?`FPs;O~4@z;? zkeqntF)I8bt>?`yRu~G}dBPx`-a=vfD*Qy? zMLM+8mqN*f8xEvnQDMH6maRiYQGRaB0;ab&ENfP+kTq*os||bBjHfpU%ld_pj`-$5 zXwG_eceF_X#*{P8IL(v^Vd0)`m|5zTs`+!JdO?+j55iA8OP3&jT(ru3Lilcr7gXy8 ziPD;#z<1-Oz-aADc@$c3IxbPoNDJYP2z*2Q8>@>p^SCs`VB@^+(LlaffM{kWUy7n) zoX0!%lEq-~J%^D37b5WX|*nWxiPjj5uvg}xv9CcY% zwF*g5RAUvvUeJ5T#YK7FH+%Nnb1&`%EoZZ>kS(XP3<60ka z+u*?yiGv_69^QChZQM)$Bv^+A3rixk4&o)cDEL^73+Lo}>#+HHjZ!`g)>fv#2CqvC zZ;?+FVYE2uxVWHhJ|hUqOB0RS9*dU8-=^%?szIdCN0y+rc=4 zBEkh%WJM_49p+Nm?hr?14MVJtB-1Hi>+APRGgd-B|NEa)_=180;g8{L4Dh*4^|8mF zl)FB8rw;CIIR$Y4aPotHAk6khJ`>^(H6)7Vr`twG2pbuqr8zKeS>A`;L?VfKZ|IAe z?PvHL@HwzR9AIChVkJ2_3CfyeGZ2g_6BdY|nAK2j@^I)e33eWql!9tWghlGa=!g-{ zG0TNAtlTk{?4o|_%SsDn_nt#?514wPY>I3j6KzLS|ez?1wRgp&91#~+t-&t4Df z=`7u4Nvn5N3J+ib1oEx5rA0Px-YgfMcaEMFk(!DX46uOK^Hc(-Wn@WG$x?yCD{XOl zW+p7=$8<+jB5*N`0*>DfmZdUYE%dNJFpjhUXkp-)L`ksD=KysW*1M#^D&rO46#OBN z#;}k%I547el=o`suL^Wa5Z)>B5(lZ80OsH=<~L|;BB<}PZO0J!&A|HrcB?`Y@4VJ# z;emLD(Du-HIfUCRS{OGqRKgRMKR?Vb2e=5Bl9(z18N_Q(`82z^%#6#~N2}GDI;X0c zdA7*>a>U1eG92KTPsfb5@9IN!o-EVsgY;hAcMkax51F^b$zV~MJOA(L&H?k-oQF3h zvHFya%y;1UtTk1yjD=o}$nS#YM!X#6)|As%P5%%XzAH{0VHY>ijf5&>-C_7GjJ;Y+ zk@rluY4)nfY=MZY2ZlLrot|_z%_$mrA6CwR(KJtd5{w7GrPqr$Ebc|-Dd&Z;IJ8O+ zjJN0{8Wh;mX6HT<&eju#HtZ%k4#ngCagck;S-eh;X@Vy|tW5y2Sz+aDqD4YDPntLG zf_U;>q!H!3=~~WPhOiE@X!va&K_c_R@}l6-d&n*{8hnGkX zyiE?nX%h)&>Gs4m8U=>w(Si$VBla2r97Y53y!X-K-ZY{DT8@9M2N%2B&)bHO!X3cs zlEtBca*ftQG?3xXE#&0eiyfq=!4=J|x89=3oLJEZB)6&N7vuwPf}C~MTAi$nU;;#| zrKo{RpiX@WoNTIY-C+)J@Sdbl)Y`TxX-snxqABt%Y_vK#z>Fcfqk;QrJ_mdboTeP0 z3>b&s1n0!3|FQikNE7E9aU z3F#f~66;2042x#y9th4@B?e_2hp>mMXBS*)-CmrXAVv65`93%@A|!nips>)seeyS=sJdwXxM(bB!R z4Lx40wxoZZOAeUv4Hr$uq;IGjmZDey!h2xnH8Xtzd=psK&Z}ldD{Grw$(hyTLoWme z!ep1eNS?RJM#HZ5COUPemj!JXFLMMY_?%>*1)cZ+}DH zeDf`7Z*SL0#>+2nmM{O=UjoJ`kzRlO4cQ0F$ZfA}S6n2{O9-)2->#dI7%>%_%22uS z@#T_>bTcqC0KAJG!UhhJV9^>D2{Xn0l(?rT=V$pG@HsHI9H2a*BA~y25DJ?CccpP| zYneN2Tn!ECVW~wpEH&?>6=7Uir9zz+@8kmyQLV+{szXBo*|Ybs@`WD(=0(chXsuFZ zJ47yF4|id4V0b{*FU^$NWz||wv@)^Mh>HXAAas*$O^xv1J_yUyWLaLfSU*fuxcjm+ z7Wd{a-6&UPuVR@$%1%Gb~LZ!R`h<7*oequ}PfA9JU?- zmrN+f)3GqhP=W(F+5g8OyT1P)Kakg7e;pRuBk~X5`K}y2dQ{!b^!4{aPNb_(@o#?X z?{%Dc6leZ?@1Fl3E>r^Q=bdtmO5gi_@>BRPKP+3ezKY*ANlD9;EnBwAUBCS~xZJ>? z7)Bre`fvX(UEMvh|G)v2mkscL{{8R&0JJ5;E!Q6Tt>6AEl=8==6H52L{+qv*KAe-$ z+czNphH|W@zJ8xP^vEOdTbmYBp7OEzGEE<`|7VUlU>B(QesONZgPXes+st>J!o>+* z(ZO%{N$P1&djVO=h# z<3LUm9gY$)>m)2?twWZJg9(bq5yZr+6JTd#H>nN>2jTqSbHL}oyNd%=50YIDH#19@ zR3L9^r8`Na2&IUx@4$hNU7b=_425IODx~0xFk=NdK1lF0+X)NNo)#$Fp=GS9EWx4L zB^sY~gZ+Xh#R1q+JN*N@Luje(ho~Ij=z}96`U9^mS_>HCk9_9+AcWo-qG*EdB*ZX_ zX>}!uvcGj42eppNGQ_P#e5ho+F(dyHap)_p+($YON?LI(Dq*kYNXj#4iWlWc!%+?- zsgcIxa4|TB#y$J&bMhB|{^x3t(E_)GU;FA;BpFugJYf0hr=OPJ`0$5y=S~t9=w5pH zS+zL7{q_$lCExkZx8?OW-jveP5%rkifoIvN@p)jvFy@1t12 zxEOejLmB_2Klnqr?2=1lQF$r8H~lJaEqlxWJSi;A=J{8j11G})zFXW~#&12p@#X-- zButYaD>&ZqAos>S$#Fzkk}@J9*yOORu$zbi;kTzs>V#9_-}xNyIWRL0#NWrgc;oBu zGnZ1>xHseBi+8-`rO}W39Pl~db6~DGphgQZ#ATSmT_==~WC}~AHzFL|(Wi{HX7>`s zNhl|r9Q09vvhB64^3f%~p&;C@%b%T)wzjs)jvYI78!iF7N^y&mX{<-Dgh8BhLsguS zDp4vXe)F;AzQ_``7x z4^3TKm?(Ri$MkU3+ziMydaarHyc7}zN_WVXl>ABwwCt8(U#q0%FM@mbfZN{}{DEjY zX~91(73CH3zyIRTq_S$UJo)4kYM8;rK<IK(nJ*;lqN_>1-4sF3}}299_19(_t($v`H}%{T(@w5?>i>zqxU zbmZaGHfKnuqyEgx_p*i$$+FFxe&)5xr`X}Zsd|id{2$kY;6TMIAiQxe0_WX~mF)$c zNu1y4nT}DFeJG<1Py|J-Lesu3oqR#=J0}IOm_IVzb zdgyS2l+~+hpcsN{8{`{#Z-%i{wjb#jSKrb_$(>TNbdmbTr~lH~=&i=Tj8Im;0f^hh@XXmnio7eeXbde!eaOUU9``YL)&^-@8Z3%gbfSqB2QM z8k4`d`|I+RuYOg|KKpF>n{R#_O8F-F%3pp(UU>cm>Fn&3Km4OVhU=JiwQ#4fByY@F z7mN$!B+eazD=zNPT)k?QeC%T%cUv}&L#_kEaE}G~X2+aVwkN`h-w!?q=7R%Xg*)F> z{cb~M6lIp{p{cs7PbW^(*G{qGnFfUlAcNzESYjt?nNaE2F(U#Z@@*~l%4}~u0{pbS zodwOdNL0SWXs9h?v+cdT+Vs=mN}6K5EZ)4+k@i{e&o;x`WSbT*x|zaHhc_O4q}RIt zjl?%~dFGUQdcZ!%oQ)73__z|B2J_mdboBr(pp&LaB}w2R6eitbv|PU9?H%WGDv(TBid{r+%9{)pZ7-Q=#$md=B^= zm;(;j{@#N_IkU1dX0N2016pFDph5=<&e4HR{MsaI(bo4`Oqi90rOplauENTdyZhSCrQ#%G9^2$07~~0lG&3h zMOkGhQNz2x==}FpW943g!&KY*C!`I(vK;i^Sz5X46M@`GEvk`$125=7&50Q~a3YUg zH48b2!QhM4vCj_-4B~8wL79N1{RrG+Fzu|hYt`@i4}bJyS-NzoJofnG^2INHK^FwO zySPv{CY!F@DF5*7??`smBgR!sN3UFX;f3(2UXL9INwR9yYPg`eUB3J6Z^>VO{VN!U zE|*_E`)m2Zk8p5wPJt9-*X1j(yaJ2(3TbX>md59sKEq^cE$x(Pv1^WeKMAYyPYZD*Yl0bDIB{IGJ|}T< zob7fB#(DA5!TQNJZ}8^ZbW4*r&!%}{^l>-|gymzk=xteBr_Co=Bn;DR@YWM6Zee*1 zgTcLRovq)(S~yFGr6Drkd(Q^xcgsmM&to$Eijy#?#PZkHZ@+mq-Nlc{Bz!KS$#uBp zLWteEY@YXO`OY+@0S%7DoA7d>y1nT(ZmZ|L%TrIgO}c4_%R8r#TfYZBgd z@9+m$9L8DvdTVkBq|(K$%SniQ-U=8A%Zd@aczGYa%^rGLW)fWJT~HjJHuIjri`S%> zzuxwH(?ju-FlGuN36I4h22gNGYS`BV-V%8Y;H;-UH^Wfm1EX5Yz z?5r%qM2DfaCTq1$>m+WwZE0yyKbIF=aDi^G&B@7*TF#c|_0ZuXx&=5BhiN54fo~=+ zFwuw08Y*Z=DOhi~ix~6Swh$@y)i78!Ka{D7VGu;+=9`?*y}>cn-~ljEJE(m9kUm6-#w?bV%f-g#@Jq@+NVP_vPFd^S|# zcMm1Vi(B_fZ^Hp8EG~lb?0mJFry^}Ocu(zfJdH+MKXx< zI2y1^va+&5I5uo;YnR!CvscHeD^{#fKk=n-AH$uQ!BOBUD^c1STiPT& zEloELkGUYHKiF4xWK;m{0PVzyW7^=90>Vpvm7$j45#7RbYHj zx<;A-i@xp%39qc6OqmprXzDPKt||fJ5iTGxl|RnwY@n-8drzGm7to2DXHC$}7V(Xv z;}K?HZ~%+B`EtR!OOeOfoBgJ+Ud-zfyK$yN18{J6AM3!6$oNCt(B?^Z^C<~E=?=W6 zA+GJPY0<70#^Q6YL>rFR;6l0!gM0_ZeLmhY4ji#qxbUke1qG< z8`_blk2fNZ?Q`*Z;(&F_Maw6shfaedRNnGMi}DYGg1d188=mhx2Meo(40$XZ4r|kS z^_26J<#&orc7L9GlV^Gk`=kp)cn_SL9!DBL%pAgB+VxnaFPgHmlg$})`c5O zAk!JVaC-0jaodQpT8}O0R2o?>43|@eX^O`w!+QpM>*8?WZJlnq0iO)-q}$6RcvgU* zZALtjhN<9LPV;%SIC#ZR18G$TJ9xe6PTXyWy?3s*UL{ZeAOpA*omLjA$HF*Onfk+S z3{n@4c?hh7!P4L|kBLs6ZHx=61^6c-5Z;5=t=>r^J{M&KoMJ+nZ8PsR&MSTj9xdNV zBfJIzqCm{{C?W@zppmf5vM|W=_76A9<}<+t!XnOkC*h2MxA}zEfQU=4O~ci~d6J^0 zIr&CDh2$}lO_~=$d~qu)4<0-!Z|~ZxELnHfDp_7vtwxL%uV+b9TW_#~a1MXQFnD4} z&<>!{n186;W~CIa1qJz%ot=dP@hV^ml&fW|LOvz}&7iP0gFJqi$Uj4gQ%d=abPU{> zXC5>o{P7{#D`{2$q{Rpk&ol;1_OZk~|&jF5A_`NR3ES1AuyCg5O zNWYgk=>@0^u8zh=Bnj?2+;P<0li*{Vh65bF&~JMl+{t98PQbOyxYQIUs*5Kb=1fyQ zJR8U;dmtZEiDz9NDbzC_kt$Ooe=24h1+5GqpQrRCdEU zH#Ip$F1};~>cE5_3z0(ueORmmd|i$DQ6KE@gOz%LTy^y|5`<6sq4u594P*4Qq!TzS zwMd40gYZ{hEoYy*MvXUE=bF_kpdcTT0E|b5lN6bJn9Oj9qE%4;}^K zC%&Y(K>GvBu>9ghrWMEnByh2P0AP?sIu_!1hql7WvFWTn)24X=a>d^1@(P4{4YUNEwA;4aD;Fo&C*3&7Kg$+ z^t$Pmev8N4YyGNF<~@FhyLDRHoP2ftVbh!|7eQ2(yXg*I%6H<^pHnB&6u0J))l3il z2;GZ^#^;Ii2%y;ic7Q~l4GVjBt(*= z_ujnO#KEaac)V$(izi7Htz6Det_IQ{@7K)2u}sY1AhfV#1m6i`5DB*9x#Kgd{DB3i zUR_*()&A!uu&lW;_(JfuEU#{G;+o>%(mW4{fi-w6&dD%N0b4Fg9pQvK6nNlR)Tq)d z62c(vy|p)4VRQbT*;T_|m<#c!{cUJsN@gMOEg!7)C6oQp7x z@%aj_!ktafMzccvb9NhPy<|c>G>}jd%wGy7?EKkAQMgVQ+-4$TJF?4jlMy0hw_*iBJ|@@dtVDId|w;g&s; zQcx>NnfXvEVWb{SSe+C%rY~&y!U;UVfU-EB0AoDvn&bd`u&-C)oj+QK zx|0C~cFaoGH{=lS12{YtNZc|OuOZm~>vLd!IKX!`ma-kMGd{0)H*t_~=Rm8J_I-P1B`q}Tj2(2+Y(WV|%k~KvN2rMx%Tn{nYvhkY&&(}VYo(2LU^NbSZ<=zz zgM$@Q+p1RwmUWX{wq5SvYVR==EM9V{(o5wPaGTNq@ zYKR|o6ISy{OQ;@`=FmVK%pdf^%`&Z2|5_O-P5E@|98qV5t*!p-|`XcX6uDJOL|klZPef$9}qxE)IU^`xhYZ0 zMkYq$ip=-#eGd2>c&~B52%gN0RLRXsSNSrZI$&4fZmQ+SfiX%n#JDYpUj~)%5YZ~= zrhXt4YW(R(4WKg-a@tVV2NHA}60VwtiH?4@)Uw^uXQqi<7%)^boxuuXdv8*s{WTaS z=gcR=C)ehu_#E&#aIzd=pQR7-zPW~17IFa`55osPsmh)@VWT>xLdinyAgAWi#wblxCHk7j6Tm%^$49Ky4 zyJ3Oa%`c0bwXPbwpR!{r5oS}DUnV{d@Vm#Y|EbslT$)oQ?L#M^=nTp*4oe*x!JE$iLMD*QD(=;u;GEWcb+2k}x_bxohr_B>1AA zfJ>LO!o?gcqK&kEr1hM|0VTbS0;g4?6MeM0Y&x$tc*}U>Hs8Pc9GG7Yz_llLVCV#F z^1Q~#i7_e8s=#><4bn5zA^C6QNkF`C&J< z3Qs#jNt0q>MePkKvvH?H#4S^qWZMuKk1XzBnf?-`o=Jt`f$WR06YPGQ13`LXI{z8ma~mDg^DAMrWhbKp$ofDW9sf1A#Ix^!`s zU7#yqt=rRcPnmVQeZJ%sTr{fX>_Pa6URIPKnJMFvUQ{TBMH5iM@-SD*-IL=Ym0ukl zUDDmr31o?~dgW5Md03`oaIk-}_-%XqYy2GGH=Wzc(~>eIH?>#>0==;GgPWP`a>+`| zK`zw^{O+FIvyY!5A2KQjz<#=xDa%cej;0Ce8l1qcgxMXSYM%L+q(af&-(HWyQ#&O& zs|X6O;OW~3RiHy`V4+}is8@y#J|zh_L@J_kS1 z=fElB0A(=cHNTb7h%mA|84FTN@>j^guD2yKEgK7_SgBKU;HZT>h)lja=hItLA9Q1L z8z$l7f*%(4bq2?(!U5Q3{xk=TpUqf-Mp-(CbeKmYj1WHN>8<&rumm^UP@^-Xu}C-_ zCe7e6MGZ`J5#*5IRuug?y4m3ohbB#A{3L_Z{21?26y&yk51&ZCZNqdVh1EwKC=iww zrOFv6O+f^+Jf!Oz=DlZKQxtbeu{7HR+kSf=&y_g58q?L~QMfxo50a18Z2;%_zBUdWv#%k%(a>x-Yzrw&y%?;#f zLUNh}yPITuxJxpYTx2XUPYpF%D+ky-$aHXI0`4l{AG!$2)~p2hfu$6sHJz2C8a=5$ zl-1om{d)LzUT&7GSg}+sO@qNvwRSlvK+4I`#XbW3!WSYIHzP^<-%B1egb^CPpDsah`X5w7J{X0QhJUg=Tyi@$6-m%F6LbK^b2e> z2;-R-9Q6fznqb-ff+S`wg8aNhU1*HstbtQup?~@@%ctnw&H)}&$nU7md!lrHj(^6m zyCW+#SL%w+m4Nh1U~CWvEzk817Sb>Ux2MdERW9~UKki!OSqlsp-l@weJNHr%;T2xU zCuv^xSbh=DC|pzVJ`EFUhEXW`ChguM4*XIna1qAf$AjNOE>_yKAkKoAKv~X7lkr?E zUQX1*$~c6uP7;>HwxA5B*Q2^)!5L#AZ{CB$C(>f+q)QL-lHYr_kHH&{yiWoBmbc0m z8e}--32SlKayHHKZ3N>z!mtjP2Ac-D+~=zFIM33di@0VRBH0^xPrT96Y<{`Uq^lBET{Z2<KKFgWHjM3ytD`gan%g^hyS6qp*Hi`rY>8+QQ0>SbCat+tH4x`;iI zD0#%ofY&E_@Ro64r{a%Gmm-ahQd2#6C$(*gVqx#5h4bLDNp2lB!P~ybc0`u<-rKmn z0$&)tHl0@+SeH#Sodr`|P1}U=#R065QS0LLhj8y9NzTa1ZXz;x1uv3GNWw zS@hdHZ+$;tYwJ|aoHO@y_th(tTc+l+`Wk%>%*rsnMZZepddwevRCGUkvo5 zC~qf6e+(v%->q1wPwdUdyu+novdsIjqo~YPo%>$7nA6F@ArYO_H7$Yb9DA-*eJds*7WS*3&XlUTBgV#^f~{aMIMw}Ogfl5cKmQi(HxMx4kpnmb z<|@U&K09q>HF%{WLl^~|_Jj2d-$Fm!tH@cyCQo@9@%Sl`zFsVs;4k!GJ>nCgRcb4` zxKIA1$+Y$w2!YB53)y&E){7!5!V}CXrwQPL0_?m>WA}qO% zGN>)R!S!T$N)9BVVcdypne`zX)Ihq2>w<|9Kho1fc{M{va`q^bKhg4qe$^Ln6}{DT z>J%Km4AlW#wQsnyK^Bx%eB@pmab!_hg-I=lVTg%86V8}DQAnytZ;{p?OG^*n#z>sb zdVq>{dFI7&vnaOXhQud4AKcSDLNCKG@3KGJeMx(L_4lKIie9ut;4DVx6emhg_&697&pD3SGs7qB-H$Sp!qs&DT$hvEZ_AxwX@P@SIo1L~FI#$m-{a4;q12Hs)lKnDxu$=Iv$_!s62>$odDTEJV;f zpJUC$-9W!tr*$W%QZ9AqR&;1|4-XydxPhln?11e#%{9$An^EI&a&3;%2;NvR1RXlY z&i@TmWGQ+#*r~~{tDTgTSWE%XJzZ^+jZ%!doZk9t6)BK5rKTaUmh(-&_m}SG*$`!M zO$%7P`S^ZpuI2+aMgm;W^-biM&dv~C_p5mjlaw6DkX18Sb*%A5b?gG?pH?PNOiDn z4CABoF!ac40-PyeYB4b=IXcTB>#r?O^ggH}`p|=`OZBiL1M8Rl&XR}So`2pKqp13% zxxd*8xj%0V$vAq$(AidSGXL>YP>I{ zwboUTImJ-m@g2#+cl9F&ZWZ1E-=)Amo45jU)!SzcRs!qZH0>0m>C8_&nivZu+W~*9 zKaqAN@}OGd0<0tUMc0`lNA$>7v{G>HY@#Zpf+h95`+7QI%!%?zgglf&-e*d%jReKu z+k!>zgQ4CjrSfv-y`CWWtGalyCVBS^LX;CJ(U7<9^WX_C`{ehFUjRlZDP& zm7yj#Hn08VgSi5~m&e}F zjJMCEX3&~=6X}=ySY!Y3$=%) zN=GwW@#3CM@ThLg4GZMbcqJhG;ZzF2QHP;H>+wf_4(3KY1|=0K>W{{2e~+AYWOu(q~VbHF;{zb~ZdlyY^eU-d{xefIT$sBF)F z6hhB#G&u;K_#RFVxodf=S@k{!Snc4YjTOd=mYnlFU1RWrOc%174B!Hr{L;Z&TM-lq zmcw!I>cK|-kYZ?)-@!=0+x^ST;s!&1`myix4uy6xgunY1%N1gsHlobmrMhvRnyMqR z`SiDfe^i5K+a%t-k@v{WOrJB?l-Lm)vr`Tw|_~d^QW0e;` z;4a)3Z0%-JFQ*@JK`x5B#!nw2;#vZT;*m~y^+|Sj{3^&VP0}gf*)fSWV`S9su#G{N z!(R(7=`q&({BEMj>;G8*lI`d*L})H|*@vv$FW=ohT)F%W=pthcx za_ZL%`|68bU( zCvSs~MpVS-NHu-EB3iD42k&f0TlGs5$fH%hzHKVzhHT%vF1H>bwLO-zXv03w=DsRH z-l$kjSSzYhY;%3o*ZqAWpfI>mW&X8NP=N;IKrBGK>-kpzEywetby;cY52ce-iqM${ zf^JV_G=f`bxwP&v^+1jPZ5F$Nnw{??&~`jU*YN`w=^QS1S`z8%$5=p@EM4)S>(gmV zAK0n=c@gV8>C1{qQbqM2T2+x-7LY7MPjo~6s;KGRsTd1~kT>>5^M^ zWct{5KFX45n({l7AMLob+^DE_K+)jeV=z`#kzJXJwG(vsEtbcHAtho-1m&h>R@jAv zgglChg(5OBpRo|6R9LK!B#s(ko?jHMrEXRI3$T=&Fs_J1)g5 zq&`db!SGSIBRNRW>Nrx1c{?1=}_Fl7{3n$AQc;0l8O(Z z*11`vn6(>jXo>sh{Aa!zf{kKAG7v56lQv9F} zMo0{mn#R=hA?pA3&}&&UHkEJMx3=)ZO3ReyC$FvoYVv90=Y!sA=2C&l>ku$37T`uG z+8FziDMkblyvdkip*40%P)5n~Y$g^|W5u|>^VZ{*Y$gfSb_z_J__whPg>YV&}E?ug-<)mH2);Dv*6;~MHm^hZbi!>0|WsSo;kTyfP@6M$2#!VK+^d%|J;<{;HE zep%Vx=%KE!fsDYN>w4|{H3@_${nWJR&=(DJZ~NtRX66rbN8W(br%%Zl z8N_X`FD=_dsbkf~9ZfGhyMComwnSISo8_RYT9K~wV)pt zbQbr?%Tz19M!{o7#-p3n2S(xfWeIyG>;MmayOK6f#HB#uN!!>s8w6P}e6+W>AA}pT z_LRM6nq+!Yx{V^P|HbOa{oRVYfT;7;Wf4zhvdlZ6uk7Odzq9NYAdJKZeZk*kP2^}E zHMrMW-?1>QMA_oa2f7QZG4)3|cgQlo8I0r3ys%_o9uvS5(r=5Nll){*EWa z%Gsi#1j+I~v|~qTs&J8vqe*=qqzFcqXo#s=93mA~sV}Aqwf;-E!Z*vUX?f%J@6sq; z5wmmxM)GdH-CDaH@g}*0RlN+ew-$$spvUO})C>PD#Q z)SBb5b~yK%J)9Z;Qpt}orrywHnoXOO*M~&Iwfnrkd9?iY3uU|QoPGlUBqs5RviE_Gr;55;Rx^y+Q@Lib-oJ<01jUvImPj>O;${J zMx)-TSN>V-o@dsVF4m(QPl}m?9aRdU*7ul5hnNc>ZF4?&wTc)U`R-M0B+8OMaPx9V06k`{yaGu3oiUW+y6jBIIa?D)dlNzsiJ2cEc7e(Xkk>Unr5V7fpVx-Kl{} zEBXyKP0Y5sRh60^wKs~YCa>$~{=_;fEp~=ZT@ZR>rMxD{7L9CCNxK38m#Ei4L~Ws; zQcByu$OKCCneC>^{=GE@KI`kFQx{FV=rfP@A1Bb&3peWP>rHn+bu^Z{ej=Q;7?`6x z6!DvjOI?8;lX_6!8LPj?*lwW{`y4Xq925q& z5eU?FL)hMbQd;EIis1o|@$HLYN{c2Ydl=Rk2G^qd{yG&R=@A;GFkS_n`z;2i8Gbba z4`QTRQ~sV;n>p{l?z~A ze(V`2o18YsD?Gz^G zO+}Mv^-?gTw&F&anYYjA-R=Om)YrO~M!Y@4JJ7qX9heRbf-zT~_g2bY)X#0IBRwOb z?0GK8gZ^Zui`>D~zzRLM7dAb@qH{fD49vrADNdht=ZPUVw)VKui|=W)ObtrVt7Q~v zpPyrh%zw&QHNE#UQUkMF-NUWSe1Zd+-8i_$6h?kDB%9|_a*|J%Z z1_TA4pV$tzlB!OPT`zjnQ4~tFw9*v54N*SwrnuJ@4Vj)-M!MLJypy5#k|p;suX0s| z%?`#TdJ*Z@yO2woJ0V5EbRU`C`JQO1!>C{8Y#k!aJ9$YRG6)W#KI(4Aua-O1fsS4Z zoxk2^1fh=cJqUAzJ*7UK2Z*OEj;Ae_u_RlMf1ZEL@}DhxC|bcUnN}58b6DzE0WRdR z5V+~tr8;c93L2$k!QbB|<+~@ngec

paY_5ejkH3IFhlsuNJ9gUN3tcKf;e3^PFjX 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

;+IpzD*h0BL_tDdSu6SX2=dwn;} z)hsdKpXw?z4&pPdtSUI*nmHZ(aRyPGM0K|zB8FQRBdGnMS(b}Ar72uTQ%KUhl(wtP z$wYIYr~&RoJ|2UGo`ENm1?HZCq#1lA4f72|PQLuZbI;+`zyB5r*IkJICO?ku+J$%g z`WLwI>Z|b@9ZdJqEK*uh3a+^6dVGg~`%-EK6dsMhz2E;KiogD46lUj`KBqhlaKK*E z&3@O?+=4o4M;$FM$Kk!DI8b^JZ@=vpoKKLxTN4l$Uk_Gnf+y;8>RWy~9TWh)aAC2T zI0`&<_Xnq_iS*|2SHxY8Qb{JMf2&MAi=}qD`o8m>8MzMTZU{Zx`Py^7t^x1mI8_c^ z1;Dqov>OM?IXUS@L!MJyqj8o@nfBg0-h&^K7W=>WGsLaRKt%qHSiA9DEL*dRel6x9 zJ0;b`)r3>BRc1P9S>;+Dp#WW$jb^Lr!&lv7D za-UDt+lWsDRLLBad^*SvKrhD=$uwPeDQ&B-Sh5(eUUNB~`ql4H^S=)vy8AmxW>+HChl#_{{cT|TbhklLZQer*~XMc3jDcQEg)d%CSeCb<(wbCR%d%3ls% zv}h8^-B9Rvwu@^~M&}MV@8oN;W>T`AZVW5S7AxRUGU1rY*-DwT&V^G8`+!G2v-!C0 z@^p;+hDSW+N@b|8NTYgy?<4xvb^I_Cj z(Kt>fW2EJtl9Gnf(nB` z!d!)%najbSp%{a=oD=aN=WO!%b?{IbO$8R11qktE6&Fx7U(3u$H{;ugxMYOIYqcn! zNAbkr zIE)JCB&EHf38hNkN?^))Rz zrKKmCuENVx8q}|CmsQ=YiHDK<`^2iMe2M?^uh;Z_@p?PIVfv1hZLZ?(og@^~8EZ;v zq5+9h5)v?b&TPEy--g81e}fNx>LXad31TcY{>E<1F3vT!`^V*rW18!1iW6gy?`7jX zDv2h7s@^oV-F-O=jMlqB&lJZClR^RYYw@iXy|uVkOrH)?;E+vF`CRDHf*Z#y>D*~@ z&8ADRin8#n?rGLYt#XcnfWSvKIQ>)q3b-#`8c zZn^nJ&c)jC=%bI*1n4rvQDGy-7mpn~woyJtptx`&jvQ`cdfGjw{otpbe3ZM4-)Q0)q4>#gYmjAi!;GOUqgl$>?qlPPA}iJRl-~IaI+-|fJlyQGIC7{It6oemxngnBj`N24|!CQiZqTEKUryJgKUDO)J<%^WfKhW1U&J?9;rUL5+WgAu(Gj{+VA zJPOPp3g}zn$kxfLln1y^9xYEcdh>5^o#pd$x}s+(*xYtUL(*MzdNY7Xkw8qHS=#+m7l>dZxhfu1%* z#uqc&p$h0-98KN;%^WnCcgxOBMKYZ*dc12}z&lQa0t4i?+J*-BU)qQ4!aN+TsK*_T z{Wk%kixJKVu(W!msa;RtJw^P>{-IqU2VdWc)?Yk`oP}$#?^B<{OPp>8 zI5!zfk+nP%(dS=-&Wc8~94_Ldt_#g=&Z1bbLo?>d1!>LI*SDGpqT@Vx=4c~Zd317b zI6O6*jijTjU>ikn(IlDM!Pl-?jAoj#s-RDjef!D~pxLR#)b>vx0DoZXPDnp<$@(=| zK}XZluI=JNibh9+3m)d9NatvD*4*DgEv;EgR0!v|&cttc4JQ9efRc6xNp{NFbYVfZ zxehhKGx;SC&r$6)WZpmv^O2m4`>6d^VF35xv1itm;Wd6g!U=4|7F|F`s(&zxwlSG= z$t&UjFH9B%#3Kg|9Hk>o}(1w_ZH01+9JpNcmY=SWojX z&;9CQL{tS3o*qw4Qfm4VY?sqjc{Y`UO*j9Gn^tQNs|zln~kUs8&qdrLw zkA3_TnY=K)6fiu(ab26ghe|wMw5#vPEy<$@(>?^=<5Mwz-W>W@*@vae`*5VZ8kyPD zR3{GwxGSxj3y1UOFEOTL+FF|N`j(x{uMdaH>X2W&2SY+Eff%X=3R_{gkz9$hkdn4`N zrW!+%syz~DvwyQ*||~6Gmx?ymZ%!px;WKf$2$R<6LdZ+--ie&%cV+|&2siVM#- zGyOncx7nGoa>YDqq|s(47bcr%r+EDZYjD#C--~;G@pBZm29Q*;0?E{jCmIiWmP4Pk zd}#YJoVGy2$@~6SD^bz27a6zQj4QtWacnqm9dgstIROhg-#Q8MsQ(D0l{uL=w(P;G zmGeU;Cnu5l3{Gm^o3f;t=C5{c-;Uz^e9X$sKss%^r>CXR)QlfBwT+0SecXd(N3r+0 z&2-(U#YrxP5QvYWoRK_q%SXX4+V$1jO6%?fnIjV@52;1(Ktj_)3;~pyXdgaQX?83X zQ>$ENW{#aWPi=kdcSd6b)oJ$ZJiPSMR{DEsW}iqIT$CNEg(S3<)H;SvlFhB@`BCL* zUM4y<4=A~mp!+kX+?b3K0$ik}eYxqW&1q4J+Iga65npCxrWox|nH`WF>hA6+<7iy~ zjsSNX=e*EG7-{SLM z`6r_t@8<%gG*G=TO%xz6$cB0cZ8Qh^{K!toH(lF|!N#b<&{&Q!#Y|$V5rXp36X&r7 z2AznK$CAU+DyD@ZJiDbA+sn9kY|;p9XV$^=$|bafV~P|wuLKIAkw;(qkNnHb zk12Gt0-YT6jy-*G1Zug%gJE-12cjahn>4h7PJHiodMIF~DOzgUS!W7VYsf@ZfD3{x zfqB@oI~vuk^Re%@N73YuN0KiRU3}Kdgs;|@n=~C=y=daj+y2;#aL=EpSkak=#F$L% zc<3-ebSh;~PB!}U4B-88RfSp?J>MJs#ZbXO^E`B=ZonDg+JM{Bv@mWe_-^?k8Ib??WUwe2_(h-ab!T(-Ls z>G3hxQPqsB#116KBqNHuVRA~#aPtMZxa!KwaL-SEjwhdf8lU~lXW*k5oMZ9XY!6y#YG=ftI@|XNzDH=E9Hr}yn4P&f8XZPY;XUyv;8DP%z?c-UV%A2oqS#(f z#?b@ZCxePJAP;@C^pWi|BMn|?z&GJ9*$j9QuL|R*fCi8OXK)`L8I6Q_7b8%)10DNm zGqvD6#AM7SDB;-IbAwUiFJLI9w9ffIB!r=%zJ;KBnz0io&~aEf)HLa*V;&m#LwIxo zS<-4Q@kk&_c~((_Rg?WRYOZF|ER6%`hZN&odK5Sg1;lrqj$aQW^BClVys%Y z(17i|2Kbbw(}2-9mWhNzhbySbnS>VlJ~+6)jJ^=0;l$|F*6HWsPcK#S`XcxjMn4MF z#tXc701Y^Z?Avd{JKp|J+={%~XnBS+jkG?801AoSp&5bl9GWo=e-`>m<{j84w!FEA zrkk>i^HB8-cYdL1&V*~xPL9a-9XfRWVjmO*;u7%(a@b5wv+4LII&Cg+ zn_9lKcfV}eTpT`J>6pwRZx}h~;t^ZtsXki%(k`V%i)ND)TBvY_3NnSD1yt2de+sI< z?#VoYy?09L&PvL(OmrG~0GGjk=sDvLBsw+Um{vQ}`-f?a3H%7pRudkttrSP?FZz{I zyFGVS2D0cwMNZ7;&nq$|iU;(aws~p6CW=l1U)#DBPkrz|k-uPpRC>|T)Q;?beh(Vn zcne{V?Lze0eDt;lkhpdpj^6p-`0ctixSflXk*u8E#W#Uh@}izF1vKUgr<3n?(w>g% z+2^J0&Q>4F(dq8yIur~WiZpbll&&O04}v$vQ;MKVnOy0m#_$ubb>W*Y^r9#w3|-W8 zH>JC(pwnP7cg+UxsSx{I=kDOj#(g_@KK9el1fws=YVp7cwjTBv$+2t{X{&Icg-*WN zM+^;|=-%%%Q$TVpiZW2kdR;tMJL#{N=W%SSIF9QMH1;8tV}ip?eMqKL&?9a9*0FDB z$HF!$Tu|(pxbbv^8pAYO7%zcil%w4PXd=Mu7(~icMjgUM*)ul9tCC=1w6ogX0^u&)kcFm znM#n&O_}7-q{tiboe(KcyF|u0plVGmGpD7%R*v&i_jA3Pu4RK>_RA9!;;~?U5fyunS>YN76;8h> zqK)Q=we|IgMFpZB*@Zve_cZ=cQh>QPZ^Fv+*I~u7CDeG&z`i|u8K)YZVY6`I`K#e? z>_%N}6J{6ZJKE#?7Rqk>0NY}q%a6YHYWRvb7@`E{p_57=+m1t-iVtM3n2R=SKeeZh zg3x(Gc@hY7$JcwdSU+Q2T9$f2Fi)#hUb zJy!d7(iDQ^qteL!u}x;v3n-7FjH+pB!b3m14;ch*qq9?R^o2)p?sva~JMMT7_U$jl z_bWe#w4L>cSW4%7%xBiT3-HXp{}3xzt-zW^i>M?JIBuQBs;~EKd=xOUiH+Dd(94D6 z9wgG|k0Y;K{NNH64%qHIQ`-+d3Xv!3bk6gk2UfP~zLDq3hH{3Y5Y6oacxG=O7N>w%uU-l(dOv#O;$j7rQ_>;`&`06UUp|M0DINIO`)|V&k3WW6 zuDb+n{i*ongO4GByACrrE{lsxG_Pg*|MA|@^cRQVjH*R`M{XQ1-HAN6->(x%>!tB1 z;8EZ#q5uV$5s^l|PyTy*fcxar^pxeO!GUoacgkwu6@1Dl5R?)Fa=1#(zX;!T=s5UC zw0G1YzGNdc%w^Yoax^?OSkkugW&-9_ba*;kIA$Qd(+;YQ}m{UNFTIStLt#i`{sNJLw zr~oPjZL95}5!WOxdPdW6n(hn0YHVsn4V?^UXQy#;l4^kAXll?4yc8I#poO#M=2l}j zSsKv_ngC6AUvNMd_0s9>gMFmy>gCID>39DNuYBTvsNG+LsFXxhf8#;ik8j|ax801K zbt_T#<}PqK0)c{bZUyf|A~mZ@X3wIw8G%9p-K3-Js76xW1!`*8PP7Z3m}z`Toah@l z^TOdHFxxHy*2PoyT5T?qK$2_moQ&=-J!%#fmo1xvB$_4CqRUhVYyCrFlq|%_zb3Oz zsp4B(SDEe-zm`|j;w?HCmgakIt|reu<0!ME!;b?8%TZiB3+L-Dud zkiO{-pE&YS9It$xKglS{PV&){e|Q$<-~TR(F1ikNf830PU;HQBcI!Kl;fq7+^5y8g z^WSjShyM|2dm9nHAPtC#M8a!(@!NZUjpEOI5~;DV=w?3{^tUj)Qr^`hQ9x}TLCx#t zF76`i??g-lclq$&U~mN6;H7h-=MonBBY&7*UFwX%rs1^~Hl29piA^$i&+reg`t-f! zg(P1$lSmUdm|HO6nR5sZ1HlHF#!K0! zBe3nwE%@H|zQ=Jv2aX)6Fyq;gzcaQxQw@m~BLGa1=Eso+?y-q0gv#RHG2K7B@>kDibFf$#XyTxxrgVcmXtXj1k zv#ve|+v<*>`Kdo5oz7E}X3t08YvpKs{CV0ICH=GF46wexv5p$pH7MP;7q7js1#j)% zi~WZWqoS%B74;41s@_RcRXK>FlTEJnov_?fdke@^d+1!>TG2{%@1_GuX|Xpox8ZPE zmDyFH`xOMS)4AhJi!8HgyIsyxCHI`~^3=7f%BJaAqea@u?e7t+FV`OiL3b@iiPj3~ z>B+|Ajrcb=Hxr8%&NiCuiHUIrbl1CTED=NA6d13?1Krc2krtAsn?FUhFfNMqbvDyn zNduzOi+P7Hd=>}$y|gygwE(0Ar_$1L)X_O~7R|Idi+{(qmu){C1C&+TStEzK;U!7ygLYL+uF5h=Y&yDEsvzi07`9Mf2(CnDR|duBWaioW)Eb$!%yGMtjor zXzi&VCj0nk2sj^+Orfp9>(E>JLYS`SJkY6HQ~z{6z;CGeg79%$doP~b#l<~77*q}( zv0U$_M*)ulGl2r?)jpbo+S=5OFJHF+=Pobe7$BD8m~1@%{Bu~bVi_tcsyHUtkGFQd z#ocgu$l^1NTkW@qLTE_tuKg{s-xnVm^^c?b| z9-(Q+d*7YT=BcBtzdhH{hOyEpj(u*A?t7!K=#Zj>3xzp&r`?)>WeFb+uy0&TE@j~M$-dMrrF;X1& zv(Pfeif_|}9&H+Xf3$1e4~-KV*FLvL``kH7=CpCgdo<^E(H!$CIC98&KAvC6y(XHd zt*PaBiy=FUe#qz}%RT4w(Dm_9a)!szBv{~0rg1XofIa4$HN)%eRc|}$dl3KtKmbWZ zK~!oeV7A{=n_S>Te8~oMR_%iSz|)AM)48Z*+B&8^T*W!jAVDP1Mgm55U&U*KLWP5; zFltrxQ`0_B{wiW-twdxzw=(nEMC5Y;Pc5zO1O!^lc@DuS0XhPMCMx7k^c}o(XDlN$@yveg&|mBqtE0OoBjFnc=Vwe`OqbEZeI$dwZ7w+SO(?H4WU6lZi_1?m2R##w^76=v+6JU}ZFUNd74F zry$v=vK?os6CcElx4vpYNpxwe9c=;{iGB9)!WYqx<$2+VO!8Bm_gRjDnt@F%dno*=v5AHe$c%gmyWzO$(*Nv55gey9F6yy8lqOXuryl&X2l z{-fo1eao9jicdf$Ck=4~+6BA^xLE(-&+bL?&Q^4%cA@*~Mfm6^K8(W5EXu`zDPLvu zl8-J}wHp0*eGPYi@bgG7ZA93@Ok}0a!K2^*F%~agh((1(2+)D5_{$5EO99Ep2%7OL zZz@H#zYLj4xr5Vkm8AZBQh^x^v5bn{mrl!dMRzKR?TDd5{fMcH=0!gWO?|bjyH>QfFY}5Ij$fmCb$KTK~ zV=de1gF-`x2;)e(n|oM9uyO3s-VZ(6=Tw~H+^C21ZaWVhdNR3Z9^gK?^gJcG=>r!@ zt)@0^W0#qaxpQdxKw6q!IBO|j0Ci5J2l}Z=khjc$@BV|&BVp0?2#=w8nLZ7UCO+8} zuSqCL6L$wS)K{#SN3fjQ>#iW6zw^lJG-H#57;2XqQ#P*WI<2Mc_5dg5anvZzrLEvl z5FjMFcj-}JQYfHFL^MIFy4F_wnkEin{JNw8}3Qz-uY7jX4u7vb4^?nU62 zuOJQWc<9c%ao$buM1FD_wLBw@wsH&s)`bg-OcMq1=#b zzVXfil{ARefAqIx@f@?j^v0Im)H04SHsx2XT)_Nf`+NEpo&?SaEQt({LTy_G8agWx z@1q0bxO_U!BCtu2&6xmA3i%D#W3+H7LqrFCr$o1wpxGTQJZO@44mD&y@ZQ_8boo*| z_@ker{+@@BGJg@xQxIU~^T@bpM9fV^cpo(gy7JIjR?qF*bRbR8oeJJaiYdYDlKF^? zO(6*F28hP@9;%zZsnQbOzP;4QCoPo7v9k^GJCRL?(c%SZy(_-b35d4AeupPYL*=6Z z&p! zLlvl~tmOh8ZDi9Cu6(JqaM#!@IzL^ygih_a^FoUx3l`muN4 zVJxP6YUD!w*Z=kFX#Lqwkdm<)foLv}`)Fz=F&6z?P)cs@gl}Fl>XIVyxBv24EGwCV zE^5bH;N0?2FL!=ixMmH_%X}60eCQvMxt}`{mgWFYzk_zvhh)!SeCL+)D45=9YhF-jgfZgal!G5V zeOL5P2?p~Brt=OS1w0DOYznC7n!vHG7DoHDGg@OSnkCJU)+QatY9V$B7f-dw)+Zlf z97Ea#cq=Y~xeUX?^emp^w|Y9-uBvUJS-|0@t~4HX{+q$Gks>A^CbVN0BZ!>GLo&&I zt@B_dOn!qEnWPh&|A}Nbp0p#yao^Lqg5GhW!JW@U(~c+pNcoR+Z#;Rq<4iP<@x~u- zJk@0)aou%4(Q}ojVB2{-<&PF8^uE2eN2jF8`Bk0@w%*RwiT#GwFZBAva&=NMFPSlJ zPMcbmm?slj-PbJ-~f*+MG5|G@#YQNhUrTs5LxqZXxULOs-Fxm+&e&`4kX( zLgpBt<5FMtLi7h(VLFoGkde#*)xpM4Iy zzVs#JuDR3zjP;v0Bj+=p#rr?{Hz>->MFN5I|NZ4ND4Cy&hI@aBH>uTg#pnMXIVmaV zcA4c+p1t$}7fy%821q98Dqip51f`2WW)#5(Ip@-#U*M(ZQJ zmnI8rSG|TNCr+sb0I>t0V7FJjWJac<`5?-gcOxTd7J-vKlr`=_QOZI(N%Wb?R%l-K zJtlIr{a+?n$}4J&qecORs*0aZ8|9o+prJtb*WTELi#M(|+U_MqMR;W0YHa=QdlARa znn1dmou!CaQH03UcqHWIV9p1wr8yuUQZh4;N9|c(SQkoA=GY6Kn22+|63xf3J=!%213Ed5CZ+wZ;M_B8a7-JR2&4RnJ_?$&MnuSL4JWc342~wE zO>EnqOs9BK7NZE}f&;bOx&Dw46Nc76IJQ^zW5uiibFK9N#T{%@<{_tQy4If-4xGhU zSLVu}^%Cg5XK$H_BQ1U{HVAaLbyxkTGKh!6Bco_Gg)0kvq&FSGoozw1mc8|MngV)j z*CA?*7n^pGSt_+hUT&88w#rP57V`wQi(l2})P5FZclgx#CTlTCi!8nUJy^YN4c^#w z7=5pAM@CE$24=@$pt%d-&D{u3OF-?LM{wP5{tf4@SV5<#@(W}B4>p6%x1TcZl5^Lh z{|EnyAN}QLQCQ!OD0*OMZfW7d02dX5TXzQ&dMBe&z|wTo2q6#j&55K8iK3Y_(>K{h zLGj|mRJU<;Z{@FR^NkqH%ZW4?)jS_+Yg;GfZ}Qf2f$d?GS;~VyI-2ufp6>JDE$=YJ z6i_q!^i842^c#cSBNwQ6F^tFm=+t+|6;03dZPD{C%6r)Yx6gHq4uaaBj@<) zQzbJz!2Jy3D`%pvkDeDi3Ir)&CQ=;Ea3URBuo~@qo`nC%8;GBMp3#1H1};Mboa52W z$!@?nOUEyE^o|JZc4Ye8s*b6j}?O=x_U(A&3*Sc0!V9UC6N%bCzl_=c^7r@~YF*AsO+^=-KwUuX%(uS# z_t^6BzeB<53sLs%Z{w+T=it^G-^Ph6O`ymWf*t(x*v-jDGyR~{H8xP=l(sE*@52Dg zy5()xAvG?Z;5z{(=ksnFK>bAkyzG2md(8%8!(G?zI49atn!HHM(QM{7^Ag=5u*QGJ zku1x0KoSRJt!uBsk(Ry4PA)J2jfNo|G}ThxT#9*F%h4A$d5gD_7yI@fK^;N$g$s&| zNt0MEZfN07;Gn=j*%q&+li7oZD!Cw$iz3^o**k?o_lQGTM0g22({<`%;fa$sunFb{)2%3c79 zeKlQcU9*{{WU5+?zh9HCqpKgZ=7EH00&tA4IJRzs`7yEKJ5|H5wQ|#iD=?8{v~1CL z6G&AXYO!QCO)C`^&N7Pxs>?BXyRw*+Qx!rDd>#4;+N!-nYC0*!%b)zZ0o6S0n!i?mjcKX?~j2j$K!69!;P06yq``aq*u+vpUW>#UM@YFq35I#y@%3_E4mlSqku<&vxNebV;Tc%0Z>X#Q!Ohz!2JwjEb|E>11Xq~LZ3D z5F&uRKhQ!`G7HFr#{zYl3|3dyJ5Ji@oKGehf{aN2QhXzoRuZxbLnXBc+sE$S%l0Zy`574+~}&lYawd^3hI^y|StXM-Cpwpi~L3+n5o@Y23sgqDQy<;91 z*&IirX_O_DOPpy5w2_9mj?&UyL~}hg^-bvJwVc?t)YAmjj>CxRYexFH8)^1u6EYK% z3Svyh^<(+V9Y+AB?6p^MM~<9_YEfWF>wI*% zY4g$of`D|%%w4+<8m(lR4$^(aQQf1cu`SZJ&>Wn!$eU


v}++qFx~b2ne;8!sR$ zKwPA;V*s&HN-y!=k4AqOYC8mUI^c;Y(m}_mF|^}OWisPT)%|Xv=K}sC!UUll`(C=k z>Y8_%JExFl>k3SLckiJlGz*+ll4sr_G|x%BHq|1{w3swN`tjSPx~kseksp&g6WpenS(jAi}4fg+-dyPFA%$Y4Z^!Rkr1DV1pa&Fi9g`{^VU(mB$^#RwoEr! zbWbubg1mnzLHDrd?;^j(U`fdw_I0~xbjGT}0_suKsk*+s<X_bz^wG17Ci|wjX^CYIWAt(!VA}3(9{`*`VNjm*ucF6-m^Jgc3M@fCMggM zx>Qg@+e7eN<08Ub1iSRa;S062WR77Fdrt<-taul zGyB-438|+o-`0CDFLyk9ZZp(T`SHFUnfK7W(0IW(dNeG5b7O>iwvP6>`)KnH&C^tX z5#7(->2z-6xX6tq(8`mCf8eO~TVDFDsmQAmt zD}RS~Lh=fUqszg%>U^X!+~vFDk2mf}@sy83Xx<~;3ytG?$7AwvKXad(h{2z+^0Utr z)m?9QdfivBaqYEpcj&&o*3sr=kM^F8L?va7 z+li_sSOSVc6QpJ zNtzi?Kd*w5N&$V~w4y9NuwP?m$nEfoKA4K5p!+61`AZ*4@tVD7B8>Nky!*CI#~ZL+{H@SM?aM{QMR?~IK8YVado>njtU}h2R{Zq+ zpGE{7q=t2HwjtY=Wi@E6-j7&LG7{)~HF+T&O0A(S9c{8UTLfcdi@5}O^Bg6 zkf>ObrL^HiZGr6uBqLxWo9;=J4=r5{NQrYCBOkB)<3E>H{{Vr#WCJS81e&x9BpdAe z%Yl}_xIFrGsBEgk5AOak7A#(hs_IJkI{UbYaTqI?E~IVZ1oZKnC({(nlIeq`2W1p` zxsXV}NhYo+;9L=ot)&HyB%hRzc)$Vh9qk9DkW4MA13@`8j()F#)K+R3=R0f@sc-4r2IqS4jxJ3y z@}GbK#6f$_n6=7IM!Efi2I2+$62LA#MdtWVv#8YS%amEU|8cWrOLy0mC? z5V@A7`d)u8TB-ex%5J>-V_ZZ__Tif^KZAno7_>9})+U;bIugKbcjVxsx2{F&-7n+$ zS88xkjt^Vfy0J1l79YR$9Q@y7JMpVs`!P2^5-&A&N%b8u@ex=NABh^~U)I%&rE$_C zK`637`+dYpwj4ad9A)X%w%Ad{e=6CRwrzlZemL%6+eQ#Dk7ir+b#`(r##RcW9XrKh+@XPhQt8?`*k3!|Gmp$O zCxVedHWH7))J)FjYynEI@lQ+cnQej7Q}{T;~+AM+u-GNP#SpR+wqiroT|;Z$D)n? z^loS3`<)2EEhyZ^T@X#3wa7}$GvKb~AJj6vO8m;!0u6p$Jby0gY8VOto6PT{4 zjA%R*96r^x=qNkx@dV`s;47`tPzT>U8%i_LGikaxCM?PbFsGy>1Oa#DqrMW%&&;Q& zaYyq!cYpGeSbxFQ7@$$|q@-B*t8x&Nl8o~D25Lvq1V(%uHS%OW$A;h;L3Y!ghUO+i z8^Ii%vYdAosI8y{0GZd2^KoemchWI*Wks!NH#vzG@I6#Xlf>aY=hXCZ$ur5hdOBN` zsV!Z1laHhsFQ>W9bk3u;k{x?J?YxhC3(`Wv?LQ{t7tvud5y4L{h#vyNTv4*$# zj84Zmx6Mfe4mJi0XUpina0wBko0^9-3V=1a)NW_oVT%$rN$_a;56@L@C@)G2P4^W? zV5}C%X?P3)cRB<=TZ7t3?V+|Q<^o_-bE{dL zv27)-&@L{ZJ@MG%@PGCnkhAV0wEe?((VLrqN1u5L{*-j&(nQwMb5@bZ!m(`i0wg5R z9}8Dz65`@;u%;Tn|K1Of@Z?Tl(;`IC$$9;y=c1OTDU$cp(h_?+Uf=vW)+}4b-7^GT z$QPl!W822ml^6ZwcN17QvZ@y*odV*A2;(rdy1k5xQqoWkXWyqlI93EY-y=s59=9fH zF=a6I3VyV;o{9#297nL7s9JuI05>o2nYCFcpA#To zIqfP9c!wFB_Egh~5A@9fP0qYTUk`t^FophZeArpuhDVNe;F{c6Tu8aHy;h5)+<8UB zd^th?OJXCjh4=Qf^x)R{Ntm4#k8MdOPajKm0Nh=3UB35r;FHC~?9xT981J ziG?(3HD=Kij0RR344J8zCR%c!(_V|{497;S&BqSFl(wp>&S-dM(DrNwcVw8!nT>dc z93}JzIPf%1%LrKYP@_*;gX*JaeIRiJ3bb}|TXM@DI(Q66XLko;!s1YvI-dY>H@6LU z6GWBPtZX$4qVK1zNZJ{1+DC{xjE)~uk(*qMxF}~5Y2pbE9s~3dm#PgG6c*yP&-^XQ z-+dEqy!tBIwx(GXF8CbNHsW>W7fbu#c?EfRnGKgkZLf@i81#ncp}L=NW)w}95QL4Q zd5ex0O3{R7@yoyufoTFcqd-|;D?csvYb94`jAP0cguZ`VC%h)pqza24`2HtR?lBx zcHL;g@4OX{EQg4b^L`_|s+zzoK$2#SG~sfX_TrnG+fYK&DEf{jB_)`*jU*T^Q!)bE z6BFn>(v;w2t6zcjs<+V$W}TY}d>$kqT~pIUvn%;@U|v9zG&IRWAhVsm0TP%;56@+y zM%9vy`VH$>(BYWld{mn3(g2ou5banKa4$er{Hq|$gIGN$zcLr2cBQ5>kq3b*aZz+; z$L9i4;-dPH8aqI<66AZ{8!0$)*`d4IVvzo>$VZRXn7St=$D7@AwY81dw!IYRZ&+^p z4@jn4`R+Jyo5OJccQy4=-W#CX3}uJ&Mvp!;`LWpcx$`lll?uJJjauEq&V(-I#+Ph!nrf@Z)n=_rW-l8 zvG2OevN6Yd&&D6=crx!iT7II#NOg0^cRzQZyW>pO`AGS@@43&%Q>Huqc+SU@=Xm0% zEQPW7%v~QR_Q=1X@j|bMQrS|6-x;|ML&H%gm9yJk;_KL4hVnbPGY@b-Ir`0r)M5~4 zdofMQP}5SA;HhJo8S%Kpx9I8bC?AU7DU1 z<+TK+Xja2SbA(wK!O>oS3-bsdf;OKGc<-vCz#M6H%AAbS$()S9C&Q~#DBxUGn3hvJ zA(ca*rjB+TI$Vi4dHG0=jWt@-Qz^`+*{LBG z6Q^o7g&d+{?Kudeoa`pJITFywf{aOqnx;m)_{dX8rM_@HZDD5+yHo{+b zG};S4@-AF=!_`<#N1oYqyee%!fySCp_{a;wJOu*x^PYh5so?_wuhB@4orQ=%B)9%n zncV>5NwaKWOblpvsg7$p@0hKrx=UlexuXH`nRL#modpEz?KEo4#G^b^T?A6gPWjfY zdyOq=In9!`v>d1EJ0{v_u_HYp5x2hc9lQ?5=70Dfq!6eNlvbmm^mW9}UypO%_cqK* z&j>EGI0c%zk*5ZFXgY_xY;--+a7zHWIHI<$5pTV95IK}bYt}465_gBGJiB-!C!q?g zHf0sfH0awJlvjEef%Odp#dR+;GZlOGmJuwE!o~|%8u`}Y51{hEQ96ljrpA01LF+{F zM3@2gmB!{JZFdEGPkCo#rl6b}_I~E!qhr~A0%<*ca%f9?w~=&ImH;jYiB__G+fUou zj$=!;tW5KSlNSW;52($8bvA|YNBN8IM*`aIGu26p5R%(vN61TD1ZZvT;6iCK-&OYa zX&Qw2gywC_n5v^GFP!w~mbN5&*6~?+s;Y8I^A#OLfAy!OOXfIol>J7Ik+q{Hp1a6y zx&1b5UA`P!9{dfOe{eTaW-mqr7kMO)qPd$Rrk(x{{{24e?mdj{d2TkM0ZCk((;RulEcMWnkAzuku!!i=A(jR z8p#1M2xWnhDUv9>r%#2B8hgn1OLKd>8KW4H;Ruewmm1_Ro+uBS&tQacoH%L55z&j{ zQNW|X*+&7%C;p44Sa>|iNlT8p0aGz|7o`U?uAlkZKTiayJbu3(1Yyg8( zP!+Gp(}4mS^$@(FdNJZkHlls+@6lDek6Q2Z2?&nvL{;ESV`B?#4mTPNRR^>RzA&{( zd)w)dDVk;?eDMSqhbDQ7AyBohu8D*B4nz}>k|RO`v}z}Y>N7)wvmM)v_&DesyPg8+ zB1xkN0w8;j9>H&a^&9;8e}99GAAL7&y77ACW>|1=?0jY@DJG{{Vm$%?$+2lj?cz=x zI`WL7_O(F4#?BhFbvGi#0PD0B8KBlCHQg1Y@oon1{P9K6^Z^%){B-si=<6UR)Jfj} z?I=lKhGg0u?_-`OvPn7gBdVK0yfkt6UogO^yr(AT0@DsULM{K%T_`D92|tm}03CuU zO*XpG-qwo#PhO21uDu+qmM=q2YMOZ_P5OSu>E&O$zXJ`8)aE~Y7+oxV(}wf8NWi|r zIHQ(5ROJbu30#Td;+O1$H+9q^Eg{saC zNm%v(7bcXS`m=NGyb*7i`!=_OG)Dw5O&f8i$jsS1mBWwBiVymw6g3Qs(Dp z8N2OTWHg%iq=9&GG_4AiD~)=q9j_WNOFEqdcY^4(9Kb{OR4+LZ?d{{_mkUlN$SyzI zoJ&K_b;z$wdX2cy6pW|E)t1(FV`4-a_}y%ajt)B5<)T4+98Dw{u-&0YNY>ME$;AXN z*!2gR_}-$T?b*lY?P;jov=*WF*LOL(V#(4a*mCVv z*#5vnz)$Z-;)2Bpr*?ZEHCrP#%t1=Te1wrtdmeiU{Vkn{T~>qve#hjfIPI%n#${Jr zL9-zP#v$>g=bnq6Cw^#nZDDaSdblt%*#D;W?Y+W6DPZ`4U{-1zePFa5pgAcn{z^cM z7HroU;koHr!|q#QqaLSz=k$M->Bv}(^CZ*E6aMh7!P;4f^Is3VFvS#5yU79Rk;ZO( z>!uPU5+vVws1c8swV|~=fJ@dC0ROfdmwqVAe2f11r*Gi?7whngKQ~~_VlLJT$u5b* z{Gtpz{ijlV{s;S*VHjrTB;b8-U&XNipR-;0I~c?R2{aG$?fWWlsNs1mFG$4Q*A|<+ zeB6dr+R}~9+skp`nqrgprK@J4lZ$!pf9xPOe|#;$`X01*()`UO1*mH9QCH zc&VJ4`8R)SE4AXouqZPI@ib{7(`oMV2P@*8Ofm%=Q-%JPMl@B@j}E^lskue8%`bC+ zjy?VXvnwGuwp61S!C_8#VOz<$7N0m{s{zzEI%d$4=pRJVBveir31fbSo{c5SMtbqk zJV%P--Sa5mQQ+*QfaYLL#HF+gIgxWw$*8Fc9^gJzl%2+W#UGkHYckx*NwW8mnMUHD zu0;`yF-}x{35YGa03G|EM7S?`Oed-mM3pp!kVy^4Xo6L;cRa{zoLTj@*C3LP8p8?UDAaVa2m~-(L zaLr{`Faoz+(|J@YHFg@Cn^0X|fvSTCQMY?9{5y9eV*3Gf#DpQ~7k6XB+O?yW?W)EJ zojSm>CQ0;-KvOLpovp~B`JGtWns4oHpoX*-)XaYHWAYcBWG_FA6K=IpGItpiCS`CD zDatHx9FyP#Zm91FOirPux9p^=??kfS9NJfAY)*?XYGy{`sp>(Hj}A)*D0f=9$nk-9 z-h}llSD=sJpiCzyui^bsfIBmwX`=9GhmS(5DZpDGxHQKXE+AmYT@Rre=1ODpRb3QR zSN-W*t1b9)O1WnBLSw>B;JW0Q;u@`A##j1u?l_YZLz$?N*%&>Ob5RBJjy7|1$N5n@ zfu$;^s4$1|9W7B?AMM-^b_-W3XHhfU*yp#mk6p|(^bX228|#=O%U796+;I?DNL#I> zu>kti)M%ucx(&VSF=?mahU7v-Y$AGS$G^X;gY6v8_LipgG!#Aqi?IBx-D3jWO$hcO z?ckA9)9j>VTy@#yShivXUL)|nhroNpuYZlC73(m-zSzsfE-_^I90G16q;}^-5d>?c zo#pecyd0THN$8|}lWYhhKU{s$g{GhC=WPC-%{X>oAJF$SJwAu>)XxQN?Xq%AvyJ@G zQ>Ss{k^5cPtij;wR6HHJ5`#Ii+KFfrQ2t6z@}K0leuwh1d3wjGqyW3I`F`*Nf(^@Z z>3<~*e|5uh+;+`Uq|y&cBo|Y0UJ}PR;qV7~xG>X$%a8b!4TLVZ>jK=H)I<#jc z>zip_W#P1{U#A_AU zw5|l-xT+9~=VapG5jr4wvz_0?D2}tkan<>AIEHq7o*b@hMn!!G<`<-xxdXDIabao{ z+WGD5;kR*!52uonXL;W0(rj1x^`JdMq!*MRJ~f>{yV{>)5{<*jVR1rTW;J7u z93+Ob-Zjn5Xy9K~dO9+a2@rDd*+bfh9tr~4q}48<_&{X^e)G`pu=!K}ft>hU_%2$D zmOt*t-1oi@S6*@vZ7Xx(!45uW%!{6yis*wT^Cyw~lPMWpYul=VwAU3vdBY66%>(mz z@JDHrs4*`PzdlfIwA^E;H7{*%feixY1;D#MqGL)))r|{EJ9h5C-mm>13Q`uMljcce z&wbyPeVC6jBrjhLPCZcdtB3G3O~}yO7>?}TgQoqZ@NcD~!Ixe^49(>Dik2WfHvP;{ zq{Z!;DQR+}I7-_^b1c~j#RS~bNjEN}aWNsZEl#GYrj7*dELeWH<_H(0xN9JVPL$;U zmBK|PWi+W1XmIH85mf&6e&oOF4$R^%kv`Hoz=bXK!Qu7N?2IkT_Ty?I&mDdWt*hkD zf(1o*@ujV15l|ZH3d8eqQi*5mGwmW1c;4>s#6B(%$gGMM4YcrR;|M6X`6#W-eKa(* zpq_sM_uV{b5{>briLDj|N@Fhh&>uEhwK13$arvOb-b=U1jY{6>7D$`nr8C00sN#9ce-&)uf->BcJ ze`{BkTF>kP;jthi6SHo(0V}!a_ZoMO?EU}jeFuP@Mb-AR_3rN7-dnOIz4wqp6{Pnj z0xCsBiX!@{d?Jbk8v>vFieN!eK$;?=bb-(bf%K5N*(956wq$#+|MSdy=kB{VTN1LH zY~W6^_kG{#b7tnunKNh3`RgO_zPJ?8^QWSVlB?b9Z^c*tb`b~0lr^Gw^;*oFIElB6 zgdcd=!Wbbs^)XYeXS|OfkbEqwqCQby59HM6>Y)f8k|su{@z&UGM(>@*^zT5KFs!F6 zt_(7GX#Io>{0PX&*XGwvl@eWKh^mTC3Lh#q_`_ro{268l2=+0Q0Dp%}^i#&flChnR z4?Zl#Yb$ob8x?L;!kqu0se}RpoXtz#fqD3%s!;-j-|^cdbNeyS9nZWgK|q{- z^Dr4Yq3(Q~g8K3IXT}#>j=OHkQ_hCz-5u`xwhwxWnzc zecJST%Gvn#T~EdJIg`w`!JUTbg*UJw#8#S$E)T1*x2cG0AG;I;n{Ujr~V2t2sq4D7;57j#)CBK)Z(vO&e2UAHHzL{3Xx zOgqO)Q+qw)qQvxcR%kbYy{~zSDI66M!^P6W{OTyt?RBKQsTQT7wGLiSyn(Sc3j;YF zpm^A)+sn)G&-))jB4W@wCKH~nP*i^KDkk6cGkD0%ZT$MT;GHrPp2uFsYY#nzNZt#n9 zsC0VsfS|FZ-Z0~hK{Xd36e<-mdw5GFJtmhr^pm-<>U~JziasQ-VqQ0K?mYU)6DWFT z1?HW00u~>61oCon5W~X_qr!rcwwu>)Fe4+L2X!&g)FbbMo!Y1oBlOhEFmJVHG&+__82ecxeo zK=l|wi8;j07}dDd*w*a}w=)p&!A0wq=)^JE*~q=%d=woqA8)+$5^5iP3el8y?UMAO z#x(PkTB_Lbx!CZ7+p%)WB;G8U#hWF(A;YoZVCtT6?=CO+e&`{fbS^i3?MrLEgFnLy0m7QX z;y`r=uDqmx4E9Le`>%EQ{nNXEOzICK_pZyB-?WH@jC%@F>#t9$M}$+tWz; zDI8xqZZxhvAs^>{Y9eXn4kN)1s*HJi)lPijjOi#TtHa-xmI5=P@sA}%#-Qr@+m6AD z?-t{P`S}<_bv8>jJZIJ&Nxh5tALheh!wbM*?tu^xz85X1^)*!d1)m^;)*I{0n|rEr z-usV6EV3|>9b}-S4olskDSGG%U${~$Q-1b@nNoa9yc4e{OV_s#;q;_aEO)p`)z6QO z7x;8X?<>sux#QXQzQO|h`WoAV`I#&N^07tQXRkb5arepJW}>Gnt@(6+yWf3jdgb4j zpF53xw@+XEz%os_{vW=$(EEIyDWe7 zz<7gw`x9yc^)$5Cdp~h{!POPVpNlKMz5HBZ{#XBtKX%WHFU()Bz_@|oHf3Nu`S<1L z_P62o=?>GorGK3F;rR7)XMMPBILZj-Im{5y!lI46jJ744O}Pl{pbJ7^Uysqg2%#LZ&<6BI))D>fYY)%X=}Qa3<>SU4lQ~`wTYReFM%p=S<{f zWEz68c=v8R_0)gx=2w2jTd(o(QgX191Zu|{C1^Tr0b39@N@A!P zo$oA5YAp;7_AfjG_ub(hs<9_kC7uv3b~hE%xLZ=s=KUiyPB>6Z2IVWg?zJtIMx{!5 zLkZftnvtI}i2^y1WOm2;3H`tY+No0*_l50v@~Nj$cHce7Sa33jGu0t2e-U%tAiMrZGH%4YPfqv8Az~-fZEz%ljdiGJYItnw#+4 z1Al|JJKX4Wms+B3j#m?3zKP4N}V?uH3AK%5- zKQjYoA3q7Z%IomP^6eB1;oQ&n;9HNZB@;aibEf7{U1_^9yc$Oaeyfb8@&I3|UE(O^ zT;JM(^+n~p`PGga{;?5ba}#meF%!t7Z^8TP$mlm?gLPu%o?5yKpFL$N)@>=r+r^DI zYIF>K@>VI*65hx8$4|gTr%W^DKlt=YJin?2S02;Ab(m=*dk*=A8-~IBdqcp|f#%km z2@;dsp(%t@%<&t$$Zj|mSBsAFk25GYFmugi;Td3Jh_+{S5bk(O2JzgT5mL0%A0T8HqGW;7RYRmcgJ4 zLSSDYpzG#hsFTY~BdSNC;lrm9lbS~Zk?B~q>}^9_O{LMbFskej112sm7F&w8qLfB- z@(T)(nU;c14|PO$$K!)H-y+uP;O3udGZGTAN||g(Iv0Hj@PdJ z8Ai|fv|+YyU-lx7|Lr~a%thxTIVKhroplJOdLi9$2qQC|gBo3pjqH0eSDV_;~)oTF*bIG$=^T05G}?E)V8 z7+?<~Hi67qezK*ASJbv7ScV(x1Ee20ZGGM(BS&KyqaZHs16*yo1{? z=9FQ?n;?n@fxabbMbdifJ}knF>En#_xft7&ubao@%9A2Br#4R`$p zZ!TJZGtW4~NScaa(qH}o#RWeP5d=bM$D_5inFfYwLn11g2dyrfJAri)GBWs7Sl>ac zrhmD1XpH%t89eq&0XhJ%-_E+Gc}Z`-zmmxLqdA|!-(i4&VBE%^nbdcF#a~uqcUu>x zc*D^^CVU+QV`e6%VMk8@06+jqL_t(W;L4{qqw^n|FfTp=_pYhJy{lfqoKz3quOUU# zOoR5+*FHNTg7Ld?!kx=7j)qFb!{5ra8PQ>w$iL}~Q`g>w0veGora{yhKYfF$-g)bb zO!&D!eiMtbqe+8xVsjbO#D!xn<0Hv~^A}M?4Bd0@l`t>fs^j39#jxemjoI zh{6)7v!P0y8F|sT?uiYgx4JQd2MA^*4-O&&zk~H7nCoCxbK34(Y}r0v|2+3kda3;( zK5_7ZWYd%8h)&5v zH6>4f^M?nGbW|;MnE&UQ=WyhaiwyJWr$75S8A#MiO-9|rk35dNQQ64J9ffz7uj8Rl zGb*T#GM)KZulo47;$ zWBXt0);Pjx(!#me8W)0%|9k-{WAczPfs(iXd>?f$e}ITYubCf}Rh4+{?f0>{s0f?c zPpek1!CLCg-@I)*4XjmA{fZZH)HT}CP>s&o5=3T9B937@w80Bl44r<^%`oZ%=lIhN zv7(|9L{S&Ebgq||@orl@jOT1n7LjgAf&!~nO~`3Eogz+$K@!K9JnTQ}#zsi(j_Uk)tyAxO>oNex+; zncpF3-Mto(DTSQqWVZLw-$PL1h|R)|v8~0s%|2e)JSKPV>-L9y2#% zMNc`=I;ux~LnmI}KwaI;L+VakB{&g-ze5TEfnP9=CgU?VN`3BpYr4umiw7{N{39%P_X4~{Df+9Q+>AM7{gSrSZ*3Po)~rM6-vp`2@M^E`S}buj1z(VhL&zy5{g%a`MrV~=(u z!w(h=0?N^xYNHfu4w(x#T>oXfIBg34_0xM0@!AR`%$tl%N-~Sm?4A>Wb{c#NqoJs- zq8gNXyK&v!w_@?k8HU*|x>0#)yNdFaSwF%AT8QS*98-H3AymWBl>NgvMJ8rCUZ7u$j!=lOMPnpFQ^+M3Ir##eQ71ZXMSC;{T97GvBBV>Wrr`sp=Yp zk$DAn_Iy}6?v^=(x~ zpSx5Jh{2u|lYz9DZ0F!ZFf&`+q3e&nTB~_sm@*vi6GxB6H~#0Vcx~}~JV{#!c=j!% z%$vz^LA})6oRJbj_~tT1v=F9$U4k{>?FIhh5dsxhZN*MZz+LMeLv}_s^OPzb*4Sb7~&o>#`E&BP(UWT2q=vW#nsIOIn{Z8ozh5h zJ}D_4vt~^oQC4T_rh{=aM*GQ7VY+<~MP_?Z(N5ypNZww{GI@QJdh}DwUf#;PlVe4P z1kyh*3ID-V=j@fqLGVydbo0iPCw&~+s<)w~Yy+aRrf}qnh4aa98jcz#>a&Rx3aAE% zH+)-@Xki?zZP$`vEh<0A$9RW zntmoWNQ_0?%geFk$$w(hb=M${s^;9~1QZec97YJJuLr^#Dq7=0D#cP_i7&bw6@9w+ z(JlknLW~+Wiq~H~T>&c3sDLoZdIFT*j6IWw6Q^h95qB|aS5Nf*N(%Z969k9~M56A6 z4Jj~g>|Jt|L=!*6Kg}Ssy@Pn9mEWe{7)D+z=Xf^~sajHf-Ruh^DP_Lh)z)|u4ryb7 zEEYM@v~R*#4K#@AVFApVjP@OP{rzpYb4dxta&MurqCX80N#M%{=P0I=TE2RI%isL* zN9lv^;6p(0x1g6w8GXwcKXwX_SsV}fIRAa$_Mw=v%jLsa?hI{|L7%3yy<*vQFEGH? zG0;Ew9fUv-0zn8IN(clQ?uQckLsYgF9-YeU-o3|2=S`hD)-W=LDEnYGAA1OpMB#tC ziRy9x(@#HxSFgDX>0}nBA2Sb4OSWP1 zrI%syxN+Qp^lVuVRyz+>IbGat#YH9>7*#Zt7zwGNuZ#LX8&7Wh!lS7JJRWted#KCZ zYt$;JJj+msq>;^OJXm>){j%llcX8&UzsC8eoq|Y72D1Nla%{hJ@9&UOQiHBZc?hAN z<4`h#+jv_cN(M2Bhx1=pfi1PGP=gJik|ua3Ekq-4j~EpU{C2hK|(}2q6r86NhO&W)fNW~cRg(WYO~6ePU(2+D?gLQW+zSK1GLR@B;rU*o^s|H=zQ>AY`OF@q%1zpsDFw+aylw*{(pFP-due8 z*kg^3cY|D2P|zK62=vAw#Bs!yy2&*A@CF{`V*F*9RZOqD6}_n#Ls0KmR;3=^d%#ZZiH_ zTN=$c9<=hq96^kXb}|2{N@Dh;N$_0t1>CuEJ;L7KiLg=eH1bLn6J)4{ZK*)$gei!k zS_{oZG0P+YC<0Yd?X7%&`~COv_`QEd%>$2M)RcJ$N%4}|UW}IWrr@hLe*;s-j4@LE zL&4k|X0QxN_9DZLzV-SNbcc3O(u$17-W2B$`L4Jdrz zd9+SQLwhnMk~6(XIPq(k`>7)_d)5r(q^40fI++~4jfdH^2tm`CvBEK?Ph-S%*pW8J zV^|c8w??yUM}k|o3pyzIsEtt1*2oRD;e8hj^k?Q7;WUBx;45Fb22YJG#EX~y1j*x4 z(3BpBq|@iaOXheC_2-W+%tx#@h6i>{m@uIb*_r7^1(ca{ZFLBtzWNX{n+SLVciRGi zSMZng`q(j}4BW+7mlV7HVMRC+1WB&PDU3Q=h6fs7}>6qJYqM; z{#&oVhRU1nM%D>)QT4)W81xrkm3o+h%Mu)*c z{O*Io3pKym0#~d>AU4B6~vLP@~4-FL7U#r|{G(0o} z7G}qoXA`B~r4!yA$L74-o`>^VbTEm`N``<4>B2i;V4K2R}G--t;BcCAZU; zjcaIcee~lTyfHuorrVot>L;_HcMt+W2m~Q800eqtssSPn5Hv8hB27L(+F;OO0|DPq z;R0v}jc<)SY+4Yk=pljtH$;+Vlq#15GP3IH>rqfpfQ1Ve;J1|KedbLXQfzC)+U4)y z{Ih&3_?e^Uqk%is7lQfj)8K5sF%y1c&o+9oudJPBX@{H6hzzz|9eB&dNR+E=-f4`3ro?2iZ=Kr|V%CNezMnn& zEW;!SV|C;gNy+OsIc|4<=XRtVxqusuP&B^w0^)D`0mjaqgO_gqJz}ym5y$b+Mn+Zh zhNYNx>sN5j>8BZ0Gp$rjWcrWg3PY<8rKTff&C2}}{qGmU^|GW_DbUgTzHql2)iU0aOBf4voFoqj4J2|K~h!^637!mqWJ zhs+JlWWGnUA#9oE3H8y3&|s?cw|7%bkh3xD4MxQi^V{?Y!M(rjH|6+Xr<_?O=ApUi zFr35y4U|S#8uhzutt@+gJ*H0|Yt+Ta0IR!v#Zw!lFFq$b9T^$PM&iDf2Rq7FTUK{` zl|NKYW$Uo8nKw3C347_WcbNM_Rl*SF!@6qS>7rVs&c<>?<<2#kYYYwV3>v~V3`tgM zG4Tic&Einq$XUH%1GaA3Nd4U&V_(EeBjy?D>1I9p;ExX=ZDt{AUs?svtvBMd&s<<` za<%eCm-1=j*z-~nUQG9Y-rtU$S9}ABN6tf69uM9B_BdWU`bcDb{!(Let}il}J%b2}#kdOLx{P7LL{jb{sXrwP6XArOQ>5CS6@0)wF~Kf~P+MRvm) z(4gVk+yxX9{5${%sQ;w4LPkjZ3)f)1e*onLlOFyM(7f&-vuE10skrvqYYby0f_i(! zaLLR_$Mx4Lf!aUG{}9 zVB5BB)bl<8_x<*_WVlmumV&ci{mNHST~kRzs8KYwnuaY!MU+aNfEhHT8bL*qmowdp zm8&TAS&B4XN;u5Cv6XO6&i-?|?2CQfpg z?Hp2pQ`Qi=^!JdFD|kr7jcC%50-KLK3)oN*+m#JFDQy>LuD(mkdbr!AG9##Nq`AEj zr8V1-5>2UCAJkR0m`7pS46v^|_#Q=O`&y3Ickkk133YpilCfL+{4?-={}!Bd5|VFQ8(~Y-}fUD=$A2=^+Jp=g!|@2Gt|YU%-O0St21JZ*G1&LiR->$<61#Sl zV*RQ$@Y0a*h3A}U46L@3*)`m7u#A|G+<(KEFpNyp7UHFiG>Ga!8Cp{FFo|kr(&7`) z%G)G@O&7z(FPG%^rY+mex;Krg)QED}b;KP$9sTNW+rREAs|>T%V}E=UCmbo}w^Y#h zhKpfP>n4NhWK?$$mumj%&-SMbv`VE+Zf+Vz$X*NvtP+Uph>!#YKjoXP^3!IHB z!(_bFQF-%GYP|1hjI?w^6JlbbjKNk({=4hA?>P;BOdYDU*Xw-aVkFoA^SO_=$$ z@l9y(=Mx42b5{HbYxCjWT+LX68_XmYaxgyhBST&K+cn2cBb{G&do9h-gAtsxHie1n zAO|Oz>%CVTcc#JjAOwOC2twd6g@B*oE&^MI<0OG)9Fd<0EAIcy=Fzs#;9L8#k55a? z`4O-(6c?o7yAHMoPF0j3lES0pOR09DBFMNZuc^U{ynPY(-_?lt)C^QV`)_!EbSpl4{k4=-uEiUFeuB3Znvs3M zF_?VJO?d5lKS%PO7R0^xIv%AIY09^5L=p`PSC*I2SY{2Gt-G*|hc??*ug9MEH=t$Z zW+ZY%?ZQUH#yx`bDaEbLhO&BPSq(#)~^RPpmYp zGxnW+DlE*wyYH?+9#yr(C2}m02_6>dsLSbVIyTcduB6sAUt@S6Gj+-s9x9f=ONRCM@p*=+t}<2U^71NU%Oa7+&2st zu}~7tH>NPx9MB5if9id?6s9h$jL`&VjMc^n<$~k+cl*1D|k!mlrLV6 zF}z9A!ZlZ8&F%Ev#uM`dszf{Mg7firGTke`{C%V^oX$DcZVn{f@q_P&1_HtjgF4@S zpn+>&M7YQFwQg@|UJsn!q1BYXEym?TPiM@Sd<>p))r1jE&3p-2l+VKzC-@qKKo9~W z76LM4>!0_UzxtEo#O@pGICPH1D}i)_NpACSa&pnS3g{6|=&uA{GXKNUR(_A*OArD< z2m~Q80wLgMxa)d#CmA~J)UVcMbaI8zxKaouD{1Uc*WZZ_<72$|v()TF^rGN#D*ZLL|2hCOS@XwO4j$}BRIxM?G^lnKySSIdpO)MbQY^_q>8 z2H$SRVRK^x%ODe-OaV(!iHK7fGS(ni5M9x_aem#&02iA--^ zt8Cj;j`-_N#`Ryik_QKk_{)@u*zkiNksY6f)JgNv_VNmJB&VZ$b}m|~Y7s_tJRT|q z4=JLW3^pz&CyR_VpMF2dv(e$y0Unlsw5U;tj}Fk`?#t4^RP`f_ zSFEA|)F1y8d8eF#(r2GW$}fJ3b1we^QmLMyc-wZYfAty6y5ur^?&`}?FnSaks;cqY zC7(yZK#RV2lbxmrOf?8fI_I7TeoM{m%Wch+NPMAwTQP0C^_CGwLZNWj&9hS zda+-mN4=JecHJb?pAO=r=Uj#=^)2ak-O$PBZHUIk7L=9IRzRHBNQ+BN%O=)w%H%?a z;T6EhRvAX+Ol>_G`c)V=cC=};XeHZbcb$goUG<3OVL>BR^+><6VbFL3b!1 zAe^ANx-U*EiEdXV#H64zR4UFKX1lXV^X1@MZk&g9d=4G5SN<&5g!+s2zc^9-pT3;* zU>adpZYPcY?!EFnj6F2Q9MO$~GXzLE= z3NdkvnC@b@M@57nr?8NQ5i`gL=;ZZ(GSs-qbTF=i9EA+DG4tUS(?DktaW;^ZWHxQz zR%-l3+$T^!a~`j^hEqy(09t=U0qSt5j21UB0D>+Ef&GDibPw-EC~-1JkilM2QAKI$ zF6u~*Lfz)q$dn30+~m)ox%gGI*OtJOQoy1df+B?YB0QuE+l#kj-G{}@GlVK+5;1k^ zIKHb4G0dFt=`K%1i6yh_bAReT>~U2o*0E&QF4R4{5^*#05yFFpJ*dE$XPtsfGG7sw zfUkf32D~_THlDxhK6u|KLd3Xigtl~`V`mv62+vUMHhHeGtF8r~dHfNacEa({eIlu< zvBaJTH8C6`sQ8F8acm>92i?7AZRUv(Igm!F6C$Y|Q} z=wryb`!1Y!=_N>_^k@qYSSE5^{LafSpfEQV1v%O194or{P_=R`S|^XioL^p!FCKra$Id9Md@-8} zA_l3{(SgRS6OX}@WV&B}?wLknH&EBPEk;cD2@~@1_Pc9o=yMkmxIwIGZ$ex3CPXs7 z#OMq%dSpP-VIYYSpBk5iRvu7mJc!XQKdqm}aBV-MQERIXw2QXx!jX$-8r&vEbQ&4{ zN}~Gnzd2+SlRc3V#Vc2C#M*U5m@`{yquLC!U8-6{FS+~Jrj_3Y-U^B$(_S~%q?XGa z&$fBEo+?XfYjlW_m=wobO0>T*cQU+`+_yBI>UuEi)NfnaZ(TfGK?rX&MCm}r*&O#9 z|6?8C+)j1+g?&ie7RG)Wmy?V9b8=9!Xd#wgcrMocnYVRT79o5}0b<^H4J%)Jonvw` zq6fe`mg%0tn>uG-cmWEif^NoyiHPQbWE+|BBVsIktowE-8YkvF_g+!SR4>$qhPG;= zEJ{-NXt%ylo{z2Gcj3enqUZF_orOpx?HwII;!_%FjrE3Lab7omy)p!2y*%S#62KMp7k@#DG@vuN?-fH-YTqGyMcpqC<*5sgdbV@U8CB)OQP6(X>SG*P*>ub#Uk=rSm2A6{1{woYo&^&5;y-cx$- zw_fRb8r3^ez?UsEz}tKd6xLV#pkELIK?oce1RN}OV0i?l_A}gDT3S)PrxtB7E#^A2 zP$RchM$JrlO$(;ZiAGFZ9GWZI5F0^5fuXIGOl_r+#U{kX%fMMWv6O>;{YD0P-LS5) z4a?r+MtD~xA|oB$rb2Ambmrz#x{;D)K2#o9x8V0aLx8%6$rRN=hBqeKZ20#%X)t0C z0{uWh44-X0D2t(f*Q|yLbT-!^cEU-N{H2cdjHzhZu@vo9+Ypg7ia3LeE6(ML+9oVp z!?>N@h~fr)-u$VEkBcD_?cg$w`f1XBdka?ypNR>$X~QNG$VCW?pNx7MJk7i263m%F zi9s^YS}3LOrM}zqPC13lsaX8!Q`aK9g=v{SoPXWCfg;`DJ1Vx}>Lrj2RE zU^m1b<4LN$jm(laKKKBS{q6zO-2YdMn!bQ#Mq}3-%W=j3yBp(2=N&Zl68jCX{YaoT zd%|J}7co1lYIlh`lzp5gUu(MfOF11 z8;NAL%dnsb>InXwv}lp(JFTC($rVjTX+~NK>ew1>s=~(2G?MboWIVL-Dt~8f2PN9y zN7wABn0NR8;;3Vf#`uB)9%Oq=c~)i0et_{~5ml6fG5W|cVT{)jmgk>&I!^lZr;w2( z-Q|5t(y9-&_C-^=T>8$dX}CG2wE?9~TM_EXMtnpp61r2FJDE!?M13DlW4$TfOwKdf zQJ}$SNw?Rx)KIt}hC&83bj&#Yjf*BqsYge9n4gTUO4W*lgnQS`sZ*y}hbL2-ef@@F z8kv3@Q>GLehI<=Te%K9^=75~DndErkn35_Q$9p*DgDGynAB&476P~L3lGi@K>{%1d z0fXvkRoD%f$w3U19{2vX@&~aRhqNdi)asB#W3!9vhsLk)PYd<6YyHa4$i%2K&%l^T z6Y-xP{uCig*TK8!Sd=~c5_ZskG7k?sbfZlJx(}y*m!x|#*S6yqEHoA9PKZoFYezE~!)@HMIRX&kk;?`4zQ&Q#>3?tM#MG~XOdLhv_;H4i(m1{ntU7wC zbUt_UW|1^Mi}~+Qp;SHDyUX!q?)EZ~1Ag4$wmvqB{nk^?9oO+W@L#p1m8S@N&?qep zdh>5M$~o|wetdEe%%#>Uj6y*N+i5Jdk>*ezdw2-nUteoHC`|FiWEYdZnH>5Kdg@!Q zk)(r{%NMmwnu8jJ%h`0IDfOxYYwGINYj{I37KL0N zo%B8R>nnfjS6p07^^rSy(=ng7A}QFx@iK{Puc?Pq8S`%AtE^_Kb(4@=B=>+$l%BRI zOmU;5qn$9p(HCs{a_>?9ZIwT{}$Z?ReG;@8ZQP}VUPOzwkx}^R9Vr9YEGCHmuRRZ)16ebB%ngOsjoX8CF?%KCK{X@M`o@_D;cK~vr$s* zrB!?IpJ!jdf4_YLF032ZTwMf9tlpH$*mW4VrMWCX)_ZYny6OX9eJN{I0qhPF0l1Hnccnl#>~5xo)B zv5*r(B#y|)qtNW{y{4E}xOqDpvN%0&LUPJ$AyeMxWMA1YVPm+|E z1bifMM`~&kmao`=apOjtO`yhDf8{8bp>`@uWvX7&r;Q_AlT071TD{5Cv9KTqDU#}U zIolq`OXJuTIE=3joW=YYYP>Owl^(*ZHO4fCq}pxG+Res(Kmt`*b@6~vu+fb&LB<>s z@_Xj^3F!RJxA5<8e;4VyYY@3?2R5u(!$ZIPLDv)Ir^7H#9@7GS2i>8Cfcn6$Lz=IH z^@+xU;xshZB7%&aaNQDdCU4&jaS-6%VN9d$S5kwU8AI!(GYy?EC6br0s5d4IM^9_R z>@ielL$#$Ew*x?G85>+2pC%YE5rvQUrMWqbsT_%wO-`S?v24 z^U_|ng|`^XOBzWBc3|}A40AB)&;`9p-uHZiG5djl(|NkB*jBL_Av_#6!aky}%}U)* zvLW^6*ycZy`erPN(d!ygy-Kotag72Ue%8~}6)(4%_!`sl^MrNt#-u~{DU3tOIOoCKiVG}TqZ6BCO_?y)pxrG`^wn$hJ0S zsQgIMtueISWx`Ade-viRv`-V}oAW9xz{#txy-FWZeJOi~XfBB^e4j!{ixw`#(Z?Q- zjPx|an69X(#0$?qgWukJFTQ;B)jf4%PL_sIrtWuri_xw<+xG1{aNY%<#UFn68_b?P z8>?2WHVpQHf&vPY)??<(8Myk(*W%va{>J33ezWa2c!_zrzxDneRe;W)H&4aj5#Ee_ z?6Jpr({UZvQqac3J)UmP+C7A=M_pYVuKLoKap|QOvMnWvqT(2hX!0z39 zkie_f9+soLwefW$u@MQS!=O?^xH`o6zt3WZ0O_)sG)P>0ns9pa&ykn0?cx*D6^&Fd& z9wl{fAXPi4X@#4@h~suwR$}MdtB^D~8%=NTLiUyCQR;IB!Qvc55L+6?M=RU7e%*R9 z(s$92AEhFy*u%)n;O+qbDN{PEvE zfQtM6gv^Qa(3KZuE)A8w^&DpW^e4FTiqAXDb~1r2!FEuAF@%K)U+KU#B8*24l>V-7 zsipK}IyW*s(!WDhoFta@m+Z|jgsBWtT4HseGBirHDN^5x#opl~Y;79T27PFZh-u33 z_uhOP9cxwqljfp{;!15~R%)H=SXPeMuO5f1uD%SD3ks;7&C!c32~_2Cxc8@p$^Jgg z{1WU4!-xO=Pt@%$$FV1$fN_LTLadiJ5r}spbUTEMLmo`@bpyZ|OPYUVsPizYwmJ$~ z+BI@BT;J4!%KB2IL}#LrdaETsAiUN>n-cj`;*6@4-L<=r?j6nB3#k+!=+XHuG^M=t zPxX|9Ssrz>YxAg0&|pq!?Pe&OHvlDhEP6*yj2exL1|G_6-n8B5g_orK*fF_CB6EJi z_&hTv4i#-=>)ys|<(brvuXe=6#$Z=z1>T|Ro@0)l1u=H5njghid-N0?axm&`>e$vq z@{?mkc!YiQ$#l+ml=`8*@QCo37%1wKR^HHE~L zOyWWAz-xVZ5Q{Sln#hmKXae64cxvhcBziOm^=Pv8H&D`W~WF?id!}nOa8Wjc$7Q;`LP0Br?_XrBKSgoIj3D+bfbIm=a37?x8RRFHRxe8_7T3WK(~b zxcXIM_fr8jLtBFUD?BMKGAyh z6hxA$&3LYfjvXc&&z2#2QO4ORna#hpPBPCKq`jg4d^HS0|ly;}e zUbBYMc2+}mIXX$}C&b4iifRZohkC|`EvK(JpfJ|QT_uCJox=iOsL4QOnSTn`yXGpN zp*08tAk~d7D=Q0+ zKmItiBY5%PLl5Jj2mgXc$#B=QW9uQB>50c5#VMzpY|`5L>O*n1ZIhb89tnPxWrRk20vn2F^VECL1tAcG zz{rDupE467(!$Zv;VfR7ygI#|K5eW)Mimvci08&Dnk$ARyrdE)ksGek-IYAO+r(w4 z0lPk2P93%J2+vGLRB{5gZ7DJmQ8K_ab;=lQ+_a4dPSSj>c={z)xKxkwvx>{xKGusep+&LN2)Re_Tw>C24 zJ7|Da1Zh@A5@NF_P_+gPAZ~mPkr~qvl|Df`K2a-%xI54~9*p!NMnz zXvDo&ga=MM6CtuOm!l?S| zYkg8JB_S9|$(2=`H{*lf{t2lVje2eZ+qphsWi>*l%Q!1HU?lEy($cApEu2O{oq6IW ztQqAK=`;>BhvKLX?ZI1a!Ma->M!~nwLjHtt=1@O`xJa1hgijrdoYXXKQ1`ywA^2*e zn30i+jl~IwZ|b0pgL-ZpJt*2-hUm84WUlj;0XH`Jd6`(dc|B>4Sko_LQ6ZLNuZ4Qw zBd9J*{cIWKs+&_k=f+P>O+B)C8<5`n9kIK_#CUE#<5?1CrzQrSn0q>$75ylq?K(6_VjST@!P*zi z#2xw{GApWzd9ay|Fb}2wcnCbq1rB`^h9F15Sj-=XnV_S=z6YoJOt?_CCKk<{g_c`y z#tX-vgj_NdJiKXRZk!HphYdk%gITyCpgwowD!mI|+4<>?t9RkZHr`lPc&Jpl`Qqwn zhK+B%b7r?IwLAibm68}|$Bgk1Q_oo|RfhQ^e$&k&Y4zg03(|)igRH0ODx_#7>`ivQ zA755Z{=R~2agL{cg`0c6EMDSnl6iWF&v~*S7O^5KsKcVKFpF3`WfZ z;J5r$zJ;9)w@(w!pTXLud7?E>H_5erXJ(3~aBdUXJTy~qPz)+${;_5?}n*w8lYHCEqm3~-8e<*8JmVU)+8t7A`sx z_uh9OzIf#oC@I;AnwlC+n>LmFuvYx@pHJbLXP-qRPaw}a>r9+}`e}yd6M~e1dby&a zBK+-dk6_cL%{cvx)6Jnre1bz)m6q?q{qq#L9nH5KLM)o5wnLsc_17({*mPcbIVoXZqk)E=l+|Rv>LG8H0pJBvtBEZ~g!izI{6; z%(@l-`pI3Wd-(;VPhW_!wW(Np!;N@7Zw8{bH6T4R5#dwQ&{a}~xTI)Qu6Y-E|NCuR zarKo*p?VslkC%P(adBpiq3VOUs3c^^6;Q8ilcSD@L&H$!``A!1k+fk5bn=&xU#VA6 z8J_TH4%Pi%WA@IurzFE{=LW2*u>t>h?C%I&@g7=c@W7-q63r|3AndYvXx~_Zxald_ zb?+bW?BXME@ptOLrZFHGhLIt1J~vMxk357IFS-qtKmP}cv6%;UUA!v- zq%JxRM;=Msp`EOdR3EsblZ^S~#2D(zkHd=Pv>8K#U!%svBP}ZyO`+w;Po2esz;x7- z_DH1KyNF0$&E|MWOGrm^H*Z)_w{c5jJN8sd1)dihH*6z5>omBqAV1sCDBDQeWbrnj zne+SEYtClMQD;+Jyo=+q+vuIo&X$gO9omTr<=~VK;?a*%#(q|5pQ77(SZVfL(sII$ zs&8#=Bg$!5dk+~9nr~u4ID#7Ej9|vF2vVs3$q?vlrEb)Q-DXYEnxs`}pt-tFjU9oJ z)Lgsf+P-j40Ym$dE>BNSHe<$#-*-cl-pn`B_Qx(*fbb>%<($Ys3Yi8*T~;6Ss_&eF zzK0qD>UZtY)Tes4Py60i{WO$1x=EKr@b(b*{V(wz%W9{sw2~j*)Aaj>Lw(1_oZN%se-b!FM7A1&a3~|1SyU6@x64iZ5^F4 zXlSJxEJ_VWM>g;R#{Y>9Zd zXI8%i-Oxfn4EL7G4-v!l+LOpNh;*H~Rxq^1449jSrq=OD{)rax&@P?&-x*LnNkyi_ zQQfu}>JbcgPca)yb3>BkVz9R~)UheN_0L-wA;jg;u?g_TC7OAyb(V#hIpz$@zUf_! zZ8Hz;nDrH;PvhnH=Zo>|d8#fUoFl5I)R0N4UHd@sdZc>K&vaK_O3MkMvh-@EYabIt zc?LSw-%c(2(i2Z1d#6zzieu-L>eNPlR6T`~q}yB!_wtGgeCDD{ux8z6{NcV|;a~rH z+DNN!-n@m9@tL^rqKom)Td(7hM;^s<&pnU1bLNn#y_I|_X>@RSS(%xc<~=tz8)L?f zVZU_ahd=%)F8=I=m^g6~zWd$pnDD#q`ah#;=JTKb++M0|(x~cY!i2G?s;b85QKLu; zMXng4$`f~;qdnf~I7FJb}LV%~)?DreNDtG;v%UjFY3 z_~ZS5!kcfri9i4Oe*E~hpRm0x_~jjU;LbaKiC32_!8`A~i^aU1rgn}QQ)tFZ4?InE zgFitC1R*d&AmC@X_f;PU$vOJ7;wb?mLS00LHDD%0E957J{FpJL%vEhM>8h*ijRaR+ zb31afiGarEGfk(_O?uq1b9pjZ!jr>oM*4lt+9F!9rv&^|>PA+EboLoU9DVi5-hP6U z`b4^4ladm+Fa=pTdqXMcvu_X}A!Uf0F6^NZD6JyZA|H#7UW6m(&&OEm zZGYmC$FS~uw<3p9@F^4KAaN%dM`NfHnQ#rEp6|$n7*wra2JctDf-hZv4Kk@G{^Q1M zw_WRObGtAqX&lNMcc7)SiJJ~FqX|s{fA2NG_K1QVqTlL%?{?|()Ec6Vf{ep?!lIEJ zm0^nHmH-kt7l(&8EbF-IkM**51KE*?v?+=;ydraxffrES6^9z|9tk#$Q{1` zFWvK3%$YL_)5ngb%9&=fsc~0m@AkSwKOXObo9#ulSASC16Gd9${4-8N`y;?xH{OM$ zaVKNyi3>4p-fYqrW021)#g^&YA0(u{KoXR*rcXjfRw~LHO32qC6NdChV{1LHZa1Tv z((Vn_l&s{2ZS{|u~@JB1CiPj{GoA1KVmaX$m&2Y$Qb4)$)-+UH>L`wHh+qROzg>K#0oZ{hxd zQp@6K_fjQe(;Y}THV^l+cYYc}>Sy&YN3+4VimkcfIF4(+NS#qU{W#32F4Ctm#>Vi? zIm2kLuSH{Zr3pz$=b?UbI^XR)P(I9n%x}l}3h_OBo_jrs+INd z`4fg_-ZP?MsGAs$pOtVos%3~vOgvwD%|CrxKhazc9$^^*kiTGGIek4;9Xh5|Yn>1N z+PwW90Wba*=!MBFo?G_bGQ&{+VEJ;|u$zgak3I?yKlE1`e18pN3JXoxyYDW={Q2{6 z+;PVl2KGxYy@cbBKi-rOL$#it`qToK59sd1mu>$l-+U%SDisiofaYp%Nq7hZ57l9Q7RZe4K15tOVy4-Y;32(G*CTBr7e z$Lv`%QC3!NnC-Xy01TanWZl#_#`dKPFF}g0yrp=y{_+Qte{4KmYs-IPt_! zlb=?N$Da77;qjL6PCV&U3bKyF6sEiIg7YbbpKZ#r@Nfza{stisguuasKo2JC zyVL<0?n)x0Dk9CYaC;D~gI5)%O;`?9!(?Zr8zxjkLlc?r)sDf%!d#v}Mw$(;@>AR? zlgF6N*_&^zG)(t;UjOc*v_m(g6U4w*89L1z4EZX*pmP=}ourm?BV5J9j!6>>OrHf| z6NJG2LO^p*G?U!K33*0^ln!u0Y1}6?n!4L*$WvGMLnw_w6*@B|vHY^gRxnFy_s?wodssS2EO)KSRzQwrXsPQOL-=2CZi4{8;j z67#H?Dnm9>65b0MUS#vaiT5^@uEN-Fd;=57U~Q-2)k&jA!3gi_bE5oC#rLerMbNc_gvarM`($EcLlk1exZ{ci|v13#+K@T8!*iH8ql1W32L z^sXD}9@jt-<4KHlg-Lq7lTuDi9rcI|i=sLZ8YD7lcqH<>k;v=%KdBbj`r6n3;rBaiU zMTWiY3qu1LW~W0BnL-EoQPtFyN-G9*(bip*ddi^Mn-uEfclNv_*n!VSJnrCH;7NUAZb zG1;pUOl69ax5BIoeD!@tk}i!7@1{M1Q0%Uw&`47#C5Zt&y z4Ppb@7m1em7e03qvCE4C3TOBo95uGuGDprL5$;I|FqHP`es=wP$?{e;bafd4`@LPT^ zr~2?Sox*K$dJkuRb7Gip^W!TfmRlrV_QiH?d8E%><3g^Jb6Bpuxd|tH~rK{^VeK7@wG?z$W+^W2Q<=OOZSWF>HcOK zU%RWSs!V{S%H>j$Q*ha3SD?JCjI@ew{euD&PFNBd=%4?><=9=e+Z;42On65;C;f@3 zZTyHw_3qdWl20pDEKf6G`VsRUowNr;efw@Fz3@uYLbZ{Sz89URwm0$??Dz>&j8ysu zA1pVtp9Irp^R~29%_JmHWvhwTXtJ9yVZ3>&zUQBNCV6U=R5cifyMJ{jzJ1eos5K%R z^LRk;wHvNCs%eZtR;KT7EV%0!d=Ek(2!Wx8Kri&vNA`m<+?8ga39K+@GwN)dwIN8R zRIDUpb#lr1Z#H5!4=a5wRWxG6*VS~PqNWA!tk{Z<`U=Dmq2%Xf8G~HfuxS$)bb~`c z2wjW>88!>LAOt=t1T>Cx=%rgIu^dYU`Ce|yIS0kyqz-oxJY8*#BzmcygAzsjar{VN zh~cjEQbQF@lUW(sE2)YDhId@W)k@=2S~Rt1T*mNuP!f5(m)uPvR(kIXd8IKuIoZI?f#TjEF#Zy@a1@h0I^2uI z$TSpJttGRL40tk3!$Wyf!VEGE85&n@t|Bu&3TfUP!#I$U)zaE++*p?(Dl!I%ly(&Z zTg>)~x?Px%I)|`NB-3hWne8Hsb#=UiS6Lta?fppF(17p-iP-keQXF;PUHJS(=d+)q z(9qC8L$}fRESc|jZKVYNJH<4xmL?T~@sHqL{@ST8(mzcw|RPuj#aapSRR^@pJLd&H-tp=?_PGSU)I zP>{v>RZq2bREI!jwPies-Vl@5!l{$=LJOx-M~7$++M$SuM`K3~b93OQaV1d4CG!>z z4MeuLM&alMlc~xmmUZYbd8q}WQ!K5*Y}7R-4`M&lANm^Hsqdto%i%0ZIzEleYSmqI zjrvu8hl^8PB~2~0b<#0!rLEN#`>wuNwR#in`@|YGg1QAXByIF{LMRz(9gQ_cMOg@O zLuAq@Gk*>j8173w9m!=fGH6hDD^(AP*)H{DDJh%>lwy|(pVD2Gh~c4!R9L7lq>?d} zhehg#FzL7GZ_#j7!1T*uH2z#w|3tnDpJ}gUU4QdR@ic}+lLSgUYFG&4c&T=)zRh7$ z+59+B4ZUH$eGzSZe;mH3T;&ls#N=n4GprPkIFS3e9)`QplX7I@ZZYrlpTbtkP>gq} z7Gny&>zhAx=4oDiCHM+AUamNlWoLWYZfc4T3yVc8*WGyCmRO1n#^c0zPL zza`M+%SdIIf}EeuF5>Ji(QBmpLYNox3|AX`hXQUeg^Fe~`GhzOcdp-I(tB+V7L;Gm z9S{WAF*1zWUcH?+WwYQ($TWwoH12Xh*?#22tdIB-Mxcn9I0Ays_;m)6XdDLcPjtwh zMygrk_|~ntPD(UuEH_qFAdH6w-lSBj$4N3m8e+7I<`aF=%PB88GeGsUFUHsT(SY>L zNtGMu%xsmvFU$ydFhi3}o@PKZmMYG7hnentJHjBo_AyxaM1K-^k$RKHmS$AacFU+l z-3F9>m%g39*8Ug9GxgDr+ta4s+uua@1*;A*wE1I`O6R)V9x~ojQc|dsy%CT8;~CuX zvw5UNczal3d#b2&Ka=%t!e9RS6n^!8x0-%bm^nD(Q~e{xwee#a>SrB#Td+%aymcF> zCPq#-y4_9(6%weh_&Ll+qk3rcbmNA#_~!rIh)XZM#Ng=d+jsClz{|G8pm;|)%L{{t zYq{Kxk`m-mZ+#O5wboEC{elJa4P(Bbpb+=p{|8gJ~wTe~JYrIC#XF$gqArG7z#sDI8HYK4q|=mbh7Hq-EtB;Fkfc}oNi zR<}bLt~Ob`<}f~48#nbQ;*~JiSxRZyXO<&tdO8~3-+|<>or+6ooF_Flu19?c^J*8f zo>_EL0zw7?(O5Wp&%Jr=Gg(IcB0FVpvy>%TA6lj=hQL z6UmI%6;8sDFpEo1;^w9a8_GX0YC~c@@mxz2PQT3P7!pss3eI8Y_~P8EMXpDGe#YM2^+vyLs*X z!!aH~2H~=`Yw`FaPhjzpi!f#CWF9zWB8HnB8P+SQD96U7%aMXHsHT4K*%M=V-L}v$ zdL?nbp6W`HljDsZb?FPQuWvGVN9wOU#5*ZG$WQS!p|x`l8A_5Or!nWYR!VbLBiTy> z?Hotuc0@OC<;9LiECmC)c-YgyLk}yFt@hZqr~$p((pSTJH`9LEJnDI{HhOfHG1}TH zQ7}3iX5$_%Pr*V=cYE;QFxrKebk*K>%WhAdug`{PtZG0JzY=O_Dg6+wyH_A0nRb7& zrCNXt3g2PX;Q&K5g)_uoRrfg1xD)-hW5;gPl8I4RkVC-}FK>>f8h!Y}^->v=o|bIv zDH+4NJnYy>=DXtLag1s0Hf8MlF!k3Z_;Pqaz&&OHYiz@Wn*5AbE00|F` zL}POuZ%0rfJVKI{lDh4oFU%PA4O2T>dkrZ~c;@4Kn6!3Wo3-3039E9ovP(a-;Y)KK zOLM#Qx9eMDUTS2Nw+@p<11P}wD|7j4K-)?MTL%@L%p~U~~-ED}7%QI_C zHxE8+&$;6d_P)O`SNtBw5?K%Rr|@uT=^oR+sVRwuZ=w1qT%>#(<%z1Ax>4Q4rAah8 z4{RE$%F)_bhxqgyBxYorF(}5Y2D0)D@kzhi@|aDJbA9x@+BY*}d~unNnKL%b=S@HN z{I_*gsNM~L#Z%`TF=6syy`4Y$FidroQDE&eny4zXskPbI{LrD9{7g=Ll*53%rmp;K zeKh0sr}Tq4wbZFE4>PEa@%{JSA?zF)V>S(-%H4ePEx7T<8}Q$k{)^_i-PCWs2)Vhr zChUK|b2Dzb>05a9)g|nhDjaw0v4+8|Kzl$rrZArj@o!Ma`)o>{&qhsc9U2-NO*wPt zF2J?de3`V>*8HquX%R zRbM21G}(-!6HYlBci-_7Bca~Wvd0*29aA{Qr2E_#uEhPnzZc7vEi)=+jy>jR+RUlL zdFNk970i?IZI*8j2V#6u{JtWCk01ns5I8^x433fZzknfOxVwwBNXPBh*SkGYlmwKs zh=mymp2o%&)YUcN!}Z0~Wwpaxk)1TL(8MtdlUY#u%JGxyXNiE4l4?pnRdcbJ#7*%K zZFWDoVEsh4TpKjmVbC;7N}`ceGmiKnqL5N0As$N6QOX$Ig@*Vsq!J0S7D~5Em6Wbc zDxIEUh*^9f364;Ym+8p7rY_|$DTPeq zd1szXCLawpQbNHYt_4OiRYM>iaaP zTD7ATmwx#QOyG6M4&q83RBH1WK`HqT5}Rc;WHge|l}HH*5sjwfY{dees=FA)5jvD( znNnw>9l~%dECEID^QVaFxTpmFO(#)LiRSKhv{T=IEB|EdGR~81nC+cZ55wm8U38=u zq9NU*}#Q$gSI{@pv%Cle1J9M?T zC0Wao_e$*8N$ePpkR3>vX`rN}WfV#&h5n5G6bh73S^{O2LK*-67gA^#*_#YIcAVvS z%2TpsEo-l&1gUqzVX8 zPc%%QS4QVnRLJrVzfX4j^{1q8MyVY8`aN=3z-f)!4ZM^(P`p&GyZHvG1_#RkIOBWq zMUJikn*nV6egA*p!A_H{2Fd zeA=$vwR-46kRu&jzPxVh^Csa|L!a~vw?l*sxP<%KvGIkBRBQ~#QgTDYLT>PX05^5W zd+A9^L0u-IZxM7d^%e4XMh`PDCqRK#w{(F!pW<+6&U$-1qg+lsu&GuvYS^;y$?MpA z_tin+Sdreevxf_$gY`FAYV>Cf{o8N7YR`>+-DVX@<}H7VB$3mR^>u;3_ERmBEsuTj zP=^ZXKoFEKa*KlQEIw(NmgZAniJa@aW=_L{4f^Mkw-~KG-OOzaa~1wn=*%!NGyNz) z#s)orMH@L;J?pHFF3R>qzYIr1dkP4p$Tf;^JBIm^w|h))X8(f^ZJYFseyhJaT!#Fx zotl2Cc?f~lY7_E|;EctD2e2Lw@R?!a@kf6YCj$wE=AGa=#%7~{o^kV=-Gkv_@L+Np zl21*W9`Ik^!`?JpGRoz_`bOnS<4~2H=?tsuo`g}jk*N#m6HwHDCK2X~vo*Pq!H*1m zB5_g#u{7Xih62_EIndT4J^n=8pfmlD2L@^w5O^anU{$1Pnv(Ffh~ve9s8XU z1wd4yy%_g+X@|1-6WKOt2O3`x!}`RWGXsj#X~=Yxgno%81;&ms0PP}Ofq1M}VTVRO z)YB>5Esc@{?&kDd+{*N#uOa^&%e5^dzLPbPs3i?sB0SrmHO|O1ZsRfBpGZ>c7f+5U zwBTVE_c7Lu(XdS1$B`k3>sjS!hxn9XXd`ByVpwu_=iuhD*Tb9j&Wzxb@iHxI9eRfI zLN_&`RQa%eLoUuoBzJ<_b4Bv8kN*`8&J2V_aWUJry&>QEw||q5e)JPy*qk9xJn^I~ zga{a>_r@D<$iMyD_vFJL`8dS-70JVoJfd!g4))!PUzpb4edcfVrt&W#gT16`@>PK6f1&Yn-K(@j9ECFq}I{No@0OSFr4`Ot^|5{GwV^3lKeQ@I`@C&{ev{`Y?X`V2Yer^&0Yy(ag5 z>)UeMJMWZxzV=1=8Wg6cfQvsD`;B|={TKN<(!cqZ+ay0PM-{)>zDrRC7h*97y zQGi2HXk z|KY=p;K&|?4EHhxakZbpEe@NR{@N`NErYA<00+k)o1KFP0k7w zCB+5GZD+&60i#X4^zZ*8xDzYHl?yHK2(R`RGf_^GH!hlzu$k?~)yi-E)4xjRx1W&s z>}2u2`%3xr7yp-JgS&kQz_vYLBOA9!{#92==Zm!xeEUNA;O9OmD;6)p;yyt|avX(h!q;BgCR?9;R+7Ngd)J@e zB~_4LNDjw|<09*oe=dOZgV=!AHa19Bdb;F8&UFyn*BnvL_QY}$vQ6r&QxY;n<*Ce> z0!_$e_Wuwp_(FzElMuMxZlfV1%H)TP2g>Hb(RoNWbKBd=I>T3ZvdRKQZ zHZujdwwt5%W5FI9iPjPNN^N7K{OZ5{TaNzhAxR6yOK$@JY3Y^xyRMf+ToWGr!E=&) z$6}fH_FJVmBTE)Sp*m?z5kASd5l0B6r>hU5u7<>jrsItoZX9uFHPA0T+wYf-f|-&4 zP&OXzeQ;z@+mh-9Ks(~bjo^AW4i2ffD#M*8`Kcv((8D~EJJgypp)uoPJ0Md5+e8Y= zM!QSR*m~vqtg)#T3TLx1Cs1?``XuU`L;r~w02r1urXM>B@!M=*&8RdMhk2)NtBmyF z#><@R^x#)zwrddM=X}xB=9le_WwP~oD(!@RcqqzS8KjLj#SM`#E-fqb&$dDicOH1N z?@)vc#St0Wm=ZD$rpZ=hOMWV8o6xb}OMwDx8*E3mEkrAmwvkZZ;+ihfMojzRO&`vc zJDOjVRBtA3WTl|ZSq2H)#!M^I)`rHW?G08oZoD9Af`?eY=)36;d^L9X#!$-e8U}zQ zpX}QV$sayxr|Gk7Q6V?|%_ea4!&Gi{|!VCn*pm;S)vH*Uk6HYB1;OaflJ^*E`!{T!f z!rqKo%-7+)UDDRvC&eYXI#&^>ME4%oZ#A>bGP4uPy4uBlCZPa{i1vkb+(7-ylAJq7 zl6=`<7Qq@fRIif+J~O9KyBik?vcsz5*v|uh9-ijocI6NN=ss*^+Wcrg0NT+xAvUHN zxA|~06KhhgUn!%Vm2XAIXuOVr-6RKhO(9w%8Q*B=&)KKVSYVo$A&rfL?UdAF+;G<) z>(96`FY1Ru@MlHJu!{|{ECIg^fMG=EJH*AqDmUgSpEpGT;&|MaDbIDwj7%^sAdCX{ zEL*62+EroC&rtGm3^x)p({XT&!{ZU{EX)NA{qd<`>HB!YymCE7S~|xz+H+hagHtkY z?vN3KhJDn!^`jrV^d^d1-8h!=kLwhBC`slR&d>D6{S>*#o12@#08$9iEe}I<%Z=bP z?}li-G;ISmevJ@6%mc?bn>WTmL*^0YgQmB)SM!wy9Zxh&k84q`0hGxEcFYIm!KbFC zD(yKwCu0vs!#MlFdCzZ(qoJ9Y54DW_#3&G>z$sCnp}7cP_B$7uVZ%iR7d-@DT_K@HXjh5&6qo|50)PY7-Q+U^}VBcWzF}Suyy=Hc42p zND>CgBi$zJ-+8ON3n1gZ^=svU`~M(2zVst#pDz*53$^ltJ)e>z_k0>+2Fhgn)>mcA zZyuJRCtrdJ&STQPc$Ex(;7_!!CN8>|7CEkxu=qUI(=E?E^|b8#{(ng3nyY2QpWGqU zP~vLKaIw^b9p4F<)9{;|$XQ-+wep{{ZG|$eZ5RG2^PT2gg6)i-=_!bc#rQ|=z6(lQ zA?^XWq`07oU_0v|8U3jZi}W2EUxMP)3K{FgVmbiDN;nuu%E^#^xV`w_e~^PuZjt^S zF9@V$0|=QV`LiH@z9<7XA4+798-H9WjlKop8Wo3vj12<<7#~5UYzaKL3OR*jpgnVnp9|Wikb|=2783j<8Xjmn| z!H)5W|2PJPT07fGj;|2czXQ+<&?$|mkAk=|RVGL`_R|rxvuJJ2q;TrLEccNk%_<^~ z^dSvscPSW*C4xh*U9{O_$7 zwVz1%OOPHG7$UGUnPEF|f;`qQ?Nu>3!~>RQ&Xvx=X6>7iG0F5(wlaOQ-Ik4xfB2?f z)85UPYQBx5woUwKD<$i6$r&YB0t zj(AMu^oKuuj^ZG7Xv{BeD28R&kY|kNf}4O~Ov1rJ*8sqH9CW7vcxQ&X{5+iZLj24S z#w?6D2@tabku)4)m|f;G8{isbB1#j0G8fWHN+gJ84&6AvQ?v|~7jrygKFPsv@`-0O zb29g6VQ8mi!jnZmk#YJtQ938GKT({tKUo;-Zl9+T7yZ((JoY{O4GRL+7#kCk0Q6!F zMbRt#7jCOIE&F8HXz#SM#?sE|k8akFb+`TU+J z4JbESys|_S1cw1fXbvz`!pO}Sx#t3y0Qf$CekJ6mwdx>8a6V=X9XTP8%RLL?JnWzx zqfLwgr%C~~8EzKHeMdRT3jhSLe-ixQphHfLk-=`|HlZwbReTB;E;e{j*3;dmetkZV z-bP`#iH7~$l~*PG`yP|QwmN|B<&ZN9nVML%O;=;f?*rHRhd=N>c?_E4_a8hYmoHj~ z>!x<687iGFtT3)Yru4x*`v8_>hY5NO?%XD>n{SoXSFVs0(0O51m6Uz*L`jaf#PdM zuyfo7j`~0T*Dq!8o_nR}>eb@^>euDh;M(}uKYdMdvG^l+JaOT8q3gt%AMnMQ!$dU3 z3EPcuHtC<&<+Z)C@t$MD^td_kLevub5Bq^VTyZANO%6p0?W)-;wcmM2a&vH%KP^Fg zIc`bje0Tq5*;V&5fpTEGsuEoS*k%te^-paVd6Ox!~G@Nh}U^qIpDcMsKejfJKise@4r)mx+X9O97+$w zP2NdfJulB*C_TyGg!eat_)y@Cf6jKpZ-O%}05k4XkIHcG8f+DRum}EdLSO!0akM3Q{gD-gsfg7#gE#*ska!9xv_iSiBrh(Cn))vK0h zn~ogfnz^O15nSu3Dbn21riwrbToJHefOTH|(H7RG%!sd(_!P7aayJH{C*(YW?I@Dg z6~%Z_Y*1N+K7V?%)b_$doLgY*DP$zmCw}YUu!?5+4 z6(H=*|A-ILm)`N<9A^}IM}Tr2ZyAA!#CSsgCI>BVd@-M+2x$5kJs~UbtRiOkLGE)+ zoeAJGl$L%V9P>XiLY*7{%<(4>A=8I7sxP?}ipq15C$1|Q$b?OGkIC%3c-(Bl;dei7 zl64PY{0~A|JLK6zyjTb9QZe=<;~>JF%zPlPh(hNMJd+{!JsC*)$S7`GB~q-LnNc`B zkQ6+Oi-%~yQL_26IQ%=2(Zayd(op@Gyp9ioNElDp|9IDMcwbHqdYa2m8%kLD4M zDrCoR`lYey@!iH5a*BMzBAgUn!tTy6AwP5*7pKDyUe(y}_Cps=Xe+R1tKu4p>#H#x z|3jYXhsK5-SJsfd&A)oIo*ntM_Rcu0o#V;u$0I$?as2Cqj+l|21nC3#9_Vb9Kwr0b z(z7Hn8S6N2DvFCa5oWEKi$23Dl2s_z)SPSIeX%+F#Hxq%nhd#&qHj&uy zHV^tux-f>&d`b>$KV+j*aeWYsS9*|yzM72ntrv_Bso-dL18`3SHbbNC%zQX;wGJ06 zTrRlVDzG^=KJja^5dPGc<2*&2?Yh?j;P%@-Ii~QB-`0+y`EJ}yUYu^Uw|@9^els2J zsR(Xwd1|$`9H4o+!E=Vc zI7xl(a>cTf9$B~(VkKBIKjmj0`!6KCa?8I@2o8XSl4mqgu+lv9x0F047x%JL>OG$o#Ufm?^ ze7GvO;p(epPIZ+$v2K;T^z-{Arwz(`ppj{8`>CA%5%Y)?cdlS?Xpuc-}xT7;Xw$2yrjV?||}KpJW#1%MFl^Syok{?UtNZ_JC<31v&Vazfol`~ zktV&+`O(nW3NZ}nN|#)S6l7oFAGy7#G*rRrgCo**aGNa7g?D98^7 zc4Grd;hi4Ol3^R+M0CQ%Gam``x~W)O#E0LRm? zoE^lN-#-L+f6S*G)EJ%&?U4_Pni+xEnf~Ek^k)GWPqBRjfT6pH3RRI9flQ8R3AklN z#j7W(w{U$p+lwh)h`M-0Gfw{#-EDa5$3C6@)KA!>(R}5+ z$Kb%GV=x(YKOi0)cm?~rkT0~U3W&VH9)RP66-&oM0w!yXO*NXG^>h3a#?5JC-Y5EZ zesdfpjVQKd#T7;jB+F0x6B%cC`Z>|Jtxg+HG=C?e&_usBj@UCsffxlYUJ6`Lz}*Zu z#}6qS(5U@84;y)cej7KwCWmo~?Dr3-jCX>8Nw^-!O^r3-g$yj-Y=aTYPMS0|w@C+N zqb*o4OE-y@HnC@n0w<#Y`wZ7nyedghfS^Z&!w&rnjwAhT67R{z!WWwg%3p`!!h=`j z2`X^&mj-}^b_5KL>xWDOU`cZJOmMNz7yqGW#W(jRToc7G#0~Pq70AgleG$2{td>ih z9M9Z{A7{821#KFeTcrKBuSwBm5NWaRm}I=|U2^r6D*?s=P{p6p4VbXDnoYG9+GG7`?d6a z=_``Abft{0Ss(&nthKjGmVNJEWYtwyNgUE3=jL&BbzJ6S7AK;>DbWsHs2AKrqpRL3 zw|?jYvgh^f(zj`wWG$U1Bj9eOBC2@wxj+jP3cqKO-2Uz_V1d6(it_+0VPivCj%*v8 z@lGkd6J_=c?d@iR9JvHotE*>*=Nil1&vAooxC$U7!Sxq5Zj;L|o1>sSm0S^YrhIAw z6#bxy8{^6KZ&{vZ_K9ixisR32Dd;G3iLfyc8)@m{}^lI8fvml#^Nrkpd|IZaP(AFYR=2 zj6^e~H_|KxH(97(#ejIs!Spu-#1b*iw6}LbDcOD;)aHT#B3ES~5`eb1oTwM51LF>X zXby`6(%xd4BdK}&fQKo@K4(TTfc!(!vhztPSa_XCN*+KBBTj?i z=-+8h);~B;nYAN1(9K~Z)8e5i=RLMv%>&vu4N(y8#oe9BTC&qTTS& z7y$ZqtlvCHAM2|)m$>2}ySp<0v4Oa`iQB~)5P1eN!;b+hnT}1DwB!FszmB*t9b;%` zLz%o7|JL66yHuYnyEP~?>BV~F;RYHM*A8*ip2`!N^JWO(VmXaG_;H|f42pBxdsydC zbB{d`#haz)7wfv7S>iz->nu{w$Sxi9hY!A>V792CPisxD(G2^92@6+*iNtRsVyKW0 zy3>=fGEaI#zDP%g9Y&)M;HE8s_5ek=oQ-fV_t z=EgPwvZ) zK9QS`SL=1%HAzkwmwU!Sjn7}ZNm6FL#YCiO+2ze75nQBB9Di5@BlB>4IY=?O4`X3_ z=)fV!&e{zHP!-a6>}k32J%265`S}L050%X<>f)69BoQ0@OkC#-3WURtluK$)ucVgb zNXot=^7>70lLKG=qHF*tKfAO{T-fn-fUAAerj7FY_kJX)kMEG|H5(*|O<)oZQ(Bsu zWbuD|OV+JgC2;@}Vqp8ZZA@C{n9I_^`E=Kxy~V~u7=jVdgEPMAAJKCOXbB+afB})%Cqv%2@f#TG(~YAm$s>tS#yKl{F>a(l zmM?q-p^S|;PE>>p0;MFUNhTDkvTgta;W@rfM^8OsYsXdQm7r@5%FTD$PnQ2k3>Wts z%fNLSmEH5UA%SSrjDmfvUmAjZ#U=SF^OfHOx+%N-GkvySw%arn2{WuW zE_hR;4L2yeDIN{sxy~#Hmpu;>ST+yj)^eRSI7mR;#K`!VK1vEs{aN6CA430b*S6Y+ zd2uJ?wwIUBkeM?J&;|^U&M-9WN7Q>@x#5`~($Bi9r#JbJ1>1*vA@1qm)8Z;xF7Etl zaI*vKf*6qDfo>V;Z3f5t4Ct0Am!Y=30O36nIIM$O^6 zZL^Fs3F%Ua;453U%A7gX;4UTb9#pWA?ld-Dz7uTk#_huGyJ}?d!ubmLId80Se5JAd zK|dTn%&RJp1~Wx=D#Xh~HIcrgYd-+n$i4B2@ESKjG~#G#%jS(2#vKPx9lz*Lu!23q z(V2cJK1Kjq6BZ8w#14+~mXQl0$Dk(xV{xXp8^Af-6>Nl8Fc<`f-O@LZ4K8(`l;y-h zuM2e_1VIM~=mS_tu^2wg5JB`MOJ7Zp>C-~zQ3B6F5uf@R>m z_qfPo+j)*rSThbuX(TZcyTQ8cm&?-&q@X#i#4O$Oh*}VB+=W-bBhoRLYnS%T{ETDY$A@miFC5$hT;~d1rqylK? zT$g}3jpeuEk~l~4Ac_AdYDsg!Wbn$hk=6+_!9aATp+EJ*ABPF&+hI5ERRcwA!iA4m zU5Gb3mR^XoV`;`H5Tn5Kr$88RpD@H-@RD(o;AqVWp`6N6Q@mKr#>H;Xj8Iz8V9%(t&u3SWVbr}P{9rrJIVa`JaxOp>5H_U?VJR})Q;u4|&`xdXq zv)@r^F*gy`a3MVG$7*vF8$Zf#$3ob-grazeApk7t0NYc%xKhbQ*NF_`*9`^Y@RqKS zzM4lQ(701PC5y3%#zs~LqUqan&Dt=z|x(d8m*=4$w4C^l-@S|js*^If@a?OI91xJn?Go5Pqnw-jKXBG@*! zvQiEnt(X7%)q5pJa9ErP@k~(GIk>Gs+)Ik}hQlEGAU8en7|#RXYPWJr&utD*Eq3-> zjuQlrckVhQix$qp=FEuPU<|h3>jn>HCK${1Opu*i?c``DIB5Y(`XjKBgnrQvZqB-W z2XtGQTU90*KA!~reryWCu^9r5OiRU`?9q1`v>J{Lkqa0b5&o> z#KVd4p{Cy#hLJFbx&_&7{iABNO;A(}WuL1U865g;12=qbPP!0?c8bGrmY#J?{Fy*q z0_LLX@;vEjt(KQ+JLK|WaE$^xe|{F5_}V=Tb|3&OJv8rkaH|Kmmj zL=kzmUCw-w1786%q(=~+ZmGE`%5_gB56*`c{9^o0qo4)i9sz4C519zk zb3H~~1+yR~hTQQ6Om~Jdcm(5RI7_qfKHl7425bl5+}AGs2c8tyjLQMGSDAGJ=$+t! z5@m>$k?c}KD2^qWB`WeR(6|c#{ZrzbbCZgl8AX3S70{CXRsmCtA^-8?{{$mJKtA`` zztj5RSVkcCe}C~GWbvX!a`)XIl!qRANd5%M$MXvc(Wa6xHsTO`+xge`OK$31*W20Ny55_@!Ij#(dbWnU}zej+n6J1_``Z8j|!#;Kjti5!yz4}>q7nGp$7rB4rp(cKI&~2 zP)fsuGC<{^n8cLxm>}o~=OS%Wq{D?YCF1xL|)MH zS-EWIx^mIi=$WE7H52<{gr4Cyec{i<{F+GA7UfqT+OJJ7)Xs-cp|9{b#yoN^;%!2L z?F8Lv$8pXDnx^0&IR$G@H^v~gL+zD@qG~RG}wlwCcSvIda*4VZ_-dD)O zxJQ^UVcUtNcE%m{6nlwLAVz^01=l) z_kVqTv&s{_;)?lLq?twkh00Sb-RVUE_Kjo5I&dx4r*d;GHy%2mF8)Wb7>>iW?s$k= z(47#9$1nsZD29d`7y=9A0^~w;GQ)5b2@sFPp0{$X^zVH{;sJKK^B@W-IDmB~)4Ui* zq{&J(xf{nHfskQP z_y;E-!gxamaRe790+x(`fTX{x8_H2d@+!-eBbs#M1~6K`2qzllg?%jzVkQznzc{2# zC8`A5#&GDw_gpC8B(P3S_Q7Glv<@`j=E;zx0(hq#!TFxRF-b{GQ!aPQr5GitNv)Xo z0RVRG?L9)K0hXKd@>I(+X(AWck>eBTZR>n|cDUv;2Qn13!uFAonJOz+EKu<>45J%+ z$5_wyL$K^vpU6=o8dtnYBaqpjB-Oc)6+hM`@qJA)3{Y~QHz335$#S&54SIf{3jui{ zSLi|<1oc5&4LRAlZY2GgN6t?a&6J;?C3EML>zavqV7*W#JHh#x@LyJ17%m3erSl*m z?BIBD)+giO9}VS77Zv4cozu?g&jvR|N5*5u%=@4Nnt=YsLuUJMe~0w%f82oW1+$g2 zU7g`;EQ+`lG6#^O-CZ~rw_|z$)IS5z{RZHd*y<3hbF?)RkK>n(4<;TUDVl}0i=Y1d z7xKP4??nGC(fsYlq2PDF`(63bzyDC{IXf#0N)!9!!2W&OwyI{$LK4tbgLc@C8#{+; zYjL=gqg?PD9J}>!C=ToNX1&=lckUb&MRefcb|{`Mz)c9GgF_*T(dzE*LED9x93JA7 z;kFNM1}1{TzP_PRjvj5mVNtmhVC_K8Qy&f}&0!Pv0S!%hK%bYNC&fjDSUdQ&?XmrZ zim2sO01aykDu(tYrAz-HZZJ}bY7~Qz;jp&NvQMeec($WJE8_KP#^D#$2<~l_%`5{X^p#!m?T&z#>qW1#u3=HK1_=M8zLdasr zc>Um`PswG=S1K_5^Pm4*u35cGGQjk~3NS#*mM#kyFTtGd zl6mv1R1tO>lwtEQ&zG78aU)RdjDJZ0%X@Gek>j4vmx?@@dT>DuQ7_UZL4BGo4pZQt zz&;OLC{w$)uScH!1f>*9%N6M!aY z7+LI@jbCIkIGZ`Vc;Ye>5aKXgI7`ZT$0i+RR2ydnkH5Yi4-=5&f z!aA7p+l>eS0!oy{+tmf`cNlWGv)^&y=3F+ZD1v!9(ITmJng;<@iB@vL49aSPA{1~CX@OJ`y8hz%M*18!MbUwlqx{hy!8 zEw|i^Z^)X*29$LdGv}THtUGcNjbbD6*fW2Wy6gpk_O|kaHNz!@qg+E1`@Rx>XK036(!m zEJ#;Zzg|ZsKx6?%o7c!U0eJ$F1Xon3fP$`+(O$Z6p6tHy?Xr5!DsWvUsfdQDwNr(K z5HCbqxw9cg2{PgXZ5X}C$>qjPIFF2a)1maNQ9&kx?|nl(($rlCP-X-hPlyfh6)1gK zXNmEU(+h=yL4Z3PBd20mZjPhr5LvQhag~;JBDg%2_%3$8ww|5&q#f68d zk%;()Ne}hLwS;%(a_K+x0_47LgxI<@tV~^7Xhk~%F?|?v+7j>#b~o!9CLJPU-g)cw z^7?D9NM!}Yi9pZB&Ye5u%U}AEwlRj`xc002ekJSIt&>+?eHA(_s^z`!y+d~I+9^K= zSifS$a(U{hr(_X0;%~X-R@uDeDfz=69+aDJeVfz)j3+01Sy>qlFx~R~AN)|h@cGY4 zd3l+N9sBL?eg`o{3jy|SmUXz5wgC#yU);1ww!RE;GqY#QPyX|#^5=Ko4Usoq831Q> z5)KNwaHzX!(~An;Klb?Ja{cw!%N5JOi5&pI8^vHW2gOFEIHOWp{XBT&x(nlIh$a(* zkWwT&yy%-&o!Xdrfewb6A$N|x^sE6P77d3HGL|H5eRAjDii1*Vk4 z4hDBtAQZ<#-%rA*41mLbFjy$PP*howH3(5MiPGGffW07e;Gn-h`1nJz3~QoQt5;*) zGbp?E)W{|P5WV;o(Og(`OqFLMS$7_UtODKXO#+4%gw3Zh>68e!b3P zk3RZ16d-p3uBRkI*IZ7ps9HOtnm zTa{LwIC!S){!JS0dEC3um+S9f*&7E^TbT*(3whVwdrX6DGcu<43k^qrKNnYH< zK)rHKK|?z2v`jz{Cqy6HUv%7?gl3ThjVC1$BH@>b!}K-Ixjh&UD4(55>&MAwSD@Vs zh6a=e2T3$!DA4|n2ongjYxE)7!`)N?$Ar)a12I)vsAroWgb5Xf;|g!Ln7A~6^QHnj~E4F6o^saoKRr$QR?)PoECt)F2Z$u$7G02Y(+(hbOPk#wf1Ci zvQzOCmDUja;~-5LoZL8Z<4>*+8iu2cX-=RMH+rW>x{E24ndS6g0_BXE7zIw10_+Ri z>;wSRwzhR)qn3@eB)M&P6_y(yES<11(f&EKik%ESXP zS!IQVdhPi{^kN-QF=779V)-ISc;ALK%9%BWjo8|&u98y7xqkZcr84l}f6(jdqaMh) zLj^t-CLybdw(n2KK@NfuJ3@Tf=6WLhwjF~3Y79;17+I>=PzD` zx8GCB$XW2rbUBx%c-=C8L4~xpb*re9F3hsjUS0#Hv&&Q?lL zWQ7+ZWoBnzu47&6z)|F71UE?%(dV$92=;^apf&zYbaAHZ2IE`FdM47S22yh0?!m~?r{qT?{N?I)`gxYG;c1^Sax zezo-NeGF@hmn5a)DqT~s-}0uR^y8xSNYs;-D=~ZhObOWb@`1 zrMtZe;uv_F&o3J`Y{1@QC*p`#PX7)H$gPqmGZT(eN9$fy-J>X`Wd<9)>~xt z>T94Epba4Xm*r~A*KBi@xb1T5bywk5#(cTsgCCRkzURF-z?`pR=Buy0hW$;2iYB=h z=`34*1!TF;mY@FYXR;8W{lkwuB5!-!t#ZW`D=@Cq$|H|H0zml&o%;vD&6<;w4Z#0B z3IGp)BYW%Cmt@8A%XQ8-MKxoYZA%>6*cUv>J}FA7l;++#z3qcaArY-NebO)O6imaL zrJ?pC)FHu0(v$WYl2t)2UM38a5FdnyFrPGaLCNh%f-IRaCYe5nD?~7^Gj+{Ee@rGW zh{Hv?*%*+c5Rk2tIDS0Fi~e9dxZ3g82=OtH z&!1gVu1ZlkW+>>7JeYPLC8E=|GW~=dwnrK5G<4?eN-qxd zd=N$DhDa-}tJr7xXZ)Blnf|R-+80e4_@y^SQ_qYb|~3QfgKjALThX#u#~OmiUSB*6{S;ziZEdFt%!Rpo8X z&24hvz)@Ty9+XWlZc|{LGG@ylPjm0yI-&cV*=1Pt6lyqKB#s~XZ8FpDNxE>+%q!FR z`Pt!#blMdpmf;ISfzYTzg>eMT$>r4y#c!EVoSK;fu68OF1ea%WS`PAO7HW22>FVy) zKIaC|O9gOKHtf>?^pnyHBz5jh;;(;I`u02|o|#waHB!oKyi~Z|*-r_0r(@%G$8EPN zr%XJ?Gct71ZKBbB4R=Txg(#ToWT9&57i0_av&}tQ+gp%Diw!q`FUB=3|ZaV-qh}$~sbKs7T2e89UEa4;mqkre7bh12Z-C&Sp*~kFk@w!6e z7$5U&>Q<;~Koz#aoLr zWTb781X}mYNYg&74N*rpES5L`3+^=WK(q)sDam)ix}afOqluOmb%_0(7YgWD0PtrN zvdae!Zv`0M%j!m*Lk@o;>UhRdaplf}J?AZENqjA zIsygEZdamIl;p`^({_ldf>LORh}jFUlx?iC99;38(6xda9aEt=g`ud~t=wpv#tjPi(e+V}^pp!z|dxUnj-IM+_{N}+T<(#{r5VRM! zl?d$`SM?J5iP-SX#>nvcO&~ASw=_W56Mf<~N+3l#z}cQbnq^bIIl0=IKA1j$vTJ)l zo_GtUD%XWE7z`Zfvp#o%a=K@DaM;YbaJUP91JVUxaWVFE#~_}k?!a!DRg@tIYj#6% z@hq8D06F(v`(*8^mGaON&q^P-{O8Y~Cky9QOL|gJ%8Co+wzuCbc`nGu2N(VPdGn;N zt6h>Hf~T#mRrc-M3$F7f1-hA^^t3b_D7z#H^94DEDY^#5#UVl*4q)Dj!@dm3!F9rG zae%&WUk!AMb;wOOUXQxPl^pz$>z(!#7qbELenCEzqJwTcVBTA^N0x&_|82M20515Y znB!9<%}0GmUeuothZZO|{y6VOsgzLNOqT}^RsgmKyPKfc_(hD*mjP@q*FFw%z}Qx0 z%QNxY+Mk^#n<$1FkTp))2NLB-TR@H-IRp;9LCGzhC2k-34;dWb&-R-WrW|hX@Zo$v zVF2r3%V?g_>0teif6_1W&K}72(dVc5n1C`Nl2M0x1*lhxvf8zuVgl8EkAVChU#9Wt zhlU4JB{qvFmxh63B>cp}nr{;~-y_CGqc-C{LVjR(s%xxBtg*Kk1!5G4QQ*ud5N$Y` zYK$j~V_E_3EIbEsZr-?gTE1+)Zq6yDVHg0wzI{g&{G&e(^Sk%dO8wCmfbH#A*o{gX zWO*)uY|q(Pq%j^Yip`|J5YyLKnxx_Sx)-3k-B3>762)?Uz9?Y&fsxC+a>YVjjP>>T zwI5N@-B?_M%t#%=W+D;XMq}bhfJ|__TP}%?_HKZ0BanfcF6jX1d1ZFWhJ6tWTmmJ& z%2hJhb_g4AaJ%rn{w*sH2~>NMUdQV@$L=9?@TrZ(T(6L zfyirDtiT2kGKCqQKn238(k-~-1v>|9ctfR8_Y@q0^o+_YU-^a%eez?n7Mng77U5K& zM0Xl4zWGNE;{I?!ZJqCIZ`%GapYxrd zyltBrUftzFP1KK|fR~kWca&UU%I6gr<9k|%JsZ;-;|G;oR#LP4RPKSa`fbo=L zO1Z|#0PK5*IGvbj%#=YLGD(6weRzsu&cb2(?H00Qf_&HN?R{cR@$H;>s!ottup;wjO!J0S?58x!oQd!lg@GYB9!* zT8O%GL$hrL$_YiMC%rT!d-~j>vdCcuvKDDP`v`M^EKZ^qBN*{{xh=)Q}$eYLf6vP1v z=XS=END+=~Yp^FB4c!rF8XBby4nK#`-UCNAi?{d+Fx8am+MjehpN4fpaAw zj!0`a+5sAF8g3h;Wag^EW6J;6c6ln9LtJ6wd=Fcm+RIetC;HW-@FWv~A9_o0w^eVr zuH?7Y7wzCu8f3l8lF!wBG^K590++ZzCvzJJ9P;EL@T3> zkLxD;9u5$DiBTX%ffxm*IRy;rGR+FX!I}#bE?8WUNk*`uw6qX%6qn1DD;G&cRk_Ly zB?wQjom>d%0G|@DFnambJ@Ur(eWCDX@iWbee_VD6a*_*!9Lfg{)GL?rah_rpF$zpV z0WOC5N0SEboux}=;|la*$hNGMG*=LyRHE$O+n@@<2*e-7K^8eTDI1sTuFT9dY*=ue zAN?}gVrr74)rku@uzc&r+m%xZMQ1n4NT3UxX^(;vtPNZ-*c@@O7s}(w;=7pLxp5+` zPX@NzGLW9!fKguQNC*T_H^e~>u!crlcYl71B+krJC8==)FHuLsn`@0BqZW%|q;YdK6Ikt>9Gm-FTbq z-hEU)bl*3}f$h49M%3KYQ4abXT!UYE`;F2*+%8^dj*NS7kHkH2P+EWUUlNz@1{Y-E zcrLHt{c0I+~ix^d$MjvSm6#e-aiH*?GpH+BR;1_t}39m+T`9M%Bjqs(UoZ&{DvoJ{oPVjdZk#IzFel&xaN(!gwI_U}zi z^b1{hRwVlc4zKt}uJhrZdWd^jB}r*{lHkrTHxyXs=&!~&Tf)=|prAW|+eA+WsW^;fs=X>#A>aO`|f{OcGL&uw@+=A!omWG z4k-oabC({HYwL!{qaG;mj7!Ob_^WKl=F4mdhEZ}DP7y)F&jwm#Gg7NU5=0yjG-GNprZ8u;$eZ+%i z@mSwc{0zm61e$hBKSTia9(-Q<>NbnNWgkHFen~*z_7p9~4TO~v@6D1PD3uKi4a@3P zt7P`v1@i0PKP+YCvy?Nv=0KhJhvVca=uMdox%#P4klKQqX3R8|r*bUz;}Dc}o|Kxa z2cn}mSUq^S5r-MoQd&7jI=lO!qlENLRIvSE%?=f3lK{}ZvyZKyA< z!=8BJDcrc82QgL)fEG&OLwm|9A z-cH5Olye^s@ikt^f3KHg5J$xMjCD+7=xfF@e2n{^=r+;a`OSCx$8gSf8_z_$iQm?r z4exx8bJLuI?x%n0$4u=$asTtd2u_!jRPX?F?2nsaj`=pK1TxP%cNnOfjTo{H3+C3oqj_7IvfW* zaIIu~nlH5)A4S9&Zze6ZvI7Vc(8P^L(j{hM6o^qEMuAI>0tsJ&VWFsWha4N^Sep)p zgEA))olKBnE=bbTQ*re&6W83+rJ>=Na)TmM3#c9{RBQ^CPsm&Qo!^j_ABg50iLl>`F!9u>pm!6ERJVX%mU|Uoa#@g zt80?ON17CLrxKxAmBo^mm#ti?r@dg(g%;8WhZU6+sS+i`9jM=og*gtDQn4`wCk(~R zm^In-?X;xPROn>=JHu${QAe+BeOWrb`y+8xmTQ%dLVVWn?bk`%`YWXC=MRc2Jw-CA z%cSXBKbM-6IEa|3kX*>g<}IOKfcU#{RsA_A6no*vKb50>JyJHi8X_Gab^~p|nch^} z)0^Hu>X-)`dAQ!6J*Qlj-*vOBTe%|4*>1shr4u?G#X0o>;Q8ZYPf7dJuS;1~rW7Xm zrF&t4tp3J7%KJa_m+}_Km-S*JMQ-r0;eG`l)Wtv!NN(8A*DVFxKG+}mP9TFyGK-4x zaKo%l=V!_;pR6r0oO2!zmureIROme1gWCcAPRNCw7Yc2_bEctxj;$bUu;L-NVWOla zXF|zXue9|yDmQy_0_ISJ(G4s71cv*hv#(XMy#>mh$Z!mQGQ&+h$4M__-sk0Jo!R(! zvc#s5J4lPRF4Bba+AfHjJ=!hO;UAU4)G?{bBj+gF1Pa7<6)G3QMEg@`dL}135WQf> zA&GaTNODFAINkw3Fi^}~cnYwN2--lo=SY8-_-i+TbGZ=!>NVgvPY2kITW(s9^vA!m zRBwz2Yle7mx|5?eDYFz{d5X$~r*0bejO93}$pkkw8lnZ2u+GTOFTk1xAg{*_285+@ z*;0u6$VivOB$t%TEP>dTOenJ~mL;%1c&JXi5cPHYZMT8joa0}Si3cc^l@*YQ z?v?JIUU5T&S?SCo=Pe@OblRm|H68#isz+XeII%|W_ZAQ2R#zVHGLp7+YNZ`}Y( z|DS#KIUJhoQKh=emR+vmib%hzD(agE;@|`~+pr#Z@~Nk!2<;^&I}?W|5FG@%8p4vc zrVi}4^GUaf?#^%PZtd*%WN}3EWBohhv3B;!S(b;PgYC7@%diDHnyyBDmS9bf{?2w1 zDu<2VJ{dmRyVEY5#tF(xzt#`l^qq&iLpbnh#GKRA2Qe(2?Pv?hlA4o`{7_6;NQ4ah zg~K}IImP#JX`dvF`gPRpsidoY7xCJ3I-%1b0HwiP1LmY>7{(cOCyki_QyhKbo9jKI}$uP?nj3HI#??cu?0mhN|;%KQeI}11Hz>sF+!TOdfT!Hd4aFJs9!BL6=q4G;!@eft&bSp|M zzZVMy*paa593j`$!9R+xVzngs02pD>Z?Av8{K_tHV1bJ@IZ@VJb2&DAx!43^v3lGJ z?lcO;^tm8}IGJG2F^HIX5$|sCmR^a?7}_@$>$>JU8)=*__)zq3{b-o0L~{NM*5 zDkDyIJpD&${rw}7Ru8dT&HF{Z^!M_CzxudjUL+z*&XmqpM9CR(PM>KeP*=Q(z%NQqDKT zOWyJT4o|wV>EdSET-4w1mlrl}17MXY)TMH&<3bV^JEt{%fX0*!8))1u z!Pb4^TW~YR2bLe>h;9&1ObG?u!9~ct_k%;8AOOK9a&%D?!ojv35b2aHJ%LV1P0E(? z?785s=B7NnGd(VH#>M&}FtiyWcIMBo0BDkN%5*p`!i&KIq|}3kGaPeSBg7W^Lx6ir z-q^C(@Izjb36)B``fqB$JG}H?tX8a~YSeo(*3=u%cH%A>M;Sh(SV^~*|wLSn4 zoaIjAJP148^s@aiJ|4cH{+M%nn}LV5JRIlkKF*^<;1=d>0hWnzvcCHQBLLR{660W~ z6E{1l)@^TJzt&9(K>k70IqBtcc_3>W?qoi@)WPfzxlNO zqPvkP0SCO0?p6=59lcljn(L((ob83P7okm%tKBl0*z!+|>15x|+(dh4_=q|F%b9M( zU-&H)Kp&y;Qr9VH>rL&gMn@D5{&F+3!a?kdDloR;PdL`XgY`pd!XN+8mDP~G?1$Ps z@XCYnAef=bpmU)pi;N%!T#6Pw`;r|ik3qa|W*T)Ac(G1p7(^c`dSv})X<yjo$8pvu`LM){|65qmN$0p(clXg;8xz`7HHSg2-WQCckfws#1Yq`LWKRA#|y zB0W_CN6Eqkv*P^6Lx%SDF1^Z6F8^^HkQXdxv4p291-Q5+us#~-)(vr-3vx5D5m00= z9-FwqAh@V{bVHI2WvNt{O77OPX4sL@u*ZVn*ub^lggG}z;OI8#+xw`vivU|_#4$tMSRZV-4-+WE!~T#28dW1at%8p;3H&&u2iaB=|*SifeC%$_$_ zHg8xf`+oFO0O`q+{>;nr>}xwD9zbsD-eXd*dV%yGJ0k9TzAA6O>jRR7YqgXUKOM)y ziIq({QCtau3c?V`z^fpr_qFOr$IG$c=tKHr`t|Zx!#Mt>S;nP0}>8N=owBf5de+l3~4v9U7gLe z5WSL=?et8?dG4*T$5utC70|;CX@8KnJ|+ce@epTmx?npZ)%xbVf&Y}}{wA0Q&So8- zv$)tc0a%U%AX~ro1tbHJ2Ni1puI4M?siI@fM_q-|P(|!$A0z#30D2+UTg6Wqu$?qu zKVp9h_#x*A@BALXJKHS*qaXm;;21$t*mF%33Zv^4yc7K9IOgw%NHDXE(fDYucJz;T zuBRxk+i;o!lm{To14oX30n8UP@ep$|mIQ9^!ex?Nh;>&R#Eb2ERMO_&tOtxEg9A8J z!d#8R#zb&`Qw#><;TSc9G?d#EPo${vg@5>|{l(ar@oH4kJelGj?N)G?qBsfa(~Lrq z?RXOk%)SP18oL&j(bAH6$GDFLWB;H>n!B?k1Gg9|GDalH4^HRST}T6Sa(aol3m1Wj zA{8_-w-;GIaMU;$Gow|`Zc5ljz33nO#DTGZ?>v0w{7Qw%kQAc8b`oglqHZq$k@Umz z#Zg=s-qkP-8vD%yAG`DqvW)5xo0wbIXOfW$Tt2IdBlN`maR3;n(jE zC@4M(@iK!D*~bv10fBd~-ZsWN+Yb*2kUZ@@h>OPfM+m*q!7_)|-6;PU+D0no4({dH zo>-U0D78cHCV%{}ww%wbv2Ww;tgZDG32SYf{%Lpocf{vJcN;sOaX7>Yv>uef=53Nv z&OQ&ZhYqG48_TIYC+5MVdwfXi&*pc~E^c-uH{K|Q#N8Gjm zoukv(#$?kv*|+rrQ|5mv*6$o^Y`a%a z^vLFi_QkLf<9KHup#y&SX8k$SH7SPtsJ}=|nvQ;It{e{L)y5a`;z;{A-!|3b9AXwR z3dAT7qrkMJz$F8?JE_lMoRbd+cybid;NTStDJbO1amjv8wg3$2#s#iUF9^iRh~bW( zlr)Nq{)go~6R_f4pBIo6-!!g@%PPH&+DW8yg#>wH2I6SlCrm6hVv; zIML4*ce^cRXkj>tbh#PxmaUMXjzSrz-y*^8qvD;p92@2obX=^YY0!VU(bR9ePqMN# z{-^P;E>%JM=Eg=D+4_dW<0`uJ_KW|rN?EgREtGh!&m)R|?+wPN`YCM4tcc z?uxJ@JM-bKkEe;eB^Xptnbk)PfW7 zz(MJR$O8Y%+azK8euyo}lFYmessF$KPaZEXlRMt^PHZ3z@O!T7likgT0U4ET+xAIW zS)q!VnyRwU(+1p8PSr~Q5fSl}1FhVGnEPRWD#p@h7+j@VQ78{#b*=@xkkvdm;ulxE zS4Gd5_~2pE8ijLc45GL#>b*GCgNIYeuhS3n$Z;460+^Y&p?3N_y>}ZwfgisgU=c)Y zSbCjajD~Vtld*P+GK?(tK`zx`af(%Tf~0YHm0kqV1+PNcArD`G<`Y~yvq(>nR?PaO z6wrYI2loJ%c~dSCoYS6}%e3ApLPpJbt{Y8G!AlD&u`eHQ2#T}q^N;PFPp&N#IMqmO zxKKQ>v!jjeAMBTWXW!wU>8B!U(mA_C$ z#*C3u9YDA_1PL8pFb39-B_^U*N^2VW6S9bmby_rJg!3%tQq~m@G-$8&#Vo_l(wv`+ zB<$vRXV{5#g^Gh;!aN{EP~cp~0Xh&FeT*^7oZ+?L0c&N9qO!?;r88N{mV$@CJhjMxv57zx29P(Iy z#ut9of_;H6_zQhIUSP%X$ogSOrh-3M@}HVe!s-upAs^P8dNFAj@6KOquTf|^PS@Cb zi~=zV#3*oSQ(*im;1VjU9o+5HOdjL}hXNe1{?ne~FxtQs&a3<$uM5`++Bd;K(cBc7Gh#(#x>n0dSn;(`(}K09fL1U0ip8X9H+K znbmNGd65{qF$-cd)^O;MBp!ltRLK79e|)p#ee*L?U0JEutnFr>SERXtUpjk^WP$Vf zK3s1fyzdc7tezq`KIaw z`8-+c;l?@}8^0^>dWX0_`aZe-npKhlkpzt&`E%L)-j7KBvPv2F-Q)5+$=^mMbCr{7T(^SHk7+FeE80E!=K0XDCGZj#qJiTbH;kb}BsX>FGD)Cx9CRibvefQ^Prnzz*x5B12p`Wjc?+;!LBCg`YA7(2lfT!P$M}Wu2pW zNInLxX^zDauye{0pHYDDXn{U$+I#f2VfvF1A45*`WPn-Zf*l07%6>r+CN6+mR_u)J zE1Ee(%<+&nIoRI`xRMK-V}WyiWf*?jzljA4$BFn<{0X?YsW>zNBCZkuj(gIwG|oUz zn~d}{K-uUf@#I#CH@6(?G;}O*?^AxZ;Tp%@KnqMTJ5**%3?$5P4Y|QBxLoB1ZtWeG zfnbvK47ea-rWbOWd$2D8Sjswu|2T56HdtrMOsBi9bYP-x4sHW~Fkgxdyr)x{DI+48}GKDhJHbG(Tb7kxyt zKi-aQY5xMTtMX!PR*MTMeV=#%rV?nsl=)-~w0Z!U-v0mRQJ%#rHqQpw6p$3pq^ zH?GmrKUa2~D0x8O!}Y_G;(VQi?PPqe(u~D>2~&XUEdoPWAdd$7B@vvn*d1wsxv4mI ztV5ccJ9Lv+Qj)JC6Uae)`irGgpru(2s_aL~Urm{{8XKNETnlfOAt*^48-mhjh$R@M z_z-Yx4&ffF2Oq1r|$4xA~OnQ6z3!&7PV%r9>+@yYrmS3bvlu9ptgHptA90swgcwQ;C& zwhWre*)fa=ZHHi95=2!5I}eKs%Dyj_G5hQkavH^g_HXnm?7~gC7D=6Z6WYJwX1-8h zdzgA`bL^le7#%qVQO{FnSFhC9AC(0Q7C;xn%c_`kCX{9d1|XXohx^;16RH%q#C$23 zb5(Xb=TF1Y?uKZGXP?^$F7cqeb;CN9)vYq$IX2Q)c#PyYLHW^`ldU~R8+g+BnBy8l zz`rV$gx5H-gf3tVL?JZI^kaITGkRB8h3m=npd_ z0b&7J+_18c~_pcw?pq4OonJtED$^#ITllm`6Ez1XYYolvFt!LO;?~DK*oHDIVAo`&LJ&cQm77EI;E{8al z1AKQU0Z>L+D7Rk$TU}>{(qXx@-Zbc&@CS4N4dT7oG6E&mV_1jt7RLE9oSx7WRWWKi z#O251c0v-scFO+m1J`{#_WMa#BT>G;T_>MP-n40i>ejRqwTTjx?T3c$wk<`oqo0Vq zeT&%9-9p|bF5?Hk$Oq-0_u(chcV}+M`uBoKgIhIi@+O0ks1TennLfwhHt$@gG1f@x zjC-OPXA^QaA?RYlkMrY*AeSVa6sW}W8w0*K}?Q*>~I2}NDQ??P6qutx< zhoT<8a_diryq~Lv9gFw$DZr%@H-J9DAfz03QCaTbR3oPp6^udV`(V=>(pU4Sq*Shx1aF3Ny+&I=M$LCY~(#3Ubt4U;1-ly=mx=gSfmr1IN4I;001>+E@@(!XVou!n^3*XLbC3t^j`+@xX-2=2Njwq7rN}C{TPtU0tJ4R|l2M@7`038x&O<|73AqFgJ|TNg2fw z1kf`Ag_8-Kzb=Mx`+^bV{3lFNC_MNGb~UN|X78*G|DV0@0F3K6&K>}V-g_Y`3)o4q zh!Rz-E?IJyCEIeh;~J;59k=a0K%Cvg(Dxa4;dTeh0j8!3t+#R3-e z-VZq7Q2y_my}f()@D4bDAPI`MRQc)8el895b$Y<`g)jac`hUKB`AdH%8PNS601f`hPk$zrZ8uxXZY}hiWoBc)1bBqWgrut zMdR2EG7N$ZJ{Sm11xIlPX(~zzRnW#iG9tga=hyOzSH4mT%WLFo-~GO1z2a7BtXwYx z&CkkY_aS9|rWMrU21vQy22_?d#|1fbA;+SV(amFn6dVATK$3o79D3m=)1`f|1S&b( zVb21LdjSI;#xSR`cM8I=XUce|WCeRAJ7rX|Gr`P+zV@WdYDt2yMoI?sv*U1L7R*i4 z{+tWU!M>qUq*W{c@e+FKi#gFdoSp)UZREkK#L0SbD_9Za@g zuqzOp;o2NGJJ4_SK%8xH793HIA;V!OeK5a3sdlO<^TFm6nf)|~Ix^5Lxy9wMcaWiD z%l5-X6(`iTQJriK0QODob>YAEi&5EwBhLA5eT|>92RX+9)AQCUrQ62?xYdX692i|r z#W>S_Kfc3h0ZP9JlE_iV(uIE3D;ySy5l%-hL}v;*JCw|ti1dRY1Y~32)#dE^$;Jo` zH^hQZ(>PoLgqI@d>1E#lNa{+ZSDKH|) zjq?nc*_3Le#8+!;xAv`7V8|5Y=VBAWtHtNAkA?D5-R?vfzR4h`G&(nTzU=E{oCa2p z{*PoeTm$K@O2c#y#f{*Y3qA8?HgR~T?o%E%j1Nno^N>v8nl=}bDLLgZ?zLHbnJ}sd zTqpt}fX?k3P|aeWJaJNH{`zjFkQ=VQPS(~psLp=g?$Co1jtBhCm9xxRKlFPa zJ=(0d#8#~;QzkQM2E)l*itX6*%s^yZ{%kwNP7@uXxC65t3XYWq5FQ~e2Nt;LTnZrD z1VPlDhEvJJGxc10sVuI^1aHO-J*vgK>dNg>T3VzB9v0Wc2m3kkI5;!{rW~%CYyQ!A zvtLY?mgWP4a8iyPYnAfyLcMOEmz$*<`T|JKS5}sS32ERmKJ!>k^*FXHXY@pwsH%bo zt;y-RVEDF4O4TM@0W@Rhj9@1c$A3aWXBGbp5L;0Bl63Zw)RdOfSs1zm+l5!GJ9v_;fEfU zFa4h{Nnc;Dy!zFzk(a&nCb<{V^_zeH_ara7T&6|`WNN5Q0$tDJX4|u1x>w>*3KHj# zKu!W9ROu4hjZWzuo}}2>Frr$XKP{tBB{S^Llh*Dr$(S0KVmTpYX~QxV7(!cPeN+I$ zt~slesV`7#b}@2x}msfee}yBK7!YlnCxgQ;f4u&SR!LPHJxGG2Z}&CAil z5Ur1+PGQiYVnluOBLv^m-<>8L2`{#g?(~df!)*Nd;@B{o#(q2D&`-np2OrKjHV=>Z zI!EB}dj^LTGdu{#ArdBNw3iD&2yD3A&R`qn0pFIxb{lH+!C8oO4vTb+pqPM@3T8X+ zY$PT5q_6b|G#KHQXW=I8FHGm`f6l5b$Gel|?uKU=)~0gKD%v_3Bs0XK-n?6X(~Cv? z5TGHRDVRZHsjQFw!hj6)2+H|wVTJ1N#JA>X{unqR4R}6izfSi(mV+ zFcfO|!=$lsLOCWL2@E7Kkifu;3Ii`T9!p$}!_B`=Qn>0^oS!9^G?vJ^YUnS<)o;48 zGN{mi(*;9hrc%F^`iGMh8J{#(w+>g!+uD1yK4ikP9toGgKztZLUqN4@B+B$ypKi#o zqeN2np(JSmlV@~vT#cmG)>f*zf%DbBbb)5aCmEG`O9j@Eu))i!-Gz<*F7Y4#6*iei z^=i8=5S?Rz^$IcSd8m+-njy20A{%SjC;nr<1iUH9UU!53h&%t$U#ecKi>fQ2RQ&lkOkkOrZ%uWDY~S9fH>{p|`mh{tYEcPn8dtV7g3s^|Ce z(oU4d=A5Ntdoc~d4h;N|PLbKiJfgRLivhO0acRV?zaPvg^u0yb%TW~8iETd)DfFfj zttx%~lB;*#`#02HPHornK)7 z9BR><4?2gzKjF?Y28d&J3OxNMABH-U8p$ZbZHN^m+3v&vWkcbdU4vBs4Qe`ZLe{KV zqmt=V(MB5g!4LkSJOt+U@nc6}_bCTALi~~rY1vT#%|J507_$EQH@+!X?A+$=dRKmX7F zhr%Su*T4RCx#ymH7NJDpqCA|PtzzE%M8;dGxS~k zwY}I-CY*Ht#cj&I6x$v*XzZU(Kib zk%et*tRA6Gs#`I{OU61Nh(qMSByS8QsVW(+8N>AorDigoaam`;*l~hDN1iqgJJsjdn!7xUPQy(Jz3(q?oEikcNxSENsT7Dl4QDWq#?NOCKsxoa2XE2Zu%Pb$ha0!gf2{>Ohv>UaJ{d^g=J0*37n`f8xGK+61+ zQh2&w_WkECq!H>43c%2zWIUMx=fiQ{p*op#NZpsAe8ok1IFuWMwDd5TLj%%uyiHbB zmqNFD9fziIc;RMzYPb`UmrXbv+oKZIOD{j>blyDS_+LSNnTOz{l_9dU^y-CDa-33S z+$dDX(OwIgOm=Rk^e~NC2e6)@d*smrs@HvWLzObl!?+K@;y2SXJ`Dkm!5%UR=o+MpB{Q~1Ud zd<1G+YHMrdO>caoeCu1^mOuT|PeOI0F;aL8%<}g3HjE1>jE394f1ezMbbKnL$Nm0M zm4sgfCiuSn`{lZ8ua&~0V(IGakgIWMdLwS86&064lKw9F#y7u-TZDsHW$30|&Y{YzHCfHfrxr~ARM^I$M7&C{L!zJb zhHFFKDB%rAgQd`4#Ua)dA)=!X6Qt-?xI`43or5)reyg|UYu?yINX$Oubk1)VY#U9z zEnw^E^$fu>QA5By;*k#WK)4P!q`60&gesXp_i>r*%avrR71F-NZ8c$F9m<0T_Wuxe zJV3svy^>X+1?pRHm_yts8sce>IIzMd;}HkDYzL&;`QvsZ4W0~Rzw&_zJ&8lH!03>a zuf+{j*f63{%GtVU6V>0mXbZ{}<(R;uyLotplW{EY0NfA5uVlJ&O^}PVKmB=Y$BAAY zH_XBdpu`=*XAAebiBk)89T(0e8E??y)*yt z{)XTk^>)Ww5O5+w0s{#QTof2^k&0!h^F_&UC+0|uNo-RvSy4Kyvu8+n^;@u^oZw_O zHX)Ue66aNI#Jv@5?Z0vNEGWlV}J|e z85q9e!h|YXxM@iCB|{RcSB4TRYNM~6`9l)wH9v=P^ z_e%Ea>kzL>4<^pm;@#%$_2ji&>T_LNT_daB`A#7rS0kCBy1Ubm85>0WVqAfL%^!R~ z+FpN$)KylUvDB?QpOx}WS~uT>Nk*up>ntc$< z@Yv%AanPF$W8-;X{**w{Iu}f$3Rw-E?oE(%Z*A)Z-7u2pie98m!gp}I7t(Lzkb;9+ z10ICU+iLSQ3=UEzaF3ifRlvwMu;z<@_QQyOGO2msO_eVFIDjaDN`j@R;3BTc=xN8A zgv{=(Ti2@U3UqUI%!}inw+X7D&gZempThwNZtxZ7Ya2B;cj5qKNR6sS1PG|BIz?&t z{{2T}@7`_7Y$qJ6iVoR^%8N6f{voKoXwtUbvSm$p{2=R<=TNArp-wOei=bKtI{nG` zT8ZUcd6-*riO76S#x1c47&8y{z98A_Z^La9!`Q}zx@5S^mXMtp{hf^FvF4{_YVd@l zm2M@$^vr^D2-Uq(h7NjRVH@ z^2j5P;P%lZq~x>ZBOm^ds+{@EXZ}py^rkmSeM7x6%TrJ$oZe%+rYVhN{Nf@=q=S(T zF>!^-xhVzXpPiTo#XMlOvtu~q z%_xyz&kHisdmK2;fPVa3tebHl!Y6dub4)1XJp$$;dBYr!enYjCSZo_?vac_bgC--` zx)C|mkGTowTS)myKrnxczdb zb*EsMm!C6@eJ4E5*_3V%f=4li`pkk(;N}_B4;txq!ZP{V@nTaupRvMBxg8~fheA_2 zKnQco%5aMxjfOu?_|A7{8N%<(1N15$$Fa{JVcI9(oxBaclSa0-wt^l`Vog&E;lt-; z!-n;^6^O$hrJW`X3WAaRyu=XaSm|i%X0GD(t>!(orsgb zKmr2^3~&W^(K<`0xzODN26b~w7bI5FRp%+0?_*%Tlc*@=i!$lJFz zVzM|cot=Hs*jT3F zkF99Og%Yl^r$8TT&W2kd>HaX7?hmML-|4X)Wv(ZuK{5mqd1Sa7L#bHEQSyC?tH9_* z;B0U_!gOx}(_JOqtBj;O5uwqe)0{2*FcXMxfEnZ_Jxgfnsr{|+{mhRg)jL(Jl`CdSCGnkGI!E;T=<;lPMdnwrk-P4$ZdYW5h zPvVP+RsV^;;i6HcsvmR_`z?wo^v#w{u z0c8rC^WrfW*<81_8ajxJ<<#j8IdtfhZlKD`i@=1+k&e!Om3k+BwM-_lG9hL#4pYFG z=lD}SuMP%Ryya%kXEiC!oa{5>*)WgJPTk`zmyO3Z7=m4ukzqg7wG>+KML$_b!XoqB zs`KIonCPUsm|?)@TBW;ZKy}7%-`1$(orGz4#IOFBg5eKtnaLZlNDp`;E)zHVPC!k~ zmMv@bMj!hT#|7K>G}@Gg*=YM_&z{YyN16bbcI7!BgY*!GrBg%Al3uYDI0KUv49)X# zFuL;abCya(W;;|lP5B2U(EO-m)LtPz=+R&5m_AFT1f5BdiLS#k?eB&3{Y`oUjuP5t z?zXvdCWZcTFv+Rz#kxt%wMHG;ti1m9cgjaT`f=z|KP7K@%bRh7ry30L6jkez30=xT zsCr0+G%cC$Bu-?wa*V#}Rj-!HiV866e=L9a!4G0AH>>KJox66!`0;bfz|YIigOvM# zGPKc|F{abOJZi)E9+CWlB1q4}J`GgZkl8(MbvT3Z-vt$9(^!*bVZAd5RWQ8mMx)1M z#6_Hg8HReZT&!(!8udRLcA8R6MS;PCp)r5~#-)uxre!j?=%f*h&!=&GDg^zEhKcx^ zTO^82Wzw3IOhY;s25AF5o|@hn(UH9=MWig@yglHUdbtA}z%jU|P$ND}rGql!MGyT)P$f8v7fx#ymj_Kr@u>kY5N&7tqg-Jkk|GTbc;8;^0* z^}xd9Z~Y_Xnp-bt7}F}?M41<0y+}uIKlA_(==i9stAJER#)TmrO{P1qJAxavOH zcTA<;eb8$fmSV?P;l`U|M%Rm8i$=nN8kzLc23-hKy-ZfawU7|2Q3*-v0hdN!*MxTvMn!L52|~>^c@@= zRq1!?7O$)5u7>HEHSYEl(^%p0lJ40M8S8~!~8{t^k!8VH-kfT<07<&)!~hZI;f9%@WJ1LsXC$RSxSnF@q`*I7=tY< zEtU7b|NZjm&wK`BDJTsM4RRf5^k4neUrPm4wvpNW&Ud~Ohglf&n2$zB{qmjfdSa=0fCW0 z{D5{^DReK&$@Iq9Wdu(ark!i;JnN?A%tmpF5^I(~ulWw4o*B|Ho_RBWnH4;&pUv6k z%SfRpCjNYX5z$QpwA@Hz;m?=cghg_rDlSU6(*@DiG@8rXl$?X|Jm8-z6W^rX_}B;qF25u)KlN;KC$k_W^1YZ-uXR9wukDrD$s#yM_)piRc1 zMy9B`UVJ!=Qk6$4MIC=@o6^LNKevpL@|!nj4ClK$UMRL5D0YxIqdAJf@ji-mAcbr) zpfZOx8`LqKM_MLz<{kzWehEbg$!zD38%wInAj9CX#}4WymVSkWxv~`! zU^!qc*bVDq5q_@XbCTgC#d7j$IqOB;ule~<5dwcs+Fq04xhh{GpB0D!^b1M{QlGiZ zj7du78eOQd4^hgIdVUKFbD*-I9ECp@_f~WK?Xz!k>nm>}DJJ z=!(>P(HK<lQnXHGcfy<1NODh-Yb=voK`x(%=3V=EfPjKEvJqPB>@lo$b%&n8t?i!G|A~ ziO+pQN-w`e+C~QD@~?eCuDkL|@nL=na-#~Dis#KY-Y7$V^AQ>P{m)C!_kSw?(%B`M z*jSDa4nbW~o1`?<$Q$1G9;tw?;4?MWshPU|5Kk;~Z{Hx)$mD`aL}^ZAz$*juO+EC0 z&(<2FWt@BHh-1YsD~!5Qyhel7lwmIRCp-as)oa!g*%;k0F9K?eBHuph|mQ9b!o<3k2H!^vnTL!I#1pSejTqn?KzJQSg% zdm-WngOpBZL!jS*Hu5IIjved6W5DkpSL4{cwZOFx*GE>O{d|lOE$AZt1P4xo9#s?PKKH(tOEia2gH|O zBfjiHl}6US?CKjFGc=OAx}iZC-_PvZCwnft96HwDpiFWy*hy1&@7y8Z|F?ftL7X6T zRKM)jTjVk@fQF&#Js-N&GayyFXU}dOW@N0t{&jb17}XY3ty%@6rX5gsP$#d$VJTI@ zy!w@|z+o51W>DV!uHON}9QvohIAnPUd)LlOl!ns4DjB+D_`dyZZ;mn~M&F}zb_9okA%^+y2n@Y?C1!o*#H5cc(40U7nKYE}r;0CrPlDD?qfd|t zuk{a=hc|1|tG0^&DC}x7hb285YVC?~6IX9$xO?-`im)tDw13!s7Ac3;fnoX* z@ejYDUZe$MP#ZN4y1=oQ4O&7~eN^vc`(`9Q-fV$mzzlWOP&`D^_;@kISe zkLMU>HOR!ygwgSr`o;ESy-9Qb{_nq{d6MD%SD*i)eDuSAAZypImCt?dZ{?luc#E!q z{u1y1_sd@p8j-ca0eq%m?ey#4+>1lhhvbcKe1rVcKYb4d=Zmo(tAb6A@5-0H^m)1O zz6a!+-~K20{SUlXo_+R!yzhPQhM-vw)amuZko+F`f4}%|sj94$4}IiMU?j$(4dwap+Vxz4VBWjbE5 zce^fjxsi1*I78r;^}z{eDfuuBlB(Odu|bB0M&-$;o`-(-1{@k>E_&0ytd&XtTX`7J z#g-|Sm0l&YvZrTQ+S+=!UsYyN9+)#L{lLkMTpd4LlyYf^ML)!C@am|rJHdS499K|P zlMdadDVg~)(S20LPCuf$D$`29c+aa)X*zDrRCgyBTAq&ilNmt7@)ugHT890S%jcQd z#p-F)#TZ&>4jL&1|!yj)F9jXb-iLfU(}<(hAQS+2V5GD*T_ zA;?WfsJ~KbJs;9I*SzdD`RDt7D-{P%%EZ^cFQd)JWD@_V&3Ecu@01}JIj$_mEftqL z(|R&JnG2M#I(@oRb++f{o6Q&T%z2UYfeeW>Y6NCje`=vX8U%;)V1gD*3_+n|G;40okROMpeDH;t82vYprF$ta(Mny*8L zPRiw%Zv}HaUB8vig%D0`v%jy0+Jo`Hq#lfLgGdz@?08f^MEXv(F+3{R;GSIxq^AA>EQ$cLj=T`r3*v_k~ki;FO^upY6V$cIfFBBJ(H=T-CtI;#1Y8tIW>UlZuWm}J&pqx3?@phrH2hQVeF zB*gE$;|{3FIt_;Eq+~-^GMVjkEbBDZ0J%8eA~R=-V+2pyXecW!)OC@k@?J^JtAzTrVr9DP`WkTDSvZU2d}p4{Z@$yH z(;Hv&cfL3_%)+qWPI&Zlf7|#bhv>g<7D;ib zzbym5d3KNUBWWE@Ql0HApy>|?W!vG=b>amK|5Pce!7UJsOH&IA#e7-VrUd3MW4Qfo zD*EfY^-=?keuE*4k(M%q=U#OK+<06G`?3Z+EQt@WBQS8>fP(BTUPPZre3PFVTTOJ0JrZ;%@66Rs>YX@C%*d2u&LjS4gD!xA>J?24rW$vIhcQykfbZdm0EM< zlZ;+npoa41hKwq0rYFE43XDK+J`OdYgF3wowinW1Xp54WOBwV_t<#Gj9ceB%BC0kA z^&$Gmu%I8qjDE%xU8s|$I%%|}x91BDvnc1z&0D1B?>{dEIXQ9#Bx+{BOr1hGEwi0v zW0|>)938@@qODVsN?@1`*Q*D2Zj-V*UnQF%{nNO1ofJX`F_}TmIx>A^J~7)7cR1rL z+>o(PO0&jxQS5~;*p0O)YDFeI59>)O3#z|J`6qaJV>WX zFp%)DBVO4SR0BqR`z0j>QUld7RQq!r-?@;8r__9!!ZdLykxTV+Tput$WOD&Hv^frN zf+;ds;;Xa@dYz&*PCSr)g zS=fwY-=kk0k)vM`o$Zv)n*~Ta#oI)n@646oN#r#1KP237Dk5pP`8Zv&Q6^fSf-0k% z(8YPsX>bt@Sd)dlOzFd)1Q~YD_pqnyWxhD>F!wh>x%~{*-M*1b-68gyHj;caTpfhr zRCEYk%Y^!{S3VY^P0w$(5Jv`|?Zd!1ru$TkcYZ46?F0~nJZQ)AOa4sTT|z0nxxC&+_o?!5E08uyR>_-@24 zln;F1eK^E1_M51Zj{+i@fdmHP#Xy4L z?tv-05#|Op2TbaMk`g&oTrMvhI3Q_Ly{bc%8{Vy3*69L*AUJ1`&~sAc&q`6+g(qhe zulbFs+>WrAj*|v|lwM(4!sVjcx>%E%4YyCG)yW4hmt3*|SEY^!^|@Ys)ee=^=cYPd zSQcjD`C`QY7eDO3=zCbS(GVXGnaJoNQ>Iw;5L041jup~MMNzy1aiQ`9jxuy0u|p{y zUKvg+T?1*lZV3)|80I?{f0;!pdCP0;H0C!m4&z$mgOJD_QZ*PHn@pdaQHZpi5*#=I zV}IMhz^EnFP{zI%Wx2||P`xhjaMDRK)-4^6&|p(BT|fipZkp$gcP`PuvQW}E8RfbK zssOktC9|F5&dF?N8EGhM9Fmq#J@BC9JbGLv>WXCMjjxc`K)t}a`g&}{%mEK|4LkMs zYCi*B$Oz!*rCw8uCx)>M76%qL+@x^MAx`P6KmGWlijn}Nra2#S17gD&*TUp`lnarL zaCb)DNEj6*?hnqpS{clXWQdVz7xL1V74e5s|I@09js{9car1zTad<7-v8u$Y^M(cw zKPsR{pQ;V!LnYg*3N+jYM$vNzkHcVN7j9IPK}8sCyMQ4AM6#TWN0^Q4YViyiV_Rzb zEV_nEOrRCVyahWP!NF6KS^(M!>0&*!TlvAEC|(v_!`~+aX>TimQxv zq?sIQ$IXO3w4G7;!p7y9zfQ z_NodQGXBi%vG@+$S)WPVY_&AaKA9yQzny;WZyQG=J@JSn3$H@t!Qpy=_AjSU6xJv(t+7LN*yoM8oQVOM?s) z>u=M$^DfQ)tOW=I!yc}W_IBgoIYr9XZ9)cEKiR{ksJs@RZ*(=?>7C!s z_vlpde3_o$-5)SAQKMP$kKwis)?^ft%Y`}_UOM9%k$o;MCOZq_Js^P4P$>~^$7-b9 zCXoL87t?7u=7ux11#i>N3&%!sJj=_<HD zpQN#AnB2G5!DwpACOPobeo343!w6}UG9Rm}E0n3h#V&QJQHq5|N-4ocDKWbU_G0qb z1%oBrW?c|j%uy=6wY3XUY0WrY&5>=})+tODnQ1wJ(Ao6*5#tZza3f8(1$yW^I(l)1 z%CA!I+*I2|WQ^nq?~4foTvUN^l{6a^sz4yqoq9s+pl*PDWwH8)U(~1ruGCRlT^W8* zqXAVj{LR3?>h#!vGT$e=56i?1^)7;#q-3fjpf8^)Y4RYIn`2bakU<0(lYNksZ+lve zyJb{eBEB3LEyN~TrT#R(xeMA04#!cOAe7$XahWPYMl$K0rLj)1mJT}o`0f?g9p`L* zD~$$TXjF`wD9%A{+RiejfEjxF)Jf@sI+-+qg!?<+BiFtD4RZR0qjKQUCm{U=BYKej zx#EhwV7^lia6sn@>i;IQ{l`D~nOw2=GF+prm(h_?HLgdM2bR&wJUL&{@tt|vZ}r3< zZa&JP6TGi?5C*7D>D*-E&fk>UCMaJrcg!3MaMp0K)>nNN`3G=jr(l!~lCefz)RG}B zGUNE7vuoQDZQ8h6aq2#th!0XEma|_Fr=-oK%kxRJG9IPdX^Vr5|Cd}{8J1$VYY8-p zZsJ+qlPBBN(0Vb{WLRC&krJ%DH%hlp`TJ!SH-=IRs?Z-I!U-#{v=@Gfloml+e4-yx zK7a%0K^!{gVg759l&n&{>E+8UL4Sl@ z6f*R&CgCCBc-sNA@sKj#b!4GmlL4;=P(cGya>}8`V>jka+%EIc5FQT%c$dzygnb`rC+A1)R&)9mh(G!#5C3@Z<3ILG zNrIgN+7Tin{-SW0pOe#Y^JT0X=p#*D{Q4Ezl4K0%Y9Ge(8SjLkEsy?@f_?Wi3>%O1 zc1mGY9q0wtewNvO4iOxodnQwR5D+PXcaMsMd%tmvQ0-(8bsB|=D6S22pi(ds67HIZ zV+?ph2>H(Gn~vC8G}OQ|4rvMFvWEKNNErP(e`qMKHk^WsP8{RQmZ_nk9-0Ss%b)-6 z&tdIyrF`LwUy(0<;V)qDeZBnb=f9A9?)i-};lKEI-;z)M$;WifLVgTMNI#_GxhHt? ziKpaO_uMOY-E}9_@Vy{+z2Q!+6IIpFXzJVE_9pqWKmVLOyZ->jG}L&ls!*IzaK#S^ zdh5pV9t^1$vwn$Z0s{#QBrq@^22wr^#|R`KJVDh{`}tB_Bw?I5Na*>Sp%euc^5w-a zP=YH*?YPFzlhCTFQW)LHM;yaAXlw75XP!AMhhI1)ot?eVnLdKeEmjGDk&bKGmiewI zgdZmW`f(#n$GnJtP7s})J+g2A5qbX53Dv#cH!!UEF&?k-bAv&tG)~6+*-44vu^i*r z_*4VX*Egin`jl|9<%kDPEcglk7Xb#?`5=)p4JmCdRt~p}$?(9CO1E2PQM~=_MSzX? ztAMe^ajt_GOmnRGvB^pSLp@)aKWRmEkaCA{)snSfB&?IPLP+s}nUDg8g3pvRFS@swsB)@HpkKME#0&6&Q~8-8jb4mY0KoUJ^R%ok31?TKK*Bs{0AS9H-6;9 zl8x)rpZ)A#$nCGaT^br1e)ArVbI;N$Wi zKlzEQUcCkf#My|G2Bt0WgXxIxboQo}EsuRNjJPT;&R1igxw)At!OgkM9mm##QrSjg z9#Yh3C&rx~IHk4^%%KvQ7SZj(d=_%-M?Bb?>N_E66FFkrP8>G zJ9_lA8ZW1gbmGKWXZAZfr{8>eGCtdZ((Q*2pTc@14^m%XOorOQnU*l=&s%c^1-UB4 zPA0wW>kPLjGtXHS9N?OSYZW>c&&F}WUJ38)2NT`Lw18C0MH;+f3%e2!b|z&&N1(*` zy2#FOHjl0gqNAAc z8)us_n*A9t?h?C!&;RY6+W3-&4h@c|KnjIWYG7A`y7;*-jMUfQQ|k#va|+a|@W#bN z%cJOy&;g$hl^8rE)^bPUdZoW${eWU!-$LEn6mFfQ7S!PzYcVwVV(LU`<(9!D8JVE& zcD4b2BqKP4n}p>21XMB=RMhA?$Fu?SIJf`Yy@|O;JNI{VXsj>diE}&|zQg`eFyE7; zFfUiK!62rwREE#%7(QRyrm;PJ}dk z^um!-a=N(_S2FCt3UorceSrpcF1)b$nuS!mIxsq^ z@13-PO!HYtMS=aPTLKf#g(??qU_?&g8as?_W!3DGslqx5bR3Y8!@mGCVFz^3)*}w+ z2jMvLQXuE@59{HTA8QqHT&AnzgG_e(=%{0N3Jet1lR9;+{$2v*!2>0f6jz8#ypYba z&Q92jOZe7T^CC`|2VgM0MUgRf$Ax?B4GQCvjOLa+w96j=aTnXLnm+rYtlMrA3_>bSw@%q@~k7M2lKwtN9*|TR4ZeaPb87Y)! z4?GJd{bywuy5Mhv0apL0AND;S#=JBxJ9bB2}iRItBtZ(`ZR-6a$yJQUaC`A`Sdbl%{a8tumXv_^I3^H9*JThq~rO0#3(ooxkXdk~EJ zKuxmq_IW^p`I5T#eL1j;g84yjd$m3-6CDR3!Ooitb&^@L6U=^Wia^UF z&g8?ngEwZv6w3^>NVJRM&EkBql{Ia|v7EX^ zivDBEMBjPnn@wc$VFe;?sS@xJ2$44yfvUOeA!-oxI#Rbtyzm>#kABI%oweph8Eg8r z24z%I(j9YGs7^|Q5fYwl=LH&uzOr9Xx1_Xej9-jPu5IzIW7l+ndCRVN#&WJ7+GzS9 zV63WSkb-?Cg>(eB_qvWBl>7?Z7Nw*+))?$_FCND=EDy@3A>HoRIV}TwvurSimBz)Y ztD?XI5A<@WVIuswIEx-T;r{4CY&e#dLxD%d2#1G!O|kG-Uu@K<59=BAG&q<6FC|rW z?b;a?#*d8~Ht5e8K#BF@V&l`;xGo&DYv&HU^Jg5H?CaL8)sK5&H1&xmpH|8D#~yoJ zI=i}+$)1HcYu2pRIP7~gN=;{JmwqJvBruS`Kmr5vU?9P8p9eY4AUm&-*-fc+8X%?g zIVIU!T06nC@aqJ~tJ?Lol`;kfM^Dcn7#=}fZ3@bfBd3+YURanXYgX5&-vbXm4W{~p z?A)oHPg?}pUY>p?TOKaa0 zjD-cI2+S7V=5Xo_zKGDW^r~8-K?r2BhYs3wv57G6MQmvCOU40y+@NKzy;dgsnPh~tlI;|1R2s`9y?dA&ioczYHj>QB;u_eNE$^J>Y+um)(dc)WzkhP7=tuq2lWBL z;Wp^%g@IUJ^`}G(Bp7Mzk~-|EVuy9k%*M?j&?mZSNa0Rmvz83zd?Y^&(m&zlI`ZK) z?OEt9$JGIiJHxBq%7kQ879<>7(>nhUHW}{J1DcUR9otaRvBIv6vW%1xUtL=#?|#pF zBm-^0O)QN)J@fR_^3$LGM0_a!{m}3Jmbbhahr*fin_vG%jctA4ci%60x%u+Bzy52e z3aN(F&pNr`h8ti=3fF1@_fJ0gN%_p(cjIua4kz^kz`NPJQlB^RqAEHRg$9SbWkm_I zLNI1|P)tLd&i3IPW*y5M-ki`MAoOM!@(l)Xg9Ck?SH-oBY%}qIhW!k2Gzrsa`yqnD z#uMqtY@Ovs8TS5PvLZ)J?^kEOHU_Wa(|-n1muxGp4{GZwRBE2L_9(^4 zLwPdzSDI5}sW6aTVs@zW1UMh&FWVTd$11Yr~0 zRvA0_AZU4kkx2J<;#OC!WUktxbD0_cs5|-(50O)0NHVi}yD}UNlbk~xEvScQ7}l5* zGFNSr^wM=;yq^H04hF@G>k*DI0mH1M2A&Qu44v={ebIZ8)+l*gQcXcSi9NOhftXK) z3ox%%yN1)koFF2L~&15znUJR6ZDjA)ZiSATCV|+aRYL#R3D@Sw| zfrp$tnB?3z4LZG`!(2wSMpSi_we}_%JN7G0l2N%CPvRp~N5wm94nL|AR8%coCIzqp z|8U)q3^h6wQsWvh1u7IxZRam6(ST`AV2(iAph1e?#Jiy*SO;NE*m2~5WEGT1epwYz zb>T4EIZwqRU(r~hIvK1BpqqRgKfdQcsyZF(h-n}sJSLDxaY_WmaABJ0h~i9dk|~rZ z2;p>5z6*auLE;C0rU64Ap%{+x%mn{i#1zeeo7P<2v)2R3b*MLtc7iH!fz}# z84r$|8`ZrHhNsmpZ}R8C0*#2lpNtbSz-P%I8N*>gzvkh~hK}7;JH(eoBeF0I8lVx` zVLba~dbm}R$~VZVo<12F9#N?!8cX7JRe#6x$^fS{JQ=Gj5vxFzDf*6U%M&AQGBwsN zd6l~*Z}narjs|1`3|*F;ecU*1RLnx%_|ZSIfKLHq|K9r^z^$Z4sj47zbW9nV?E983 z@||hTxG}WQg12KNlApy_G;<`&tu zbt_bl<;u&iy+&$l>!CVs6slix^w2gB{-vd*h+CwL+n3#XoBZr&KbPBXyH&Ps-J;TC z;JqqMAWkSTOoW?y^RNe-VI0VHboS{xH`dCO*U}iAm^p$QBjOHtwoSknL}8bOa#!sy z8b~HG7e*+HqCP3Ic~gTP&~wfwlb-Xs)A5_P=mxO1NC6{* zbGRQj=Gw3}DJ?D3envFdA?-}-ez$!%2xia}=zTg2+;Nl5gBBXeE-fj<;eW2G#pC*A z+4``%AZPRq1`G^lCPOs|4Nxm>il_2tl;=g3SUVKxF4l(QEl)^V*%mOv*C-P)HNPAx zGAbaIK8nNPQ#y82i`GCg{ebwOIwLi&9CHDUi$kDe2nJ0t@Y73HV~)W50Dscs@QAhT zM#ee}k|#lOHKPhlNzxbUy(SF_(eI0_1>&wQ$EbV$i94}DaEOM43AQFz)O!H3)ZQZ~ z>@~McbD>$Gd=&-|#|r>h7_nljkN_g35j_=}s%xv($Lc(aV1xF72a(5-abeiSh9F~=oC{TmOpsOz073F*u_(5@dW zEQVOvHcySsKMrTZEWVxT8O_45?>4E8=M1-ToUq*CHV&SQhNadlPSepN!SoER1>kSm z$mYQ`(T?PXG8gSIlsblW0?s$soSKfRU5C0mBr~r-N@`aVK_Cezhtdu=Ot11q=N0>l zY3VG?xv*>u6EEJs@uosN)X5*x-Ol}44%GjVFQ9!}>ud51_jz{_Y|$P5-f`U#qeh=2 zwd0l5aFoG@xFONs<{1vND4>UZw*X>13B$s%Pe!$jcc-88oy>MR`dNSbq`zg*Q`-H; z8?UEV*pU`l_}0^z*7_x$2@E7Kkifuv7)UVO=fjR8j0BdOT9&(0;nI&1lzcZ=G@0HLe8Ter!GLK~tZc!+ zJKi!V&pdk!5^Mu#W9YMjD(4y)22Qy1gaHx(IF$^_$iek{NJcf?r-oQlAQ7I721-gv zmz3-hNrmJT$EsfCCvyVnbjcioL1rkwF=CY_k;xurphNOVnHeEQhG9qp7}M$x{R0e; zAa!MrbgG0pH-VJKRflxRpi9Znfi?^Mq)HnoF`JC?ktv#%1HJUnt&2kgGF|9Yf*;H= z$-<@*dCY)$%-a=y(7Mn6`6s2mz8=ir64}4+X?fclUng5vSIVTHw}!wNghATWv`l3N z2f&a`PY07Q1I(PfHBjqSDna1n;DPWnEf{L3 zQthOJlxQdG=b?um0fV{*g7TS?4SGjuDjqmxVzWbOwjd?$fxmPxw<&#}qPQduxS^gw z87RSwdg2?zRNI1Sn0C1q>y&IJEN(Pewyj&X$W1rjqPX30$tCjpfAEJ;4YNavaIZEK z^;9Fih{w$Xk}0#E%x$Jkh5p&MzU?hAfOl2)kkm(ET@(Yi7*`Wu!2i* z=*}D;bj#IF&SH>ZU4UC~oHKbltsK(moNLLr8N~rTCEqXI4K)LZ(Am|ehwsxkkjR0= zJEhs_n3lKec+k#t{E^{aSy3XVVCa-EsB(^QQ43Au^+)Ld!r6CE_Z^dNe+!~dOGEKy zsf0o20QztsFfFHW>y9dJ)~%~y?wbEn(d$)?9Ka3N<)q{?AC(ccXD+{y>n}u|1K4hVE50$I*#i~ z9SU5>%?H?ymrxw9v0{Q;5#bsCs9_1_rVnK~2fT^7K>Vo0(H~00eg*&lKmbWZK~%Bp z5FKwRUxZDZ^Jm`)$IWbC3hYFh1O^fqNMInra9>0pAQ9#!HUoOk8zFtptKq}L)Q6j^ zjBqj&_|vrn=Aqu+0T|~P26LT^m~^RG-zXVLL1{U0LPlY7ovLZpLoX^BRRL_0*J49k zQ4T|jm`JCPk6COc>6PxJq~riZ33q-lplVU50~E~ZthLyr zf$0IUUobvsjH(~T0uQSMd|D}t&gFuckpxC}sHm0!#lt=fW&q(p9>0WO-HC@hwDyyG2GT2?L(KfFPHe$Rcf>Ej=hZZKUd zq27qbmPQ~c+zCTTYqspgp<{;}c>a*!ayL|LZItHT9{H>PeYd>f4R4g)mtUy{j*d4q zDMPusdKC^xHz+M{ZST}FHX)353oeCzNYb@J7+h*=Ym>nt81Dn)k$N99px)~w>>AJ* zQ$A=T4OJdJenP5iYNQ`3SU8?qT3SI9lhj!0;lrTKCt-AH{d&+yN(&ca?l27QX_CUt+sG&w*)zal8jM2GC^v2w z;Cpaz5W3+vs{g0%{*1i*`pYC^qD{sI`?YDo)<=Gr%g}#@13u{<&ybp;AP#@Q+--YW z{3@Y`0}SqtL+V{1qmG7U0Zk!!prOoo_^4f!DM)B1`DOCd1Lzl{@B~xAmyN@dB1taZ zB&iuVc!ty;CH}yLF#QMp1e^&;n&A%z2nd@9?9)ETzQ@^*J#Mj%xa9oJC+FZ4yUSlJ zpcwJlUaUJ+$xtVH7j6br;gB9jA3A3Gz(CKyp%K>;WX$ilWIa^-jL7o`Psr{|H|aq) z%f?@2Wr^OVBP^=9qbj=myd2;lNe%bVE)3gzKBt>%pfUhDlAJapC8?$0o6bmQPnUF` z3gCv`IMz8exKfRq1);efS);7;K|N1lD3}k2j*~qv=;35C=mw=?eSUHULs1!e?_VrrZJY$+|#o#GS*Y@1n^*-((OE~P<1ly%0(rP1jfdVSAzIi z?JS$e@QWU6p)6R2=ut`*RIXD>RpWR8EL34QVBJl%x~Sg7Sd?c7d)*C zH%gLGO@M{PvRMOad?$SVm|t32Dws=aRDUj|-Htc4=ti9ST$QPTc=5PMnP*TIqoZ{Y zoA^|~r*s>cF+2dEj$Se%CEmhA=Td5 z-VNzqtZpGKyna=#tj-^lqRL{*qo7YOpJeXJ!NLVr64DkhG*TeR>C4`v8(}mfs178v zVPI~e_c-+GJ_6=h9`xhlsz1i;3{-K*$S<%g6yRJTx?n8xqO0LiT0 z1;!>+bm(CnZ?B*q5ICQJ&y8Rb^rBPJ%1Wp+JiL`q}*5cu)qq z`_%RTWZ;#7>OlArwKr*iFe*TQhqZV5oD`fFeRhJ5T} zAC-Ok_RGKi+rJ6n@7}!|#z!BOAN}Y@a{FsuBM(5II@5jaYhQtJ>QYF=K_Z@#@5|&! z>!~J&2Lb>7{qHMtpN!+*|GnRnJm{fZwW?ax%5WpkEz-t~>-A8eps+w*{_>Z}SHJo- zdFjhu4yJ9hwEXM$INIfR-}i3GD=3zU;VH?=#i1|^o$*kGd8I-MdIUP#XS#+Yx1tCV z>OtTeqG(`%&rG7PO=A8+JE~4q(i60|HaYt*`;7J*&P`Z;;J`+2WT0R9pn@U^Dr2bc zl?;0n)$|847%1sZIGBIHtH2IC2Y+(mg#!Rc(a$CwP}LJmqj@3JI?k;uH*xMItz_nF z-rh1lrgL{$3u`%^Tsv^i?CV8e9T--IHpd&8G!IL5;ixp!Ks{bQ zY$|};LENz1E7GCOXF+R{aRZ1_)zi3zlY;jdN>6JiT9Ku`pbDk8qj0lj8jSO)(N4*3 zcnOg{w+>N*5B(KmGrhDv5-*fS8H;GMIfFG4Gx2tY7+_O)HBtOv*}kORhHfiSBux%E z6KcOA&v5*Rm**Sf(M8iL+ov2EA&!kZC%%o&0J`X8A-{R3fD1uxa0WmK3?3{i=_^%n zp2AIK?#*a3qpXxSl@>`KS^tpQq%bb&2ZB$UpW@5KINOU`U0pKKzF)@u?UGq{m9E(? zjKf6KihT$3_cRPD`|_)`9hGq&YI`Ss!|zDO_pN&qetKTH#9ucDgO;)CiP zwb3<T51X|H3lQ=bT;D*3bH}niSmNzI$|RO#2;;fa*;}1VW&HLFXJZ(UH9q&ofG* zlk+Qtb2lV@+d9}qRCGDqDdvKXRbC2~S6uxtlPiFkpSMAivQjLw_symltCD4g_I+~$YXE{|Q*gO)?vxfn;A03%1WXc^s-XhOE-vr&x#(qEn)D~T`bF-A? zr^@)LhoHw95@}%QM0&v4D_a6`92g+6!6t2n>OI&h_>U2;%%-fGoibh42r17KG6{)y zGRTw2e9vE{@q>e>;eQBzIgo;{(5uQmFglZ<5=5Oc*F!BGdN{{EbK>TSQjKJ!YyR#c zYr1e^gyP-#>5lLEX7A*UpMI!-`QE?&8zjOrpd-9Pna8AgscDd)=57>@&uplP;o)Of zSC=xE_w3z`jS4nv_};pCi(G%p4N{zwDgXGL?@Ht5?Xr3EX6f(ilka`+dr+OV6>0M1 zWiPu8s#kVGB}avP<6GaB(U7{C+i$;Jnev;!p#JmE{w3&Li>hY{R|jK>`ICmT3{>Cp z<~P3uXqu5f{nXv^Rv0bav2z!6!LO4io_b1Yu_?C}e_8$zCzD`y7lC>HM<4%a=&)A6 z*hjfAr%a5G$g5xZa+Qjj2tbkXd(sCo+< zAF;^5Cf#Gc#20_o(T`#LnQTmXopEg3<#=+Q<=UVSH`J(_?a{}clQpYX3GKg(LkBz8 z29`!MKT5BwI+;)(qaSH^MLDE~QT854SyFw>j_r-APrnq5AJ&6y8*9!d{1hB$jEoP- z!4oeC_|xboGg7lAUkXYfVP8@T)k##9G%PKHN2NM{t>WL{D7rmap7ZZeCbli;U2mF^Xvaj?KG;#n!yzpW+Hjx|9+#fAGVL-m1Fjj|ocV$s zHQ~-O28d%zNSBfo)0+K*(k1g52ITq-` z4Iueo|G<}fv-nT^R>oSMmh9D6;egr9gEk$X)-fraJIq-w6T|$q@oXACEez}D{-!_O z{4mjPAeB9ho0K!K;Y0N}oUyfFCV3c!<5QXKV~}5??slE3Q9$Bd=?C5iI$CicTnv*f zSt?ZGE}Qe4aGmw@`gZ2+erH-b3)A!4)rU-qIn}h@o=*!m5@^=fJaC`D+LBW3InXce z1477mu>B?yANj>7hlyir;7noO=g{T3Q6fI`t>;AxKf&$+ORnvfr^7xDX%ESW}an(`Uh;(nfIK9sYf=pE^{R{%tXmD zIvpkIXf!Y3E({E?50H^W>0#c8IQaZ=y{$k78C3>QNAIQ$4U&_W2ji3d=r^-MZQJaX zuBN{*D*R$CB?ju8MY2jtfuf`tgQ~Mr8}WfykoZ)GMx346px2aXRFIN~WKvNw)Jw(7 zyp+f*|7F6p_BHfV8UVcl66mL!n<2G6BqgO~P{9G)7uevMvcbLtbchd+j7V)=t$g^y zACe#Z;D-|U{M zO~Qe|^u(zC*!F2qDKa_Ij)R$cDX)h9Wir;loTnqMxwSVq=f(y!1a+RkHRq#8n`IM> zdvcCreKn4qM3`7zH02>nG`@RP+A)LG65i89_G)^BunSWNg1E?%eu1diWBC|d{?AHxqQ4qGH}Yl3}#^0XJlyaOc)E5vwXReCQBJp(=F~H_Q)19F+V~FFP zG)WhOjv-}2=VqaF0`cR?-bqt5k0@|X2#$;q$C=J1nUmg`+(zD=)do&NDnBqlCreWG%5e8g8y7tnb=ZGP@39z}CUNqi?Tkifu; z90Mzz4kQ@vXR!lvvf&1mE^6XYfBKrmM^qTS<8(|%W_n(3j;w~1`~GK-LXUf&968w| z+c(z85Ong6jEt#j8^aVaWg+-@^9&VVOJqB)EZSvAt5t9F%mcC4Pxak&%OEdm2}aE2J~%Ctn| zl93#Ch?5L;L1eVgfFY}kSN^eS`5KOV{$6+h#Ot$^M&EPUPe_V*$Dd9 ziK>ywoh0qhu|DR$fYCFS@4_;56qBIc>r2N?EP>1`*jhmomqgQpYzxK7atN*w% zqf9tou03h0adqH zH>bGpAXB;@>QDj!82d(BQGJKAADOhy%Hlor8R>4AkI+73@bh4T%mag)NZbXHMFNIj zO37LYp15BR6jGoUSJl)+GO|_CXRNu8xHAWm>|bZsu?#BdUYHM~=-cJ!v1X};dYBC8 z0uBbLUM@xFZt8Gfx3)&5+H61Nfhp&G9&)UKYB$dLk3RaG+;r1rO5^8aifbK#XEKXM zXL@Dhj#4SiE6{mCQAutG9qz32FlklcYUzghsgr$&U`%zB&Lbwm3jE7{K*?*|;-P&C zs+iFOoH-qM1(toK6^Wez12!3lS)?J9uBGARob|Ut!ksr!a9|c=e66&qB+9cK7+`-e zj6Tv3OUo@}6KcO4PxKKEKTYHCp6}JtXJyqBaFla;cn@rw-kB_}{GFhkiS0YWsYkoF zrw@n!{ltdU;NUX{DnY6GBh0{D2#$pp=acITs%N7xMSA%*3AF8l#5)dLxen4bx&sf2 zY!_gspYz>D^YXJ{d@dC3jO+0}J<bZteEH4Kf!Q6%lMAf;ARe6uBl@d*BYy&=|r3ONBxj;Z-Jq|fb_JrLbq$5 z?B2COw&TjVWhQV#Zmy**TzRj#mUZHWzZ}=vDUlcJird1_FRU2xEp}E;o$Mxqj1#sa z88goxY62s$SD7_54oRu@jT=^jNr+7Y+LZdTDM>f^ci+9Bf%T9)YnIKMwn#})F>d;l$@l*G`*Oz}cgXARc%6Lf>t6#C6T0rf zFt4nxg^}p35(HyT^$COV>jRUVy2#1!r-b`|{o=pCz)Y1VpL_~1H>oc4_3Inuhd=xg z=<6gTypIA_Ky?yU`ywKkWHtwz!u{=)vx#f-w<+U!x^YGr zocmf@x`e_iRQ1I}QY~Z%7iWdw05<1oy^U7fAd~$kq1x%FWUks4l5%&{#*GpNIsKgP zHkp^74Rfb=`Y-g(g95ClrpNkKeW8|vdD&+2$`^h^V7Rlr*{y68_66=ug5zUQCsTqi zv;`u~X;+)TSvD^}XZS+zXPVvte@=NFVeVHNOXWJ4>w_GuM~Sw%bzZn|I*#1HsV1ebEYQ>8mVV=EY=~~Cl>UGzlGI5=*M~!2T#-vV1YORI^S(_FFzZ$&~v`D&M@b@ z8>Uy7+t2+?7z_D%g}d{P^&M|ouXs*B=esj6w?Dt>yxPo!#P`7D-0 zcXzmjNq<`x8^`PE1YiuhDgj#ABJ9F2k*-wk7T`OqJmhxpv2+sSM(h2cV!%zLIC92`+*Ehj;& z4OUFYUQB%!ifb3%tTW&3H`6Tze+%We9N{b@%f`hT88^p{omMHz2{6dmNQH&D&|$qs z>Y(qRjtm?+O15%gOQu{}@fzp@e?ig;su_Su=0)1TTJwwK588gEI`&u6q)g}qfA72B zjXny=Tj(HfY+Nh9`~LTXVVx{*d+S@k0Dn^Z_9s5^aed}P5BmnFbLr^lkexes$`&xk zr)5Ik@a8+@`Db5%+L=LF)7T*I`-At%NgPI|=Rz{AVVz1!z4dKxmwextj6z*PLE&0? z`@7yN>0oT$@!Hquq)iF-tFOKaDm%7<89y#p?!6p`jK$L4-mV5xX{eQktge7RX&@!! z$wa;Ks;i)?qXwJvR=M`NYvuIm)9TMUasjYxj=%tu%rTDn$^KTEXnjUz#(E{Se2b)3 z?*y~G0DAjzfX24R*fx@bWM)%h2v4ZqQOEE&9P=Sv$;-`F)l@XpxfrMAU;@CQl-_Jo zrp)v_10qDRHW*FKfC`l~s7Ha6eo~6}5`~AxO5-$RNNl(6H*a~BM!H>BVCoguA6utz z**sD)4u6~nmdi0e*2POI-7?TA@lJI{1DI<$-_n3;V`H7_ekao>9g9jjGV9}UZ1U9f zWT~hsg4QV`&F`$Y;uYm$ui(vvS@e(Ey!BEDwLLRPyyOjhJcV0ooKW9R=FJZ3affXH zs$IBPowgw>kMYCyqP}(0uJm+`bM$G_5K6PtF&=3{pc4m*ZBI&iMT`OM6G{=#PcYB%mYJblP|?Lc0cU9l>4vL^X?Ro|_OV4c4sQ$9B=t(~Y{V^n?;Ye+vB?!-$L>;q7xjA6F3bo8CyozWca(LT=HoViE0k8NJ->x^k2%=K|X zp8vhL05{e`G$?`tXI@_K^TUiC%92`m?pQX=*2Wpn8Rqnl1;g#{{`SfvRvh}H3n~(jT?`hN9 zIE($Z>CW`IP`+;Xw!XHm&h*ZArn7PRZsYTv&K=kIMyH{lJ01O;X`Sy3^KxEs=x3ar zzZW29Hu^bvdhce>N!E!>mKOuF(onw&Mlf4t1PoSQO{czGN;k6$9yxMK4P;W^YgJXT zyyWU#8plY~d3Ante=eFF&URpW@tu-!H0oAeO;sd>!41DRECgI|&eq>Zh#P4{F7kMI zK}HpEXXCJPPW+s&%9`>(eGC|4yyklHWGkfFPbg!IWy-+ft#Mr~B-?9MLRF>O(az4Y zvjw?9Pb*$6lf6e|5;`N(i|cT$71FHdt73_KU-TGYA0)$_o66M zhBb-VHP^m`#0hN`GT6Y~7?RjB52{yf!HfTo*4`jS7aYa&6QlL`Sq$i|{UQFXy zot8|SX)toR2~R0(g#LCIK${qn*|8HcI}F3BlVg%vwgswUfM>M7oA9LLkRuIrnCfVz z23lom@C8Y!yTM2`Q;pIBbuzeMG?W0SWck^)u^i*4!GLcH7?^=^91JX@bJAW5mJ%8? zhRT}+JS63uK0Y3h^0Fc+EiKfr+}teSkcQi-%E;8krjPa1F$R2g_4G?db_(jvb}*{# zco4&lx({`n0{!QEK?c+@r4_(f8&nTrZ0P|_Ea2zaU(1j7R6Xt(%NHecn4KAp2USTp zOrfN|GQ6^j)$pE5r-$M&p1~OokZ_R*8wu+(s-H?u%hm%>Ul!I~f?IT6xJDCkS>%U2&^XR- zpejG?*uFGQJKWQW_0yyjRpFKuZWNvioQDf>R$rp~Cs8*#=9fvdHPs^ILb@Ffm3EI+ zXHT3irOeEH9v59wUGj$hpafBA-7yVNLiY~w&eRE$^d~Y--Q{$CJKw$GF6=uW3>#*j zPH5K8KAmCC_l3f3+<4-7#c}#M-($hGaqN@vobNW>VxDK3e!em|VLRWw%I6GszRwqT zp?F?ty~^u`v(R@exQq2)Y(DeFpD)Z^E_dAj&)%Cr$C+H`p%>^z1Ko{%-&cbBKAe3t z!x_ztX0&-ES&QXJmMyPxUi^;zUY?yqj-8y7_~bY_j%+7+jyG9RWJytEEhEin#+rR0 zha3*~4I}}Q*mt12(F@SX_uc9O8jT$UNPzr{Z2ViTx2kSceRbKv4;l>7euko4^6g%o=>RLoo#_k>F)i7k-qq(1`j zJd(}{^2`Q4Gb^0rSP+8uRtnGhA~41U|0d{{rK6wZ!O{BLh*uPaB}$Y(U5}5pwsk;S zwM#+jit=J90@y^odepVcvXh>-k_Jqhj#4;ueOL^gJAVbbqr1^IXrwnC8!aW!i`@ip z5EEZ`H&X4X6D0&jJ0ak%QtriDA?1D+QtnlW`ei!no2jw@z>*Eel&71Z@nhZ*5P&2az@|(X;~W_6ln{)bG7d`Q1pp$A1fe2nvP-fv z3MCjDmHU0RWrv7u974Fr@=V7zP=%;fRsDOh^0EM zOK#8t#H9)t7xc%oKq`p~z{ zBElioH*%rFo2eU~*qN#vZ42q*_2GmU0D%bV!?q9lGqqphFLa#8z;bpQ%Ur@)O59P zV0;J!#^e$gXRFC^Dh$JuJaHI@H)HCJr?6Tvuny8QGBGY!VMF|?OcpmPAD(U*NhzU` zkb=WtHP~xbz&)9wjLU^Nk7>g^Wkr|lLtkv@KV}}mwLI*rU|zy9Q;nP#8~yCI)9sui z-7339c>A1`W}c7@`!hM3)8|xX7ydfsO>d^lJM+Es(BdLS_iTJrmq zEA3FD<5&H<3?#77Elt<^rp};Crfc< z34W?my90R1MGL|85CGfJ$dHueQ~_8uN8Tx&Oa%)Qkl-AJ!N|yDSOy}UQZ!ZpDPBL? zdJQ&~Dq&>wvP3%HRRAihYOiF#KpDh6u@OM2Uo0>Xf2y|1fEa z^5I`>A|e9;oRCP%lE$JP3bwPa(5*(fn2x5!cA1p-neRej5*ELr;Pmr?T`FSUg8)>y`9<$`yKmM zs^dHI1_H~R=SINisETk9hOsHU!A;fCQ5fLHd(Qs}s&mfC=fj83$Uy%vR1`K#HiU3^ z;)~Aqahuvg+-l129C=I4>r$R=eDnF$5p|M$$oQCxCdpyBe&U*nCwfUIO1D#$7ll?9 zODj2^8@^}##Uc3&zLr_B2Yvbw`Z-jCK?NiQ1J)DhPSWy}kvq2xbErg(5@)Bk%M_j2Ij34 z4oIfis+Bvb9_EVE_T3rZl3z0XR5c`jm=R*x4{K7^W#_^P;84J!fJ1@RqksdruO2Pe zMNDSl2|xhH?TZR>0hkX$`lM3QvrDA4n4 z!4trKk&@CeF1B12e=T)K2!0d0crbueI8RauJ35hordzU9zFrz>;K zSrT&^d!o+FZ|D)zGzI_CuowzL`lekjU+K_A0VhFJDb&Uo@ayL@OAlBUBoVN}IZY2fKEx0)ILNYgsrG5U0wR+F{Wz@G259 z5@!S^qL5bNaeHnAP;~>-FbfLwF{B?G>cnCcQuAcK0L-y+#%bpFsYK@eR`1RHZ_96Z$6ka%Kj=)nhIWVc8D_>ccs_U_#)kH7!@xb9Y6`-cu6){WMC@3}`R zDl4U@y9;{LhxN2YJ9PH%-nAR5hRPL$9~cNgRnThyqxzwqYm@BVvl}K~V~dvGRM5)) zPSI;+!IiwEKlQ$6!6?UU^0Cv~HOs+>?tP9KcB3B1H6zL1xy=eTBc32Jrn5T+_3Fx2l(fR z4B|(9Xv-y3m{EN2mq>Ln|J6Eh!T}P>Yo-Cs95z9}`jlu_DQzB2W*=NJe`K2 z<#hg%VxP*h#-8Z!)3l!*#+FU5nj=%@O^fL; zNi;18NkE7Tdo@O#3@eBECqeNJylSwoTknf&n{<58fSRbK8N<*e!dV(44)Q?blKmuJ z>BYY1!?a(%HBZy;)Vu!SI}(4plhW1Is}txBsGXsTgQB8*m1^OHn_*f1JUaT;+b3XzuwS3Y z!V#Tpc0n?(9pNY;M?WsijD`TXbMl$(_aWZZlZLxlHDD)}l-6PSsh9Hji3@V-REsVk zIP_;_=Sp5xqg2#4OI}I2+B?aDBqbC$F4%^2+y&26Hg|Q4%B?hhZK3xG{41@>MzZ-g#+l>(WyRl)R~~Dg_9% zS+;E9>4Pk-8#B2@WJ`3$CqRv?Tu8ZJ)P*^vX{h$WnG`LNh>o|LN&)461l%Dd9Yf#j zAM2Ft%zWfwc1MgudY8arfwx3FE*KrfKMGE1`-ZeA)hO{ebZivhZTq|0r(Iqc^dxYu z@v(>CXTf6Sq2QzVt`hfL7-R8EeaZw3*^vpbQ{BTj>>@&J2DQ##1p}Oi9?kK zjh#-0ahfJF0$@D||4^@zkTOO@h#SYMGyIZOcb{a{?1l<+EXc64!}amWPgcXIbNrfQyfI8FHeG$~;rbLmrk1-rI8N zib|pH!s)89kwJOs^|$1}UHhct+Ew|z-~U6|wtW|V+vUpT%ksjDFDmeU=JaWdUma3e zRVi=2@uuwDv0b*~*VjKFfAS}PBK!C4SE3*#o&SwZS8TY}*Fge4jPhH+<0e(a5|c4~V-iwxKB=pz zL|b>u^~-|_M3)wnOR2v`iu|<4LVdBTCs9Z6zys;@0c=qJ@P|K=!lDv@b{JCtx@SUV z$>7k4eDC`|)D4jU#si~<^LxoXnrtqYL3;p!( zzxi!FaZp}Xit#Xr4YqU{@4FxZH7fq%8u{km|2jf0Of%TFJOaV zllU88z?nvrxv7A@r9ajuXq5qJ(~SIDY#tWsrebDsvxcE92yS#uZ3ePXreK@?6!pq(lxi;MGM0K80X|7^pFrp?WDszR)!xIot! z+}Iu(!pREQnz(+w8$dhMjlq~G`{#5YnY(|?{npT$`AYuXiW=Z}L+N%({GUB{1;Q*r z@Srl-n5jZ`&<7LrGx?m(H}8`3Ztu2D?kp4I>Kd+VQ96UNda;U^K$1GRVYa1fI2 z??95g3UhTBmQ2jgZ5-3#O(6T;TxY&ZM4OcNnctK1!!Ne}X2c1)=riU%e)DUvD4{DrInTf{PxF+XA|nE`Z;Lh6a>3`wEJ5E@skT9_&Ap zAM-T*emX7_pVE3NOlsKaa8qTQ%1d&1>(8XgG;YMPov{ywF(wX-VD5*=@*v%wgK=xQ z>$X|>U>lnH&H6gyg^npR-XtE9KG?eE7j9)htDhA3-ID8rzyP zeaM8+_OMuB=et7zhXM`-R+$2$0oY%IifGm3fw+~8ErppS^1*q+;NURSj`r!BvQlcl z$X7hp@-+utU*$?$57Du5IY|5cSt`xONpBjY)pl*G1rU`kM~|M-qoD5`IitqdsEd$# zkLjQ4M&5bnv>H_-pq^h^E+v?72M2p0$v7gxP#BBaJ^=UqYJ@cnlZ29P>NEH15lf~^ zNoro{Y(rZQbV<&G%^xRnl$ax6-g4=hs$-#44;>`|o1mkJyY~QmXZdm@AEyi4Y4p!2$wHG5Gdtl#1!RL%A$10u4Z+|@x=(i@#xmiL3w$!UnJ@Y)}Kv03d71aaV5i*kwP|pLk z71O%h0VpNUl9XD`ABO_#hXNA-nkw?@A#)4~y*PES8(Rz0<0t!_QB@Peck%;WPT{p) z0Z{1)52&ZehFL;PC!cQGK_#_D=4fh3rKm>QQDg!^``(lH!#sp^oL;<(&+@$ z)i7u*p!&Ddp_9}N1E-l4J5)N&^zKCZ8ZG`zW!T)C*Z5128i1PeG5FE<%*ah}Ow(>q zhA}BR0{K`Qz`rBn5f7_~l4h zd71q6-+oOVJ$O)d?cObS-+d4GWsQ9GtA8txJp8a6eDqPJ-nDDjF-9JRw0xuN+OT7aUWleEOF(l-#$vyYpjqo?KCN#Ut`orAuv<1h# zhKeRB$;DWPMSc!WgmAZs#!~54G+t=P*?(AHJUPab2cLlops#=Z>+;#pdNc{BVvANkldG(3v3Jb0372=x0_J+wqGG%dQt})hVe*Hf)`%|m|iX3 z>b<5vp^j&5{3Li9fpU`Tc6d*6REz0z7wugpygzn6Q;2-bF{m$v0C=* z-3G%g9xN)WRc#6NIZ`^l7sduD`A)SZ1evd5!cM)0l~AdYlLO22m^m?hPR!}n%V26J z>AH}{judHd83yE9TCS_qKJ!X_^wf7w;JN^kc%&W|)a-zq7{-BudoWAP%JWKbK0x{U z3TY|4Du)iA0ss?{*WNq{Dfm3e^}Z2@j+;Yx6ftcd$)!N6-(g+4NxoQu+h~ zlmOgkImDq3QrYbHG&V@pEtJ?IIBWu2z>0Cg7vkj6a{^f8qXx+0<|FQ*>cX7^)n27r z0oZ#b4Laj#P%Mo<4GKn(+@Ba9Q|5(EpUop*Y3`Uun@{z$_J3GTqtDi;)1r>wrlu-s zs0X--Z_{}*lKosPMycN%#%klx6FmW)^Aa7EwCqAj%gVFZf`yO3M!o_Crd21e=~NdHbz5 z!7m5pS3mbjnSg%(F&I~khG_hDT-AeZ-Le&o9TLGvuco#}h5@c~qjKA}t*WjB`Z%atRXp#lLw#tA9LH98jYW(4kzAs&!UAn=c z`uL&8mwoK}Km0M&xm}XR#sY#)c4K-B3aFh zrLi66kld18YG1Q_ZOIWV(Id#DYIA7Qib6?LAIW#O+_7?y5pKMDtM_31^h&Vh1@SjN zhSMt*YBXK*NPlbX5(MF9UK%z5!yPANeDJ*Znw|!4DnaU;D`7Kt#yF0)fG+_6?L(nS z8H;gUq)lX2ZaIhYK0;Jrsc)>m4(gyMZxwPsM~p) zaLR|7{Ve6K62XJ54HFsl~ zn>kRLi3%5-)z#$+t{*viRzY+wv^klkv?9ak1bSP&?AyE59M6W-7ZraBx6zSF-4fU`09W*2yzsNYz*ZX`6zN9mMsI4YMe zcd8CbE)0ws9=9GB~p(w;w;{wPgv;xJ`4br^xM+9>LgKznIfp>Cp7L4^#Z zKDo(Z7e-9`h8^OV*5$qhM%T^&e1tjzUC<{oe#4145jYfBT?(-6Q!NHn#pGlbNq3+P z&ycRh!j0QsUVywVNMX4kb=@EA5}!Ly`~ZC?0G8W6syRyZA=QtLHlG2bs0+E$r3m7L zPVSzIIF5c*ZIHN&w`p-m3L2)}0f~01dZB8P;S*@+>)X=BzyY$U!-K_Po^B*8}LzSMY9da8RCo_E~uhy7gap@rO`XbXk7m z*MAKl{V90^lJLLvTmKBUWe&@$ue>6^_j|t!HE!4C5C6@-kzf7QUzJNOE%F1Xtoi?b z`%BV#>7x9_U;KCZgMa<|DxFKfkg8w^_CNOMLHRjI*nbnMXnyd6AIgV6@?m-DrI+OH z1N$XEtq2=1!}1E^KlsQa^5Tmxsx63LL;Sfo(eR(Y@~7~3mpu63gYu1Ud;{e;C->kP zjdl&GXLvD$aR*aA-+RVF8c$ zluVQZ*u_m6;X6!1|lQk+=zfIb+{E>MRmCzP9@_gy8z5)v$&VA@G0B^;@@y%;(isUM!Y-Ko2=r)LmSEu(t$l6rm1 z00!6AR_H{V5-xN+E@vmb^D)L$>KgxZPsURHF6Eih_-D_xYJS1e(Kphiys}ufZ!x+l z3CL4&hf)>H<6QmDbVidWGJ2P566yzp&F0$7LV$X8@E+^U2smNU{K0QE$5sh61B;Oz>nvf{`KohN0^{ z7b`$YR?m@Fg5~VHSlF(}%{K@eMzW$PZ&e`jyHbEBG??m*^-8!8s&cq|#u!09F^SVJ zaqx(EbOgrIN+hEM(&IU0&>NkH87-z91lCDs>ZUggZe~$P6TYX*%#n%yvrs+LFYY1$ z3IM_J5u2t^3j(k_2II7W5lEv$y4_W?6Loi0H;E^)aE;^lkq>_ey1)Nc`XJHF*?2`o zg*@@Z6VTCqzx?ete;|{dJbCQ#C*^Pc`mf|K|J#4TXh2c#G1=WzE-kIs&FLiFD1lK< zY&1}%Nq&AF)F|95-~H})HNNxb&&iWdegN4*xs*#M^3KbwwlwPnJl#CU{=o5@U>H?M z?AYFbP4NtsK3(l`V`iz+bly<{^*aRJfAW(T0 z3-W3AL7+m$FF*76N1>m;L0Yd|)^r{{cu;)VIr8}9k7L6E_7*_XHKQH-0opB3!;A+8 z0H(c;KH!$D>H}&Nl~S$T{8oMK=zsL`E^cCM=I(q=ZL=_a_S{W_bK zPJLPWjm_&)Ly$&+KuGOR@Sc+Yv?;;4J?Hc5!m-bTPY~FqA=PxMbGiN|!0%xgd&ii_ zH4etxIZwSTrvT(dtOZ+73Esq0X*BvC?LCi8_DdM&i^bdc6m+&17{DL-n?-lS)^wPU zf^B(lde;;qDgH#>%$NnEsh!tgJ1bLiODlErdsdu_l_in=#k{TBcT1lIBD7iJ*c2EG z=~&`LAM#;iAJeQG=I4xJL6_ozYrU!Z)qp7;7L081k8C;`BmYc|RklGb9^UbBdr-gv z=@F^1U~&%8~YfL?HaRrPwPU+*d9ic?2rSpg~}%V-bZD>E`lpyP_3*w9m%> zG|)a*SdG;AbH`C2xs9w=;T^zzwJ5nk;xS{KISNV@GCp6{jGUWYLQ1U|y^EHKB~NaW z!S}qpYz1B#pn|2ZZ%D2}>Yc|)1281o+S&;qz6VCma;2uaOsb$?oVs+~IL1m)*#h_+ zc;^~&E%QqSs%?go^JL#KjCK5OpLwO)oGVbp^2%$+Br^lLS;3&wz4@|zYn^OvFjD`V zNOLj3uye(4<4(TPAIp=8BkBk4+M$ziX2Z~sfV+v)PSBZ`sUIWKXERV3@I7&l_pA^4 zrDQH=DqPg0V}V^+S)w}T4VaIkx^PR)uXa`-(FV$uonHs_7R>=i9-4-G>(%xe~Ob>ZOTWh0OoR|@coc-uC1-rF`=-qKz{u4J?%peno0?S(!!P~PFUrN17RiMk?}y&^KIP%D zDD}{DLm*Kgy-bfsrr?RcBxJI?i4{uVC>V^vuy%=V+;V)n8II%M7)}B-H8p`wFUt46 z_dNhXacO91kk?;-L&r7dgKf)h%v0?P2R^p_yu3UeQ`vWU(m>ziZ$9+4b90;^eMLo? z_yMMu!D#4T{LR;-0y_G+sAKz>jD;~~=BflCK`3slQ$-NV&;G^v0aDjCOaO$u!|U}X z(h}9z?}e=zQ&qH?0wbiD%P{PkbV!c*0N2U4!rd3tFro)GAH0=2(WNp#JJcICxVU&# z-f$D!5D4YC4N3vi*4;Rf+ApV0UDEbTH7V4&&c3%&)lzJOR#!VuxY9P%#g?mb?p!N2 zDx>o5yJw*;s$X{R-mC&Y^lR4}+J{nDqGh9&%!_=s-d6R>GW8D(OArRtxS3E4{q5_r zn;}y=-+`(rPa(#y%qL{5^`{bo`Ziz9J<2b5x(m#0<@8A{IG<4|kuKN->pKC1tpM6< zAA#yT7)Hf6ZUW8=@*^mN6I7=C8#Fscg_pClr*YwHRt^l-Gv3s(b9Ruq-^>yB+#Xly zEep7qLs>X31~D#1Fn^#hRW|K~VIHzv>GstAF>lf-9@%bY(>=x0ypb*M!&IzuCAqw) z9N!z10_?wR=VLgj|CMhZmEZm5C6SU0Y4mcgBl6PqfPCk@Gx9S>yW}fhx?gI`VJjyQ zCbh_HPqvq}b__~hc9s<6dch+Mf8kZr1A~b~$EB+eCt6E#u)znle7d7$=9}Gpqc~8D z4b=kJ^+|+HP0M+9C~%_`Z~*rkrQik)&xs2`V*Zld^n?b(FuC6xF8MtHUphC8mr<=r zIdq8+506TFdk>C#_rOrvF!ZGkst&}9E!SYovj{*3C*uXGE1k@cd6=F=F-^08WSm?` za{)k*fD2?g`X#fR0_^pjVX#~NEvhAe8gTp}?)B0Kv0K)veAc8u|?Wd0bhla%OAs0oX_IfnR`^ zEwewab*U_0B>&>Qy&B%O)~U~qpIx2#pk0p%^5u%%kY>9_!S4jqQyOxitp*th3PMjh z%%h>JEi01Xndp-7(a|_reOm)6Fdnz z@?%gllMe7Z1cTCENX6~nyBmW5#yp(niU649x1Bq->WY6XIEpdBEqiwFK#a&I0R7mw zU$Oy0<$~^kYa=px?#JRqS&QoLPQ>Yk)HMuLCN`!?6B^vq#jEBFf3z(n0USwuQh^9Q zqs>wJ5JY7QHQ|%|*{D|Q%JDG*@QZ5Tcsh;kiR0+9>SZOFNwgapPW5DFsXCy?AAbU> zVP1wxA}=IJ2Qa3YdB8w_KXfJgg_|RX4jqEw@@8!0Ux)gaAIRrE_fMeqtwvsY`DFli zy8s&Y$T$Ay|CGny|CnsqyhZiF)7UKyKL%iA)eG<=L_L2@(4DaQs3^WSpmGK}u-(X@t!hIOIF z`NOI?v<12}Y#PL|Q5CxO4y4 z7;G<*7x07&Rle{PD*34$V^&gL+ZL^~yEUA8{P+bG$Z3Z#4gu_)J2&YmT6>z5V~4U! zB+5LhOI-Bcel%ZZeNK8kpZ8QRi$1d~T;Ftc^(ha?hj3ADZnmx~77cu>JRr}Mba(mk z#lQJO61?<^1Yl6v-}I=Sk}>vYlE$Q!<`Z?4hErxy7?Y27AC=6Shhd1hj@5|q3>%mP zv-mKdOMD)~9zX=_6~oek&bC_@Y-Vt*T*Ui=ajmD1Y-3!@jfR2>uxDc2@?*?OZu&OA ze8+On_09U3^Ezh$jvJ}I=k%EB>4u)Qmm^)vCvGS*C-8=&09m`O`)|K^R(|)}m*lA( zIr3b8RDSb;N@=Lfm5+b@w0vl5j(qR@kW_yCsQmG7K7Hzw?>>QV9EdoC{m``g_-LP{%FLK&syKu<38s zk8^b>aHAA(0QVcE;06wF8BuBx=6j#&kI&XG7wvZ8UI2rkg#arWv7o0E4RyVDb@fAE zd`ORHwzhRj5u{)00K8XLluR30r5YE+Nx+(b62bb`whkOi9hIDHAC8toe`2;@{MnE? z1K>mHGMm258y5^gsKsGePV9Zq7n|h;5Q8gK-;9g|nQ5u0ub2J1nGOnyA9r1E z#4#^q@~gV|ULZrMWnaMSjekBQhrU_lB@FYAGI zLY)ksi*sOL41n1z{p}0JwDuo4nI!l@fP_-G1WCJl2Glq;d7tICtCDR1`0d}GcF47obr~Rpq*?*V^NcK*K0}>y+C>eDR zi@UfH!g+2P?|2oG%3~5QYDUz|D?s%A7L|M_06;LE??^W~0^8L0PSDi8bFb>sgOd+dsJ5KbJOX$+;GIr=|P~}mi>T1|#IAmyfaHAWL$|w0J z@uLT-+tKg1QUad$Zk!g%E)`b}e%>5BV=P0t4fsv~9>J{BIPAm9udG{+tpfuidh(2F zItaN8-z`pLfvel9hVz(sBrzy zKF4;FA+eDjNU6St6COp9v+cubY}u-`Qa?AApcDEIqktVx$WBh4x(Gp-A*I0fZ4EjP zwZ)BGYY`(0`Q)PZ|0PVNq5e) zXYj+t^O5X*ao;n2uqU(39Ct%dy+sv~c*L3|55_F938r)28}08i(_Gaj@DBp()aUMR zeoR8GZ%g3(^SFOMq|mWp06>0q_y@+wp*D<-O_Eu>2|z!_WxIL1gfWYCL|mS4)%-h=-8coicGmQ z3Za~fA<6roTPlitBCTP07Jd$tX3Bp()FYpHv_l@=U#ENmuV*;>c&epacIA8IclJ?1`X)^aVW3` z6u=tKw7&knKJfcEfJxI(*B~t?$~%AprZpLc#tADY6x10%FgOh0y+>NFcFPzf&(bJu z3LqjUmy&Fy(4ktUM^HHtr14RzE4X&88`6X!a7{?Qfp&~514qog0MB!Be3+rags z0mxw*y-;g21U>Qu-6sIxb3#W3@5T`#9@FEZq5zu#kHNT;7rUm>7*wSs?R4G&RkY+H zk~NscMdAv;B0e@Ok*lvtRxLoV>_V+ay8vN*JIv<}(YjDH5U>&gj2qaLI8~VpY{a051YGDZhH)Fs5c=~0v|zmM zhg3O%Z5N&=u<^vrCbqZUzJ36Cc?q4$H0;h(a2Wv7q3ayF-t+Qubz`3Kr319#NeCBo zp}U~+ptrjds_^o){YD{0?#c4Y5KiXB(0&N+n++OlbYbq2o`&%cwi`&hOka+KA&tll zqze}=$Ul7V`||((KfkTxpaP6j^DyhfGm3IJd#H)jXyC8EXkyO82H*C&cK16XJFIPjj@6J&pOtF3p~BM<&5&&l7=l91E{KI zl`7gMbPKL5C&#>AobDPN9Y)z=)AbCDbU_E2>ctH)KD8~)>|ARQ<&L2 z6kwalz<_q?QkxtfDlKh1j)eO>1aw}ni~^>8nnudWGk;t}mzES^ zhp|xV8*AirOOJH4cguKaSf$q~L2~Kxbx6V#>!Osjduu)z*KdL>u{)eULs9@rIxbW|1$%Rz^%ah%*uOP0Dxw)#099mQrSBBrVh=7&HD7k}iNOwSDi zlmr}jf`~ji8z+zW4PO_{4C7^dlxC#kxL|2N0brSBns$g33sC$~-VdgO1%4QM;h}@Q z`~iUM??N1`NXFX_NqRn{-@)r80U~I=5jR0m1$w6=UD+M-9ZxLssULU6gg1nm$^${% z_}GYyk6eHn|Up#GPxN?o5*>tEDA!!V7p8)LPPwB-GL(9aWZ>Xj__~#3thB_&*VgN&$@d7Q$`}+u1mtT}TIzxlE!Bh1%W}Z~a43 zRa1-R5(ZcRPzr{Wsqa6>17BmK61Z>%v=+7?Q?Q)SDvs>IY7Ip(GCJ9aGt;~CF* zp3^bdT;EcnOAgEK+TTAUVW{2VI7eGlq}zsZ<|*)L-lM*E8GlHh0Ug zF2XpRO3x)0jvIq9Y<|8UA-IA zv=-=KtCy4$(?+2{qB%@p4I#rZY2I5Xzy8tfy4jYO!!~xcb67e7*gvqRM(27zK6F(9_r9T!eB+Jl@+ZG`kJMJ=%a+;# z`S;&Gi78i_yzurFd1_aQeCd<>wQHTdJ}lv+bZmOg_0FNd&ES#_;C|<{r<-0j`&XR^cq^>8B*?)_A~~VP!JsfDV1_F*wqFgoRdX|0?VX; zUBp}I@;)r`c^?XeptR2xQ{9LsS8e&`6maAU!Ot{fj`I4(NDYbG(Ho&*pn06sap zo`g|2cS$3pm9INK8cd_TS-KcRk{n&^d&^lphq0*VB= zvSIWOCoE_`Ux>Di?VI&W~2vWcaWe@42JNJ zc8l~Tu$h9y^_lwE8K<^k7!#ZfkIDp8CQStUk%u7w{kUS|fE(C6>EPY;H1@Wk@`vwO z#(C;iKRSOL3d}P}^0}_GQ6kKXNHnnSzY##-C^I%Fq$#!lhYTKGo zC)}8INpW2>?6N}|8g-#y^b9|XWOki?W;qD96Le>L%klZA=0lq0lrqvkUoAcqqy${U z^3RvjQu)amX3dFuJyJj$FiyA722-I&PId(4%U?Yv&vuW=SD$H;=GsDe;7^ap(>O5^ zCa*1UOD3d_t+TwtKJ$9wLbrVX%7{Gv!dbZp;QTL-^~mppqB0VU$hOLCsVvJ=@AcIM zva>oDI8aoEgE6^hN4dUdoCkN6W1cx*YgTX0pWB=QbG5D2F0uo-uQo-U_-0WcdGOWa z;%M2`MHy0ETp_WBQXDTGg~2iyS%nH2E({2?*8^lCphMuvfGIG_S`5Q@@j@Ak!pO|n zxC~*oHUJPl8XS^rPnvjh3w1JIkb`3(nNUAtu$`p*uuIXnomt#3K5D2|>k$A!(0S+On<&f7&1&2vLZWyCnkf8Sz)fm8*pe(^)0PvCP z?_dFfg*i?Yxvlyc7{*J3fmnu3mVVbvCRGS;4XaL*Qh;3T?Y+=VUXJ!;PA?>n&r2;D z>x@7+U2=W$J?k|2$N05;32@z}#|;PT>^u8xuQsfGwpUhzek0HgKxTZTSE7BFRlmQU zy23_;0_`?0F!HVMCz0m(fJDxH8>irM5f(r_B-uS>+W;OFL7#rE)&n9}H8PV?7+eJ) zJ^}ScV}tEd4n6ZVI}6Ze5#2<)jJEVkI)HIEQ~|LrCQ(PRp6e3py$Dbph!TJlz;|e~ znJ`O`g-1yBL!HoM6!rtSc@1?!44+ZD9r~4V@5@8_=zpv;oakV9$2k;O2?f{(4cH!) zLx)c(FK4?hD$0Y6g53(XM*;TD*Z1a2ll+7Yl<_ae*>pH&@V=?3R_FM~-aCi+e;>x1 zQF-Onqp}^U)3$DD&`m+hV{F)&>CKluG6<<|=26FtnSmC6;?RRJYIr!H>M03^78e)j zNm}NI&)PqiS^mWnUMnADCI)oRD%&dKgI95ircJUcwt-(_Eu{6ioV3Buz+WezTFX<^ zq;;vJSVBCk6`H$N}rq@#9W9u>x@9HAaDd8cj=DEMc_9@9`IRw+_R}f^KRAA@PT6w*Gy6HuUAfX z%U7OhmQ66Y+Js-dM-Bdho|HdL!LiQn&? z0(dA9lkCWk39jd6;YfLbA39eFJ{9YPje|Yo`=kK6|Wy=s7(wkuMlf0?pPhiS0OF68K!x@u`)`oe{)a^S#r<;m2aP4zWA zen}Ny*P)7p()CSE)hdmcGYWNG&;icybMlIX5>5HWIG9hvzwwczVY~z+0f?%UFW%{~ zbxIFI;(em;95_8dOx1~Q3h7Ftf6&S<-c!<9e~&1X{%3*V0Ag_5QjiG5a0C2x`wJwq ztXVX{2EX%X-|@;ez3g#=ZH46m7(>Z(N|A@JAD8j| z^VoO+4YCR#G6^HJ>|dHbI#R+f{ijhsKCYq5FR5SuruP|tDqo4s0_2gPxwb!yb!jj% zNDv+(milcX5|S}UrcZ{U3Me`xlVja7*?&hD87&|Yce7n>&p z(77?<;>L=frxm;kuCpx6E7MdR|L~(I41qnzITTm{1(dIYhX-KGh?4E??Xb~>Hdb0v zAol@mCvT5Hg4>QmD@a1)v*D8ay?r;|mHD85O7`YM!v3KL_sPYUt8x;jtN8B3iHoYr zW%usQu-%ZCw5glmlk-J9_1+G8_B!=p$v5nd{R4wazbvRZC@IF~rY6sU%0$C*Y#66B zH~iOA+$@pq(~^mkVpPcqri5ZFu`H-J3?Sf7h-(s?4>(n%AxVoR(u2VVv4>8qpYl|6 z8i%>nzib}_+~eS@JTYX)#3V24@Ya@M@pi{en;;COhGC$aWXr}zE>)>b=oq;Ui#AV| zY)MVk+w#xj*?E1(Q^2fACZ(jnC;#;6P4e;o^semOoFS#PUg-q*?txKPikIdLu_*=FLukNzOek!m$m@|GR!0fZ0Wx|dtUx(ca1#MTp<7M ztB2*YPi&U2J%2%tb;AA*0zPtAHPU_yKztVZ;Dr3k@3zTvzgv38*N;PhwWWXqxUVgJ zo!IA~fbvZ!7sIN435`&4*-%kTq40C=F2VGMG3x10snR9w!DLxJ0z0){7<{zR!cPB?i)-542# zkapjIym$Pf0wBA0ZBkvaB#G@$$^DS;7{>_o-kv>oMGii4S3(NVY>?T0O8}ks)<#8g z9LeOi5+lsx*|S$v?==^F1n~*R5DcLd`;nvPq`s~~ii-1eQAo*qkB5dU=h>J`PGlwb z3AD!nR=P3)cyb|%cLFKl*wv#7UZz()D)GTqnJjL^BsyJsMz4zplEkHXm0Es4 zyk?=kl04jsFc`2DSYXkKgl6d?~y7K292oGJ`VlsVW`}RwjaetL!tP#eh`xXPzA$5e+E!(%gFc` z2f!r&IsQ$L!QkJEko3GNnZ@YGIi4z+KyQJ3H3Zdc#f&z!zm=H{_`<+JG{hIXR6f&XD|a z-QFwbfy%0kf+_&+CnbgxI|SXS%4+HC#*|rYWw|h}U{i;5;lIT=7TFy!u>iEs&{*nx zX|f#=Y>$owz^cQUe$4{w&g8i~jkzj_7+4ASLazS@EL5c&Xk#E;L8$Ul3mQvUDH>=zGI z70@s$`LT8OHap8LU;fk%1>4z|Xs>4%B-=m#DD3%Qy!e%m@0B0DdQsjz+a;fTq(MH5 zafI{E&2`1{^)KBmZ=PtEy7F9k>)$>oWkr4)y>oRauqG660QWT^s}t!`DUdu^lM&MK zUGn?nxGbZEFMUnf49-(bm}H;M{Yofc!H~Jbg3y?-yK<`})_)1=4!R_xuojcy$g&n& zbI0wxbtrKAQGoo4s$d9i2ZLjP>8AOdJ|^B7 zY2xkM8e!xys>bH-zkj##J`1vt7t$!E>Bn3R3DnTQ@M97Bc*_ra`ru+S>1ruv>xbvn!fm8JtoJKT86~8>2QqGNZu>pp46TU_@Jq1 znwn4OY3HUvxa$Ho7!Ko=Te2DtLajlaDT5jpWmZgPY#Fo@=sWXf66%>;-aN^wx?4i6 zuc#^)cXlCwZy-U*VEtVAPt=1c3JC)G0Wfq!zrH&c5>hC`Bu*(%ZOqi>iF!^YP$G9s zW3F^e0?uED0?VQR`xA{L_w^0Rn{OS5x<*)~MEly@TqFDTZq>0UMztsuGhSuKemy5I zUmzWZ;aJ6A6;zecFzK1Im(|t;ZI~QBd|GXW5O~kSiJWN_W~-n70jvY)`;Av!|%ml!d%EQGbh-&D1kC3{htY zggWQO_R<`)0Ii`CLr`dSnA6b@Pbl?YyDT2)HTUHe0&rWS&HXuZuy!v=X7;^sBqAY< z#iW}b((NAf*^St)%ovwCwyhogoR~L01q}a~gz!$9{Nm5-mYq#S@}sxg^9?AJcS1Q;|K${E9r2+};XN+^to@P09`jV=lsVpxRf+)Scg9=oPj)vr}{aZCX_DUmF z&n|5GC_#3*9{8seNCp7(eS5b+($E-2<&|j=qxAc-RPQ%80xUmB2JbbZ8~kJQWuif% ziG0SPIwd`?4zHoBvHhe>03eW9NZj?%+YS&uKGKD6$TQvrCr6|x7sf@Qf~I}&lH`mQ zNOeII3|eAQO9F3nmng#&hzrSeoC5=8@DB?Os+7sduY~0Heu)i1Z&HeXB$`0cz&W z(wKFplHF`S{3XSwQKrV5NQM4T4g+{Yik+{mf5c62Cpy>xp#2@SAL6OpFPY_AksYWt z0?-}@h;H)3U~{E0{Z7X>NOgL!Ssah-mmt*3awSCGD3Q-}>@LUW!d~@V;o@d5H~oi3bwzD&-Eo$+4aF z$96QABab7mi{XUP1dMKvV`Cx>a|lYVFUf(;V^o;eF>M+=4-F5(Hdg?eyf$fi^9I;x z9}<0U6#DOZYJ%%6O1HB|Qi|91h4o%6n@>BsulM{q`CDHUVEbWT=k=bQRkDA3r5ZEk zI|}q<(ULM;s$_d|DQp~kXWOHB$2TT!#z)8Z+P@O_>~Qv(-|3BA)5gPhj&mrm+7xgA z_tmDT6Q4tY4NQS#y}Bw<3Lwu&@nrza2}-oLMJ51fxpJU8IKK{~meD!Pfz1w}8@TvR z)*TA05(OZ^0g2qUs~vLge4Fgt(FheSIpPC=&50d>Z1xu(sW*-w9hY4TJDoUU!OJUk zz4!DCK;_F>X=tdFuI_%7$h&L*HU%z5M+1nT#x0F>m^G3~f0r+}tMp?tbb2QnXEpH~ zl?42jED1TCzs2*pa48aB$usoU{I#>*G!ImU06>igI`MTZ7Gh$cCHgOjUoq!%?M4 zX4xhfU#*uYjLn6*E=p#9i@5sFN;tbj`iFhurLolB^AZ}kF7Y63aj*?8rB1O(fPkvhw12-KCO_o{0b20+uZ@{BQ8e%CgQ`n4cD@;bvMRyqW`<1kQ4$#884@J}hz zNf)m;@g4^7wA@}uJw3gLuEF=JtLJ_4=gQ#`mFM8G9K)e(3LmE z-~6b_Zz4~#0?qd#(Ql{fV?KY*dxrvRKmj}NqTP*a*SjFuequ@`BPGLk?%1TM8Z~B1 z>E}0=$?0)|T{*$qmk=ex+0ER#+DbL*dg@e*Tn6AiG7^wC-aL*?;sI4Z!;R|s)J`rT zsYShz_oTz3XGKM^v|PHTV`VSW&dXc5-HSyNy%`?Jt0?8}@neIw0rU9_x>-y9$xU|t zSZCCwPcYcp*s$NYCV=4-n5qDuhMF_AqruHzY{I%QCYbrc+-*#gMspaZ4RkpAn%O$0 zL9(IFtCC#|6>2afI)S_-wtLWq()>9>nY;-A0vX_0W3ix|>U=|XSG*6riN?sVF~|zJ9bHnntm>HS z*yzcEj-*#3@yetIJm+{+%CJ)h!CNCsej97igcVe$otWl157X^$*DC z`R8Qp+PmVbyBqrtktuJ^jYEO;OaU{_q$%HTxqMBI966&Ktd!m(f2aB}s{G*ia4Yy< za+(%IS%{wW&!K{VFUQS$?%Am)tWKP~s4Cgcookc6-XWau+6*;prBfhraykpezvORV z58R+AD#}+iHys_l(vDvpPNos4QR&DezPsdj*NI2+y^MldnFzMyln->JXJ&)9$3T12 zPAu?FfSB+2Y#lU{scv;oE^Sko0fX%;4t0~P2hKsLgFU%USf`v%;1GjAZL_Wy@G8Zb zxCpT4l~s!u@f)=@Dc&~lBLQp9#iA%9+flaPuUDR^NT%0%D&l(0*LtFnlb4lIfNhJt zK6PwZ?KWpP%j`VP_kOld=gsX-fz@aW8VCQ(9^90C4&Z*fw<4!}4h5D>0Rj-5aAUFz zu${+DqmYh_^Z-NwP~xdP0R8P{1~9?oTA2zb+z8`>H1BE;l1t9EAcat!tewHXw-DyzAbvsMRD?x@F)zQc0&T5Kl-IK{N~NIvTbXF z=8ygfw$GOruCdv@SMC!0gi~rpghe=wn=0T+31&*hQK~sO2q|Nzry3iSc&Hyp2c()K zLjc+9#k1*gct=cl6{;R@cBl`qkeixMv^haOZ&9|FXszE=-G_d*|Zzbkk< z&+KRA1zXo4^^_7okBL}BHaCVxDr0{}0Hu&h%6;givj#95bP!%+LvE|b`(1)5`|;j;=L0iQ2vzCua&0Z>7` zQXl)|Sig9x?*^cbjVXfcs9Ocod4-ywH0bFk(4+Aq$rS_b%(iuCle$5HvCY@;J_!PJ zkNAsVM72T3zEw%XrsZ563al~(%v_Bdqv>+)T&o%!B~PcyFoNxyHbG?)o~^%CPJY?Z zC66=A(|pd1Icd6az%ZLO)ktAso}4&&0TTQ@(myaPufOr0Y}rx=+ae7*2ClZWJJTiY zxFJm`_fFVFp~|-5;edkh@u`z(^Oa(qzX$zQg%&qY!LKDVN6TyL$X+?0ptH})>q#4o zE#tJ|Q~+Bb{BAsHTQeu>DDghi7&eFTLF~^)0J_hmf`)B^Kz$4b!GnX?YzO@bx~F5j z-{`=*?Stdk_#X{nd_-9(-R^?~|3ZC%WWDJQ^|Vw;cCGgt&LDZg>cn)zS#ct`B@~$A zFSjIhCsBt2t3v^u)yzM&5eINz9XdO)I272x6d*8WCe=nKEb;$~5*YPCntgC^RQ0^q)m8ws$i;$|K!Q0k&U{$^bLEL~CcET?VRAV8 zKJ^^|OI<93w@`2FWH=xb{J|LN#MltP^=ZvFt&{VXT&COYp5-Lq zQ4GmU(vILYPghh{77I6E2xw48ZXDpaz)0u4U1EZkZfv73jPnf)4dJTg1EhG1Mhg|1e*gDUL319GG|q zU|w%gzUkEH;l>=>C?)gVz5?+!JS?G0|AK0C_tV|pq)JW z6pSFBIMITHCb6mOk^Ao3CABr>s&a+?)+6sr&XXNKQYl40{6;XHwoe|oe=iJtUsc;B zH1f?d_w)?v39iyo^j841{3XYo8s~DK$!jX0$KB^`g@k=r)wUHEL$dp}aV#O`1k~M* zf2rJcZdxJ?#&Zn77++>W2+95@Xb*$FFm`ho$1p9|hVaZJ=WuMxtnUl}(Qf<(JKAKR z{fZP+)`=hXNAx?x!4H2N88j+>*Z__a?Li1$gmF@gbfWI|4A5r1NVg}~-OVNE#;CuW zOA{wGhXM`-ZY2d)!j;HFts2(3`032i@>Z74N!y`-LxG!40UkFtz!;=&0ggoaS|!qT zQYW;T#MjI`z2HaiYRSHu*)g=c-H$wE<`c*b22HdJ+ZzxC?r|Jr%npEfYtop>8COQ#C;6 z^%w1i>Z-9GfUu8(w;(>~bY~h&%l>qe50ad57)q> z8M)T)n#tSv5BV_-4H6ittSpfTjN9=Y4dE&M5ASobRVi25+72kV7x z3O{WpJiS0T1deS3>VMKbB>>@}hOBfG-nk@t^<9Z~zAf&?4@hPyHd#>5s=qx^LsMXi z#*z55k{K|AF5)=;aZ|vPUnLV2`=HPL70KT6wB{R)*c5D$IGoQ81#T7v*oVpgcsl9C zi3@5YglW@0$OHH9QA3~HT%%hqpVvS)`H#&b%Qbz^OqjVP-?OY#RkD41qw=-mD0dg6 z&bzw@m38XI@Zl>zMWBA6SzJ~29^1R{fvV;Yblh1Cs` zUtS}@p#j|>9vc~y(f%I1hl)9zc2XN6@Xn0_y5zQ_FV@)~wrfhY(^x9olm}z6-|L%) z4r`Qo4$$mlj2`!-nYquS06})PcM6=gV8YEH6uUQ#=y733U_iS&`a9QL%XM6sWdQUhSRRBS)^wCB z1B>1XNJy)$R!B{ghqwWNPe6KJjS&H;oEW?&@c|fEhNOB1q}E;8#ZY77fp#jdN?uPQ zFK+OZIHZ@O5$Fe3Pz6WPCnJ)v=?TfqEzxhxJeP@BvLfp^X70aY2JV)-kcb9_E?03oi@kZ0US>coOY*>`x0(@_I3QzBpmKMtU9@>wMhAVRRY^$E! zIeD^0Rle-n*{t8mm&p5*<6Lez7?xwF$CIHOm#WUDe^>^GMpWvZ-!`Npamkkfn5Sbb zjs^O~?JYtpnuqI>|IwLBN!**$6;nax2+Cjt*F(`sX&suBD0uw*V7rNyZJBv9hEmfd zr--(qc*rdbDfc4%)_?Uf>ULc6N-HE2wp$oR)y~;`@|v7ijp5e)v3)j-IZg=WVAlLu zSvY|Qn>5JljkM8)N@YlpQZY$%S*vsx%9HcWp@2gHhXS`F1vu=`rdmx^xo)KTae~PX zNw&N*5j6YOxjGbZC~$jHKqsS^j{-d7ZEUzxBHd?TIB8fiiZ)AT$tInIQ@8FU05x?< zK*;S$6sJ@U1y+v&gomk8W^^?7w`2BB5%LxFbSSWt{i@zk*^)(8Fzxw}&kA2|_^73=f$?3y~BrCf> zp8A<50dADZ*Z%f@OG(*#^2|T^oV2xElw)tcB_I6M&td~1OWr&Dj=cKpvl1L0mAfB1 zDEHmfBp!D*HVC~iMmCB(L7k2(N9yx;$T&b$Y!bjf002M$NklW1iQ7T+$`Y42k$$M04O7sO9UL#9cz^=+BxKP#RsA5{aWZs?PrFOIq5U9)#2 z4hY9nUf#NUC2;J&U@1CtvRG2R(Pqn~6_%Ni;`&EV7)-83azuxQ3Toq|| z@>8m;;pX|sNKmER%ka$nSf0CasF=tpGEOyZ+zbzQ9~W0%t)5=Rz+u2@7L1O3k%BgS zR5dcV!Mpev#MQYj;E#U!U0Eo2DC347o?0Tveq|6R&@c?U(xCE(;5g%4#2MOR(}W`N za4yU_aa3-n6(_17vtMWMj-Rnx#?%Rb)I3!M?GkI#_ZDy>u zJ$al0Iuuwf3fRFnFE3j*Hv^Pr--EjqU1`~ixnv@6ZH+~&3zBd@{N^|1?2#k#h2QyY z`OI&ANeYUKQJ!=OjEu^WpZ=p6x zLBH@*pLhla(FP>9pg`XL%rmNb<}~81YHXCB`P^rvs32Ry!H`@zbz1(z=RPm(tyeH< znUE8&za}0?gLt@w{G)7aiq{v?; z#Q+p;hz7~@Sm*c2?JFn8uO|*{+q)H6S4ntgia-clp~bw|`t*ImKuhuswj& z5$nbwue2wSj`r?vd_mM*$0DQe_H_cT!hqAtc*;y;FE) zUDGuj+fK(F+a0@O+v?c1la7;}bZpzUZQI^K#~tqA%l*99fBGMJ7QO?stE!qYRT7o>YX?y#)^A{Wj>)xtU`9H*HAB|I*_Njs zEy>YZ|Fo>Vc~Ua=cVcDr9~{BzJ#RO3$b8?}@^6c|2|2PF+iV?$)EKtys z>%S>^4P6(Jbtkrrn>2cHz2}rJJZE1LW@#(-vDSSh!$d}l)JuxML1?|}irwcj4!rO& z5?`S%nR_Hh_eD$f=X#!^yB}uavXbywG;XSg$_6HQkX>2hZF1P1OvkHYF zAJ!@iWvaPn{zH-2%7Gz_xZ3-UKPeBKT^fNzftpEu-=G%YA#lI6YpQfxv571}!oq;w zw+7$aNy8LYDXZozKI+Y9=$?rDR?EaC+`QN3Oikcn`a`8Gw2Hdz&8*YX4_YM)I^XgF7 zPVn7C^<)a{>y~axVKqb8j6oG5F8Y+NGDFCyw!8%zoLHHnV@kYfBCJ_=+Xka9Cy`x2 zw}%?8(H2qi3MPk|=Wi$zS{IdL4mGAmA;OBj`Eg$#r?0vItX~p9pRa@`d{d;Rh9#>2 zQ2cI<_VQ?-$-oD$`)dG--s?3g6IENA7*Aolpu)6FCoB`41LtGI=6d2ve|lj}tFU4j z&U=9|mBiV$=rSQH3Zv}iOmqtz?>kA##$RXX!&HLZYHPm61!(SU0H#SgWoI1~_xD6- zD&w1PKX?{g2u#@!t#`cRq$Jk$m0&eOqw+S`8uRnPJTi18 zAVjiY#!?>h+hQcB@&$(}kK4hrMzY63aZ)aBCzl9^3shg4PbL}o*M zMJWV=QGuit8ZoSVNX}#AO&L^e7h``4Zct}ue(obAH&cM{0(&{as0f8F5fwr8C$dykjf`ex%$v1a=+_Za0)<;hd06-yyRQ2%g8| zF6oum=O~`g@59UMg2XU|d{&TIOzB?qFbi_EhE7UEF(3VF*PjzRL)~bhmZ#{bBUIiz zx55G%2mUC8Hz?@cc~|TyqPI?sN}m`W8Fd0P_gPz?PzcoAo5*lFSZK12BvAN#G0P1ml;r$^aTBa$3wbS7) z8EE`=P9~iTC;ND%D5aqg)MorM?h$OIQWY#xLJbjoDfu#C?l?8yneq2Kaj;)2Amt+2 zK%vK;7#a=-#u0)B4No<2-u`4~N2xR4fdV7Z|5OQx#~xOn{3t4g>MniP*0F&g)wx?e zGC>Qj82LGPot4tMBgpiw#4}hQa+n3Mkv$##VPF9NsHvWUpja(lAGEf!!|tc&JJnYW2)V84F*u zPo`{F(TJGVoJ!V8ZU2yaPsVyKZotdTT4SMF%SrXD#n_i(;^LDC`m5L3yMbX|nPE;xA zrF6$V7uSYqI`n?@|Ij1~^c5BYH^!BRj6C0Q7dwrSMIRWfr(UkGPZ6*y2DMehO|Jbp zGdB>*Dk#`cqreZLxSgHmDCzFA?uppQUH`cK#>YE*r_#LW4~KQi7Geu)nv(68i(sH5 zeEggPhLopN+lx!0@PNGNSU`LGOMpGZ76li$m=r0LsAWwX0he@3mEbokZ)V_Bxy!D{ z<$7UtAx|N`l?1W0kF<-su1~VV^?P;m&O`N+3uWCo#+(IBo{rv?jlh_Gg17IvPlY zF{4)SpJA=LvC~{#5TB3DwfQcqOoaY-(pxV%Pk4^{vU3(Cx3}<+(sdZJv4v zokg1$KG+uH;A=wd#Mit9M3SEYp$E+hPI&SU7&#z zWt}(19FU(?P@X7T9G+)boXD*lDyU-=@PL2e4BphtiQQ!2F!G0-TFKB*oP`}so+D*G zN(YPGXWT`Ig9A_~=@ToqJTvp7%E2M5Z5w)QGw@XOuCcZ}R>kN0)#KHbAY_ij_o5#r zJiI@e^1{sGli$m2261GZkaO6P!-gxbDtChPW<#VDiH+StZc=L{^9rC%*10=Iq)`u_ zj96Y}6tX0h6VJX^%dtbadR~&9GR2k^@n=aTGr)|fc%I)%I$D5mf-giID~RI+URkaJ zj;y8}ox96fBld%ckqEEEB9`c4W9=w#5&IMIEpo>vEq?r#ixM=@;WA3;(Y}jBhn(<1 zFRsNQO(Kw_1;O}8^F7V(zQXLh=R6hEV_*u#xS zDyt=2Y~M*^Qr%nu1!KW9c*;<@rRnf_> z`mv7N=8eDAP?Xm1=G2aN^P_pQVFuPz7GF7#~WVrkhvu8_MxPIesviH9aVuOuIo#OWfzJ zhS3BDeux#;7xQa7_QL$JQOec7KK>2 zt|0lLz^rH6y~Y+`Z(RcwCDZpB#<=Zt>c|BHE1|5e9u`Yf4HL7()tg34n{lJlOS&!o z74JubgC<9|4lDuFu@C>Al+A_RgPN3s_pEf-P*DH{E-nNanHNaIF&e6|Ho?Kd4u&LW z5@C|^nbZpI@*IdmnssItlggI`Sl2^CSSW=2VHUZ5<5e1%l3ff9#fIWO3sRLHq4(7$ z@+I^)h0egW8J}RM52ric9jJh9vzs9s>G_k$p?{mY zDBb;}3i8S;1w#4XE&9xlJqBR*KMaDN4s@U13hVPe#{+!hfHrem8-Q`7mqXdfm?nu1 zRFkex?zemvzk#1GTT7ZWJ0CgK5wseKH7$jhhf)}hsLr9{oXAj1sCB!Ijq(AE+tl8< zQE4Q_%JMgvvn7_dw$h4;?n?ATKOu|i5aRMI@wX8FONurOnxwv=B_y||+yLs>BaIHb zG}tXnrac3ifTy+OzEE=ThpcA36b%CQZsrC2a}#r6G^-wj{nzTDt@U=-phrZYR|jQx zAZ4C$sHdSH4Kp*@sO{L2Suw$NBX+z?T`A?GNfUR#spQiEsP~?an}r(%l@Uq|swLnb ziO`7dm1kqUO0V~-S<^3vL9^AJz=vv1J?9UwUv5NeZTB*!(yf0or1NU(!IAYAvePnz z<5TPiTJ8H+COz`I8V2-M7tZCV)Hzt z@gwHjVGnYx>tK)gD36nsbakPGcdzu*gpxmIlc8?uzC+>|zUU-0mcg;%>s&vf5*QdG zw}>Uh9@QA7s?Q!R8ENaBeiXwLlQ|mhr&}0^#>ifa^W-l>x(mw6U)Ua`KSgmx;c_dU z=M8;;kmN<04%Ndjv!QvIkGV4&n7vWKyQfZ-pAXz_oH#=f+nDJXpAIUd`gEKqt{!m> zxML`2+o5P$S~)R~8W`MWN4a|F)O9J8t;9PG!cm{n9yts!O2}teV~SzNU}usu_Zg@o zC#5-6WOULc4*Au=IvLiXBQz6QOv8lR^AFPH4!F;ZO2*iUkAItHU1lxdmQ__#Nfbwg zOODii78knqy(aA2DN-;{mw!>VFk7oGXqvw2>gBYmfF){o9^CSojLstOO}8fry7JOV zEz~@l-(URaWyrV zV%LQq$%tF6FJ-P5IWsY4@)kKv_+NnSox7Us)@>`BgwCdk$ zq{VoVl!szHY%PgNUyDzh>25R&<-B9CD;b09RgT_LI6r2%Jr%=s?|B4}aFkz39_~`l zZ2NUr?V6WG*6|fH=XCLqF3n8(45Mpz9m?KvETn>WqzR7 zLZ*$4=QV!&f7c?Ntnf-$3btNC3O~g5 zs!W}*awX&Hn50I~h4l2D;m7II&BLYc&AlPW&G-E}S9qL{Y4lkD^|06f)x&A@!ocKI z2Sb~;oM0#JsOOq&&5?2p7(8^8c1B>imyxHg3ut0Kmp8T2mKs~uQ_cB-#=t{?uP8EE zZPAY8=j{u}9!@Ntm&{8q6M)gwCVS)G*~l&rW@vS;6);Zg)V7!rl|;fm>OsEbkJwce zo*JT)S-5O^!}hV}rU6?MXVggpXIkF=*~hBm1`Wr}L9l@f&KX5+BdamJr1*5+)za{H z$uD79CHRQEPP$20W7LV3Xs5WSONy{r$kzC$aS1Sim^bRE-)BE|g|y}Va)g$PW4&{T z_iJ9$tJ{=90Z~ex)bkXRG`FbTLORw;HuaHX#>Q!Tipd#XDjWp`fajg)7>`BB>fBx` zsfPKjZD35i+N-pjFSaU_ZwCwU_3`pD=C%4$pgRcy+ zby!Fqku=A{$2hgvY8^)Vjm>BnW>4dvvhaugQdlF9vhaHF(*vD*%C%VVYJ|34WSlX~v6Ty}db$~TXoXr}EE%st<&+eNxE$viy0}17G<~2aO z+iI7Njt+)w6ensMeG4!0>!iyBTM?xj(z)a58i&2Dl$&jCYl}vI5l6MnH>^yWt2laa zO$eYggw8_AfMS$s0jB=NuI0e@Q zLApnuTMGgf3fwZ-BVcogusstBUC$*1SEOkBJ)FlE68QS=xUb!IJbE6NQ8CH{fBc9% z9EF|hsL7c;Yt8(7{MW(Jaw_nziHRz==P7rKogJ4^@Da5VnMht~Pt64PN#bGebml7l z+;+=Py)t6&R;+(J@OyEN>Y-HLNjnu#=4AmVUbFL~c$JTXab%0L((!Iw2_v?d$q&$Q zEt$cU8@vNr1*qy~QjATH?L z3rdRq(EBlo&SiT~KfjZT9|R3bmdRe63iAberY#Y=*r5)aRJ~Czl8+r(@yO2U+lBRM zzud)dag?vOw-X`jVLR>#$v3b>d@B?K!uyl@2sr+ z{u165E^?ylXlqNv_ds{%3Rwz+YD@&=e7eEWA7sk--;P&47I|bvdbjKnWloSFf|sw# ze8FG0Nc8~3GY(&Mq`N=uOs-^vgXWxt7sIItVJB?w)+~Wlqj#hg=YO*M7^Uva+^W*4U`j`~99`fRxPut?wy0$xuI}WSzw<@x6bg z-^Jx+zd9Fsl11b4w*0qrH@hQK60*Ep2|IN(_Q;t0gn5c4&$;1a5|ednn+muY)H$AW zq#rFyzka*2N1jR77)6+n4y*URahxA`am@KG=ir9z?Nd}#otfd)EzJIGNFro|+JJ78 zW!qO8d()RQ>f9l}s9xDw2)RO^6XamCvX62pj(o+icl^KN%PTQZ4TbN1pfy~wbgjn) z8*4P#UAOz2z`IwUK2c<$%Z$aZc{te6LR-?dqi{&c=^LAqO_=RvVfeIFjeri#)g@1x zIlk3aZU<)6j-Q_-`K89k>>Pv(Qt;P>BYl?aB`duAPoOc^EK4QXkCfq+1Nj5MuRnEP(d z!>dNEm~yJy+LSJsBJ3P=f9{Z+xFDHd5|-7mw0}TZQzXW%uPP+lzj8652uc|<{Rfux zM?%7=bB4Z$Xm!hzNk~Rd3I zUUm2RS4%@{(2D{i$R*|dfWQ5MmWLRxLK(ngTVY@%rgGzUwY25Yu!~(|vi=!=&dnmP z8R%{d&DvcNbjN?S^wx_9sU#N0mZrZOh+1rBxuWe^S4^G++XO~{FifAGW0ygmztS`o zj?PYU%f^dfAE>V$>1)pE zvW79b56@XN39oBe5FkSuO?gd9GFnt&Yv~&*;_2$j%CODl%bJ;LyQ$mMi~gc6S&kj4 zQsXiGFqxnxI@k~e8lsma_$==&PkL*tkT;5se7uPdi{OuuNJo+%9`^mPJD&z`C)5F% ziEo0uAR_kF!lr-3-w1~geV!K6&u1;ccO7y(Bl7+UedPMg)jP4jJc8gxu17)s$02%l zbD<8thxe9L4_i=Y+8^i90YR-h?@YmeIoF;J5ZgYfpZ3q`Yx`okwu7(ZB~FrCyS_c4 zFYS6AKcpcilk@R}UOr?o(A@tDmR}fBv(8!c3(~X`S2*)hOuUj9K}wLNy{LjOh@RH2 z*a<3z86Wch6sJ_x!05-zMvq$<4K^UXXQHit$u2JWJL2+xDa1x8d~Eg)_dzA5aiW+o z(`gmz?2C!N5A0+pJi-!Z2Wh)Ag>jF`)<0yYOBd$nM*()v$B8^6c6tfqV2@b3`!|WA z&nui~C?wm5n5=j?tlO5sI{T9Y>4Vghz=YVCi3(0iM&tP(S*%R$gPC>A%W!Nb7uBb> zc}LHGXICa#mFhBZdmX zTYy*Yct*mjYMMn^GJ_2=OE8RlQzP+JC-7p>VYqm+N~Yl!8B6uUUKxYS$|kpmR_N7Z z)3~KT3}S~EBk{3Cb^p5-_~82iv2tl)q@AU!0fd;JI3-oMyI7kGer%CYh0RVy7vpEj zBlf&{fn57*!$~@i)ShVvCgmrp9e~iK>AStU$!Dpd5%EDf=o`zQG=?97Jqob$;BvEl ze6T$cdE{?^SReI{C*qlUvB{<*aPba)eAM8J@ne!7KB6d_-MVu3NM5opIvElmrF!T13o?;G68Ge5XY#V#>!u zUQf>iclM>=&ZyHRx^qh$0c7LKiua(bI1cQHJQ4yGH zz}`-Gj;TEcZ;HFegy_XCapL49PFu7)jlh16*~w3}pZX$sSrVL~3Vu$s+$S5-*QUlD zVg*T|*Avoc3)@w%^E=#qFmZD@QnPuzA}+Ow5ubyzbr09zNe4;Mbbe_gh&snN0gI^_ zk9_PM;PLjIs6canVnic^wW|%Nt>CXWyll8SFq`Z#Ky>9hxw&Rv{G2-E;D7GHnzP@z zQ%6klF*b?>)?4ETdFA&k{Tf&+9);n&&!P;o1t#6}p8(>1o1U)eFFE zvF(gWmf4TOVWu{aav6P%rM#mlxA_6{JLOMc`9ajXRzt%Mx_0Yifxti{6wd?ab@kCH z%ze*K9ue%k5K*7+lefmR-L8{pN$78E2erdxh|9+LE}>?IGFbyYOf84YDgEt50ZdOd zOD?>s_%p74#S`^fy!6Up?8VBS*{@oOGZ|q2tbAP>#Ok%AXJ0q?_iAD`;7TSd^s_rF zYc{N5oE{TQ!S6DE)UYF~r-XFUF;ym-ZBnG}i(B;<1BUNAQJq)XA#__O_S3_j{&!^> zsZ;bhsDULjAYn?9h~)i(6jiqilNc#+(@OT;{;B^(%xL|DXu=|g<7H(PuWYA1Y`Z+R zM_g_p=u0I(=QD7jfBWK4dmdU02L*(laZQr0Z ztt$Ne$Yd_OjuIMLsoa5RC?X&2uj_M%M%KcfsYomUpz?7yE|RBB%MEI(Op2r|=uSka zJ&*}GG;N)B{?%d*=Dcjm*G2S0v2i|}py!j8RI=%Fh$XheU)LR%pZ)1a1D&los_4WC zwp<_Rtu42*qJej1tUZcobj`aGZOseFR+t0dyY+`$tK?Z*Shqj5HmxS(@s^_3=wh6M zq=AzwQhGgE>k?{0lUE?)+YuxFB!^lDA&*@#JBXLPAn;;Uf1jJ_As6Y>UI3+yCk7ue zkBKd3yWOEXK7~!h6Y~U1EiwsGUbO4SyE!BJ^-Br!ih7HT$Q20ALn&#ir{Q!IZL^#M z5)GFImv602_OmmKuedMidyFbNjYO9HVajz2_TeskI{*z12{p3j)U4cYgn|%WzbBBv zuAibLV)N=gZhbW30oZe0J>A2nD)L`V_+jZ|b$PE%;m)4h#HTcZSf(Jcj8I&6Y1x$v$J;SFq^wrG|^z%wxI)B6H7MfzH z7%SaLW-FUn8V;e_dz;WHrwyJlT&;7+)8wbNXQeQm83^d9^YlYaAQ!`Ix;yNsVMciH zf9`c=aJZU49jgxV*mj?2M21~6QAej+u}S)WL^_F)xeOz78GFX~>q$W`a&gGB425Sr zq!!j6I;+6o|M}(^5HL%D4BfJS@<>E=-QR<6yLOAvpap>z35tPa z+R)NwMJ9{nUvm(lHpP-=-<@o(XYHz=8pqs<&A)TkY?l5Vy_Q=A)Y|R4WvkZRw*nME z&5eAFJECWdNh$YP-3|_yZ_REgosPX)zCbUFaa`V77lfH6#JKF$Cd0HDQ7Z;4#j}kk zoE;OxMUDQMMcxMgOCPtUx%W^fw=N}~tTP(Gy=T53kY~6xWQLx5vO`JFf*S9L* zx@CJ1e-(i4^%or_N?HNHZjBh#0K{5c;>~(DgD-ORqUynB*Tx}QfAOVwEZ*tw-;?75 zhH!GfM8ewi$))*|T%uKUhhh&PxCgfIo_7v%k|+Q<>6_8?Qsr*mj2N`V8Kcb)=Z@rB zcA%>~q{H+%qU|cF@?MwQr&n1JZ8hjnW^W-ea8wdjQj&yShkU^~v>vDXU(w#m7uC9v z5cn((YJcmkib2`3TsL(o&TUnxP}Wd_w7_g{2Q&jYtZuusj^v{C4kpvFWo{ryr30xdmErKc9>FuC_NTuimoKN?kS8bjxCmn_ zv*etMCW*|b3{$)YT&f4t6>_rX;LOcDydqGc+B_9Jo4uQk<5#T5 zm_8kD*>gD8?W`7e)!~L>ZOL@WVa$0}h7v{zj_HPg2>Bw@` zyDpWhyyMQ(Te;?eZ;`Kcg&H+;nZznMk zqhaB&-OxX#$g6AA63)Gwl(9nXd5L?CiK$n5!+M%=yaKXkqlu zEr0fk4s%xA^%)wE?r-d|mn}86=v%9nMPJQ_>ormkYD^)^vV-cVQ!tNgu2T@k-NkBx zKV!_tAEb^~YVL7Si*h;1%2oxW1(QlEO^!eLHIUS0>1wkqXHuR9f43^MlqNLV3cmHfS%P)^cm(QWmh9rtNJy*2=InXgvz7Z4|g zm^&t@`zhZYgdDN56_NSF>ox?$Wuz;~=bX*~+YVt`-S0B*z5aqYmW`+p7Xv`&Gl{ysmdn$&03h?29|||EyBWp8zA39+$8@uY7g{Fjbv{+wT!To4U_sD@0^! z;eT%oKWi^|71~q?v}WMDm^xDW;`^?OX6Db?xW3>4Bm8M+3UnDEHOa+^49+)^VY-l! zfo&~s7dG1{l+wz=*a#Te7*3CT6z%GU>}%Izof0akKiFe<6)6l41v&)-!t$d5{|4m| zn)+K((KbLADKI|pQCa%s+#(A=3MTmQ8zq-SM~ zyrc4)Ev&NBFAauD_il~4>&jOVG&|XB&8}XVwm*>4_%xFo8>7k$0TpDQ4S033O;yp* z8szcM@t^Tl6)E&U2xOEKc_!IhK~BD|ZM;0$1IMd93r(LPs_bwscUpU0N0dBK80J@D z?bXQuKLabe@yH_vUK@VP@{&pqglR%&2{C!h7nB8+*8AU#8pd;9w)}SMhLNE81ajy;yEy=_z?YPJ3vp~ zaHaPzt2x+XIaP7DD=h`x5pzZ0R4yT^%;RHy^EH3zzi!_EtWm87f_VMgv;^tYPF$b7 z7=FF4!Tg;e_*kIjvBLV-c`s6uheW^Q*Y>|!*>bY5#PocS9d_n70KN>zw+U%wpwwh~ ze*=4_Ikn!f=@ZV&d40wXdo1&GRP>sa3nN9AQd^W|c_f=kce@FRs?i%35(_O!+$ysq zb;B%6OX(+&NHodDTf_cYr6k@c2>8Det>6~|iglvJxfOxKUiPBK+9$3(H8!nu649RS ztWX_KHx5?~?dsLPiEy@n(mdEirJTOs#r!4?kv8SC*`3om*S%`9b6R+7g~p@gYx4n- z&KP^7Jf|S(i^7j^?yW*H1%*EaCA}AD)|tBF_=e^i4afXG=JiFSSMKxtjf*~JyM zBVc{BX_UpTw-O5;r0bbL+X^cIV<5Ys&LyS3Un0Uv&$_^I>Dr6xcgFiYy#>9AZp2}y zoW-7CN-mp#dc)CfZ`4%g(_swewv#cNj|r98>D{_Mz=9HYG_Nif&fA7rLo0MD5H))> z8+4DZ;b@WnFB_Nzk{w^c51<9fO1scHC8ZAhnw`)lrhgph4ZTH(!|j>m)#bmEcB|q( zpU_3#v2KFb(B=lWy{2*D@nuC&V!xG8QZU*EeAyj_E|RiiA^qBHK@Llu)F>$(`C5zq zRj_bV!K0Kn}kEUCr zrn2=3j@nLN;;bnEt5gTm&b;Gs#@%jG)yO!VA^N8nP+X)RN#4$c^6ol6qejP#U$d`! zA~HX2Fxx=y*F%YMLP0+M&(W4M+rPi)u&*VFGYhmw44aRxI`r!d(E`+*Gql+lZad2s zWZhEkd!%gJaTpPBi_YCaVEoy!W;B0Gl%CuXt}Ve+ag`)WfBS zc@shYMy&7E(OLJY&6UQ@aeQE)zP32Y#TB_cJW-Kzv8-1tRSy<}QaguAq-Wa}*c2`> znuaBo-lNFk&Qb0Bx3sHhodGv)xnp8UF#KToC6tZb3fplPByP0-R z)`6_TL0_t8b8lAO+Jvl}bABK!Y*^cuxwu6^1AhABUU3g0lOeFwWEpCq2;vU2Qp;+; zLVejfiD5H>R;Tr1J$%skkVW0dXCG9b^{Q{{L`mQWS+IpqeylR0bUnT7%)>lAOoi7f z_@8_sO9+07lihmJMETV?KhdRgTTqq2uO&1Kc57IlOM%+qz!=w|vyGoKqDeWxOi2q4 zTOm6#J)I-ldw#-JwllKO2jMWs4tyK*U--sDEml%LRS$Fjy^{Nf&aygl%{e_DEz4Cgb@$=g7*Y&o?VF`Wh9!*B1i;^j--{p_@ zfA0F;k@ZdIB@QHP`lx-qSIIY;^~}PEK7~!(A~dhD+D!Mk@{1MOn{T(_NS1_KZ|3wl zefyM1P1GvvO&W+UUc4ZhBoP}~dVYcpw3j))+a5mqq1Qf%A(%k0jo0xoR{xiBd-LK-9^rb z%k~o9&tSpo7tg+tcX$@vq0ZfKW_ucEUDCoGBZ@>^Y`hAiW01eI#*5`I9zAI_VWwYJ zG13TcLZw>!9sFwqxE-MRD9X|X|C`p(K5~R&e zM*)}O(hTNRThI)-xRsfhlP-ZBmGe@^z`yk5r}4KWVyBG?0P5LfkUW7;)Q17SnY z)@s%EUqV%NU)NuJXB{U+ZxLp(iRs7Lvlrb$htH4Y3fFp)qaH3|4*3n+u48~(t%uk- zi}k_!8laBu=9-+>&bj6RSB36Fwe)P-nycpfy4KLM_0gG&89$JB{TC8p?2;Ts2yJMb z$*BqfT>4yA|JMOkPz5H{u=mU`;-q|Aof%|$61Cc}THkyb!1|ffE9l|>vBuQJ?%&`3 z(l*1rksCdFVT~w3UDB??7>=P5RAX*9;Xp5Z3lMxbBGw779t?Y!ZX%T}{5@kKnjfef zPd9ZIo7DVQmc7#%9{Az;# zC6P8|UeNCiY2-TVvn`c=dqd4Cqi=f`E~%mH{etZAhd%_iLXYOd(X>4T40!#)a(zBC z>x1Sk6;To9`jXdLA z0%?p!xyczzEZWYg78?oH593JZZefBiFSsFqKl7?8vDFlUhlqK2iVNk{$prk7Uh3b+ zs3rE0U6OjF;*o~ecer?i9sG~!EqB}CH*31TT~0G{I~}pW^nP4>UZ#Ga>7Fm#%$Cpu zJjhCQi_e)A2haEZ1yW$p{@vX*ds}vOZAu%*9;Xt|Ic9>m?tCH~Sk|<9Y`;S%`^uB+9}SCBJS4V7^Nx=Hn_e`Jy|+P#K}8`}~nAdBFezI9>}nQ-8fJWHxH zAN3E7I(5Vw=`;t3zz%$BC>q+5s)52u4iuEpX(hSf1aKXr7PL?*KvFlereXw2@+dLO zz*_$zOC~dZPXD*8_cr0lxJ<1HUM`-fBe3WfEr<##D9(M?>*id%=kPO+pZH@(06Tim zy8$S#{uitvNE@Kt)@VtEg)=I+qM=5!UFfB^IN_eje>QLy&DpJCZ3Apg_z>}-X8c+~ zom+WTfvXg!(SVHRNc|@VA1A%*MHT(Q_;>BJD_xu?wC1968vQo&q6v)> zAP$vh<2h&V4clBN|I9LsNDWd|rGeRC5~3o%edK?OK;RV(Ff4@$9V=j&jpW@&bq3qZ=cK~-11UgRaF66 zW=6-Lb&-FT&85+W(otEaFHrKxd`1q*=wt{p!mcejYfL#+=A^)P!@ij5Cw!TFlK8>U z5tjS4V1!NWx_zHk?4Tw?Sv~f%Or1W?6pv0c5U%f}#ByEGH{J*odz5AnzGI%Y=(nQ~@O-o-T z<5wm3@o4+xIwCa(?b`cU2q+qs62?FQp+O5dgpjR&G|q?mFqWvChOxqK1k}cMdD%_B z5WI!9>Uc5s*cW7w<$Yo4cu$*rNm{3U^%7o!4ad%t2IU_LQUaG#p4U?3GMCv4)M#tr z3!C`mk{#~^7JX7DCJKIt{HSG<9aV|dvlYoOq~{|q8keCesaCZ6BSY6irTY#w(3nMv znAjp$32^<`3Mqzs%i`DYNs)~qQ_@h3S6@;oMKGLIHZj(2lkLtN_iQQ7;9zay=G8{4 zVkcf`@N_h#i6fe(=d#j^UydTKplf)CUktFt7V&Uu4>t%a;G?YYyKg?lCzY)0j*_pU z;n8#-keSu?y;NmqPa|8-&hcXS#`!KX*!i)T?^!rM>Kax5%&7&p*F9TVr3t>5{+MA$3(@5m0Lr+V54(g3MRL z4wzZL{re9$N|OP=Uh{a#k>$nUwyRLdLIm>6XT!>AjJxz{YQAr+#hzHimjt=f;OwU7 zH1<6DxxexnoOh#<>AMwn+pBjx=tHzke#g(=zxD>BV1g0tTYod}cQzb_;y>})}pA2d)~(pYpl z<6Tl$$A=7Z;RHiVGpd*b(i0zZ6BSI*R%n3J9cljvwdDAv0j*OB&R93B$9){`d>DY4 z#BxlwH#Mf6_@!9M0>dvp{v>@0*LKQ4Wb+)vzPaNG)u|N^q=)MYTL_%7H#4T)r(@)* z>VTrK;Q=74O-y8C$|piXZLJaK4kY)U4?D8Aol@?RCCdp>jg;~P;r*1yJfm$3))G!G zo`s?V!QaJ_AK;5ywI#$Klw%g-CPt_MEm;8j<766>8hOJuWzXq)2#}HXzq?tJ!svMN zaE8~@uNiabYNciq=;RcN{FX+wTg+ZR5c}Ob`&D^N_iL&(sLB{0#=rOE5h`3(x0JA* zh(CFvJeW0>G3GO43+iac)E*mAOy;h9{iz!-*vH!cfC0bHDj!(rn;lQ4ByXdWv~OCl ztgOaPl>E4d)5L&VZBz#djE|Gz6T(DBC!smE2FuiskZkEm&#p=|uwDN)aK(Inn2NUa zxA@rDLg5;&!R8CNn_0YeGjO@uw8FN>jV`ot_qE{n3COnz1tP>n7i;6y-mJ|m?(o(! zd+aKh(li3Dd_U$bThio^jPG3K63i_lyHAxthX;-(yRMM z5ZFBM{>zFHtCnSZzyv5TV>9!9Jfbc0g0T2SjO<=-ZQLTZx@WOxw;o#AjJoBxH;}0a=en&(uNR-W+AT_o6J$6tyud-ig-~Wma)GP*eGdgMjGGc#>Ofn)C!1G3%(yQ zFmkQ}h%OHI5?64GSs_`3eUDITl_l>BLw9C-VfFmM}VOVZ`NB z!9?c!BKvGV1wG+lq9x38xP1Ew81zRJAnp#S;p(_lYU_QI3F1og1tL0F z?CS0M!yS*4diWPWtqO!HvVfYS!jLB1r!$$Yf-O#VP0_)wXK;xP<17D`Y?kAFqyi@h zkZ!asm1|_74j(>e+)ktB_IGt$n1VyuzIpVX$ar@`DZX}Vv@%9 z?1g9edg=2~OUEvR)2rL^oS~7SL;wy}fSV&tQXangq5LFrwbp7*Uq0t&9@9^sWE$78 z%$Z?(5m9)I^%sN*+3Er+8V=#Lc9z!Q3{B1k~K~G@Y6wHIRkAukX_gTyo z5^;Ji=iCo@8UiKe^NWh9+^WZO_`XWjwN87?LAy4B0mHA80zC;GoKMzPX;-%JxE1+rOvJ2Scrq|t^-l4Rm? zNZqCchko>;e|UyM*Ri`mHpx-}`g>CMeumj}b$To8eboBF)-G6a8vcJ?0IyRPj)%>w zc@$_rZCu#>UGJNpI~Ct~cJ6jO@^rF5%lXTRq9?9@^qBY;%4$&a{LU( z?5YGfMxQ*Qlh0}?3PpB)T@cA?nSZH~bvgo2t+q=nFAc0+efC#tf!KM&jT_1~$BP5J zqKuLE2GcI7zq`}qPU>5!<6@hMc@a{Vd$8y6J)kQZe@U0+&~*}))sX9ZTcf2Jw;G9O z?u*ON^U&22Zl0KCpd3nL@7?G2J#e<|}hL`(Vatuo&fbgZn5 z(o5BogAZ1g>L|^mTr{3IYuh&%>J8f1EeqO({^NoeR3UzhrQlzSRXpMUf4-#bnUd@#si2zvieR49%aZakGh z=wC~$Pi?j6F;SL5_f#PE!P+me*^5iYr^CG$xNu1WQK>OGMN+}P1$^#+>VUVoCg+Y^ z5Q*$?jtOtDpN|56JMLuuS~^HBf_6hRcR#$FR#ppbjKE+~NhEw^5x-R&FS)`KA)lw% zUK4v3y2@$pa9bREsK7F4$=;oxP{YC(Ee7*Vz(Z;iyh1cNUklqmgH5iD+Z<7p3cE2f z8+q?(LrVF`>Xbpl<;^L|v0x4K?STQ_hBcLV79c+_cyDW3dk~A=2!K_PR_jtWq7RBO z26RgJ6}jN$F%@KD4PqWVlb1<@UH-p*>v#UZf5qF(*!GHB*Mu&@*5-0T1;US+Q-{IT z7 zz^}eb0dA@O-N_gHJ1|?)MXPKOaHOu7LieRzWcT&D8|I z!wHOMM?kkR7@3?KSFE)3n6KVRD}OrorBQ>Pj~h;xfGd~NW#XQ3CE!Y6jYxn>TzY)9 z!aSu+D8%NSt&}2%6itcJo7e%E?CTbrNAjU6Vg4h4i$*5^8$ZDkvR3jNez@r&6xD<^a5NJ<7J}COF{Vu*x^(lvF+Igu!8CtDoX<@5!`WS}=;=L&XYofTY$|G<;n@P{r!8trBE(`aH zD}mLJfZk{EwJWGy)MT>;`7!dgZ{5<)_n!bczaeLvX(BK4$AInp2BixUM;?JMR)b*8 z24m^0@1j^p@jFS&lA7O8a(ohr$9r+K>_3qD;rDR#H+~Iw{rbmHS3yf~erG=<4|?x| z52NSHUqRdd_yXSj?*D`!^UP6SELeW&0+vUPPjjOO5bSuJgkb3iZHon6Vw$<}&k~gGCx8(~euP%TsWF1?)2w?8{>E2u8-&l3#|wuJlFlQ9p20!J zJC6F_`UJMz{zkkwl)+^s2{Yl4W*P0WYim6(g7ADM_Mh~W9n{}Z92H-Hh_2-Yc=MSG z;J0+DAHBVU=pPut&dWBLbaef+z&cWCnfm3D6Pzr45xKE0PLPZnOMX%51RHi5C$YY8 z+~_w7#^_w>z1dmP#h9G+BUo*LJWk8hJ#k(ophv=IbX zp}I{L$i~6MV!;4I1c;_56F7EgH`+IELJ2vKj~za2!0f7;Dt@b8^quI%!53dd4Xs-@ zbZ$0FUd2UxXy1N}4iBTMwiaz0JLu3bg=ZdnoE=$$-YOTv)?K@B{OB9a zw{1gJT`hXLx^VCXmaCxw9b2}rjQcS@I*Ks4rV~?BXzSR3imFNuK39N;b1^}>*IWrK zAOSO|;{a=LXw=ZD8OvyX7xnek24p`@pro;ZbRe8;Dr)__K)MT^5}4v8u+3JNmhIwg z??-&gZ3eV9$iV_5MzzD@Zx8dnx4-`NNZ$HtjEqm<{`(%lzx>gc;CuD0Sog)RsaWH*6s7NGsJzmFSVc?;nJw(H7uf%Hu|HHhT3Y|nG>mbSu2N3A4BU3>&9 z-60)9EB#pxfc>r4GZ9Ol*ubT)suS7nhe@r%m39O%yk#3`1z!nIsMG?U2}EbT0etVr z_u}7w=fB{lH{6LZQweYCK;N-rc)F(-+c&(QPTH(hH+K1@w`3roV}b1o2F7;OPv}ImYByaN9HFumoCyzC|;S=KX_HdF$v@&v>I9t2XdVXuR%x=NXNdj}< z_bF+dq5w|0vg`xt6d%oVlgSxcw|8r960wRP1h{MLwQ#V&zG7DwzURU`E4>_!1W{JU zwuiK1n(!8|?WN_q9i%xWs$qVQF@HH~B29?TwI6;un58yn)D_aM(&4n8pQU5gNlYV^ zJdU_0j_PQk165A=^0}(K25=V&y+}~`qiiBJ)c{9FEXSjY9wwbkkcjp3eL3#u(L~Ul zUFTEVpheO>-BRzfDGo_uKPL+IJb_(ksw&IKd*;K@qdjH-x^7*A8OYj}?RJT+{^n{F%g({wx)QkbBp_?f;skbHcRjxQwSUB$-uW*4>_Hnv=S4c`7M?=v9%SN`~OSikc!^dIfQEAP4s*W7$Fj_yBz zhraV2V|jkdo8N-1J9ps+-~1*zFTWfOE$gu7>8DMc4}9{sOc`YA<8Kch#EjQd}qu_VwehKl?}6#N*+CLA125 zH{kyd@3{xZ_wKX|NPo6cv(t!Ii*SNWca}QmG7{du~5@yh}+d66Q(_ zuDT#-s%7JuH2KfZJn6m2>tNY|Bk6Y{XDYkwxX7f&ZmCyZft+|J8=DV*P%QTH8dRRK7ke4G% z;%=v2a@IuF+;R+RiXc^Vu?9W|(ZqQ3Ts_HY;aISY?QR+~Tm>b18Ph)VdNMu5v1%Bb z>n>+}zp-}b1ER(~$9B0uuF6ku!)!i<=~>df&5YB!dI~i$(yQ6;jJZb>DJ(ait(n+0 zD-{Y7a~$e9vKwKZXH^vB9_K=^xuWawMmb`Sg#_q2Zd#+eDx)Y~;#|x&Fm1J%t5H-d zpIP>Ay!;!*MCKX9ePsmtZSw(3EgJ&~^*7k2uhchd*GH5x3R;P4f2+#M4Xy-S3Ahq) zC9w7-a6a_)Jm6kaQ*IhZ0SB_!Q^Vg+s);>&4&zvNA2x4VNAC7=(`uT={(O{f?LQ;8 zgsucuOajKLl|Wm1v>T~`-H30#%~-jL1K8sBU0PNGoqp?%H{t$od;?eCbd#}i_YnwJ z5P*HtTi=2^-t|j3vj1lM$uGYbuX^Kch{a0`g!CE$?RyEL|NOxRaP#Y4i#PLniVlGy z@i=aO=R1ifWZ)zgd#JWKGoSp0%S^5Z@5#Oi3l9x?pn<}$&O>_``~{f|-DW$;Hx%|QT(p6Iw`3|WLz z-kJWF4DHN@@@6#L*oeP7xCKX^oW{)`{Uo+R@U>Zg9%F0-nY)U zzZaqeq$Aj_`J!cf2Q-;9!f&F5pc>x^_xWCkPxQ1ht3RgiUzA>QcC2qapGj~6G-Xz+ z$gwfeJ9Ev%)pIXYBB!N#`U&Z5S+^$=GdOUtTS+2L>-L(4n3?c9{SNDl0Od(Kpq})M zp)^FjX(oG$#lEo5duSo9wl_HtMqOJQN@FEBHhhp&B~vI3S0KlKn(X$|Sf#PNo|R>M zv+~NS_lka#dN24+i1HDnKAZ5(u$`Sod*x0(eu3~-U%{5Rch16Hleby6(Zz!L9BgJV zlmw2ATCb9@VFB&}t|w+V`74WY0`6?u=bMyb>8*wHs*||fRWI$I#pki)YGiVp)R-MW zS+s;8e~o$m9uKElW`md<9-+ZPhU1bF(?^?YjhCGEViEQI+AHIHYTsA0l8Y7O0=Oo* z^EI%-NbQKmiqtZP>A>gk zkrT$EPgZ>^UJ8?&`{PRB(v^S#%Gim|%}gNK^#~%(*BV~fJb8|7&}T`~;Q&zp`PH}G zhSJJPeE;iTr?aV;p=pr`=V)&)>0-G2ouRs>7Uiw$FgY=S(z0?y%S!R3|N49IlNRQq zpZP31rWVjIN(HM71ocE&5sl%w`|hQ4paAwh^boGQ;|`{#K?Vm0qisTt5|Z6k|t))V~-g?Q0LZnZowxXdJtdv>}T<+yYI%U zXvr#oT|lCE-NiGX&CGYzRD3tM5?B=p0$-f~ zw*UbPq+MdMl!zT<Xtg;9I zpic&Vw@*C&I8tBuGJ@A%f!@Rf!jB%u1Xq*fJ2vt@E?Wy&|xPYsfJK{v|z z9Ofb`mMr4*?Dbr$E6Z`i^*iwFv-=I5&}HOtkIxO>Q@t-?rt4u^=~p7Q?Jfk$>MRg0 zL-R!CrFy#IB9j20E59r81AC)2hE^t6*=pYHi>#uTTy<=nu4k)B6-|C-=vN|7A2_1M z@{rmiPd_yNk_PJMc5bVAnvN2+8b_eF9i&v37}Uq=reV|Y@VHs2BkT4MSMu20?JAQA zN|L*>YS)fHbo>3f}@ zhf*qby_f*a#EK?h=qF|R;QdIjjgo(*ia;rW-YSCQdaKWb*nlUaw+VuI_m~Dpo)o?gHIqtsmey)oCSzN!7G@&AJ)7|%UbD`;AI17n=TaWk$6nc}K7-!P`S0~y621uUJ>}V- za&Qq=)~%8&0apU91RN5W2i(oze6FWp4_Ivgp|i6cGh90V^fNDF!}?}gx>uM%s2$Id zp1bQxz?HyqCBV^y`Ifj%9QhgiWvvL+cF;O9#q-MnYuJNPr=8&23@uylAn5-8f95mz z_NRUuzjyz=yyit4t;(Oc|9> z6E`_I$#m%qcDZtOH?!{l~>@n zw#D)`lLTCma(rY2FMjU_2x1EUyIzN@Z+r!IfARmr!>_v?u}2=nR{C=2<9F<1-I{C3 z%YI6bUh$FLC524yv+&pLB)ClLPA=(Z#;3$Q?Ld_!;EIE-> zh%!##*~_|5D}zoj9}|o|<-UEald1!)Md$0HYXnX#OMeaJ1#sk0Nznb~o3F%?qrFI` zvWU=e?DV0Bk*CwV5P9k4YeSZpnp`kpS-RW0#r?hTBp_OubpKw{UaO5Y6GmtHE-t)k zUeG1B0WeGN7SUOAIzhfO6w;$7Fw^@ybpai^*KMU%&OUI6}^I z1LbY}YvQVwn9(f;d|!gZR4xI@Q&R~XIAn3Rm(&DNT`%i)O*~pbbSl#Ewyux(D-6ij zmto&4SfoDo&1-zCI!W~UWD46co!52A!k+j}aW$4RD2^s9W=OpzPWQ0idIpPu>DD#L zjW;hfXwq4Y(EAPZsR~g6gtpuL{p%TRm6M@SH_r!)BEGjx3zXtf_rfM?u#40^G+qk+9N1PfsHx z*&9gKl`-ZzYv*j|#>ttHA+ze%A1vj&RGgy8zGEp{lefM}X0G>BxfaAyGpnZb5+!Wo0FEorc0j?X1h--sno;l9zyZ+Y`s0 zGFFQ z&p(gS>T0}`6fzaua->WCI}$vJ`|#A)AN%Mz;ZvreDCeCt@o|zaxmQ*X*$zBfJ zW(e%;;A9(Dpm1=n2{!}a>AnSmR-&nGb`J0hqiFz`W}IiAd=j(&>u->K?|Y1YhRy3* zQTe-{!UL?+&p!8gJh#0QNB-msDEs~2!G}KjFssV@U|D4V#gkNwA#OioAI_=poLfY>KFT$()Y!1p3QL)o`v$#(FAR zK`=c`!2cM<9e|I(nTK={UQ*x4YLX8F9>$eJT1~cewAG^fz>63fd46tGDM%;xRqgQcosbSUX`ewKNT(d_I$^BaLjgKwZY^OSPAiQG;?3Qg$|h;Gn=znr zb+pj{y8;el^_=)*6~yJf7{DwUtfioKOF`|EJ$WttUkFG`Ha`Wq1B^BEdDfu4z@sE*OcP?UXDnuf@stKKn91jw(F>aiH5jCl=N&~dTUXg->O z-3ye2S${S`+P7LF>)M6#tH-Rml@M^J2q=*i4oaVbNpsRY7MMjm$cYVRYUF7$^N2d^v@Y4pML@PL?Az zH?Avz3ts}#C954gR9>c88Xg*=^2*a`Dm|Rc1znQ$#pL8P9{Sm{bgZ@m)z#&+cs+Ax z#!kcCx)N|DP+S7)$jd=udiW@k#~vnc`|a@2deo+KDSqeaSFG<<);0u(XiXC($F#!a z_yj`iYzDY4)yIKnnvNd_`}=z9VE z&k%UmAg7E#e}Dtc;ei2`J5A@Pjl7@0y|EnO0AwbGC@qY&9Mlc21XfJ~d@nU#()Tk% zx|kBab87$ee(OCI7@$>OIu7w&UNkVyd|;yDc~;^A*|UjJI@dgboB`Q0w4AKss+MK~ zI2^1K`BZ@6M}CxPl2 z1o>_L`~COhrQ7a+r+FhQ0}W*dTyTP+K4`yO5sr+a$fFfxaJ0Dr?(2&4z84-b;keGBOtYH02k zfv;*k#izk6myRE}m+RE45o)`dNE2zVR6yk=h(lWeT_zBMQvTe}6Bx^pD?UeH%)|7& z1k^oTNia*=mmKLLKxccJ5Rg8eC1s5#RE~i1X3!+!Ec2Nq=q12Dmzu=Bp(r+Ac|B?x zn~|oj^$_q<*^0`-q~!iwloH^#J$>K-_)8lQZrDnLX!=5sB5}jZD*@>O>KXM#GIaE; z;EPqTza`zx=c8|(dfkpAC)G2(dpY@e9D#~!r;IdqNM>`b{*fNNYJ!5 z>Pv|pV~W&Tevb?(e5fmFHS{HFlXR?LQ(BmVHU6V|TL8Kb6BE!K8&RXNU;(?-`FuUm9Pz~>@X7(b{bAm7Gy{bv&0m*807wqb57n*M!hqMan_$J5<~$#h1Ly^X7J7cmfrrQN&|m z^KKWr=ad9^u+aCZa|&nkOpD#SP(CIT_s5lhD}jqr0w?-LiGK%aSQlaa&R(Z1CY(hr z+;yYqAp|~jZeGVF)#OH-yS<~4R=-xsL*Bl3IGqhS&P=}|aG;XfTYP6j6 z3F?>%jE~4~13NY1XIFYLc9PVg%#dm(OrBBQoD=AzL>M&S@R0gJt6|g$RT?E6D2Yq@ zWEv5~OJe38QOxA%B(b)k*4&>Vy-hA-4R8f`#!2a+IBswyu$mIkaDX;SeAV+fLZ2n; zX-yZ4Ma;KjCXx7lhs~suweoAhvdne<1+H5lyOtbhkRce8ouDN<|8y*nJxEJ&0m_Dk zfH{kXK!CiyC-b*p2G&V4sApdGH@8q!eLDhTYBUZaHeerCM|HI4R(z?xO(B1l=rwwk)Y1@?%FBF9vS~ zfqUwvJaz6YCp~2C?xSN`ADyv!nT9%Ax|XL!{wz6yJ*3jnbM(*((&MKyc}|XoX{En) z6Lk`ou1mL3Qq1nu`a5Oe?q9?bFz+<FaV{9^8juwI+rHzzWoH--(y)$x9C#{oqHk zXD=u8_L%Qqzny-zd83~$qO6`<5+^y@HFwp;#Y0f9U26xmhs9l3b`>)OQ#xh;< zOK`HZCfZDAsqF-GEqN5Hx@4vajIq=p2iCM~r#|nQ>_X*q9coIO*w&Mx&1%({1ZArC zh~G0WU~2zQXeG^+3pM=4N1rEo4JX>t6KJj4MDV={sq_p+rutFNiCjP1q3P5F4h%no zsq6p)h z=NjdlwU@>;;;5HI#7(a@*9yyjhn2q4nW2BDidYU>Awta8d=27npXH=SKBox_j!B68 z>v67R(08YI+Vpo=7}HNw2Fl1P+)8G5Nv9nHRpAux0f`lr8GoqYg;!T-+Av`vS#B!&W7Y$P8%c+xYa3!!R60inOT9Gk5l_ZVK zxUr}cxNQe}$-Di|n)7`BP0%;SZ(2Z)ETS`{Ca~yY2(t6LmQ&4Ot*o|d=@WrgSo%%` z*f6fXA)YYjti(?J)px8v`I-C8GJRJ$Q=F&CkiLv z=V~0U9Fy@IJy|{uZUs`4CMLQ6rv&f42yMO%v!sjh)4WYG(n=QT6WxQ6{qU!Tkq=ZL z*nBy@^>6oK`=<4{=Bir>%#1UiNu-ZFi1bU}XF*6w!*uF-(TAVLb=U4dZEdC7H?jqE32rrkCK{3KcsJYf2N35(l$mTR09P+T z(Y!2GHsG2-Qhuz{haVwDOs@gaz0|p)i^)xM!f>pM6C^KE7tt{)sk}6i7j3`E(8N$F z8GWt7+kKv*6)`$k{TG7Zd=ETC`(!i`rqlbGJBa#_ZV-Q(M3g@yAgeX`q!bX-cSnE&ms4DXi&wh3C#m-4x@wL`CW z#N?-m6i0J1Upn)L?>2iOJlVPi)JSJ6x|ot^m2-~1%L@P*Ht z{OtSfdv%|^udRaV!*bU?HYeR5R|2jCE+`3DU-QW#7apIya`t;g0e7`n>Jawz4WqJx zJb`X-CE!Y6MI@k3pFo~GEn=qj|CrPaWr#G(aiC}k&ONB%w;O-wzMb+y=Xiqw*X%g@ z_U+&V({=8YYwC2&bv*3&+7{;FyhqmykL`Q3b%w%poY&laR{|?30lmiRJZptWb#)m# z_hV>lBfXL1{dVp%vXwo*6>)zHcoU$LF`VoUkiB}d1+t63oM{=5T{H!Ax0~p&k8xWy2e3sxuDw!bV6IZ`cpD9i# z%+)mn;3w$>wqzasQP2r=mWV-=OZAkFR>#Ck%1B2w&A1U{TCT!O^)`f)z3>x|N{;_u z_TB?duJSq`K09T1c4m98+NNFgiVz@r$AAIjUaV8w|TGYd*2;D!@fSPxQmk<@J9?s(x|TGtbBhZ{rqa1F}%*sx^6nH@RTeK;kP zU3-Z*J)psZ48j2~6r2RJj6k{>*1=IHr->gh4rA*EYf10}LuoNlHM|#jkHTUuGt&(V z%xvWG|_?NbbH-q5+&10>5~u|Dc{^^eny{aU-7?$Ls+6+m3WePtOo&Fr1PN z=a?}kd{v;yL;*kskiX*GDh1n>qn%*lSsXZaQVHAz3K;^=4fTsu;lMeD^J+#0k8*=L z5Phb!v_QvJekO>j7XO$#vTzEs1=jFEd?uGW4Kj|-$!r7W=svZexb}7dIQOKH_JhbQ zQcT5(Df}bo&a~`trxbZW@dl+WX$^gcpHan(r|wd8by!hj?d}F889%$B;ANX5;F}Jm z4PXAKSH`1b=>B$q=qMBN>2!?Zekc@_l8$8}_;<9KG1vS~@YoGY@Ty$!`s4FhkPg95 zTqZ5Vnf@nHF1RK@9~+U1Z0v#T0NL#U8TL9Q&0Z{Ffa7rj?`B7uL78a99*%JD5)oG_ z*A~Y<#QLN%izjexHmtuAG^r-f!+xInJ1CY7>O#@5!I}-3pcjED4+&65v!a!y#(M1)dgg z=fuI|do=(YxDX15lNUBKj^Db`l7J1wb zq-d>=mIN#b%##FY#a>X5E53xq9T(aPtR~OCiQO`t9mfE$1iBBx!nIWa8yl_Ojse-R z=m)?XEvSIVxo zcG>gt@3E6@cea_{iW%15(Gh z>#rngl2Ei!*-1Jrg5v<`pa4w+aEc1ju{j1Mp^mGFYVH9K>+=BqVNq{~Qj?Sn@T& z#EX+(#`w+gp7dd~Q0@W63>}|VNB@P)xMn$7p!CpNKu<$!`5;avunyRNj3?2u0OGsQ zmY{qeLVwC3?HqnI8{Ekfn91+R1lI}7iyaBG{qVCD=3fFntPu&ef9-2umv_GNotnV^ zJ^CB@zsGR$F%kCc-7CNT^+VF!)GW)EEt9vu{cTcLS0_7m?2zC6?)S1{#R_@!(f^Yh zZn$38oR2^LDAv21ceozR|-*W3My0-4_>XN(fz8mycFa$vx)49aVnDuT+z>>g%m%wo* z6C5aL;YW_Wt=slPt7j|#b+NJF#bpV=lE5iQ0E=`|8brqW#k>D8apY8q2S-%3Z{fFz zmEtKRVLfU|z>>h+CBQ{8LG3K~9H^~@H6(($;ZJs1J5e~7X{j}K_?)`{;fxz%^jgeIJ-a0-^mv8y4lCB-2?!*0VKT>9T*=x zcu0Qrs|V#>?|8es1FxUo_j6o30Hu1Syz=U+ppL7Pk9_z;0I`SU`R89i5$&)5YLL6` zx>Ihy{cZBI`+lZ0FC%aO_qBiis%$uKz1)50N90+6@&w-Lf8j6SptWJiQu*kI-Yt8# zJSTerst*i}$bI+SC+~jOJLSFac^52{?w8iqBk~|NM^%+&@~Mx1R5on@bpTc*UN}?s z15oFt=*G9)Am97`4`q0GSdKIulJ52vY-){7?v^cE)cJCMZ;yQCi}%R-Rm-OH>LG`!eE`pV>8;U@T+c7*B!taF{u)0r- zLGzWRH!~iyC>%Fge+1RFUJ{vNS@LU7uNQUGX48k8OyWNI zJ?yVY4GA-T1@uq;kafo#B#;gxkWYN_FJRUFS*4ZPy?ZxKO?u?ck9iAybSB&JLJiyK&1$SoPYl6SLM^6{*)Sg?AyCf z-ifvJV~_tHzZr_c*|gs|h{Afrl7Jro>Y@Yr-Zdg)hj9LpS*%yLRo8Ti*Issi-Jp=Hymb?CjjRQ#NckU#`3EI$6DHC4l)1 zxn$GDvJ>~3VcWKC;`MqpEeZ{%a*0-ka}DO&M=joI^^O;>(XR~wAoJA0bRf!H)3u&EyClGIfuK9*c~8T2 zuyp@}jJJVmrfP$vU`&{xjC-TUgEL)>=)Vm7t3#K5o92&#TC^ZGWF7Giz_D@{j2OBw z#K3_uC_P*i7pgxTRdSxlkl}RK1LD{6z~Y&pz7r0z)4=T>0q8!^eMt7V+6AOll9v{j zy0UE0kN}*A0wDq`d=H#7y8%qnLi*%FnMPJ;$YqX;G~9wS4-DIebvwD+X$h)h=?n{K z#=~dYKr2&_Pbb&23Azf0Od|k#35>CJjJC&ESX)$fq`R_Jk?tSplKd67W3EH}fubmm zlM0<9Etr$CnT^0G}e8M!R3-mui zhpCK?c<$+Ls?+6TKCY{jQTI+*pl5@g&hDs2c}xW)4UKG4U9d_zh8nR>X_G}c4dAe+ zLsdgzFf zk$Eh^F@QT43p{q-($b-u$cFl=iOu9ZrfEfGNnqhfKo{Ty+taX!ZxMg%3zEL*VpzZ~ zo^Z@{RO#nN1(Q=gw{|KxogWbCn;7QGE0NB0+eLGz@ z06q zaiS*`Yl;Z08B0q`WKmT$tT!X_jsN%$DK0FO%1Ll2N zW`bo1hO!{0N)L4e%Q#aFetDLR_wtx89jKa)msu_>UUb3aaDp~KQ45W3&VQJWSs!C# zK5z+l%bL~oN^L;SP?O8m81m;V&TAI$Ci(QkM|34f%0L-T4SBbk|ksQFOpTQ9TjH&5Tngh=Av1aiN zqTS>KB$87MFnO6O6FGjXjOIT_r#(iFm89XKBh-TjJHfRbfzs8hempi^v|7_Q$J3c) zhVu@si8C_Xa_De7fUYnUo=~_Z=CYH;!RACo`gjNq(S1E|XbKOdlY@@&A_bs)bQiBy z2iofQ1MM#ie*g~fyp*|W)F((5D2tLq7;TfzZ4FuxW5(t00e=MkMWW(zJ0$~-U|Hsq z1)ceD+k9{MPnPcK`kh5a50C=XU7w%)_fXzLX~wHY{l%p`w-yvIA<0hd0*8HxbdGYq zJu#;{4i6w!$kqvk2tfVh!0+K03qG7$tYAsNlE9lQ0rXXZ8{Cj7@B>T3OgI+} zVxt@a2RH#9U&|IaMSKGJ#If^+>m|K%tx`tBBe1SApPT3Y%=y>c7?>NpnFvZZC;*(f zIiLkLxoZi2EMLA{kHrpx;)Sor;7oPp%9Y4}Oom{guA4@H)dWZAY>dvRJRXm7sPp;F zuWrV@qTn|-I4QI$MVSLghmX-LIH8uGs*-IlZ?Y6esRMR<;2g(%9a(&S4e(- z0YJ$#>Fn$V5ML_qxa}tJx$lu7FF0;t_4)h9A5+Vr7Vxld-nr!?~vEG(?UKZ z2M-^XpFk17Jh6-f+UY=*j#(Gi)yXr@JOh9vE=?`1^3qE$sWaG_039=tE$?BvnE(&Q z$Ai+?)GmGfLn>#LA2@GF%g4Yp=QCZ6)cSKqOJD+YPlIzt(97_<57zF!md)x!GX)AG zo|NI3p|3N#H1n7_voEmR=s%>_Q(549c&t~cR)T#^I0e`y;b8!@UO3kT@EHq20f_N; zy!ADl8h8p+J+DBSH)c?H)n5%7uS>;MR4+DHCgceoX8@lZqapZt%>1cGrF$%JS^EJL zH+PPLt2#yUvs}`!;bKW&a+73NTqNmm0GZyjRnkU>F}J{bCLf}_&eFiKkD#~*-0QhH znc!2dfbWi#>KBaj635G#2ZFP(k_IIWE#?OXhIO2sm2{9C^Aw1TL$nEnkC_2nk3;d} z7z0&Iz$gCfe9S4v$tdPCgwt#WEs02VVFN7C3li4t#x}aCZ@2V}9?`jhY490LN#gfn zUWB5+ov`Yk$$UVm%tkV15zgFq)>4YN)3Bb2I3X8OI~ln(+W=1z8grG>$?&(%&QAF6$&e?0|G12d zjPerJvxE9hV+=dijtmh{d>s?efOtxgfkqms7^_&148>*D$AIy?#`;Y|TVgl_zIO%! z_S>;8Wja={Bw$J4?3BP8G2c#DxEqP3$iDr}l9!i-V*l;E9yKo;J9-4hJ z77oIKeOSf^+GW>{BeJT}4$e_nrl#hJyXJCnX2XI805$o4HK=9g>5(QkZ+w}X(%GcK zBGNJ^j!i51%e~$)waU5bs;lHb|NCdUp}+d-t7ZAJrEp@`Dl0)J!_5YH%JcH_u#t_+ z#`DjYz5DjcH}1Vx$^eYtdFP!9UT4Dz>!MolUh=3tEdOBJq7|(l7C7AU<8D)WsHwTn8UhlX%mv3q5g1lmI9$SVo7eG-H z7Sbl9rV?C$4IX4_g@q#ljwQ5YS9+PcOVlbm(7jh_W}G=SP`WRHQ%_iWlG=ix-lVb0 zY-^^(lE3pa!->X($@eGUoBZ2U@$=eL_e^(vx_gu3X5XU~yA3aX=4qhtC;;`*PKnY| z9WtCSS(V;3Hi|yRs$cHBunFmGvhDE zj#iu??(gZxn4ALcVEFL?P!xuj%+xZ_9#pK5VEZl^-}@_xExjG(g>eSPSX9UvT`p6) zYzqu*Z!9an6C5Y~R!eiIUdzdz+uoAZ$}ygDTe74Iz!%3>o&cCSOxZ3eM)L`ksrf8_ zzk@?>vF|o$vezuW!jOe)&tu!uS9Dub*ilSAurX zTx0$FH@>0%hJNznpXzVx*RO-Wpf>%S7@qVqPfO-x=g3$7@gI~D@x1fSlU^83jKhBr z>$Rt|1?#w@{yhc(;13K8fd74w-2Ksy$-6;AGdlWX=>XXOv;Y1t`N*Ajq5m7>pC(}a zu_Rzg;H;Iv@w3gT7exVg4iR+r!A&VGv)t(}Xzi>G;;D<*ieW)YfRnB+zHofC>`4W%lbMw%Z|0U3pQd?A-I+$zOhjpwJng_z=KHu%jfgT(j^TNucvjQUGDnGM`R55 z5KyP35UtpkE~%G>nsOO$dO=dt^5u#vuK-v9?t1VkU%#PR;@}?+rliU0<%lOJ`hxJ2s|A>zz@rY+6<-tE=r6w@regqyDl{Nn ztLv~u>sbSAq}8o?58D`%<;%RE(Hg%etS|K^BW{ZG=(CAy8j10I@)&o_eS8p!@EU{u z#&=B@Kk;+oI#0Xc23V#0F}98<$Q~K%);nwf(Nl|7z{zQ$QgZ=Pg}m@26`BOoLBqm# zI-ur@f$}6hi;)6SnkcaTd`AAEd}u*Q1>NDscC~meE6azXvRKDc0=*obsHjORTMh@X z0DgA;0!4hUq!rg0N|`gVWJfc_G7@CxSj+t*6^*PKIt@LrzXkJ9t6aQk^#m|>^vPL# zV$;Bjj#oL(GM!{)k{Oc?6foS=8eHv(tH=v`kP|0PT@JT`=BfZ$|d~d!$v0vlihl;~y=YQ|&G(%dXYDba|U`dI5bN$|Zj& zA^~u?Gmn{>9&H1hlcvhEnfG(`oozdSlPNx&SSiRL^pG%ENGdQTN*?{J^g^jBjKMi= z8|r&i(j7-XqRI?X8pzfgNCQPspZEf_jz>ELM|`Ti2*U^Do=?g<`d*p3tsISU=AW3h zImT%_$9F0cc+Cp)D*=;vfkq&$tq0^MKmAYn(wDv>V?MuJbLA!K$U9tHciAi2S2mbXviZfF*%>lz>iQn8vV3P5~866f^|EJ{W?zg3MkG$_H8}sYCZT^2-{gSC!}en&r9V3Lc>2+!co;bTds&9dh|)>y++h zE_FFMN7nbVPy%QdY(pHM_%Y(`hjM9$D&RA)K45=BFypPU=+4k7J2^N^o6Le&J1O>x5b-{kj=gB)9O&qW1vy6}NGcE$; z`V8+$q{+DHpqL6bqm5%MFt6c$_HQ27chGS(^2qqvFUW5j2EaxDIXu!Xfx&i+v4xUe zK+g37P$=Y}~#@7s@L=erHS#IW=)GP&z zdq7RrAs1b=3X0v_Q#v`#bZ8V72!!PI9S1>&R;S8a(?E16<2?J^SVm!UwfDq4pJ{IciOZawitWkX%vBArK#c5UQr zA^c^%r9#os(tl94w2#WVMfn(GylB!K%Z`@->xvfR5!AtuuM*01DBRT1>d~9otL*qX zJPrryX^Hoh1|XbsNOx#b!kG6e#USb<9S(Xq<}z^I#Wg4IWxXW_-p{yr z8q~zSI8SnI%(;@E8O-mz=TCon5pkztOuJCy{=_FgB^@1|^4o`ht?@9v$>}7gX??aN zU`gQ2l0ZlI5RA=JaWXj_8PkzU$D8@grTxoa{_@{*5Ib<78KC=sR9BZJCJX`+^O=+t zmnDI7Tmo1L*tns_Lfm)g8T8o*xSp>8zyxqg7w5-L^yj!Vtm0V`IK2|!%9{ZTXmSD5 z@;uPJPy9z-#oPs87Qi`qa8qD?1`YxM8CZO)G7Jl7Y>a7+$tlj6RSf5+%W-^vsifvs zD%At&4+t!$V*<|bxNv;kSaiS98)c?PK#DNIYy&~};^HE?@`}r)qP!G5=TIsj8pg>@ z12-Yu6!5!lhD>=PA%5gF{%(M22H0n8dH^irsC*dUL(0ejP(lnytZ$FlM)yiI#Us%m zj^x799a=`9Ot4CY>p;se z*sOp)0Z(;+%XieV3Pj7z0#6}f0x`H3HydpSd9dlRcdn0&_QR(r7s|=7>NLQ2Zr1Yi zvZb@D5ARvn9H#3%e9j6BOafZxsCV{d0DPpAp`*`m|6v`Y9B@3$lQyZKNZPS^tGxQ$ zb5d1bFP^L%+4b61dEpOFO3jib+GhU%=WMS$`<(Rk^h$AgIqu1pEzkc+hWZDkyrxc? z4jh!7o43efICUGwwcp(LbICwF#h_~%fuDv)e)+$!^h=jQSpGQxKpfb;SDyOKZ>6ST z3AnaB7#m{p-0%MYg`-DuVbK=~`k~}XMZb&7WB30`Mu$g1CsnIpL^pgeJo=0Om7?+r z$t^6AtuMbUqk{udnBziU2Ples{Qmy`l^yW?P`YHj6gHeM9ypqAZ0eLh{Pt0)s;j{m z3!nq{ssePPFX{lKvYJqkQHJL0ENMO*7Z?ci968b@J9ZvYfW5S|Kvu0>j9-kg*Blef zv6#vfI~0!Lp53sPh5{zH3bKHr6N8j_FXJ`FoYN2PnB_=Lo9Q#~Hv(Iua3uZm%e!>G zECjI5@y_i|Q!15OaJOf}!ka++RB;$Fo%k=);d~Uu+%rB7fHOZwX=O}cOJxW75cCd4 z$E9&_r?~7Hu$Cr08u}dOeuB8Hl0XF3@$p2P!+6d$L|R{~&Q;-pN+^ms=Mp4#DZoz4 z_O78;^Z@|7g$8vDDg*ynBRJ{ggo57T!6%#&hZ1QtFn~B?GT85v{?2i6rrD*Tp-Q>y znU}fB;KUL-vwvmRwPOv|3qLK{ZYXH%P;_t&hU=39uaTa^4jDS2$PR?*X!UrxaY+D- z7l1ryhKll}D63R*-EcaLwVywfE`xy-IBu(2s+mq+^CBj~Ay}2!|PA z00ZE%Wi=RN>=RnPQ;pnu-jcwAkpL!c@<0=8@*R2-zz;SYwU_AX!vfnEOe?SoI`0y| zV%l6!BkqKajHW_>hF~a9js$!6!%xCK0I(i$S6wU)faoa%)u#)_+WhFR05g=T0DR;| z8rTS8H%B0$qZ1ZVm=}2@{EfCy=KM^H)!C-Y=V)=N00TaI#|-DD=6pYSLttL#J2x8S zo{cK#U@SV!-?5ue;5iDXhOxdKBIy;Nf`GCErv##@rQ#@Bg9iZ8`#_!1_>_)=w(Lrr z^ucL^zz{GagU{9$3rO7GB`L)hiL3T<<+@Ixm2N?UL|gu(R`B-4mm}WwAZZ0~Pv9GQ z)4+GU_>b@SqnFuCXu;-!dE5EtZ_s)qAHT2bp!oX^BmDu;0^lheSGQ%t8Zom-PckS~ z1wnPjqgJ#mBNZ}e32=xT86A+g4-^<^PqwToaby?aGbt~4MBPxLPUKB0=k2m=?P|#ZRl@+RJMZ}Pr{#N~ zq58AG`77BEpA6X=<`U1tyiT1fUrR2%V0=v5WH`^F>Q?mP_-P7}QuEDiybG-7iZT z7J=iqRPV{p&(?X12zbY}6j-y`#z!PnQlGfY>nJbiO&n&M*mE(L7#7b?0PayJtvW^yi+>0_@2H-1P+8D&j`PAo46Gl5(&En*j=k6Tp8VT%pZTnjt^v^BbI)hw)?43-lRHiF;XCetPl+WM_bPdt6)Xu@ z60jsNr34K1B7UN#kw*f}0cXm)t&5ffED0PZ0rnXM+d)}Cu-%TMtnR9fxbIj{=C}u~ z3zh^d32-HwkOJQm8x`GD@hbpLe#T4x>1WP3NF z!z!D1&p0H~VV1Z#HmzL@2ja$}+sq>4WS&lUU>*!B_t~Yy%>_5P43hzNBPJ9wA$kL- z!2S5%($S8MahjBXGjlS~&--|6U*PCavKu6=?lK+wLPtOg17(G?e6`ZZ#N)6646Kpp zV2i}YI>9ZGEw+5{RpVHBN_s9bgd@9${vb9S)3>{E)H~<}xD9F2@*I|jF(@u=Zrlqh zE=pP32$2g0GtU$4hL^a>HZ05eyWc+!nZe?mV{`suNzbnZt;LAMM&P7zs9C}tucCs( zu!@JHMi=ss3Eob30rHcdpvxJOC>%P*{Qa7w&7F@#q7rI-PU0wsyKDuDV4SMZ8`v(B zLh{Cr;2PIf)A0=_J!XAeAQCXFxk1+ii_B0zPKg9Y#SSZ4o=VAt#rjR>pC=uyt*}go z!$!2_O?Ta;Yjd`%f`$eu1kbDozm5BRDlvX`!NQV(0B0_&*UgUd?hkxGhP%6Epr>0p z5$C6_x>7CManu88v?(3Um!Ew`t0BqujZGI9$gd3@ zVSvI%np@GOZSu{ho|HXXx5~N;FVHk6k2PADv-FR#k0OPZU7DNQ<<%{F0Kyt4iq1cO z1)NA10en9J0El|#9F_{|ov?SUL|XnJ(e6TVR9`Of>{5)eR9qSZp^o#YCyw#S=)B-Y&y?g;0sO^WjNi?&5X|=n zeUh4mQ*=5D8NXHJ)PiOvQyM!4VAbCt8JX}^0OdX9vTy?>Ooc}Vqm0=1j5?k=0^|2%e>3~*R6boQ&~FGl zaWjkEt^%V9paW!x;Yd2EW8x7%=tz#h5g#_YMav}(zy#yb`v7ccJae4D%#9#{g@8XK zd7uNy%mnZox8aC6=%JV|ZWmDo^IlvyZGmIRT&&!gq2tFN$UPx?o#1H|3E9&sFpiDu z3okq`PkiuBx$xe9ky~IP3)n}?$&D+^O0YeQ@(18x)&&|2I(&?Ua1^f)mVwwD3jhs6 zKFG5xLu}=+c&F1d)-zs|8EG|0>tf5P1^|9U;)S&CO<0PP13Cqk?$}goAcu5v+t7=N zrBG7+GGC^0#CY(i#V2{GNrz#F<4QXm;W|r~K^fo!$Uml*_c8x4tltNfV>*Qv?l`HW z6gBQbah9wF5TB>{Wf`JleG=(@UB>nw5m)(oRqz(9RaAq871;UJM< z)QJEtGw;^>IW7S-VV;m6wTvwlp!!G`ESht)pO7nd!^>+K$KyfZ#_O8xzVe zfT{opAN=7DWXbvsuws9!3M%OLL!kww5CUmp{9dodMe3+xSg9A5mdbOFKd$5I>T9l@ z@JG?Of4}T{?pblc`u61q{#S1O;0GkXpg<{JNIR1f0VneCK{zmmKLj|WtF9}Tj;3ae zi+;J_s>>ygF}G+@m0WS_t@6l!-zS-H!o2a?YK+6+%msy2MrJ0g;Ctmut5(Yg|M!=2 z6Us#^`<+ieEm?4Gycw4GH@@p#Qc_+bk#SO9ogOP~70es-$J|2^AZ~0tBAd7DRq&bC z*c&&llv?n%o1Ej*XGteQG!oF7Rj!k0QG-N!4@hYLLlR$fg(^1Tlmd?@#zK5D)5Qm^ zdvm-^o&(H#_)boKj!z-@%a|O@`&b5!tG&H&;)=O2CnsBmhKF@d;-nMGdp&JpCzfzw?fC{F>n=Rj%7 zv3fiVC6ze`Y6j4!a1u&SSfQ+NY=%CDcl10&Q_(NGZKrxq!(>-xmt7Fk%{&d_s&at7@^98>O9GYz z&Jqc57)RG;@8-w(3=@DmL50JITVw>*1520IU_rU~4z5sgPkI1UfPc~kZg=p*lehJB&XvZ(9@GCRlnc89qZKfY z1jx?uDi-jnGtv|unFsG_*WpGf8|atOre^VD_nH9?c9UAh0ojiN6no^chovOASFXA3 z)iDN7zV26NkW5Vk`ASUS|<|#qYNhHl>mSyi|e#LHr7_W zZFcj6(GF(++;noWuD_WQV4Fa@C+L||DPizKrxn#JwbF2ZpVTg2F73_D^1FNgO}_Z> zZ)G<)&`l-eAi(#}{?~s>?b78Ego9`deBgU;kmnwLNLH*{C$Bv9lvLt~JHf2LI8KTH zJgi@}N4npm`$5N=I=RGoJ(Cz3$p;r2)ThtEiCeue>7H-g2vq!%_6^S6+bM z>BUk}zgAir+hnlmu-uH}^CgSBXRT(V8xwo20KQ_h(0(o{%wm9o90yhab^$$IU zF+5eA#i(PBX&6VCt~oyNyB+frdEhx7hZBH0M_(rtq&n^(YCq_N28Ko?FEV) zjVAa!({Yg0IeGAj;fA9{!+KteuK70qaE>A620%WIbDTzF^OW4(~(g>~S@JRijx@8p4PJ1Rxl zizE$>Ye&cTNudiASD>GRnE+^l8lmJFk;2Ry(8zfDfb%bgL_8CPfrKi+pB zW`pDj0SiB@_>HXc^BED$44U~#$}>QK6k0LENuPQuC@LwQw=s>+q_DH9Ot`v^%rNrHwQaK@RlUS+|!m=>-9 zX)<2uR8;1qkSm!~1I#9Xcl|vnZPE>pYQqWTgcB44k+E(GcD;`HzaR6LwGo)OY8Tew>E$h_Cm=QPAu)Bh=;gJ!!4OZNia_M!~N&T{=La3~;v_#`z4b&}Pp$=TDvvXwm z+O=@VS|}CO)e=KLfAx=l6i;@xTy)jdD635d2L|Mp_rD(sgJn{JdxrY^;jpyT^@$j|@h z7ocZ>!)mk?=@BpZ_0wSKjs}dEAQb#t8Cu^C@#lvl82wOGjNIl zYlHbrV|F=usnRu`nET&} zxS4Ju8cipuyu6&8HlM+F1tReid9;HA&2U87hRfJ^<AL~O zXu_H{)6@?~?`H&a2#G1spi6-@ePj1N>Fn!~ijqL- zKwYyO0KgONo^`-YuIZ3(N&zNaJT4DOzZoCdo+e#{ER#cWnjHUmLW3ZEXsAO19b3`H z9pWlG4@#mEWY+-e8Kv1SIy!n~&)#N$VEO7aF)b}s>o++K^Rw9|`K$r7i;RtpYg}|t zm<8~rxHwO(O3nDqXRY_MOacJ#e21Tdeko7fm21JzO~4ZU7(hCM*%sL5*hXowZaB*{ z#vJ}m8W~#J5`a%dpXBefZ00o$h)QXraIeOP?{N$e>_gKjrFV?cNcysTss5{hI7?!(%{ZA

E(2u_I(gbmb{J&XmoV{1CQW|$Nyvulvb=*Noo);o_XduQefubi~oKb zH#+v>b%Ns+mDPCSiKl2tbu})aG0>{_*WlsBkKiXi{-L3_oIY);0p(v?vJ@}9{3>S6 zn#t49PtcI-B7F4fE3kgUM%?<@J4{)%cB!nSA1}5Sf$e9VHIs%?SMk2r@an6tVFrzm z{_>Z<;p(fdz!jHYV!+$m@AxLZ_O)P#9xe@E{at$2IrGmZMjUQ7XuihHk|g>nQ`=Bm z{KnV6O8;O9#&4M2Mpgbk4k<(Ss6zs{OQ1S#sAC{&*KRdbGFrHMxiSdc!g|PL8q9c* zBp?OISV}aIia}N??j*AiwX7=!sSrbv4f~J&nS}urOb5YsS@k#WdXrXf&4?bokSrJk z+qw7%E*^%Wf==^1IjhM*=FFKh2|SOcr80qDPon|X<o}$+l=*qfYWAL zWk>ly^!$PXT132z%V_x?O-H9hc+7%aK(3a)GyylxG&Lt=P>D-UO2%cEU2cTxC3RG| zGlD$C0-+-4sn(drJ= z@z`qS`5(ppWh?RGvo9k1w$B*;c^#|lp3?*fu9{0I@*QxMkJ zfqH`5uCr6nwWXZEK@1VIB%~&~@btBJp!wmS;0E#(rg0PFB3klKr6bgLF24v%{`hB9 zaOhibhp`e8QBDV~#%yjqJ(J|o&U%O-@E#r3hHZN)F)GcC zQf^%61VC(T48DBF?TB%^m}fJ^WzjRJE_A;w7xSH#CgPIcxobC;FJEpf9IhnyJDUK@ zBE8`7jSHXfPxwt1_G{K`L1J~1(2ufhMNq`ojZI!!8nU{*N zC<2&09G-JnF+rB7yDBVDxPYAPeFod@=ViZSN2hbjR8rAhMryjZ(71gG!V~G^fOa_aIKSM{O4J-wveM$vutPYn@8MHo;1+7jf33or` z9%qnbZ?Es#Xpy#;RH1Qk(Z-@t8|;+Yz?Q<-eyJ40!4pd^w&O@rthE+@fcpI#(8f*G z5b6ZhDOg%+v+c?URHLUB36TWqsZ(@tEip7}2zBBCmQO#VuQ5fNcLLXURCFOH!EqQZ zRc}cd{YIND)D?DBZbTyGFInokJ>Tm-eUFc#(L+QO`;?!K)LWv*xn{~qv5|?-{CRlt zQO@YKHtgUy>7Va$lIp|Hd=ADs)INq+o%P`XPPr&%ql2XumE)YV&xM=DF?M?zNB>E? zs57?FC?hSi0M9-1l+hz+%$$ptUw#D_Uwjdoo0^TTx^?R|{QQ4^hPU2&+ZX{|b>)?` zmZr|kb;%1ayl5y5m99cy+l)!_6nL?o{ZK)L)A2MbH%-fU%J$Qry4n1cmzRrA-tuu{ zKvm8)lujPJ@y2rg)H`m-dapDAAef6d0SEZqQou{6m5CDzwu zG+9X*U$_24qlo3@WpF^WCSBin$KU&!S}@+3Dgm`4s)P`oOemcknPb-EH9c(`k2(iC zhFS1(p{rxw9WC|fXeg&8&sMV-jxPKN*S~ZY5(L}N)NV2G&&_VYIw#&7b-lDOlpnCYyucPtpGUSo-=>LjfZT z>A7>~7z-Hnm4_Z)j7u-O)bO^O^m$x7At8>mCLiZ<#Yd^kO)y7O1@1~g`{>nI1yKobBPY2}qta4b4Rj@XQ;9TfhHJg!5SZ;`{%M1NYxeNWKuR znR&<|KmF^Uy$y}zw)@1*HzJMHEg4Cvxa!=Q80#v(oMy%V06+jqL_t)>nrpAd8;?DQ zkR{6yH+~9fX~>s2K9MRgLtQJnoS_89wK>P)@TK14KuvQOHw!cuOOzc3gioeZ#c(>C zi(>pLT8enRMMz3tz(uhhS8;t0!({F6I$E9cy)CQ%Vw*-z#XPNL_%NF732d(e*%r?JBdJ@FXO}vJR54ZR;+~m^lgI zsZ-EaypGPL$8)oifQ$k84?U}0_TYO^0)r|6&H3y*ojh^VUbi34oY@>6xghZ?gj%Wk zHTTf4w~ACzRDs5($zsiVDr<)g;0I^stM+n;OXJap{|Mg6{Y zXwRR;O=voCrEyAwry9+zG#H@4O1itiDxTV?!eEux%57M^+TBz&wxgU!{N1FRi#g;2 z;#h@M|JYZ#lP=`jkQALp9pgx97o{62oj{`2my--3^x4za5yDf2?eI1=AUY#EAnE!S z%Wf8jw~GK2-anJz=OZLQtyrrMH%gIhAm7{=d@<9tba&13 zI<2Ije$dd+NWGm32SZ+N7S1Nki^lxv)2GADx{*Q4_19l#fcCX(*U^dT_enMRUpze= zgQlh?bDv%W=IbP~e0)u#C3`w)NSo!u(_gs^h$ibH(lYn#u8+4yL=Pc81 zgc*F{3!gWZ?lSm00&G`lPhvPeiCgwQsZrFjy|W*&xrO!u8CH>yHaAc z__gzuRilDBufm`yX(qSe%PAuP(~vmeb7ki#*+i$Hd9-j(WWzbeS;tf6;d&I*r|HSM zOv;`>_O_}b@~mz|Tg7%-wYSg$t-u`pmSwwS5J-@!M`?mz&rk{2lb{r^apT4#C503% zLRJ{0u;|EO4xNgQA)jIx+u`}=pGThTF{E{AGK%oTi4)B+L|Ls*nLNqRwWOq^ASXN1 zSU2d1r~r9cSZ8HsAcd4Fj`}^AI64O@Y1xQR&cMXU(+uT{XkSJZ78>hn7cCl+l9Fku z;-baMTomNz8pkWs=nz#@F{#XB!uSb{Lu-1LSLH0o&olSS0{+4U7oc#|NYbk`B0D?F z#MNXzfBrmf9E@joYA2YVhb%gL4Rv&x&4CHDoQR2zGQd=3MkXdrpMsSyy^hGXPDECC zu`{d=lL@-VQ=xCy5q1VC5Zb7yBVEf&OWr{JbFU(f3TBu3be$KD83o9lHW!hI!h|vT zm`VDVlDIAuKl3*@9Vti{KM}hYKZb1)As8`kEYprg-G{G}dL@@mS1-rJ`7_WsIuE6* zw;+Pm(!oi#i@O$~(N1)&+l`WhP-KsrhN`9rlvLB|hbI#vI;c3eHzGZb7Gd=J&{$iE z=7t88RMcb3x=qNWC4NHgSRY`br#MnA(eNa>xZJVWSJr^Ia4NZ40264pE#h_Ov4Yx` z6l($OvP$z(5tar0KqLAVz=R^m z=^l}skBB7xQO^iZ$VXUw9wPWIXYAo|ndFtH<-L69kO$il5ywB$ay3~Z>gmt8!~169?vw2Z6f{1UwX3<23(u{Hb?5K|R}vk1h9l0Ej{Kwv zh>DDrBEvTCvqKwzc53TT2M&}G_^YE%5=Z?f-N;L#wAyNQ`{)HFt{qKDj_uhN20blRE?|yvhleZX) z^%Vr-w{F`;a4wOS>zCuItFFQ{o?89(x4(ru?zqE%!aH~FGU+_}*xzu@x$}9NHX}go z#XQm}_tK{0a17#XH|?4-*G6e1>!^m*o=^Sb831}fg}>uFYu&o_xcR0V@TD)^&h=g{ zo_^+eZhA~G8yv5_w#2N%)HlSxEg(KMH5m^reiYY#{2DV)h+AE>FrxI4+=%GH`IIYt-yF1Ouhd4Qu4!p5&!k= zZ__%y-dI7O!xO--zPf}K?&HYwo{9?c#lQW|d%X8jv*Ggi<4a{VTnic80;|s}2n)`jf!ai_#kIy4Gs>~ng&M0{+XTqd5RQgt3Vj))8yY<( zz9?VqV3)!EezNa_4!HYdXv&?QmPF7dfrD)bwr<_a-7Gp?fRtwCICqH=>L3Fo| zvs>2%V5SnFms1?^cx!N%HA6;58o}`}j`tA+qX{h4(LreG7KGMqLue~cZV-5lWINBy zFGOZmCSsYdfLtvCowQaE*SIEDr6aIBn)D_5UFFhe-4o8=1O7v*kl7PR=%a53*V>L!A|2NBv919xd7-hOpC z5+`Ng!uhi>iHhc=S*KBcj;0fJI(n+MsydB~N#OWeg$|yU3QrwlJ?e3ux!;)vZwN}DUlOqToW|R>gKG@f z-4c;Xr^#NPPysj2x==|+hI%h+=rRsc#o2Da_CTls>hJ0U9J~3!Dmlj!IcGPg?6|2K zN{7h~(n5qfV`#}9%fEO6?+IqpDm;-JpYAkn>{WA2-^i1Q6$pza5GIGOy;!~WOEiNJ zS@V|o+nX9&=)Bvqg3HQE<-8_;7K3Q9JqXX*pDffQ)E+ce%i2(DH4m)~8ylL;wJ6Q| zT<~t(w8O0LVq&7qysP*_v7S4WFTtevY=m}l-9UbE)Ez`jNF>}{Y}1XLx9Sg|wS2c( zQ#ja;Ex!e9`+8pWg#ZM*OC1TgTU{+c*_>2KRljWZ#zATw#~Jaq>)P?eAnFf+>2f;j z1;GoB4?XMKN;@1ijTLC5;ZSCL0q;`ECl?IJLL=5nj)hKl48nM-QiWFC2O=o_X6lvA z1l;9tJ=Pr^1l%cDNq3+Dcf0=z#64@)Sg($ePYT27)2DGf z3dfWwld<~!)!4uP0KxXFjRpIR88ZyGxK6OHTfd$h(esTTD$!j|nl#DKm-K9}foMCY zN*X-@ce~u`(>g8CK&P@VzW9>qQy;tTI^@#0Dl0Rcl+Xou`swHJ?z<~Yf1gjPm*nJR z;~@3fXP?K0jhje8a|7#SO7{tbS6+Dya&)?A(MOR_YMK1}d^$y4V?grVyLaQf^UmR# zF4KVH`Yno?t-K#TXoC_rri1mA~D0_ywvQ@vVOHFoVDn?O@bXSqtS#p{~A>&i6`bQJ6+RCfQ7CQf?KjqN)N0 zvxLFChNT3gO!4Tyr(_G-8%p3Fbv_%2y)Zlt8i=|jA4Aq{a(voya1+{V_aHoJw6QeP z0@qmL@RO1U&4*g1w}a~)2FQcF469%2Iyy)9_0@!HD8o-j3b`=%OWEo8o{91i*# zXlsJE?tp3EpcQ9`GXbG7x#ST}rxQy#Tyu=dXpo{n?{<0gT}q|hb$Tnm|MQx%Gd)f0x=Fu<5&VDVUoYdIi$06=**soJOYh3$ zNPPW|cVh;v;pISe^@p4BmwO&S+oNyOr70Jt*G|KtFWiE5Dv~Rgy^CG1tw!6%<=Br@ z-1osNm_Dk|C>lc0cI@AWf6z(l_NQJ&Qdu>2O`nb1KRp=}atctBHXj}yldP(*#;bpO z1a#iObjWr-p9`U7`k7M0dk%1@gHwtTc9A&|k#< zg{YAW&_N5pzF2!}_>nO|IRU_;k_L=P4?{FhA*i10dXb!mDyV#_F1<_VP#e)@Ha$Hy@l4h8KlKI)V_wQ+`)X$TnT8L5j~tXfogWWhw7Az&>0$u z2uBBXUunJr3K~C^(63SOtxrdTx!KqULI(^XY@d73BD>rX^&!Ik7x$Y`)pd+_H5K z=FXYylan=19wrMWCQkf83(AWE)k)D#FX_ri#n@i6&y4d90<;bSbs-KX8mo6AggSS0 z?%CYr%3*s~r=pI1l9ge}PI^ff-dnMefYCkzM>&+y6w1@;yC<1NKt!n~ClGZD9WRec z;Yl!#D>^}Qyt1hchf%h*o(j}>%BUZ4VCoSRC!Ay2o(lR;iOj^rteNC{w|u(vh}!3` zlB-VGHG0GF-iH0Az7n(Ycv9|=F-V^i>m{O9Zy~6vtwlv`4XO9Skwrg1vV=7J^M{Rm zy(DlNUs79XV`CYS5{c|2C)+_n=&kQV9NHuM3U`-1VOJ>37wZmJDw6IhqDJ{^PRbE?H~369tUuG^KyE(`ZE@ zOmhK0%Q#A#(F!u!Q5?nBm@k7T#gWYIbhI%N&YeARb!%f=HP%Er8KrNh*>g_RceCEo zjv#}Kgf5pE)GfT zRQsg%t97~Bas(HoQ8Ya3>-ci8w8q4@+OSfx+LHMYpcmiSxd5eh0?9~eQ^$y>g`EaT zbv!SvBX;gOX#OTo8f7SF)amWuKk(Yug70UT1lVQ-1PN>pi^(unS6$-i(#U(N2eoxt z{c>r5)~da9__P)da!$HOUt|`l24Ls2i$B{0J@e`C+^2fI4fFDwann~usU`+6?njx; z2+X#r@%mUwNpHXD9{pLfAM@r$lG<@APiuH9H*gW`CN%-63gT#iMvz@rl-fY+>Lf=3 zGwzwDQ2>3wyMD7c!Vk?6dMy8YOx}La+Fc&MYxYO~`+B?9+r41~j>eB4ix=n5LHpi1 zgyqB|^1Tgs@t@DZ9T$s@tJmSL*Z%-H>2!n|LLhq47<}a?|BcMdQMC4IN9ve!P;o7- zzDl;!*=Q6-W@b@A<)(rb7L?og`~p;-w*akSG1#yaB?g-sI0mW3cUM{v$V#ujq8j2-vet?DNO`=m=^6pcK?J0j- zu7mZi^65|QMknb6w1-mHh^J%PQKPbH!B07pIwLGL4{fEJ5gyMuWv~ht%;$`kfHk&S zZB(Dt_H?2~mOV{nJJArH$8o`pG&i}`WnnIf`5LIy1^o#W(>1m8feF5Z{nGdQcvzP9 zb#cKfggV`DlSjMdzy>sJdkOAB>N2Em8up+&Cm(?YIt|l6qo77wyK6$~O~#sEt+_}> zL;@GAc~U@t0D6Jc8VCK?GLnt1S#ypL*x-DoIJ&QAT*V*CpyzI-HM_=8jip<*?BzJ> zphL3}JS`MM`kgv#+g8M*{Y|tq4W)B(E@BCY?Auq$xh}=<^A^#dN^@IEN<2mv<_+F6 zno1+cFMyY2k0h9`KNi5yx>1WjdzTl@ZXPMGCJFqtL zQ9Y)&>ph~K66EiM~p+8`|xZ7)+D^cD|UlTm_(p%fL+COPP z>60QRmc|rE6z0S)w6qb-=QyK&)?3~unzCs&yx9jAn*r9oX4U73rX0MlKN9dCJ2mzw zXq?q`{T&L23~UZvQ#ZF-o2}p5-w(gn|Bf@`^C8Lk27(@sE%|7JL+XVb%u43o_CqJU zWErnMr*U4Ox-C~mGZdmqPN2GfIy&vEc=mN02UHr`khHJcY1u{6ccs%EpQo5@pxr-? zKKHzr7pNYE7@E<=iywik>_t=a+0T5^P@38s0(LsV_ft~>huX7M{=@yv@pdiaArV^my+a1bIV~AxL%zm&Wpox=!bf>2g zovrl<%bLp3)!N-0tRf6dK720zm*swkrvWYd*YJ32B^~)qHyol}n9k0c1s6(0MsfcP#01pC_fQ8LoFFUxi-DE*-cmICNSHhBg|Ej$~0 zesDjcvtkilI1|-L;b2{Quee4#2psD(z3BGLlBU_i9=0y(V@{I;0T@0Rqbc zq5PDvyRblDX<1mph9!^yfu$rQY(gL*jr5*4)o~p6D#_}-_Zf}K|9$uA$zw&5C0n*- zd#?R7Gw;3I&b{~CbI(2ZJBfrpxn%81eC+*~ASJX9p7J8BSa|^wsl?ybSq1kyn~{>A zjwT*`UjM(>BPWx}NY;5{|Cf6yRx#khG<6mpn`S=@s1Eq(XquL>7TgM#=qoo(U8%;tcn^ zIQ$M%K($e~Tix1+n9g>j^VoG*49BO}a&&yyi^D`R<9MbKY`9Ryi92~iSo$K4r$BTS zJw;3R3(YB}!AWlFos6o9_e$9=e$m#}i7q;4lR`lJ#5b7vl?^B!BP+c~Vm#}6V`D4o z8=7e}6pj46bQ8r=#M5Gs3VEd^-YA8JLR)(m@#33}<#=9R1`@=ZhLsiOg%kM4Oxf&c zs;m87@G&*DRI1XVecrrWLO2u}2YH$&q(o0kO(bq|G^z=~)7aQX7yu6yF`@L$5@Mid z`Z%9a_7qIsbCrqqEk(}??>X!`zS@;K5v%D>yq6MKBoMc+0< zY+v8DJyQHhJs)l&iz+s4bkqJmsZ{(g9RmgIHWj~Bu$AZfu6y=#ecJEX-|c6<_eaOm z?=vkN>cPVud<+8Ew6pbe_HVsv&12%H;vJT(Z6{&RYxev0=a~1I{pj?4+tf}|pGrs1 z#+n<)iz7ZIrTVg^i!tY?H==_OIpN{qh|)=1&coxy^Uc@)eTGxuP-h+~=oq&~o}K6~ zwzlF#=libw4h=*JpVrZn)Koezu zr+l>-kaN1q%6j5ZrXrda_wpSRA0NYVSpvQ`p0s3EACz-QPgRt0MjaHfhIdc#d1V6n z_#d4-3Yh8MbUG@zIP|*QL#XTESYeT*5bLA<)zd%3WBP=U8A^w@wVaO8vp9~16^458 z6bj~)3@a@;CM=EqcBpjkE+X_*{)L2ZN;9x|teGaE8C5H7eoDzKg}Zo|l*CdH%fixL zcc?8b9zAF_8B0p4jM2~lnV}Ry=^4U(52ZC-o8di*-^HWwZLOU~5gkG(mg1sH1259V zceMHE@pw@~rF9~GZ=C30^J?)updnfr&ZM(&XqQfM2FfFUt?@rXd!(z+up|-689iC>SCoE^5 z&_=cW!r`BCqAKk6a5`2VWWTZLa`;=5`(;s#r$HzaweeI%OXWdA*)685$qfJ&{#eo; zT>`B;?J!ccwEUl^Ck4cm)z%iAObUf7V(HCbE2+u0LO_rc?)v?3 zSG|Ss-1iWxJ=0iNT6NQGG$Q6rHc9_`XE+5kPPCxv=OX9XS6|2feeK5x*j*~he9(n{NTXrBZnlLokg@`QiVDG+tXu9V`E;^gA_@=MpV;}qg z!uWn@Tnv^i3C50X2QYuhYIJ`8D=7NmuaJ7yT2%dEGoD)TXIyzUEfk}2sP(gO5Cda) z(jb)cEf<$suxbwWwIVY09OsXkUF99%rc6IiFhtTK-%Be`)k~MGS`MSvIO!ZKmoxN| z0-(0h_=J(wWpZ*Hm1bd7v_~5ykovlbde$A}|@)|jbFxgoR}18ED5RijQ^jJz{W znf^xe(yXc5JFVaO!+EA30R+E1NDbr$Pyn5$ zHW8vSJvNu+B)|;k?r_4Yh32e5`<{Q$P+%YX?L2F(!8$9b+Sc4A<*xclpxJ;B4OCbC z)~15mL36t3HZ;6BanuE#Vnp>JW(z6POBx4hFkzKlUCZiT{A>L;?GYOuKnrxWDPd2{pN$?M~>@J1XwNSycLDuW-Gm>6qHb9Wa3tz&58w(LZB||Ua zOPq8#rhaPrvid5=r@>(7T`8Qs?R8wNzC-w!2AFGXdPA)qBu^plLv4p%LccNLD;R<}Wv!@5a#2RgC>B5?&xm398 z+<*f$EzRh0yOElZ2p6?%&JgRUz0y~nfuwa~Yb&0-`vEv!eg@5$gI#z5y(pr^dNe{1 z2G`d=g-?9)2Y+7Hh_(r4<3Fd99<_6__j>}W{)P)El-a@6jGpT@cMG$&QU*bHm9?ryEjy3BvD{t_% zVP%|6#1q`1tfG=Tlb5(6!px?pAX0jXUoPdit<08%x^T@)4$|>Ad5jd+;xBRvCkyYM zZaUy(d@0rSyRa~uxbUHdAL>1&BkWrHn7xO2L~wIZ&?~m$_GqeZ<_%ikdOb87?z8az;Vt87I%5Kh~ zVt=M`4pTw@pP5bp@jfYo!>O<>oIe-)0)kO{ z|Ko^Xy8y1_ShPR*8eX~cAru94!9gWLYgU4L70xPfsKD{I&3w zHX{4V3$bSHY98Vpc3#82>>w19!C+^+!9F+oyBg8gTtY?rPI#O5ASfagp_%KrK~_NJ zF`aSB%F8T_%pf_bWYoN3hl%D2y(dfa=FSeh@YZHTM^gDfyihMKxc)a zVNPWT$;xIi3XM=I;1g+0m=x55%-9~3(4v0R6OZ8hZ+{DG`F@~La&eK&#jt4?(Zlc^ zwT7t^HO2`OW z_J-0D?`XS-WCX!K^z?8OgV1!=roCul$r5AMMRg_(9Hh?>6=(fT`>A{{U^!W^5t@t{ z(|^-Xfe{Lbn`rE*Kdam5(r>{n6*mqcik9mwJwQDnWW2mLCpi#dApulcSqd;IzH~{} zF=K@N(%Vu->-Jdk(F8u^i)MU|WO-_RQQ5^>SPwZ)6||VU;&u9`5u}*4Su1EgIo38o zd`aOX)mawa9x9)!s_KoEavJ$bG?l7q8}S)ov~PZUH&5MG8~&ooN$IB(xWa!oN=bGA zDPeUVEc{(RQS7i zgx)!3T6X!QRPW~IfPOn!?u_(A!#f276UMm7DRER7r;Mx-efjtJr8@M)&PU4n4sM3( z)WBp&we)&1r`H2g*@JrMxzP1&f-JoIw2GF0)=uNZ>j) zBgOO^^#k87uHWJUzF{gfSA6ju@sd4t^b-^9FqZ4$IU0UilGuDIm~ex-bl)iB`RQ90 zyBv0D^rlV)1aZSm7VF)8?eGqHm?kqEBdG0V`QG7fMH3A$vf~O(KiB=K)M<3mDx>OG z+vz}KJqEJw&rJHJJWFBE-6a5XDnJ zYKz1B&DfOb=B8qplRk5J%10EOOq{V(^52~f3aA~mxv#aNlWij2;SYWaoSGEiDLNWf z1#y0s<93C~@R!amw|QSD`c0h4Ml^3v?$3<1a38Dq_5`ZMx-2pDJ0l~RuUgze_d98s zA?x=f9w8V0p%}+xtm?+f&wp>`QNR)jdEB+VhSnxYRP=E{BkbqNjHqd@jx8(-GGl-a zT-6U9#9QY<(&3!6n4)ycYsg5k{FDYszoq0FpcN`R=s<5f6_eWuBXcf-V}|ie#}Qno zxeET|W-tZRzef5P`}bkLS#EJXnBU$)ZyrjeZ2#7e;Cx~)qTaI@?a%Lk=c2WE?+33$L|6oR zXuV}Nzi8z?*u~@TTucpg*Hhu%VTu#rjG;m$4M7@fw6TD|-HU_z9{lCB6kJ6ie zhS`fRz^-rp3Y*A3Qa*kz7M^=HmMmY2yv$6*P_ZAvjk?+C>4;mIj@tSH?Ag2xApyi$ z9|{GL$+2hSCN#YFVx-2!(eDW@)~T?PQo!BTK<95e&55A&^u@ULtBaAp?gCtR)>?B) zp^qB|MyWhfQ|pV}Ja!)(^?1Uc9t!U+$}NjBohXZ#gQog=bIiM~wVi!NN+(%2T8cEg z4=X!?O>P5{youWFc%JPTAoVzB*l(CCldrA6OuF=edNjg ztu@4TXFJKFk^lU`Pl53$pnj^ZDvMIVH>fWsM2PEItWIzaG2Cm+qcwXoof5Y83~>XD z8}IB^WIgX@hf0iNez3QbCuO?GOOu!ZUpy@WE3L8Z^$^27gL2%taMQPkw_Q9_8S#Z2n_^s=@Wt;%U}<;)S}Tq|Kl~Q4}{QwOMGrGj_v^KZ}^QRkhNWqF)N$ zty}jKW+Mc<_Z-BM#RZ5YWQ}o_&NzqoZh%qFOF=KloY}LpjjUlAELlFa!fBBl!Hr_! zZ;Nl+amOyv_;A9@J`A! zL(!xMeGdo*X`s6SJr!Hv%9Vc)Il1jL{a7a$EQ@vz9dlRXU}=r1m-@0!Iz&cVCn5wT zwEsYviL1HU5{C3s?XPyUf<5O-Hc=3b)UH-rTklNN2I>;(GfH)T{UG9r;F8RfX6%~Q zO@1gh({=c1XKmtGT~T*UpcKkfs68PItS>rw?={Oy1;RdyW;X{yT*F z_DW<&&!e#bjf`xgqOl@O;-1Q{m6lG_X|s|98m7;v3QQuc$-H9IY9#eT%{7_m{&)No zn2{8)`*Ub$Fxt5mY;B`8fNmab{~jyuSobEP##G-QE3N5BL+SdaiRqH!P3%m>!wZ7HB+U8oQn8)dBC zCD7=(1kET4Ir;e+#zC4E+&bze!9`&rVa2@Q|1y}n zq-<1ga@P}^x_&1u)`O^UkKyreYk@e(g@xtpR8lS%O_HyrY^RCIa4$5LG696v2+OAR zZ*00*fR3g7I!P7vXM2(;poNw2KZ9sZ(@!3!#g=%MlSk1t4Ae*ZsZ^cl_^yhsbONd1 z45Fh`FW*lhUi-EG{BfjZW#G~8-h%j7YZ0_28R4r65YgjB<&W>g@BZ)vazA+?TK1PB z^oavh%IBiiG80I+u=!6R?agx;11z} zvknHcbg<8q+c0MpYz73;MwaQNwY7M2`*xg5YwyJ9Xf6c%xo{kNs@3g2DkVO~^1twh zd$D%SDkQ|k;+MDFhO!%fitP0lqkDTD+S8o4?4h5+)7y(@ZoVDCo3|o%!2%3r#2_bX z9=3hyM%*3j#YaB$0bF>_I+S1iF;w0EGE$e!K>`&d-S=$8EB6rcC#L{8A2C>G-gP0Ys&m?qkQQTNvj^Ka+ zAKOhIHs8}@5Pqm`ip^a(7>>`mQ6wEPS(Fb-9% z8b?58oP+QVpo3+e0->e5tlr7m$7PF#&+{aoAm@zYS=Q~RQy}4FFcC=0eb=lFlz%AO zxjQM}wbD^+CA>Uk5|XkI&iGu?z%s57*{8~nj)i2B*>u`VO7~VeI_>D_CWJ^WcJ3^q z#j@r;@;55l7cVL>ite{I?>0*J4&jt1#*Jisq%y02P`u@wK48`<@;PDgt&t=S`(pJ! z>jaXNw}LjQA?|w~os|muMpp8(XJ;8`8W|$#UR6~Ca&poPoQ*aH#HVGD)YjH%HfQ_E zv} z?kz(@LyI{Xp-mf$g;;Z}WGKypYIAG7I!NVxCHaX1@iZO_4+}FEczUk((5D@&^4Y(v zPi_1OzDjzBEb<*GrP-8+g^`~lUk-b0^3Wy(OK4(YGCELuja7rrNZ6f*#84^pM10Se=U&2UK4rBXg1ka&gWbNIM4>mck> zDd=UvCMzGU)K8YB{>*LdGqYs&f=kQWCLZ&SiRO`JE}nvdojkVOZ1`7kNikNgSk8qE z$AgYQ4~zcdXS#Hf!YtqPo!2XLm|9pk+c;>`fvGDmx&Ub@$+-O|w;q}1Nyl_ zi(D}e5#1g%{LlSVoD&vhWiqQ)TicP~DC#pSe`vKGCD zjy{W85mbu!nD{sh1}%c~1T;Y8ivvvZ$#EPm!o~-LA0;W!2kR2|G>HxE6iej z$>K$L`thgm);I3}!4nX^q5#Rua`3|E{vSG;TJY)5UyB=mb2A>h>`6R*(;pGBtq8HJ z=h5+LItH4E|N4uEasMxF#uMjVj?9($XxOqBA$vO!kU;Bo@}cZoZbb_>m?Q7{4Yt1Z z4puH%grK$x^wjPk1Vu7osxGj2rLftlY&T6YKuq6BIx#ivc@#rY`3wy5ybnKfVh2%6 z%k@rII?||vYOJeABXR8K&dntRToA26xj9L?2RW!fVrNf?48eg$FXF<75J#-*ZYn9I zoN*FnX0mdW+DfM|BE8|pg45o#I#N~4xZ(WbOqq-B-H(u`HxlMcxV^)D`A7-)pU*f7 z_zq+BOW&aOwwR^QU31gtx6fBIewYT)3(Q#3s}w2GLyK5hwaapyZX2*P!@*6XA(S=^ zn*OWJBfA{hII3 zrx4?Pwo$sfYq!JOSVSk=OL+n?)yRJ4eN}f{;!PJVX!$I@L+fv0j%zJZ%@eexWwlhQ ziOBvotELVW@VW?jxpJ3iLSCqvFz#ZMVq_Pd>1@QQbZ=_ z8_S~GWW;$PkdP&oApytx@ChpQkCc>nWD=uYYfl3SL?yg7X|!pk4UvL^Yy&yti+^wO zrOc$DerElqu*a}-R}psXD1!QvP8TFmai2_RxOkon&~Noc7TeHJZRZ<8$ehYs23a3E za!;j4*e?y03i)MP5{`{3^H;RZt(H~hJtHqO?4=;K?6;qMxv z*6D#DEKEC#o9{dgKv~4@TVq5S_m=9b^z^BqjR4(<4jn>AO(`Oi(%_2bW)U}$jwXF8 z)v^AXoW^?KzvrjGX+r@iDK)3~gP#I^3QRu*P6-V6$y8gDt1eB%Ql?9=OHPhAnC`Od z&=E#ij7R}5p~Dh{EX9h1oQWo9dy@AphvFzq6wmj4|M%&kfRxl8F23~XOvt0eWi8aE zC-n(ZvD=%9a|KWRe)N{VN`+PmTzTt_Ld!ucb}fv9qf+_FD=Nugt_Hbe^&UwJHDXo< zQ&^|s)F|MMvRx7|`;xu-HmUpnoXHdrZ;>T?OG_)Q&Hsqy%ai88(%Iu~c*$a9UA_j538ARG|1|_Q_9JcGN|fI57`C{ZuyomC zoWu4kIBzu?lEYDS&yxtLq?KI(9VTYPAtsfIl+qToJoPrAWkTUh4@c|HIxPS8Rru`3 z-VYa{DW3VugXm=&ES|-UlRz(m(^eonZ6SFMPepK{Y$ivoR!wbGw8^!L=D4H9+EsQI z>*PiSowbEiVP4(A1v(W=-K~wpJ+3l%$g&XBi}Gzz-|j`fhntp!>gpouRv(r2d+G+! zMnz_NjHQgw?5moL7c5y|&{%W|PhJk~gikq{`P#h0ja&zLwl;SMyNQ>dkV}G%VInwQ z0sQxmnF2<_vcxR5+tDSbzNZZu>9n+IsZL|{$3yAa&!s@uck`R?>iv;R_lJM;D`iY7 z*u6t&p*Yzrd=I2V1t5x6?46z=lu+ruAkBd=-WPjSU6jUzbutAf+y*Va zJ@vb(e4a!3fw&MHvlB-=RIgL&n@tQV`HUH?v4G`N#JNS7*>Yy=soP55Ae@gvDNhk* z#snK;$BsYEl~%HvFND=DjC0|1ODQ4e%UVw?UObzY?S+PiY0l7GtoMYSE=z8~!YHnq z^GHRsc+)VC;`^aSVH?IK*S$j(Q+dRXH8f;lEh}g*&6iiNT3{@y^(=)r^Db@#TZ&k1 z8d$JeDO?k&ESqVC-%BUmQsOE|k(-l~O2@8g2I|Gkk-nLlw~qdgU1lY@bsJADaGsI@ zlobDy;mJpz^W6b7sm;_3@(JKMlZ7VjQz(v+6gGA#$6Q^C)E6iGN5ozS+FU6j^X zj$OM;%n6DxLIZKKL@#%ob(%t0@YOtl(A?5yoZ5<4NhZ;zwLM2m{%YzDK&zY1%9FKG zB1OK|$A{BGZ6Z#j`{t{D4Zovj!d&lmcVJWbGqkR!d`XD9fk9#8^0bFD(mdCD1~&8X zq)oa^)!bDHbV?w~8IMF4Av5hU`>r@+-|+1pcKP%veyp?uNyk8*60R(*fP*JxoZJks zHz0iDj-C4C?{?GAoty3FB)uaE@i*Qn$jPU8>c6S(LfegF#Be{< zivpU*>^WkpWf+a&uK3eAe<;1vM&Yi?D2Ui1k|taUIuZzkXP8Rs15M23baJzIPbq~J zk2zN9q+&?c2bSP)NC2@?v;In`QLqIXeM-pDrxa8s*6=&loBqGkPXUc2N>~)uJheL! z9Gk<%7#9y*m`(SfcvsnnN3mtq-in^mS2564M`wj+BQ#}>)#(hzC>M)T%J^Ict6g~Q zyl1TO?FFUM)MfP^D~)$$?7wj)Qb4>&{H3$28yh#if=k}_KJ4DT3-|y10es~v*O`Uf z)~(xc*4i})qu}4v+=@+`Hq#MVCoR*G$vGxlv2ll!Ag;NJ>eg zl~oljo{0HMg?M#Y1>9tC)p3Cs;4%3?!X5RquMTjNQi^wXbv2^TTZYT8`7FAJ;;?yt z4f?6@O-xQTi@cUr;u$Ol?skq&)SO7wBA(A;4b#N~(3P8uRZABmo9(xd%J=vSR${-m9<5J3htPot42CchT75gy zq7Xm_ivv|%@UF|i2d`R<)FCeTqeGE!?s+I!x&X@-t~A!5f#EUaMcj}SKN7Kh2yXLC z&6D=`@#w1OQW_m?u(Or2(dCpPl8Q=qFk+HY=&-dHl@&Ee&(M){DktcquBxFEwZ;38 zn3_tTb#%1WJBVh&bL7Vd7))%XW2dQhJS><8QX*Jb!7eH@r2No(N2;f9I!e`8`p_D$ zuWB=b6K0uHODAN$@h!+1{GC0X{myFZQLTJLs;FCV$WjSD#FG-l_@$+%2Be(oh44N_ zKDMv*Nu3xs(T31SIOY~^>gY5@4=+K#&=muy6En_Dd&m-{U>96WBQe+scWQ$AbUd-z zlL_%8%=Q>U#mE7n6cMUJQY0-fx!EKuQ@h_DsREXQPtM_Mhn>UEx1y+GlTGAEnasrJ zs+)bOe3I|TJLO0|D4Kkg3U^Pgw*r4!d9&PlU&`*-*hmx=SD6ij=B74U zEQj!3w8_I>=UB0)@2_YmEcvdk9;{eC&*U{#zC3-U87rkBv=bt)t(V4Gbd;JHp3XT* za4HZ z@1>U0Z?QtrSunD4!duzgW1!$9Z`$wcU3=W<-m!!(I!%?rUB)DlbYOq1=^aa1W=dR9 z)UR-#DXrlzho1sxHU*A_#dpwYY6xN8Y^SNBKq0K3)`mlLwi6VYNI{B=82&pxff=gPFvuyYoSyd9>_T4ymHlzV z>XhXug+~JeV_q6w-Iy4M{v5yZ9m>Q1?ewF7x}Nw+6fxJ|c=JuX@x~kY+E@RLmgJFW zZD}zU*s_AJtF6Z!cl-%!sC<8e&O9rts&Lt*m*PHJz&A8B@~HbfT2C)CJS#FX62-+u zxZ}=0Dzo(sigttPIiGmze5t6s z83)Vikq{k(wJYZ$KFI|)Heg=iY&>=T zdhEFG2?STsc^j1_#v+glzM#Yic%Lsr(^qK$O6=o6u6iyjAP-_1Y&|Z_sc5&IN%P)V zK^Ayw4_Ri~%7L-oGYeL&ZpTSytTNfYdM^(i)L0wY8*AN3^~B2Q`fC@%^;mUH;gpHb-l8E)|mYCCF z8C0%{x7hF?QX*PBl-8c~9U=G@DFVx=JY5tu+b9qxv$?6#D;+7uqoRlrKFsr_m=v#* zRdi8N1vle+kWMHYIYHGuy{DjZDCqaQ_#GcXtQ@)ct# zQm2h{EQ{)+xkj|owQMO*Yp^cf;ZtO$z%%5}ti*)~YUcckU^t24-cMd{C`!IBS>M}y zfTvc|%_fjtAJJKx7z$P&c=s69JEFU++*hucZ#HPOhJ0u1J_A3qZTkW2*;{JXp>p)C zt-8>#AmlBGLu>+}DmiiXxd+hI;Xy|$uVy#8JH5v8y`r-L6%`FU70FWrNd&DUu2n0I zAKI$8Nkktqk%VY6as$g?_bn;3)yCp)V+Hk--o74gEP4nflZ4Wi2EJx(TAO~QzGPQZ z>5%6crMpBBQEd3RHm&>UaGZk}t|T{l9X!28I;fv%Jjh_pd^hWEjq~CAESR3F+?u-; zR8|wm@Pi>E(`sGbOJ4<@q45|9i$*Y=*LU@K5Kh@x&g><3S|>~>6)*u^D!5&AlkgP( zDDJVupJI0Y*ZmYYDHJf{WwJSok7&&6V}vnGHnRUcKLt)c1x^G{KW!E6V>O>W;p+IF zgdR=gx@2{cos~lP8CnBS5Y$mn-Pd=^t9&`~^D>O3i6z`pc%b04e}6f;yLvHaP7brv zWG-eiR?hx=$4UVyQM54dcGMZ?j1I!Hj96|SYvR7~)reYR8?y`xb6v0ky_IiK80<%Q z-g$(KN#=K2uu72Bd;Z|3z;si9{ZLB7a$=01bIu0*@|V9vT51aW9L*}pWGts3fp~f2 zD_ods@w}dj#W>t>!wp!odW~7oNzs1whd#v3LN}G%4qD4^q(ii7eBl%CM^bbkwr|;t z4}IuL!m!7|yKx7?I{VQZ*pJ{Mp8i>!NZ!Z1vZ63}umSh{+kT-APymQaR#qWJD^^$$~!3{qozU+Q1qt&>a zwn`sR(LyB}6;_EH!c(#OoK6x;D3qc(+7*FCYgeHJe?a75K9bY3@Yw&}fu?Idjk)ty zASyW>t5Va@R#T20MGbH@wc_#ryAy$Lmtm0P>3X#oVTH+ve4z-xd;6<6c;mm}%8M`J zar9ubz*c<&xx=7M+qbvu<2;gr*r;$~xx4VmYd(VYbeI}TjQ&(Ao!uTPl{n{UK{~{; zz+`)UT$oa87)h($$M1iN&QzBpB_?Kg&Z6R38#T+e0`a;^ekeN&(?ScSs^~_*}|PIZ(B$#iE;y@NQa^b`TS|jc{?P8R-Tlp_ht= zhK5!ucM1=y(`3pxTvBU=PpkWIZfJDxdIa5jd9=Rpe6oBhU!;if^Zv<`a|&;23YMZ= zmgd`QspNJH;;cMcJn|m9C_BJN3yqtq`iPX=a!i^)9{?`$n{1wtXs5+H4O!4YMZWTh zpmlmW4}ygAIrXPz>bEoCV-xhA6zLkv>T?ng^jnuUkWBC?lifdcUwvJ{_nviU{J%2# za1c9LvQB?1EmdcoZ}r9TqnzGPY~pbfktC=5l}M%M1ys0~5pHJ(`kILEp09pu*3pPj2P;+Qe?`2%Uv9z?bWBIbVbZi=9=J~Od>l5XnXDYjR zzx-XPZk7U6P&LCHd32$U^0(4fKAp5cZfWg+44yQn%tU3o))*>pc6=enZ9g~XhUZZ+ z9QLQ~GM;K9)J$mFJpSf$&Y8C3S*;l-qPfVY=eD9*bk5_NGMs(^Hoduvj(B_Eq2q^M zTBi#$-brQqti|z&j^ha{H~Sgi58=H8TDr$4yO{3)dOG{i-r}~D?;T!vsc5gPsAoQe z^b?#P>$7)XsZnbCmTly_hQ|cWErS6$j%^>HkrV&figeXwBrv|EzE)!VKHPs8RTb8M zGYs`v5wgX+W62pL;jp|RnuzYEAL?`Dw|RXe4V6Lv?Vx(-pM35(l6dlu4(0oprl+e5 zo!#`^#!a5k5aQ^E`6%Dn7nOvapVAtkhn?^^pNeAzRn8y$6gWL8VE1!td`+^BK10Gc z{v>1jU-MJojG(|7rEs@fRKli$yu?d^zIaiA5ens9zL6M>d31Us{Pz&zz8);Cq64H} zDz(BXNJkg}H-g91Z3j8KcONv*qp9=~KA*%7f0%v>NQjh@W1y1`#G*4OB+-g9i&wYF()a6J5%R#AuLN5S!^&&SKd}?{=a?-_)x%t#R{XP z&aRz1@YrLI;mN0-#wC|t#)ZlN9jMBJj?PUR8n^&&#e)w$Ood|yu6X~IW-$>;E8*FB zndqybLSm3(g>kO=*vIknpWTF%^jxDX`uexOjUWH=SJ?m42QYVb8UjMe4gwzHT-H^9XRQl0c7M30*mv)iaBiJ=mvaCWv)oM^GBO_RCV*=FG` zWxKub)2D=1>FN#?m!RT_jR?5w#% z%5z)aZuOzbkwP#pWzAHCh6f^&mhw^5MJ2P3DM*R0ZpGoqacOQH{)eyWO?e{P-wUMiF=S<9_6V-IM>u4oh zwsF{RP6kh9(eDMvYyeLn8cxA6OyQCI#Ogh!$)?&cOi6uYkTR$pM)OAfmLfik3cl5= z7UIoKJLyEV69*1dP?754rt_R(OY(Os>g_b`PrG=frPXGx*IH!v-u>`WdB5SDWd^2A z*1gJebUExaCi+wy@q1lX@3yR$CyH~l&vX(%@Hjn$nv=XR)&{}RrahhUq`W0X5Wtgd zf|4F~K4YX6_yi3jcK+k+PU7T#6$+UyjuA)6HwAq%)bWDHt`b8+OFJqDx zR=bq$38^l`CRwi4S|gR?6uAFW+u66m;;mzT=--mX40Hx8hsiI67&ZX;uOxl9op zk*%m!-jczz*}Pae^)MI9B3a1(t<4C1*L(V|G_+1v-?8rN8OIvOwIi4(mbjtn;KqEfgGLK9 z>gc6`NgwOz;YoB|ojs$K?{t1lc}IC#RkF&evMK!|g-N_}q$Ez8=XU!aTZNR$k?DSH zdH7>bh5{P1_89QcnxLt*$3TXT7gys@gGg&BjnTMR7Y$>?JH;vvr8QoBYyLU(RAXL2 z_f-zNEQj8h{%abuzo|*h5;EEwgwip=Tu{B~du39x8b#=`K z3o$1<%@Q~!!DuEfq5tV&6j0;P+IOJ0lh&PGTv*Y*&DongF9+{1Zj3Ufc8b0vBt7y{MW6UtURNi)XwR4%oBe}HD?G1FI zkBd1e?uGsS_%pBY{VUO4*NBkHMmpA_^D_4B$^!>5bk%vd{(E1?w)L-K^S}Nlf)~w$ zGbavhuRMdzTi(H(4_%F}&JOa$a$>&562tVM;dx?;7H=FRu4pyKE3rDMoG7Nk_@aw0 zG}MuGsi&Vx=A=PvENMn@bpVgwTh6CcK;gr&?ySiwqE z{Qh=ST(}JB%T}P8n;MTk{v_VK<#y!t(E2bw2z3{%#dU+(LgAHA>uLx0reOR&DI!Z3#!_bPAmZDu1_uX*Nb8WPgHq_&fKmRp` zp5KkY!W48;7Il1LIUG-HN0=aG_+C=vay)m}{oM3ef>~))KKUr_r`jcLVRx$Wj_Q5Z z*(}o8Ptpia)IeAs1r-Zz^)<-M zN=5d9bo34qvVaTivZ4}DSBU`9CO4OxNXmzF*5^?L#vA13ksMaK7JUHSJO6>MU5_DR z{-xY}jgarK=gG_;wR>U8iL9?nFV4I|v&i zOLoPT)w_b-9Y!qFeeRhTM*XqXl6JgNkEiD+`>8{Y347Ynec%~{Brl|on7Q285s#Rj zEKY}1%qACUC5R8f42EYeAy3XmUtu!x;dxJ7ucPTVs)v*?_4UohT0c8GWkiv3H0hm) zIOGy08*O*%JA0XRhx1TC5Rc@M_NM;`Duu_bw1yPikDQh&Xh|^{N{aTP&j3#{goe}c zeGE6!d2%WyC5oHO7H0n-H|ni6veqiT?Ijt3MKrnTDc z!@IhjzSxG^5fvUmhw6lQa>sxGh-R}va!`-Em&$j~*vfax&J)7UuzDtMeezNnR40Ep z9u%0&h&dkl`qT8KfEn)^U<{jfR^z@Gi}74ZJBqvM44k80qLZGIwIGswL2C8-2FfNH z7GeBF*vzX6qVVO*3bBEwaSfy<$Bf3&Siv6GzR&D3*mIlx+xMO6{O((Z~vPef+NLX6`P*X|G!niRByoghyIJf_JzIYa zKLw6V0b8Iag9+dUllmczn$h0Tg(Sj@-0;2sz#aG8jkW96V~CrCf&HDh@a(1d=`Vke zpdrG*@L01W*ok%LoJV2Df%@J7?Aun0UE6jNnx=$`$_-evVLg8T`#;cpG!)PN!`EJW6pe(O+4|x}f)7Wa5`8EjW@vw6DAG`fR~~r++36YB_0Co-TDTBt z>FH>D{&_-i#cFk87NTK<+IrvtIs?r}H%?RgcB^3z&{5kmk*T04^I#p}!@?uVYA<{EvBWK}zkbB-W$l!bt<06kD z&p5DWJ5M3h;OxsT;PG){sZzr?NKK*^pyEVYU@B+_AmTGrF4_3=XcWP~$Rk;O3@IS93iw7p>tD`XtmI+=uq;B~+j}P)cj% z@^YT+s3=8GPz>S{T(t5NZoUKQdHL|tf;m5dN)Rd{CIjJcq+*Nb8>KtPR>Yz!(Y5<= zbW!o{T5uWRfD?RG^=-8AFdbyc1H^mxfDxq&v`F@|M^yB9=QLHIEGlPQGzn*S%6+e%VL~i`0 z(~pGAR23#$Q0wi}|F2CC@lE2p2ZqrwB6|hLVjoZcbkQ1_eonfH^@DRZTiP`C(YLtLl`>Ws?CaMpHK&^n6jd5)_m?-mLw_f8 z>1>t0J~Rg~|FL+rl(=#P*-IuF7Z-_O8UjUd{;*Hy`fkw9#Ku;=glk^k(1Lf~*@v^w zT4d@e{ytWHXIdR3^DCH7*2O_SAK>7+PMbU-Ja)s`S|^&tr_4#|VLYm-^cvAYiha6i zLy|L(4x8)I#4C*HyR^np{+xRPWo^%dr8u|yi!TkO*!Gei_PQxwx%xRLIjH|4^h{(d zLg?V$R=7(hbkiuq!7&o%(AmBtlva-=l=udpC`!-Ev_eROtdvaSXjV`>zGXWU)hFV+ z5m`NljCWvg#iLD&oo9Hr(t=YWAu8j{cgcOaS@usos1@#JuDuAuQ$2sgv!*i_d1 zzRGv~9cS!MV#akQ5V!<_1TSFzYb;9epaEuCem9@7rnH<>wc{KqFFUUNIXVwJP5Ze%$1Ag*`IgU)>-)ZaPw(2{NOAO@9nZI3y1#Mbt4OC# zU{-#f$=l35KFmY$6zq8RZ*%iB`V)8qgX+`U)5GB;Pw68%_|vGG6IaEzlSqJ)RYp=$ z95Is<`AKEca2VYQ^jn=!#|Z^7Q&CZeX5uRAff6WhoB{3o=&y%qcFYN@>EsRZGPhKC!6UP0XOGgc$yNg*tQHhi75ysBzx z#;rI15}kzmNm{xN^*dk3xqrG1AH3``q(sLcdv+eS^8`cBqi-W5HxbUE2plLnfH@o1 zAeBO+1lAKx!y{Aq&>Lds3aqvXUP8cx(V=f>L^L;lA_?I`8u533NQ~J;a>c}I$ zf830Sibr{4uTegQ^PR4SDsCPn(2->zW+icP5bq$3ooZvp7%kXq{iJ5%ejzOtfif!G<+QY) zurICMgGi(9sW3(MQ~*ynV^{r1W1FoDkMtN+?daRvyrdD`5%4HgwjmrLNWHr(*kk;%$5rl+{$v|*yHWlqj zhNc7EP4KqR3cjV3^InsgW7SIpJ>%eI93qPk(er9Jsk6CG=7 zvsswzQqso9(|G`cvKpO@`aqw@OL!V53JbI8Gl~v8hb@F>GH@?+< z5!1e$Wm%c1IsFvs2T&D(kPa8va&^Ph4LBa-hdBO;p)yp2O)4wzX z3nZ>NVcP~cH(BL!ppEihZF?Evy6BsSih7$DkNG*)bKM)h1cB4z=|V(M9I@rosC=hi zD?YR5j_LWd(;K!hXP#c3_$g}Kj%IF7M3HWe02k}7u_VZuLv<33BvXY_wsKMCa)l9p zpP23%iwbg}ErSaWVQ6~j^QD`Y9M+0n+R#$FNFk@Ileq95l&57N5f?={g$g=tWK6ZK zO~$9$A2vB+T|qo)z)g=ac-dIh?WTcE7$pNJQ z8j4v_6v%i_{3TH1fuF$|4=lzm&mbQA>=JzD{fm*A5{{f zDZY4=KF7O8KllA@e^+7jUHRK(dh)4fxf$MSl)+=AZO0w`OljF^_`YM`AN{`XZ{PQQ z?~fJNzPD}L4sH(AB8?}qed}Pyx6{=73if^9PrajH*WZ3-$F+a!(>IKjpA5UiCw=4C z@kGyOo_QW~=hA?U?`(YKRT>V&A%z<%4?g$^jrGzD^qw7ebpG~l-!dHU@11n+B)Kev zKF#c4*T?>Ste<{`yAK8J#+M)>rl86CNI`Mz&LOLmZQBm8gAqHAR*u3=p6&)aQh837 z=c1_{gsDF0?WKdP-3U%7M35Y&PDa6Dry-_5MTy`EWTE11tLDOXJ8_ry(D=!N;J93b zrZ0grAwR_<3b|Q(6(T4iy zP|M-O?SFj`H8(zhf;DT=x2X)TKJq$>2Re|PkxFQ*m6$ho9unyI+2igp4ph^mcwfI9 zWkZ}mcGV(^LQ(6Z_agX>V&tZ!po`k#q%U2LFJJ#}Sdf=XCtRIoF_)8*joj=kq%qwC zfxT$?`$mKoq@u697zH1=81K8}Vrs+a;H%fl$5N>GA()Q3UVHrw6L;-dXJZyO3xc_M z*+)gQ6rf#HPH&}EdrnFO;uGS`gxk+&dy4DK5&VcSZG>s@XpepV7#@0~N1!#d4e<=! zh6y?R-S@+KXRIM?vxk8{A z&BYa{YHOk78blbB0X+5mi`cVgFBigHXrz$R)#t$j_dSS;AN~+&%h#dvo!#)h|3ZB3 zD_=%JB=P0B=u3%@N7np8yjE2NJX3#DBi!6-4fLn&2wk^E{m(}et^b$l%? z;iY8PCXD!q+I+Z)XIAT|66`{v6atTVMVYJAfHNK46W9H;se zJ5!a&Oe$7N9opGDfn8a}Plj8edRTPkP~-%4`Rf|X-CfC|+B8D*$lbSd4V2+}Ix#VhDKihBpm-V^a>N-E6UDMxy6N2r`Cwxf$D4+>^wn)Z_H zay0eST2Vnt^^l-Y&f$_LxCtE;PFR#4&T&n2_T0vvLW3}F%qb`zS(!`8?CGaG;dPQH z_V67krM-mWie-9S^XLxW4dObggD{z$eJzL})QtL_?jP-?vN&1Rw5S}?gG`v^ING!( z8&6DJig3*#PAbnsC^z>H1fr+UGK}+0M>JC1^-sYl-)Ybw#k;PsBP!oL9Eap33~gQX z=S3@bDevQ=c|wMC8&ZAEtYTg{Bmamq%CO<66z=4IHWU-d=?^D~0=D9`quYb;-?;^Q zXgrk9&65@h=L{M>x-=3($@t!G?89%~pO25dcRue}>oxNZ|7iSWrAA|Rq5~iO%RYQ@ zL$)!d8qF8=-e2y$4+|I0$EQE_&sffryO|kjM)93Rh{lc{ zi8USX+_@8Pys^pngh)wArhkwYB2tvnIzGu58*SgQlkz2vcDSA>Eh|GaaYK%m#R4V-w_qF*i4d^OP4`-q}hhxVKGR5)v%KG1YU|?%ig6D_<0;DJkaN z-CVmxMMqIlONc9`DMho324*EC2f041C}-^F(u=tJ#=7hf_b$yH9( zS8{`BE4ibzv<%wFczeqhRFqfJC^*HGQ_rias`28BFB=7ZQc|KZ_^PX`H}`k!*hOEK zjY#JSb_F}l(z0^A#5he&O{Na2v(iyH_UzfmcG+d_i}sH{{uF+G%WnwNoyiS?G(-PH z>LXO9Z(M(aaVjrEy)w3sXc5j0QRTC1_a0@4h=_=hd`%%vz#qTD{R9wstSr*fDjkEg zL<)*bfior*y~Lp1x@#MTHrF6*aVjDlgQ)%6gLvw<51=@Zj-j}?jp9V*;)LfRex;mj zh zysVa1eL0Ar5_o$Jogcow4e=}HBQ~#qI}X)2_|Tv5)|1=t#@4s6=O;Jfz=IFrjXR#< zy;t%2#uw4~`-c&iLuiyLH%j_i@y|cI9!nN19l`DGr%;$o;U#HKK3;h16@=AxA#zq8 z_Wb=dQ~Nh>6Se(qbKGcN1EvV+i4# z1_TYS-bB@=)gSbe!Lnwv%B9YtzA`TB=L6$EME#u`wVvv&Od*(KHkJKF3R0g=W>Ph}*(Gu#_^t6zke#m$iF2Pm^>LV#Y;h zc@a(vTBe)OMD4w7KbAzNAoSVk=7NLJL-~o^@MC&XzO!r5q1Vi8A4|q*q?}V_PS_bm z`-C0Qklg=gGzB#Nd@s>ZeNiVOHJ?x(45YF#n2OVoxNLr=Q-K;ugN`2bbMEbHF6O3p z1qP|)6!yF3#EBWg=mH%6Tm9V{4@2ApC;U}>6rG%Ra8uT8Ud*Bo3XLtjV~-Qx6f8xB zHMV^3&*bl_hw4;a(_kFFYEwbHeXRP;Zf8| zMh!iEQdrR6MVOnPv}EsTKtym1#g_;}d(CUIju&iAFQEt{oWyqLd}`-APO&DuEgm1i z`BoQaZgKhv-=B_$8YjZK*Jlq6QY?%1Al6?S2%2jS&qZaj%Vm#4y)lvUT?$AqWeX|T zW%b_0)Bm!BSA8Ri7cZz9wUC|e;W?gJzeH}o!u`~4b9Q&b2lkgY<13FAV`&7TOto>y zf4)I-xtEPy&$ZFbA6<+D8gS`UvetIuBf9ikYq2;&%>10jK$p&rMot=y#)k8-)6=_B zgug%q?(EsKxR!DuKR?f0f^K^F;YYcdS!t}fZ~fK(nz?hlY&|AU3S^!R7_{#w%dM3g?BjlGoegO*&If${l@j*V_vxi zPUgm&eub;Ay4=8^-tniq@an6tBR4k(zy9^_sMtksmz#~u z%naOj-ve~4z8QtH3vkz;?;$cqf>DZp-G3we>wKfse{1vGSik;k1K0DD z|Na>Y=gc+=@K;`W4eMBkZB*tjUwbuHubgA@R{b;|X;W8<@LO;FH5M+IkL}xc($D2C ztXjE(`EJCQuKPCDtX_(D=pRm-2P;>t;5xq;CB+A^blGC$=H%dBZmxvV|BOy>Ya?M6 z*Q*N`F2EB{K8>pCYLjkDODq24yZ?!E-*b-HY*8JKWquMJrV>ts!u`y{kC{RXOr^2) zu7}4(h1s0^2nX65c=rIP6`UqAc#9+K~ymIQAuZnJrZT~ zpwe%%0O7K^v)j#Mno_h3qK{VT4ho*KJ`zqRMW!)G%1p?J%wm;K2YKAFj~2uIJPJD0 zPv=vFqX|u4PN6x`vM6R=T8Ir%5nuw_&>#F1IIa}XKwv*J{aF3Fwc0vq!3BRvd;zaq z;>{8xloK8QXn=6iqq2ZXsSDSxM)IG2f!lBSEn4n)1aT{Q{O;_t5Z%&)@*n&OzrO29 zEd9b&IPc=~i7TGZ#TKo9m`7DbCE-!Z;7H8kcpTsur1dD546+ak;}{jLrN*4;{Vbb( zvPZa;b2(XF@zu}bzW09x*=H?5@ay}rbL&>jqp;!(rh;A;n2ZxlX-vxJrDt78OZhfD z^U_viB!;7~Ak*xsiw6Wz5EJy4oMLJ5qA)B*7%f1>f5JkDX-aDvy{n*fv^(F~ z(TSp(9?YFT8*{T<*w)L1^r~D8)f4nNE{se-UP-q;kmYglrnh#{xotKD!)W6OR@~`=v(HBU?{o3QV^8AsZ~Xx=oDU+;o{gk{_hF#1 z6W(V_5k2p0I`||HV!I6Ta=g3;!C5?pNkwNPcm1#W;iqxVvSsWEN>K_+sT28_&cIeL zSb)#|;(Pexx&MO9q)5aOPyVTgAH&>PvuNGsG>gQk%wbISxCWJ5eT+>+#VM7bU9?12 zyRl#NQ;^pc&KqsS-6o7aE&2noqXxA4SFC;t<=jXL$U<9ZFBf^V;-jKFf|kIp#9(4d zI*?YtlL!sv?B6^I&>wB!N%q$dpt5ZM>+^z;5=+Pq(pWT zf}Y*el#$(f%wXC;V}{T-&dgQtl)phM_dJ6O%}!~?!!HFz*t*)# z4&k$4T8DOWQ|_UMA2thtV9xJ#Jx-2yZtl4TP~Ol>m?ky=$8uyCd6dh^(>)GUmXshi zDU-Z{IQqez6x``I#}h)!&Ou^__8J9yY($8$W>1U`Li?bU^d27UAw&TC8(9qEUE?(9 z3~3i{do`83luZbUqLX-{r#~Dc1%_#;K4}8SrxwEIH=j8|Bg|=n5IS8Q>h}^uzmraD z>2#8Y8ES*@?B$$_C2t;m5Dzx<6z9{_6v0&1(K?z8kil#)YVsNFJ&(7-`sldWlF48f0Rj7pZ!9A@*-W2wmK`I^!U4ab=W z*F8zx95S?}>@+}`(CzI)WorrAdw62Ezkt4IB;#l^RI(3^jHrzF_odPAsEIQD(9bnE_G%e+;Yop zX3crl+Ew`A2d^9+YXP|S+D{@cFBh?~F;wPmr^E4;RM0+y?|$ccW92R7?|Jr4ZjQ~Kx5ijqx3{;WqoadL@)-qj6YtGUZ&6vk9GATBz1;k7!L^_Ll2MRr9{a^j|B5et@$;ra;*oZm zk8lIzBBpWi#TQ}$>HdjN{y$v#{>zNK|D`Yd6Rx=8GF)`g1^AbL{RY)7q(XaS7v@sFbDlFy&yHVFRfC5fdIX>Q+-Kn6f~Sv4b7wl!;)^;` zsKIDYz=sAVnM@xUd@r#wTg%bcL1!4WQgSBb!x16NlnBH4g~e+Yv?80@WUSd>=8)81 zlGA_!wty##c3FjL1Ia@;iXmF*1jiL1Tz!;^c54HOf{#y7|JL$gh&*NKoH@AuN8iC; zxaZK6eL zYY-9wX{9&NgXE-mTBi=8rjy5(`>1uK^kSDu!AlFiaGQh4N! zR^#Lec7EcOA>0I5P>_NSI(jWD>*7(nedu?_AdNy#WCZbRd)vt?7>{GOy|IppbZ**F zArh0EK}BZ>nyV`ipPA2N`?LaMTAiIeCXcGpQsksYVB!2c;;eg38A6>@$aVDK#f>|V zo|}iodC@4UD8t|Hz8^6~RD|TmAy5Plqhgf_a&c2>z{AJ2PtSoQFzeN zLJ1_Z2<76WgSfi7W;(-5Vg5npXk!4|xgb3QpS$)`Sk7JlNA9^F6~DTb^jd)+!qfyu zsa{?#eyR9jhQUGPhdBvcFAt*o|Fd@)RuLBtYp|bt=ZDsA7@(1ZmL6+X+cscxGlQ(W+0bbP zlxHzVMN^AA;W68qprzKau7m6j2M zpvVq13|eJ1UQ!`34uFjh>vinQ7(j}q-Y~0eXAuhKw7~g!8ImiZFBzIsd$v4sLhqgd z`Op0aaTW@#5$*igxOluaO6-6B z_nUUZ8?U#e#Arx}kEeg%$Hb!sZ;xy%LWZiB@~GhPVm!$$R&JtV??}o(OyS*o_CZ4E zaPGd+a};njfOJAvD{iTKOROiaz-Hi4(}b2{9TSqUh!ESpb*Ed*yYr6Q8NB}kldC0` zTbMz<>Ifvf+hXIBa7CU0Ba6C98&TiHb1rY9-K(;qnR8(=Q(nTl(E8$>R zJQQGWK;Y$3{o_Q8;kVi9zoY}LQwe|;Ban6RvnuIcHQA3R@Omul!UG2@Ee&bBxHyjy zc_MZ^6^7CRYd;*=$C!}`F4H=&riT>52I%qkGtLqD}Z|g+P z5a|hb7FD9joo@UW=lr^-(xyEGo`*dO`yU@C${LxY*%!NXH0(7xP<5<4(z;bU~_GzI>^Zg3;XT zmT!L9$;@onu!;Ftu4Acdf4_~EJj=xwU!+Ygtvnw>6Zw%e&9Y^S9oViPii$k2f8YKR z$4D0|T}kpbdPzP;Nepl$_3LU&)V3y(f5moG5=%ag@v@S}#3Hmcu^1qmKJw_}cK=@< zbo0dvm?MhaFL|4o7$!m_$?7=u1wLyIsD4#RApPg@PXF>(zUCGrZe;NwUGsSEL-tiZ zbgg3UK}j*fR<2m?Bw#ur!IUyD`r(g$;;y^;g7W~*Bi#5s9a$cwk!7G00KKKP)pqXM zZQuRw58N~VhxL~@0A1eJ@>EsQePw2*yL(U`6iZC^qicH$FF z5y1YN-~7fj5zo!e08k1=musVK*s#GaU$>TwGiap&Q6MET-}(q#(+|T)EO@bhRaskG z1+uYXNQ0V?zZ`^yicO`CfF&oOMU_%4df8mZ1`$jrxEFR(cZ-GK`k7ilLmG~|Fm{(# zoB%o}fx&S)CXfOaIN28PJ3wi)t6uaX9n-DY0kCw!V6;c1t^sIg0^~d`x~MvBs%TE#!h?j6JNIH=FYQl21mL1 z0LWSK*7Izs^qtT;avW&j`@tk2|>eA`o6gIre%g9tol;t7Hk z%YcT-k65;9Yub_b(15VAs)T`0kkwVy+2V!876CY?;H+BYfMmxW!Hz|{X~Ro4e`b~~ zT3TRRaF_f3&9_+ZZTDK@%4ODH-)?pL_QIbIw?yuRnXUDwL|K0PJbUP!|7yllE_`o( z#wYsg(R#7MYN2#mFhgz_3?-^z8g<=v-#Wz!9V$epG!{0KJI371p)) zQR~l`17ns+0)5l)!Cv;=UvCi0O_2O^yDz7~A6K3j%!@fLSJG|Ni5w<2NhvGaI`ZF-J!pJl)J<*oLn8*Z@0ix=5<2=uFg{)+R?vp@a$9+))e+Z(RG z-X4DVA(PAPWwamCt*pUiHZnTSUfH(8o_P2HK>TI)>pOpAuYdh@xXBjSPk!(n+K42Z zJ!^)myA1&UdrJ;Ewozr-0lVez~Dn!P@5GDYqOVl02C6c+_B16(GQm{l6vc?qNQv8Nx8WByI{ z5x9G#9qlHjmPixQocH>*y6Y^HSPa7~{UN|>QWxN$k+#)2 z9lHes`ONoL;^xTKG0aUx_Hs6u?8O4dP1*ti@AUG4IJKRscOnW5C!U)CP(7o=WygEQ z{&UuL&7%bP>UjS=8s7+voils(aG4NWS?!g7E}g?a&+s+Rk`HMqv5bMkt(Dk0F=0si z>E1`&8_JHB5gB4nS9aR21NFp`LVA;ZP_UAL-S}mIL2@vJr~PG(_ELGL<>z>@71Rv* zcJys{&%O6MLdKjqvx$K*)872%H`(2P{F7aM^_Ac{@`z#_O_J^9Wg?P?0vkBh?tbDn(+cJ-3Q3+$7h{Fwa(5c>;X{)Tn4+mFMQ>u&v2z>uMp9rFg*kkddluYFJoKb=OmS zAz)caQi?uMu6*cz6vR0iS=Be)aJ>WM#je*q>bl*O@qRZ4%))Qcfa=o zyZ64o(6~xd*;}M|=%I%kkflocS3dvp*T1uSp4!R?lE#P%{vgNpu)-Qir%+yY$ew)S z3Gk>+d+Og1*#qtQNw^P-CJVAdmtU zI9V2O_XWPGi^JaU`+pe>|>T+wY z+;3}z^3qzyu1WYE)}mbP;<8qs@dVMtXq+w6iAT;pci26X4X{^5VO;M<|*Cy^QJJzoF?YC^%w?A!VyX&ldGvGVVrXOa0_IVfB)=z)YzV|=3*xrhA$JW(- zNbB0aC*6mV{_1)4Gl|mxKb3*u^{>6!KJ&wyZSL1UFHz;6e z)XY$;_{-CFuu&6?(aVIi$2G8v;2LiMsQlMYe9Y1l65Sxk&x7)DIwhHgX4`@1ZLA@T zWE@Ab{2$BQDK3%)6I6Xfj!`k`M$cQvbu$srv&NCbUM%gia@fqM8aW1h-vDwZcm`y~ zhuPeDGx2JOM@A^zx(G(waA+TWOQ_|~TL|ki&Z3gi_`JxjS+~$u;(b9S#j}D5HB~h) zISAK$F+?M<5|}S38=c#|#@Khd zH|t(B!BJd;_rLFb_9FG-b6@z9J@vPz$O?;K4DJ`>n)~|euCpRoMwu{+-u&hpZSC62 za1)(xuWWtA?I+gHYt~YRnl^Q z@PP-YhYM{z$1Gsd^xNOwN>W++v1bbZ95YvqYVzi*rV5?>9+Kd*Awun z)QbmSXk3;XE4f0i0v|}zYyoVJ-Cey#nj<1(9$pi**4t9;fL1NAop|zCw7Q1o3F z)<>;-R69CL(tJllo&Epqi=0l3rx~l(gWlK6-j@OD%`~ zK{9CWMv4v3;&3hGFm?!yvHZl@^ke9>Q;zi&Ze@L>z`Rv zp-&X3q)h_gHJ%Hk>9v4AuHFECaP4((un&LuBlgjc{*&Es!;JuSKXzqL&&9olz;>0# z;cfipm0Pd<77+O#|M7WPzNK!vKzF4VUU<=Nzx~&)oIm-uzd1QQ)$5Vx(&sa={W{hY zQ`uH3$V#*iT##kE>bflv;>poY9-0Wk4&NXkWdH(cXz{<9F`f zYVTi}Vsn^hDf!np+I}DV_-E{)haW*I=0W@X7yirXuxlZttgOPdQaV=8UjaP@@LqV~ zDwF>B0D(Y$zedO&H-F>XcF843s=@--Z_UjuEPf(62s1u|@#)5A9)=t;L#J@bFGuSy zUu!@7@h>2OJc^3KJ@%z9ea?a0Vy(}ZQ3Pq^dk{l6+Sib)S+jbTW74m>U?qC$H`}I7 zo9!$A`QQA$2|1Z$OXs@Z_{O*F&wswx-uK>rayC%EUQ<)YHNAeW8R=4g@t}{zd})=7 znSb7SOYLVr|0NjNE8tW=wC6atwApp6=FUnwP5{4>^7nO!VOw5$*#z!?@TQNs;IRh} z9jX_CqL&tg^ik4P7% zOE0~I;1R!fjapVto^9H=kpK-_0o#__kAM18yBHSRF1i4zJNMUEG=rhMbXdTy?&-dd zw7$OUShXRVtg8+6hAnjdd|y1pc zs+Ivuj_9?t7=kIzD6oSJ;=c8{uUhN_yDWbF9BX{+MeDt0iM{Wu|87^Wy_A8#LMyy( zwN)gA*#5ikx2STavw3kAS6F2Acm35i)RtQ&flKp<{w_doEKdR5k6zN#*G*)?j989) z-@t-=+jj30DA(Y90}36)ZyIRyQEtLQVMx@KS;*ogwrI&hKx&vcTtnv>nS5JCFd2-Z z%@s@H=zT`+f2u$087WaLtOCiH9>>Ikxel0~5gX*BTy%%pUfl+(oU)u1ALJPC(pry& z$sU0hL^l9?Nj*V#`Ay$-J_W=~i5?)JEPz8+GS#ccYMQ$&J+}azW@z=!e#q3I*FG~f z1P_H!i$tQPy0XTa(S`2|jUx{pFe^Y9jNS$4eEPXPj)^aZWnV#=;>#kw)2)RLnb1|cJ12DB;(I6=+v&AyIj94&37%Ziv^RwIW(pe zBPl&S1BUzom@F5wh(evFtnNQh>hvl%KJ%0t?C;yZ-%W7EF3Ziyb-|pjSig>IMOk}G zvu%0dd7Hg(1#L@^z3|KvV3nCw`~i5gJpdPZK+Depmh#;I+H2%j(;Zfg|5y(l>P1SnpsD{XBz7#k1k>0Asw4?j-h! zAa5sDH;>Mn=J1MR)ZEtQ#>NTAJP5>^+N&IW)idk6o`F37l43$F9-@!N>td3dD8#V6W|6)Rj@_4mI& z&AEspgS3gx@6VN7=FjjyvaRM?BJdRFB-o2Ps_gNDZ8kH3#V%|TKH|kLR>X6DmRLIt zWk|ea#aTR(pYkeJ45ovSnZESPjrP-*>g~6mScBF(eW;t)cx{nyDqT~|_JwG6my{fE z5}`NZMSVVjIAz=1oGhdQX=j+zsGrP4>Li2Lym@nxTZwiOBum2&7Bv%Gjt~}4Ky7CHl-9^k1dts#O*iU`xpO9h9bK~c{yd38#sxp@X$xL3O8aL~H z1h#9Nw9wTL?uGQWaN&Ggw|1@by2wHiA{SP@!_YWBA0S%gSFggtT&~xPgw8T&I|Vak z5@BzD+glyu-XBNk{UyfY>(`@`uQ+Cu*>}D3ZSGx*6ARH&-@&+DUP^Cy^9^pnLSqv# z_+=j@-M9ZP27F;*zHQ&W1GR`S$IKTvF6O)P>a^^shdD@^W-=cZv1#$5`PKj~P>9E> zq-HdS(Du2=fp*|Eq&g>kegW_`$i!ZE-8F98sj6FnpsDV0pLu^&Pz8LXqFX4&SO=X; zB&<#qq;ny;0XCJqsIU-ltj|r#_wLUte_*lcD&sdiGk^VJ-z^ zf02NUmtTH4(VfGcYuAdoG+<%1cHL{&+dU6&w8gB@Wo4vUZ#xr~oC1qXY;mqAgV;PH zEyb>X{k5>%@@>cVZAek1x=DTr12lEik38}y=07){!MRY*PN#eHJBeTc?G&-z<{C8G zw;^%ffOO1Eiz>XpLLyjrLpo-Fi3C%Z!vlBP1@J;Q;2G~dX>g>;RW~}~^XSk%{n=03 z?YY^u^OHZfxMf+$vjDh*S`H2Yxq~nkl38_DN30-*YuBu@mfL<|7odq8$plOtzuGM| zQ4mF~Z!pYuR`pnIRfR3cL$)O`7+Ho;$4<{7Sf~JRvAQ)#O-3g76k`+bv%!aMjl0}e2+D7fG-$zUSIs5^Hj79c_b|38+Z<~J~8c0Oo{#cxX zc63>g6)>=0mKJJlupqWFpiH9;*|lenmHz%tBy29TLy!E)Qs4JM`_O0p+2$7&y8&PX zAoqpKmf2ib63S)6>(t|D3atJcP^+<2~2~yG&?hLXbiPf$kuyLIYmF zds~;7@Pp`cbN}9<{KdvR`+g?osRVz@n>Cjptgzt4^y6PsC+DHIWyCX~??GlLxX;p) zBCUh1V$N4{?#9YP&J!vfwsbWf25l_#cGT^+7g;Pyn1=>#DB8 zT6ft?7CQSf@-fuYa8q)ReR~f{m zcUe)VZRgqwtenDP${vN>moIe{mKK@j~qRBN_A)JLi~t zlR4do&b_yu{*(pnq^L9`38PpjAWm8zLDKv1UhIysj-FPC2Hf3AX%jq2#eVXkx~pgH zE~EN-DjxWl20OcdP+3qLDX?3qsHo5Zq_bI^SNi-HzKHzfE&$mKn6p2%pZ)YF1iyUR z-tmsN!-oF4{rhLXVn6xmx9kJ&f4|#b;}wCnxBluj2M&Jc+usC~KV+4amG;Dwe?#(i zouy{v;VD~ZrDdhg>rPtLag1Z0e&!j@_iw}P_E`1JUFZz@qj{WcoJ~xKUwq<1`{rF+ z?7JJpKptu-j&3k$Z*F;_+-`ZM%HF*^)n=t3+1S`+KYp>^UNOxmtS5lP}__q+Qt z^k>eT*$(g@xlQwF$stNpeq{2l%Utln)$Zm0=JLjM6zKKnv=V7oCG8{cQ2(>91F!9o zNGZ!3^ysv5#Jvl=*2~L7=n?yit*)1!w9m-$SW{g~Ak)`4*`A~KQQ%d*{G?+g<)}3B zJR_f#=jH0%i@%?={Fwl}# zI~Zbjr}cN?I+U1g!HESHRQj^h$Px&kz!Xt5VoK7PQqT=O2c~H>ZZIGiGVb_6 zta{r|U{GeRuvJ?p1St*Mg2Ts?4)3o6G^nAA>mrb2M-Aa#fv{mt&6=5~QH5hr%y|Dz z)>>I-D?job7Uiyiv61D1p=xF&5W5d4m?Ug<_1eqOgr9GZU%A#E|H*Hx>4`@zbJfKb zy|2l>aM3mP^%ow)>t>-lR(2UPaa}#9zo9*S_glYYxpT7IB(DC2{Yb;aSj=Jqq{5g8 zhB+YTzC>6Z<5{d7zV9(FeER&L@*s(pF7Q;9IWg1mLUn+%eq)pAu@$CxAT;>7rN?;; zzJ6Ho6gL;7Hw7Yjc7nH$TKQqCa}wb`~Zb?msu`dSyjRAzzzTU-(f<#nCb8y3%C6wUwECff^}yQ(|c26FOje{~-V1L4-+ zT8EcNJ&V$F0K3uN9jcSl_0;qn!T`Tp0g@hj>~Y7y(ZuDx`|h`QAq6AQJPN?${`()W zRj|tP@vIRmUG2c5k3HrX@j6EutB&wJfebfxEWcVB=u? z{KFMj*zbSuxt%ItYi@3yV*oW1RLW~O`T_azDv3+5zux~RyY|{^?W)&a%Ov8AB*|OQSoeX?qTr?%~!RlDj8muT)s}HKMuenbD=S5^c$~`XXFc1z-iY< zl<3nb%O^cA+`W5TbdAEE`%9;|k( z@aE<=cmI)isfeX0`>4!ojB&aojnxKv+r4@j7DMi+u~bdnhZYuM&zjDp;>XYq z*-U^EWYF|oecq_`g6&!i?M2(2r49D=YuI>mJZLp7aBfr!$&|B2ViW7$BGGI*hKV$J2{ zvF#r7)L!IR83_C~WC4{4wF_z|L^5heDo{x*<*$7COD^bU1`OKE*Ixm7Z?hYheEMJh z)js=gpFw;2LVN#BA4P)Z2FE^D`K_p^vM+xLk6$o}J)EPotcF>V#9;yfK+)3-5UEvwuDRUBCI)@!v=8Kk~Dm zmy!GFvtIsrj@TcQ_}fPw>+jF69DC$F9DU#GE??{9b#%OczdGm0@A|BB9(}CaY3Pri zkHgm<`xtK@FYhC-sqISsx%8Xra(Q_=a z-g(Ga#M6PmGM7fX(okooPDOf<-3%ZfhcPk8WOOAiVrekY1)lqoEPm(cE;UNip*BTQ zBHg^-`G-H+h7bRTWh_6BwuTNAy6#{Mz#X5pUtC;)z5Lg|S;ZBvu_9K?r2{YE{qWS5 z0SA+^ZX)As*mB5Xf_v=p)x|Ejsj{woDJf5Wup#fe+wA@f-QM91BR;9lEBMNc8M)m1 z$=7jJJ~bguO-r^JMP0UYcd7d>yU&|n_TQe4?-X!6WwvG{~P3S97jcMnJ}X$WGV zZ??Z~&}OCM_Byn_r1SINn;dX_2KYcu0zZ-vl|gbwV1suq?W=P}1JEXfbXi$NwM8YQ zSQISo__TBvc(cDN(t-)Vot`>q%flP2o<6OjITV?j!-HM7fF^J~A;Urvi(t9GV8L@= zQ=97~ zb;hdq?gmcqk1L+Ot@xtv(&kkim26v8b(I?s-*nSWHlw%@gZA4;KKvmVUe7w0>kobC zCS>0J<^oH7>|_7rTvb(T-ucdVIyTZkZx^iAL?q(Kix$n~eZcDKn{dxB*DpNpK^Dwt16l0TVpDNZ zj@#cE=T!d@;7)v~V8$%LVJz4SZKvSLgIV_xjW+#w7Q|1+ZK#bSTPzkspr8+xq>PH@ zSoK06b_DUXR2KC-j+eAg2y%CA-A(k*F}5gcwL3(N?~^?a(Y2*#93PozHF&Xgbm2YL zC%t%4MD!bg4H7aTK_XZQ#^A>JWvY^^ujD}sMPj~cVL23l$QxKp-F2oazvsev{4yt? z&JUC-xs0XDRysKiJ)^~o7Fr89fIMA`ii(_B(va{_OuasyrIOkk$$DtJl4L;~`HAu) z=?#t3CBY==CE*3P{puIa^Zt%I?sO6ug@uJqLc|?>mi_U|eH3mpYnJ4>*JN%{_1Ax1 zV;!&G^C6p;7^gg{8f}q};8N zOUqp#(8xl0#6f4#7u}<@t)#v6Z~yjhxRcH%pdo`JSQfEy@s?LO17=z{KxKmkcQxC> zS$P&29c%Mu7ttD^t(%l%H(q}o9o-8|>{|io8}04yc$W*1@%rm;uwUJF2ZQukj=?q$ zuwJRSsF=ZTB#abvdy$vXWdCPB`#BYQ5kWZ0Tx4i-ws^!Ay z>v3xU;Fnv~E4}nR9Dulo3E=M@e#mbB+7E0Y@eT~l>XvP_)^lFECARjWCmrhKWg=!J zS^a%a*|zuZup&UJ2qaDVbuXNU)A8mp?kk)7(ZG(krE@Zv!oVuRQ^Zf|B=wqT`=$ML z-#S(kZhh8db)x6-^D&-x|DFV}&zVyQkeBbk^iBZvXc%d3VUByw1Qc}orVP*(ka;wA zx}Q%)kJrBQ3yZAq{qM1rt5;eTAo<$WtI)8F0f+?H(}hVI{Odmbm!4$=u9D5z^DY9` z^xXBhC9YXw`v5Rs`|Dc(@?UR_u>ZehtHq9EaI~7H&pzv^~G^MN3I*u)^FF z#tOa89z&;}lIQMBz#rLH!CSRhAQ=~pOEgJUxm`nGD$kJYNO|i*0#4;P6TtjUZ@QlT z)dRGzr+@a0>w#(gEIKS)03(rlpoy^bSr^Wq3qz_Cup$Tvxr?o|ftU`F{m2pwIEk8G zJk}P>n?t)W{US2w5*;vZAmb_2qO-wYmCue{4SsG(#5-zrIc2+8~5UI|quN{`M7NV7U zh{1HarT%UTV-Oy)w2f--A}P@8L;h@12&V-a%?19 zu6-ZQ5Bb$%YBX_15~I^xo9Kf|!~2Z(!4*pnbkAVXS#4o00s>3F8U0yX~XSGQRf^P2B{?-u*SCqC`~a!JZ8T(H3I{^S4I5Wha zDo7e!mH@bSFsRJJbzKAObD?1A9$kgUtYWzr6&Je!j2IZn1WG8*Nw%)4oz~Z|*DXqv z*CC$E;OVNXUx)5=w8h{?e%|t>PJgPfsL(E4Iuqc9$@D<5&6_)$;22A6=8PFGsKpH4 zWoKzdMMpDfWm2xeS<#G{wr0(0G_)2wR_;MMRz+ymBwp!Ucn6VkD2mAYVaB6{tiL3jtvQT_XX^8wpBy>u>L}|9krv ztr)$$Rsz&iKD*m4`_U)ub^r7p+gDd%9S^*0;dx2u9>ZX-Xt%cf1Y3Y+UN`MgCxJ_( zC9YdjbonkOyZcKjZQ<-}>WioAE&xswjmd)TBW``#KWZSSd-E47G%=P7zgu}%AI}a7 zWGdiOX(Y?QZ5Z*#Z_6~{5_lelP4cs|ZB8-4oB8Y}W}Hvw5KFHHP3wLwVqiagkK&p4 z^9=s{;6wJ*2ft)F=P$DT8=tqUZ~vyf)+CEp&1bt#YA_{ z!<((}id9ySljA_qGrir?bAdp^f{_QBxvDiZ>eOess^X>U0+kAUt08!*WR4*HTYX26 zRl?{?q-xAe4RQfh1pxE|U`xy0Pwu(%MUPo8B{2YXZf(#ue{X?&?R}wksI11?OLtjE zP?V*@ep;3nY6*BCq!Y{)>2S(Tkabb#1Rg6WlM5`&iF7~ikH9(PqXxPdLK`cJydpeuL5O)=xb}5dTj@uAN>Rr72{U*L(F@5g7v`)m#j@6 zAi9p#btQS#i#LeIFzRFVS>U>u>IyEYI->8stE=+c)7^ue1da^Y)&)p#S0XcoSM(TMLlhwY|EkYxcS8d-+kFc8iqc%df{SU)1f>7Hsz) z9Cp(JZhuF!4Rp66U6QMZ?UgBipR@d(qQK&s7uTV=YtZVb=K|KWFvU+KykL-?YCy9( z38HZV0Q|`}k?N)QY{YUF;2xHoPhPwnxonN|kNVFlq|5f~Eu}t(*gO`2Q&JKs@6w0n zI_E(0+Af(?_M_FNUTb`zK3VojAr_1P8?oOL33lwacc;=cLBS!`+jzjuO~MlMSyc7( z=1UG#SVMz?Ehbq(KC*D!i|$MB(~)!)zZ9m@KdEm#)G$at1t{$e6NmdZ--Z=sDItV#SAtMp;^P&QLo#zGFu};{>*Hb7Hu+v)Iwr%R;y%aF3D|9V$CI z6-Lk)D}s()W}h<4^Bi4&LSNK`_q57k9FmPO3YO_zb^23}131HCrwxD4z4uu=!E?X%-~WyF z^<15XJWpAPbLTsq{^;KP*HCkPWcE}Mlw^VtpWXcDEVhfg=QHHbnNmLea(1fCIvg~W zd61H;-BVna1AzNUe##zD6>J9>pk-&LGqCjZrOuSfFe&r67TW8O7`osl4}%YP>E2fK zz^ZpycjZgg*K`mUP2BZU=h_RqYwV7@{?Fd@#_KI77Y${AK+QoUNh20vd_t1-HdR<> zT;rlJ z_b^d+`%LQQ0tcN_7Vyim543kQS|^eb-BmBcWKXszfcD6=8LSlnTpt5yA89j~MLKJ1uT z(Y2I+O@{T-V0&cp?@jMxB^@V*qCisTR?Lo`OF3Q)oX?+V>kMjFo_^s4`~Jcu<96k(x7b^esEO31o=JfK#MqYIR&e2KY(qnx z1^x9!3!k5313UIvOnWfUNtFqNr>4UUIo_ zN@P400obqom4bP;hYnR*`GJELn={K|QnGA$UI+l+(1e~m2sBpkKQZ0nSuoyHEsfcc z!Rowo>A3{s2H$n?SxZREwIU{GDkDA6bu*JAkz{!ZPl`b+%1@`S^2?5n1rPyzOH7Ed zfsPh??nUZp1n%@z)mBkjO4$o@6G9#1g12EKk4>afH+oXJ^pXd{NXltoFvM!xgYD&g zXvVj7S#o?N+UKQip-ubB3ok;GU=D3V;=utLNV*J{aqe$qof+%1cWD4M9;R}!s~T@V z77(PRFV7j@U0b==f|SNdqn%56QX1{Ik=sV@;|>^cjQ{;~eiyK({-d|)5P*AujB>bw zoX#1aqP(e$NH$8Kdk5>)3XZ6flNC$QG(f~=f+ed=^+0*gBA!DWGEl0&YCBGLatk&* zkDmHH$jjv6i4Z>F1rfDdszc=!1XJ%)Y==---f6B}`*rJN-^b~2emyVMTP5AMUh0!Q z_B&oot?jmb`+h)dJdS7+)ZQui$G9)k^~dFv*dMj~EEIXb(71HUq!%oHe@U6Ov~)P8 zeojvMaE_)mpF`!JX5Ga#P~Az7_iXF^9nKc>sSxXAp|`EK$$dWj%dtQ4bex<_YtT2@o||klX~5lihm0R^*E3dok(HI{Ky`l(pO%(pmtA(LU2(-fxY#nf&-?Db zACLDU$3|bf_A&>o`|YeGF_$k}=C)~|vyj+Jsi`S0){GeOO4-QjU3Jx!EU2YfUS1x7 zG+$$vUU~^$bUE(#bLo$3v$q>6$3Q01je+r=U{`aN1Q>Zhg(A zkoeG02c!&3olP**REvyFBFI^{H8*dy_rCibE_kW~+nIo?b5s&DuA?3FB^DM5I+_FR zbrzhE<=n>A^!pV;?>=)~$A)qaNzClty_*0l?dZ>bn4nEXxRJFFALA|%_!F?eXcibM ze`2!>{OD_MwC4aw5-SX1&Hj(cPtxyWoiK6dHjXCwb)*eQxxL-|^NPog3tx zAN`W0{=Lk?FUYdkl}jxi?TlAG^`Ex+_xD@9(8s?Yu#}<{OS@pM&04k0GG-OqbANlr z_J95BR=Ds&>QaPNY$Ryse}2VoxbjMi0u=0QZLNa|1VWEX@XEL1adV&DpoZ zE;xUcZGq9e?q@%6V0#3|C@@zDi;q3XkaW^MEnB+Q-uvk!yJf?RmU*zj5-(V2JHC3W zZGO#KyL`=>iQd9#x&P7SKs85IPJnqQh7(vWM!J$fwqSl-k{#l}xMZYbqVRT7@I>J; z9wg&U0Mu(#!-{W22}wYNLwo5bB#cB+w<;uPqQT4JIfo|enpnGu7(1rUT57>aMl8=p z_Jn|}I=}MS2eKDR#`LV8-L%aXFDSHG#1h$2(QU;jOeDg#6~j>@iIwHNwD>+V1Gr0*ulyO+gToJ zJ4?3ORqGb&f)Gsne~%w=|F64@H_;n>$>bA0(}Jr~oFZ6D8_#vu)ofMPc6-(QAgWP$Tsm2K3{DUCeFZ8&LvXy9m%2m0~Y z>1ngzg?D{?yAw%&R4GmEb z9#4L>Xsl<`3kcsydm&wS8V#?bpVFMkYf)o6^`ly7KN;7U(hQ#iCmXH)>lyju2>-JH za(U1A$=~jOKm0y=c^)~Q8hNa?D~*D=5`+;nQ0i`n4Rp}DDqptV+MP@y0U;Q$ zMrJLx$n;qRo=Rd6gSIs8>S3TNbLY+>C|wGJSWhd~x0~JtLJVla6OJEoZ#(C1fvKCz zuulVAxe^`;y8Fip&`3kaT{`b`c%{Hflosq+WBb#+Y@Dh2^9NK~G~(6Q*<_vNuu`jD zLdP{8jrNrmkv?-mjP|2Vp)x8dlQ7Ef?3u-ueerU8zJ8zeA{`Q$lV-gDRWW%v7E#`6 z@oha8voOmBlVYrAXNB#!ccVRi>)jUq^cG8;yAalUu(iJMcME;fo9)9N|A=KJCAqi; zR1790A(mH=XSJAcheCd?6TBIvhuXU$`wzzJNdXz>7d0k)Xg z0kmC!?r{L+SqaFyz;F#^M=@NrzxGkm{$lw_=UrgEzUy~?AF<(uZG{t%F+E=W%HiYs z!{V*7Gty=!_gPLN5pE@I^8^qF-X+(j$)^l1+Y0c} zdLW0pXP|9V7dIx51W*$gNl88OKP+D4r?41BR^51E=y`e85BzlvEzeBjr{3lY`j!aB zNU4mQMij!c&`d*J?eLwc{`hrTbyam-NwFKW0H*~qd52_D{}pIi`}%ce_#{*PK^M@o z!GldfQwNAQ6rPkvM!kA4-phG)60aEm!pf>TCo!qIB(GPW{eEYE&Itv0ym?u zQOSWyizEJ(z->uB2!t1~?ZDQf3XbgNZQ?n(&uV2D4!>Ey>UK7-KW}H^>0ncEA1n`h^omf^xNePCIJ5E+xGJ% zws!9N}qhH)svSCW;J>C9Y5kMSgnaP?f*x)-opt8b;gLN59I_o5e&n zSW!#LMdk$7#l6?&j=;5nCDebs$M1Imbi@GLpEFO^$81W1jk~`%yJ) zx)|+~^89ZvRt;YMzOY~-5-{wYs!DzuM z^>=qzU+W>~5Dr*4YeI2lYV6^wOlv_w#mc`6i z2MCf(*_{}peJqQLSu4;z7%7;GmM*pQo4;f~EBJ|3eCrm=SazwCuLwpsI)Xd}gFpsH z0s>~oT2e-gW!EtgRnx)bspaLTE%l}k+fD!SF`JF+V-M0Z-k_5}hD?y+(T$$Ddado9 zy~z?AVQS4vw%R}6W1HV~BcN_J?!uDA=(CH@pJBboO$g{1gn@k~woGH$dNSKxyUjBi z;Pv1G4_ftS{@se!Uu~Ux%dGYfAGbp}GcD?xbyj%Eg*KZ&w|P0a=zYf+=EKD~)ULgJ zoy{j;v`zcFarw)+7#J<0++9ERMyXLi@$^6=j z)^M$_*gZGAll^+^s+FIG+3kVtlewqU`51L60uDNmgOQX>bePx4i0v8%pq&U1vkN9) zZ5zSiVDiNwA>#mC?Z$CDCYNgHN)&7{oVmFJ5O&1^sP3L)lf^vRNQW zLGou9Y*Zq`E^qDx(;uZk_NAiN;*R2 zPaZI*B8A3fT35x3I3W;}mvO>yBQlQ6sGbQpP9#1{5g@Ht?h2q<1^8Z2kPX?S`O;2`ABV#{3?ykOs=5`8 zuz+s?l_v()16{35s$sNOZh`TQS4!Ubcx51ggyhF~HQN1C9`9XcQl(gd3Nw(7CLJPK4ba4p#&+xDI0as7gO#54vG>>~Kl^E$otw*q zlo=SmscvY|Koign8(y)3yll%juh=$z|9>s1Xbu$ML2FKruq79q2U9Q#)?mMz*hJvI zf95U(9?#kn{ax*p*FLoahLkeN?)uZ;EE2YH#G=IxbPaxXn^oWTbK9|Ho9(VFw?;JB zp}QkFKyWRd!^>N?Sj(?|YtaN~a?gxDpn7J3?R#>&Em%(wRGyiFPrA0Pt%1eLgBF1l zi8RF(7&nw>IJ2n8T8axSb^SVf`;9jcI2xuGzo|_;o05Mwst<`cGi8GMidg^vKmbWZ zK~y6dE1l+gz;{(mO~Mr%tsStf5?L74oCH{|0(^xPi(M^7by>6bS+>zR{g*zts=>C7 z?m<}W(tj6Nqdh$x*q9+*Xl)wJysEDPTB3*@lAo6WgS_3g?ku(J^f*fbs4pchLP>SE zRqw}(p}WrVXD_f2f`oQdZMSedytI(zgG273WBk#zz5dF37f7!OWMVYz&xjDWfL&G7 zLK_il4Fni0tM9Rr@+N}I23c8Yh2>?ZV2?rDeW1?Lv$JeLehmA@xflea-Pmy7$b|)1 z#Zq3A;-f4lB?6Em%nlu_u%dztf;}s6vj?p2tO2A4_>rWDj=NqIt-_>Tlb$i^Rn;6v|_^uLs_9c~Rl^?O!TWK~09%>;> z@2bZ&0POj1{N$qq`{eBlDJp}THB*j#BCX&QvkB*K+ z!l@RJy$89&PRqzlaq);efOul(o5;1#gneaBjX}g_*Z3uwK&pDRwsqQ;ExWC%x_%hw zR$CJi2W!X{;`Nl?MEU~RfPLobU&s7U6J&on`$;g_-r2$66`X*RvNeM&@t~H}L z$Kvr`KH1|Y)d4L?OI~d!5?yLnXQTx~mhj}v)Q^o?6xl92_VjmCuc}$Fk9L5%G~JaP zi0t1hc2s%RHj$&UVvDRWWj?V?qFw(x(X#F?FyTMm0zohRW?feW3m(k={Im_gJq6wMxT9n#1l;R5{*Re- zZ2>*Ho@CML+5wjnBdxwG!fJ`k+H`QcWv52l;-&K(;1e91L4fc*HV8v9EFp)CkQ-fO z0!i1T7^)Wpd`fV^S7YO%t)i*l8XKBm+9%nZqBNT~Gt-sXs^)&{4ncYbc4%fypQWTG zI#%ZK>bP>{-5)U~V3;~t8=gaTOP_TQ0=7rQSW|nSl{F1oQWSDn$QUGGM=>m=W3S+~ zNxVlQZJ=8eAnMz60=Iik?kZqU{g1o@BQsbO#df1HP|pVAsBDxF)Oc^5xnRgm)Z2zm zf+16PReu|J30QB#i$Zl?ZGt4F+Nrk+R4lFcRLYu6G%d;1SL!@cKYeXAHqg`VjX~wH zImE6WPd-$))TV2}t_xX`vWi*KYSx(CWXmcv(-sHzN)1IheWnH*FuQ z$avemz7$1t?t(E0eNZ>-aY>{|szuz)P&d+EnjPjc8_iwCa3JbKrOf7dhT0`e4XZf)f{gBBkXYteXy zo$N)GiD&lIAE75O5x`yhE49=9MKPZV#~Vdytn%xA4EzaLAYg%j1x~UBjt1OyxvB2c z1AzNUeu)0*6_svL zxr_8U=&~<@y_XLQ7ok>;83x&vH}#@Z(35IvCBVJEqZz3Wf>t@eU0wGS4YE$A9Rue+ zy)B?JD`tC7r*-Um)FLvMS#`to`7TvtLvn~D7CAPhG zzXg>x5@^`-nPsl$*w2GRkn2f`A}&G#!I*<>$*L7dYz*luvyTEiHbVv8zPrL!EG@Q3 zm|igvQI=YeV^2KulyyA!h-KXL4qJc4dW(;a1{m`u8B^W49P571gx~xYW&n^o84b@l z3+7qMMXRhlE6(a~{j)^^0tF@GZjD=cNKUdvvZ2GxRxJcPp0ZVx4Brw_{Nd1#Us2I!!dSnub; zGjc#J1w^b?v0fX|s%81X=4T?I)a5Z-V*uVe0UIiskq%(Sr(lcWfWut@T@ek_X<8WXX=ds}k!D=@j&1D_9Yzs&BJ)Cg*drLeXSSwY>Zs z$I#Ss6)QFKxe;;qP>U-M@Jh5 zyX)?GPO2wb2UKqi9_D~{?^;vR{d3l{KPiSoPwie7dm|W66?o&Q@fXN5!ayn?>cb@2 zBqn=QDCHg9R`RV5u!z%erqEhK}%;neI=4*p|IW|oYX^}iVsh<+=Q7HL+lY9GtqKAdLAaQ z6{CkR*AwvH*jWRUKi0JiN1j3bue|)yVEm)s9;Es*b?t%LqfWdUTiV;*VoySB9E%X1 zq}pW4(UEySyS~Zl69L>+r<5Gvj>nvcK}wiBkOCG6SRi15Q)Ynx;C{+Xf8rN*6HZPe zmpFCOVzF%9wh#T)5CVE+xDLi?C7*5`jWVvOGlMOG1)5d&;!@dJy2<()ODr@#7xwQ8 zi%2VWuI+A|BVZB`!7;MbbNa6nH={d)CSsb9%H_HrhEYUHk#`N{a|#DqQ@NvkX3yM5i7O1&*BM&nwK8Sq{L(5Wu~QC5L)7m z1x5C;kAK99v$GwOCoqW^`vI$YmVLAsA|6#vMuyE=w#-6bv&KqV>a6e24_IVMstp3V z_rr=JqL+mi=UZeU0a9uELtyeWrp4Hr&wk3TS+^DxDZ!q(?GIM_LanWS|8A$!t$yEeybOOv(whme}^Rl@B?n+|4_b|&7 zARonolfFAy6TtW`x+0}U0J_y{{p?zqlr@(eZK1g+wXC{D7izkX<($~>~XBezVEf!CLdH%P(X31Y=*e~( zBgm>=@_S-7X|sDB|0;n!oCVa+uvpSlvmMVR7Tt&yqF6Wnvp!p_XBY_8PD`ZZZVaqUY2PuDo~i1hyj*hti#67+t7}4Drq{{LB*e!!op)$T&BuUv2B`;MM7f4vBH`l(|!|_%P1=p32=+0w)5v z`*{rj?!F}g?*R)0EO0tlprx$~j~n8$Fn;ipHwN&(o%p-Aym;d037lbs1vL1Q2B84E z&dx5|wr#&PHnkEQDbosILFzZh9-GW4aKv?{^rHs&{1dPp6wGRVe~)$79kA}29e{fj z#FSYUky^}zgULI9f%MxoSzuUp%n8O+=22`DO?sRguLCo@%TMJs0_Qr1EFgFA&`8So z9=s=NEpFa54(L#^c3}H7n?h}ZBt$w`z`E!D2dv^p_gLJ*e8(6K!KHctW;=!7LYb@& z;4KrL5^j~x?YD!arB;aSiI==OsX&vvaH~#_&apUHbG?A>!7#n9T6>vYe#yn?Uq?C3 z_o?nsrrBiEb~#Pv1wM9lb-|X7uyxpQ)|}b))TI~Oz90S4;-B7QVXKO17yDTp0dOT} z3iK?W?}5}fi%Vn@%Wsz;A*9RLtnF?v( z79pgrP4+XuRvExKqm*Pz{_K#CNh=OXfyp5b&S)g9fh zUb-W-?&G;L&F>WaR6VKwB}ApTR}*93J#{b9&xSg^_CCt+WXqk7N&O`z17r_!g!fQ78VS~XMyAA$dx5_(=*n?7SOKw zx}Li$e8)dUV2^+W0u~5ZAYg$r%mU--Lr?UU0)YF8TJWgjy@6P$)A>_?pZvT`$7ET! zaE8?VBO)?L3B5OODTi(Z)QObB4*1ruyXtSb*_XMZ<%osJ@U zcqrvudNsavd7hqY%QS&>7FvKZB;EG@P6BL|Z?>p{3n}BsvcU2gFWBzJ;1e*7n~aP& zNP~Mn3Cseve}-0W3l#8+Qa@KFhfT}9Q2(|nKWMKf%he*}P#0aqS80veF z*KGx0*QB@?s+IOpV8T`yvy!5bu6P@dOTj!-0rlbl=gX0yk&b%~fV`g5cma!%HWy%) ziG+ay^HIHq`}C1@+U?J?9OM~?M8;cK%3SL#dlA{7GzT7dcR2YPI9f5$*<3rryYixZ zzA8^6Z{!%C507OUVRhEpg=?1R?Cv$$a~|Vz=j>0ib1;i@p<+(s=@OAKd#DeRttVeT zPDg`k_@?z5!W~#0FKM+)5=v}$)m{B2d`o4!Fi9Ysf}{rHwLw{?qN=W)TC1o&JDnTG z#xr5NXIUq)jM{cRfE?Xo7hv6G{y4^0{qg4k^XJbXpmC_Z@WM_O?E37PXJ5AVjxL)& zuh{LQdmgQ>ALkNh?a!Vqj;t4l?c>=sGBO-p{CMKn9CCpBNU&Y??Rf2%#!(^`b>qbl zo;n-vN2E;{8)}}^OS~L`*OIUCna|T15B3BcwjrVV&&5rD$BP9nTzmBc)ZjhpNJgOKq&j*sy3{^N~~5aot5=CoJG>hy5hy6UwtYZ_y&lS#h3q zymXNHIL}ctVHQt>4h?`HMZ;Ju`^jy#WA|=AbzIh%%tzAhLbi6X0~9DRG*0g7<19<( zz*F#>d4(@1M7uc&_jv(wvXB^l`d#mH(v0Ap0^_hXh}nB-3bySvX1l7zGUY@%@6c-^rp-dGz}H+>nHVeSmqD0%5iS@e@fR8nP!7CB zvaybts_n+uFOg6w*K%QWtR!5IoUyj_11P(mr1K=(n)=Ec&1>^rF$9X7SAx z_Orwgs$Z(F@cH-GPgZA4) zwsnly^1`ci9{;>2yHqNxsy~W9(#d*{UlcRlo2M$RxqULzzOrUC&ncub{I27+GU=-%ca49rzfqK)?b43j{217Fl47(ZH16 zVSwR2Mdnmz?PLc4V76}C>juzrYm}R)0C=U-qT}`lK?2&D)G1h`BsF^K_u$nWYT;?~ zEi5Sy#ud@)83Z|2hs*n^Tbt3KOz@x>CvJS@P!ea-z@LBxCTsyW$R~i5CdUIktrlB+ zu~)XnaV9q?XTMPCd@%zG0_c;B1oJPxjy?O)4UQvzYT|x`1o3F}c>U z=YYNR%1%orXmL(%y2U3DNR?ob5wHSx@2|At#2(AZ%N~}xI4##r?-L7okuX%bT3;>yNAEE7Ua&Uug9yx%t6_ZNb!&46Vc4ja4Am7yNwWE8YF zBs!5|K>HR*M_53EAW6#jgCW0$slKVY351A^2(r0pXqThsE^toULilk@MX)`4px-W? z8RFz;)b+)HXC=)gaWG!aRlB^X#Pggg9mE`a|VB(Zz>}NR=+u%spx3uxc%ed;8#uREx@{ya=973`(`o4Md4vUVC zvUDU-^!>Q)%xPeg(;*9fyA?rD#@V!8P0el2yLjLJGS_}(5NksLSA&`F$ir;(_KXGI zE-i%PjfCf;yc+au`dC2so&}&UfV=gZA*m_#e$&7`Bv3d0((E)nqj=B zMrGUV%%w=kwOC_U6~XH>hsH@sv={PFQ@)RJ{xL5+`VTsjp0NYm`7AwOZBzd@8QYA0 zmB7}31p*cbSRi15)5!uy_aaAspNhPOe37IRb#}m>qzm&`|EJ>Q=h`_maAmnHHKyMrDyM-1d9m?2LW31VI%DJzgu+S#b~brb~2$l z9=lx=V=>1CvToV6%eK7yvPA=&$HxP5Q%Ag@rAJO$bc}*{?I|m>o4@d1_T(+M*(-e>+ZM$1P6e#3|p7+lhfoefNG7N#FP(T$|QntiBnYtE%D8&Vaj-{!SRMa*PMAsY{B`@ykb% z_KK^qgsx>|QKSRU;nqV0+AYn(&G2iI`5_Z#~6e)hgLdPP{K&tey%j< z+msX_ouySfJ~E84p*E!CR0Xp}G7_gOHLh-GZgzWl7)-gXwlDz|xrsbX)4IuOa?aUv z+OD)MdR}tz)2>js&tN6T==VBV!I61@Iy%(NxlJBV89I_VV&~D}R&H(<N;=~*TSZHDOw1zA;a+Wx*l(lZS`jH{*KwbD|boTPl@ z?`q(nWW0}@GWI2Xx^t}h8F-++z7YeAp(6{Yva%v`U^4mnX#dtQ)BI`d88?<6F2?B5 z?`X{p(aRo(k=I?ki57ia*IEWn8qIW%E0c!;jqv&gk)Odss0fk{GW@g_@s9RWQN%+& zphGBX$tNUpZC=WQbT`@=aC|V(LpL*0OcgeF`b5z9d7ec)d)7fyX?mzbE2U_SV^f&(=b|VeIXS9HgCw*}`?vi$`DN!_*TcMc z-u2K2gL&*r)8-9k3g*$+o3_m%WtqHs+-^_EJ^R(O`kbmRyl!sU?^EHS?+pDugBMR| z^GwQ!G%xd+tfBRuRKE#zm~`*#&oJdo|C}`rlxL=?pFvYooS>;QCEKOTFM+I?zD{#< zGpSMGp}=gpmbr8_;+t(wBA}hZ=;=5Epi;Om-^$G$O$n*-F3`~m+NDuG zixC^6hDrcalD2(9BGo%sSECsiydI<1I>jzD3P@-+<9rlDr=Fot<(0+UOc~hHy-}G&%*WCV>s~ccVX?T@5a_`+fbB~V^m~E0+x?gTR_+7)wO|^PGlU| ziNOQ?_&vUchfs~;H*ZG{1Ee+F|9ey{ufos^E$F+h0)O`H&)~+ZuY&YzhUvOQ8oTRP ztiUV(`hED-8{UM9Z8sa2BuPl7-`^IjTwO(f*KQnZZHJeKetE1)ep&$8bZe!Jd>l>Z z>Bt;+_q1s@(iI7)epH{@2QLgQhQ}Uy7{g!u3i58d8U8~j(Y3V}cYW^f%mMbpAN)9q zdj>F;m%(EYx<&D%W7jY4!^)K_QIeC(&A%68-VUUeZZhw%EqUUO2$#4*)2&4IxR&o{ zC1EE`y+D1}C|1zd``R+bMPL`okVJU}?xk{%Cl@oaNIBM#h{JR*)9)KY36)Zp6$pH{ zghf+eH2;YI5YSI6-%L%|-(xg?83Fh#uDci3gpFo3W>S{MyPqIcdb%6SmX zmTnmzL7;e*ImjR50g7S|T`1Y>imYLmEiK0&0o|8gszX;-A9n9Kh^wyLXnDyU zTJ9vcp;?#*LoSJKa^aGhmW#54<#ZV{h>>wWuLT$=y_lA18RQcqX6$FVxuBCj%Jr0Q z#L_$uDeB_C8iLZ=gtEFc+FfScFs{zUm+X|_P$2FpAce91{$b8N@w2$Eu2VsW0%0kj zWha>nWhUM3PUm$X?87m>XdN%c_$3RycnNFTfXd{$nV{Nw21vc+DJbk1U!Vfo8648r zehees^#s~;;I6uoU}Fh412)he-1JY_>|OF!Osv2-%{nRM8UZ+Vu*k%BI=>bM1vDQh zMM!gL@c0gXrJISe_2!T%k_Jk{DK#|}d+CS!{#U;R%L|Gze#;#gdH7lE`{plk=tFP8 zmRH|}4eK``KP!s{A^{V4NgE1358l=+S&F~E_sjVH_cr0=-+v25TW>_duornhc@PN4OWd5hTqu%frza6R^a+k)eg1Fp%v;`v;&l4kXHdN4 z+H&;&$4{{PmYeXZSKfuOt|p^7mzWEGLWJkp%3#5gzeau<@ES;1h7 zFCnAmT5F(1TE?ZwC))BqX>-;w2;uSLXRvMCY9sSFyd}yVqLU$$Nc07m1hi{@XM|`v*DK8gb@KD>5^WVe_U{ zEQjwQ0b>d9E|@+EHbgv19BfQhyZS~NW@dV@ZR;9zcJ>(Hy{fXrtnD`QH|{Ix;v|t8 z*LKo)wE=gPVFB*3AH;gEx}ITR0oyXc~NX>HJ$)W1<`yQk0{OreL?TdcUW z(Ib&-#U?T86KoCBeR?b|#(L3a$b~|17(RE@plX_Be zwx6=Q+LBC*b;;h&Rx_GZcFKx33UH`vs#2Lk2Td?QrN;l{WM9!d3HRO3A9_FBwF}+X zGgIZ!J^S7IK2_55PFkE4(Aq3*b)PQ)H?3&w@jX* |CNE@fug3sdBmSz=pTml2X{ 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 *Grid resolution*, select from the different heat map resolutions. -+ -The default "Coarse" looks -good, but feel free to select a different resolution. - . Play around with the *Layer Style* > *Color range* setting. + diff --git a/docs/maps/maps-aggregations.asciidoc b/docs/maps/maps-aggregations.asciidoc index cd01acb2df7de..98aa21f6a07a3 100644 --- a/docs/maps/maps-aggregations.asciidoc +++ b/docs/maps/maps-aggregations.asciidoc @@ -34,18 +34,23 @@ The point location is the weighted centroid for all geo-points in the gridded ce [role="xpack"] [[maps-top-hits-aggregation]] -=== Most recent entities +=== Top hits per entity -Most recent entities uses {es} {ref}/search-aggregations-bucket-terms-aggregation.html[terms aggregation] to group your documents by entity. -Then, {ref}/search-aggregations-metrics-top-hits-aggregation.html[top hits metric aggregation] accumulates the most recent documents for each entry. +You can display the most relevant documents per entity, for example, the most recent GPS tracks per flight. +To get this data, {es} first groups your data using a {ref}/search-aggregations-bucket-terms-aggregation.html[terms aggregation], +then accumulates the most relevant documents based on sort order for each entry using a {ref}/search-aggregations-metrics-top-hits-aggregation.html[top hits metric aggregation]. -Most recent entities is available for <> with *Documents* source. -To enable most recent entities, click "Show most recent documents by entity" and configure the following: +Top hits per entity is available for <> with *Documents* source. +To enable top hits: +. In *Sorting*, select the *Show documents per entity* checkbox. . Set *Entity* to the field that identifies entities in your documents. This field will be used in the terms aggregation to group your documents into entity buckets. . Set *Documents per entity* to configure the maximum number of documents accumulated per entity. +[role="screenshot"] +image::maps/images/top_hits.png[] + [role="xpack"] [[point-to-point]] === Point to point diff --git a/docs/maps/search.asciidoc b/docs/maps/search.asciidoc index 97b10e389963e..8a93352798d2c 100644 --- a/docs/maps/search.asciidoc +++ b/docs/maps/search.asciidoc @@ -89,7 +89,7 @@ The most common cause for empty layers are searches for a field that exists in o You can prevent the search bar from applying search context to a layer by configuring the following: -* In *Source settings*, clear the *Apply global filter to source* checkbox to turn off the global search context for the layer source. +* In *Filtering*, clear the *Apply global filter to layer data* checkbox to turn off the global search context for the layer source. * In *Term joins*, clear the *Apply global filter to join* checkbox to turn off the global search context for the <>. diff --git a/x-pack/legacy/plugins/maps/public/components/__snapshots__/tooltip_selector.test.js.snap b/x-pack/legacy/plugins/maps/public/components/__snapshots__/tooltip_selector.test.js.snap index 4524f66c0642c..e21f034161a87 100644 --- a/x-pack/legacy/plugins/maps/public/components/__snapshots__/tooltip_selector.test.js.snap +++ b/x-pack/legacy/plugins/maps/public/components/__snapshots__/tooltip_selector.test.js.snap @@ -2,20 +2,6 @@ exports[`TooltipSelector should render component 1`] = `

- -
- -
-
- diff --git a/x-pack/legacy/plugins/maps/public/components/global_filter_checkbox.js b/x-pack/legacy/plugins/maps/public/components/global_filter_checkbox.js index e841fa573c9a5..56406ee9653fe 100644 --- a/x-pack/legacy/plugins/maps/public/components/global_filter_checkbox.js +++ b/x-pack/legacy/plugins/maps/public/components/global_filter_checkbox.js @@ -6,13 +6,8 @@ import React from 'react'; import { EuiFormRow, EuiSwitch } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -const label = i18n.translate('xpack.maps.layerPanel.applyGlobalQueryCheckboxLabel', { - defaultMessage: `Apply global filter to source`, -}); - -export function GlobalFilterCheckbox({ applyGlobalQuery, customLabel, setApplyGlobalQuery }) { +export function GlobalFilterCheckbox({ applyGlobalQuery, label, setApplyGlobalQuery }) { const onApplyGlobalQueryChange = event => { setApplyGlobalQuery(event.target.checked); }; @@ -22,7 +17,7 @@ export function GlobalFilterCheckbox({ applyGlobalQuery, customLabel, setApplyGl display="columnCompressedSwitch" > - -
- -
-
- - {this._renderProperties()} diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/__snapshots__/view.test.js.snap b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/__snapshots__/view.test.js.snap index 4377fa4725483..101716d297b81 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/__snapshots__/view.test.js.snap +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/__snapshots__/view.test.js.snap @@ -97,7 +97,9 @@ exports[`LayerPanel is rendered 1`] = ` > - +
+ mockSourceSettings +
diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/filter_editor.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/filter_editor.js index 0086c5067ba12..941694c19ad56 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/filter_editor.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/filter_editor.js @@ -16,11 +16,14 @@ import { EuiTextColor, EuiTextAlign, EuiButtonEmpty, + EuiFormRow, + EuiSwitch, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; import { indexPatternService } from '../../../kibana_services'; +import { GlobalFilterCheckbox } from '../../../components/global_filter_checkbox'; import { start as data } from '../../../../../../../../src/legacy/core_plugins/data/public/legacy'; const { SearchBar } = data.ui; @@ -79,6 +82,14 @@ export class FilterEditor extends Component { this._close(); }; + _onFilterByMapBoundsChange = event => { + this.props.updateSourceProp(this.props.layer.getId(), 'filterByMapBounds', event.target.checked); + }; + + _onApplyGlobalQueryChange = applyGlobalQuery => { + this.props.updateSourceProp(this.props.layer.getId(), 'applyGlobalQuery', applyGlobalQuery); + }; + _renderQueryPopover() { const layerQuery = this.props.layer.getQuery(); const { uiSettings } = npStart.core; @@ -169,13 +180,29 @@ export class FilterEditor extends Component { } render() { + let filterByBoundsSwitch; + if (this.props.layer.getSource().isFilterByMapBoundsConfigurable()) { + filterByBoundsSwitch = ( + + + + ); + } + return (
@@ -185,6 +212,18 @@ export class FilterEditor extends Component { {this._renderQuery()} {this._renderQueryPopover()} + + + + {filterByBoundsSwitch} + +
); } diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/index.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/index.js index 4fc69690485fb..127f2ca70ab93 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/index.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/index.js @@ -7,7 +7,7 @@ import { connect } from 'react-redux'; import { FilterEditor } from './filter_editor'; import { getSelectedLayer } from '../../../selectors/map_selectors'; -import { setLayerQuery } from '../../../actions/map_actions'; +import { setLayerQuery, updateSourceProp } from '../../../actions/map_actions'; function mapStateToProps(state = {}) { return { @@ -19,7 +19,8 @@ function mapDispatchToProps(dispatch) { return { setLayerQuery: (layerId, query) => { dispatch(setLayerQuery(layerId, query)); - } + }, + updateSourceProp: (id, propName, value) => dispatch(updateSourceProp(id, propName, value)), }; } diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/index.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/index.js index ebdeb22289a9a..85fdcc9027854 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/index.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/index.js @@ -8,7 +8,8 @@ import { connect } from 'react-redux'; import { LayerPanel } from './view'; import { getSelectedLayer } from '../../selectors/map_selectors'; import { - fitToLayerExtent + fitToLayerExtent, + updateSourceProp, } from '../../actions/map_actions'; function mapStateToProps(state = {}) { @@ -21,7 +22,8 @@ function mapDispatchToProps(dispatch) { return { fitToBounds: (layerId) => { dispatch(fitToLayerExtent(layerId)); - } + }, + updateSourceProp: (id, propName, value) => dispatch(updateSourceProp(id, propName, value)), }; } diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/join.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/join.js index 68d4656880666..b23764f1c7e33 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/join.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/join.js @@ -217,7 +217,7 @@ export class Join extends Component { diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/source_settings/__snapshots__/source_settings.test.js.snap b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/source_settings/__snapshots__/source_settings.test.js.snap deleted file mode 100644 index 4d2cbcb012b41..0000000000000 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/source_settings/__snapshots__/source_settings.test.js.snap +++ /dev/null @@ -1,30 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Should render source settings editor 1`] = ` - - - -
- -
-
- -
- mockSourceEditor -
-
- -
-`; - -exports[`should render nothing when source has no editor 1`] = `""`; diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/source_settings/index.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/source_settings/index.js deleted file mode 100644 index 18cda96aeb1e8..0000000000000 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/source_settings/index.js +++ /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 { connect } from 'react-redux'; -import { SourceSettings } from './source_settings'; -import { getSelectedLayer } from '../../../selectors/map_selectors'; -import { updateSourceProp } from '../../../actions/map_actions'; - -function mapStateToProps(state = {}) { - return { - layer: getSelectedLayer(state) - }; -} - -function mapDispatchToProps(dispatch) { - return { - updateSourceProp: (id, propName, value) => dispatch(updateSourceProp(id, propName, value)), - }; -} - -const connectedSourceSettings = connect(mapStateToProps, mapDispatchToProps)(SourceSettings); -export { connectedSourceSettings as SourceSettings }; diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/source_settings/source_settings.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/source_settings/source_settings.js deleted file mode 100644 index 9791931c3ee77..0000000000000 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/source_settings/source_settings.js +++ /dev/null @@ -1,44 +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, { Fragment } from 'react'; - -import { EuiTitle, EuiPanel, EuiSpacer } from '@elastic/eui'; - -import { FormattedMessage } from '@kbn/i18n/react'; - -export function SourceSettings({ layer, updateSourceProp }) { - const onSourceChange = ({ propName, value }) => { - updateSourceProp(layer.getId(), propName, value); - }; - - const sourceSettingsEditor = layer.renderSourceSettingsEditor({ onChange: onSourceChange }); - - if (!sourceSettingsEditor) { - return null; - } - - return ( - - - -
- -
-
- - - - {sourceSettingsEditor} -
- - -
- ); -} diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/source_settings/source_settings.test.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/source_settings/source_settings.test.js deleted file mode 100644 index 090d30054ba81..0000000000000 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/source_settings/source_settings.test.js +++ /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 { shallow } from 'enzyme'; - -import { SourceSettings } from './source_settings'; - -test('Should render source settings editor', () => { - const mockLayer = { - renderSourceSettingsEditor: () => { - return (
mockSourceEditor
); - }, - }; - const component = shallow( - - ); - - expect(component) - .toMatchSnapshot(); -}); - -test('should render nothing when source has no editor', () => { - const mockLayer = { - renderSourceSettingsEditor: () => { - return null; - }, - }; - const component = shallow( - - ); - - expect(component) - .toMatchSnapshot(); -}); diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.js index 78cb8aa827e35..492c891d1db2d 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.js @@ -11,7 +11,6 @@ import { JoinEditor } from './join_editor'; import { FlyoutFooter } from './flyout_footer'; import { LayerErrors } from './layer_errors'; import { LayerSettings } from './layer_settings'; -import { SourceSettings } from './source_settings'; import { StyleSettings } from './style_settings'; import { EuiButtonIcon, @@ -96,6 +95,10 @@ export class LayerPanel extends React.Component { } } + _onSourceChange = ({ propName, value }) => { + this.props.updateSourceProp(this.props.selectedLayer.getId(), propName, value); + }; + _renderFilterSection() { if (!this.props.selectedLayer.supportsElasticsearchFilters()) { return null; @@ -213,7 +216,7 @@ export class LayerPanel extends React.Component { - + {this.props.selectedLayer.renderSourceSettingsEditor({ onChange: this._onSourceChange })} {this._renderFilterSection()} diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.test.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.test.js index fe891d92defbe..8e97c58b69508 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.test.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.test.js @@ -40,12 +40,6 @@ jest.mock('./layer_settings', () => ({ } })); -jest.mock('./source_settings', () => ({ - SourceSettings: () => { - return (
mockSourceSettings
); - } -})); - import React from 'react'; import { shallowWithIntl } from 'test_utils/enzyme_helpers'; @@ -62,11 +56,13 @@ const mockLayer = { isJoinable: () => { return true; }, supportsElasticsearchFilters: () => { return false; }, getLayerTypeIconName: () => { return 'vector'; }, + renderSourceSettingsEditor: () => { return (
mockSourceSettings
); }, }; const defaultProps = { selectedLayer: mockLayer, fitToBounds: () => {}, + updateSourceProp: () => {}, }; describe('LayerPanel', () => { diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/ems_file_source/update_source_editor.js b/x-pack/legacy/plugins/maps/public/layers/sources/ems_file_source/update_source_editor.js index f901c8b93e8cd..65704b4cd83ad 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/ems_file_source/update_source_editor.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/ems_file_source/update_source_editor.js @@ -4,10 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Component } from 'react'; +import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; import { TooltipSelector } from '../../../components/tooltip_selector'; import { getEMSClient } from '../../../meta'; +import { EuiTitle, EuiPanel, EuiSpacer } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; export class UpdateSourceEditor extends Component { @@ -53,13 +55,29 @@ export class UpdateSourceEditor extends Component { }; render() { - return ( - + + + +
+ +
+
+ + + + +
+ + +
); } } diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js index de1b47ea28a91..fbc1703f86003 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js @@ -85,7 +85,6 @@ export class ESGeoGridSource extends AbstractESAggSource { metrics={this._descriptor.metrics} renderAs={this._descriptor.requestType} resolution={this._descriptor.resolution} - applyGlobalQuery={this._descriptor.applyGlobalQuery} /> ); } diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/update_source_editor.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/update_source_editor.js index cc1e53dc5cb3f..8a41d47783864 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/update_source_editor.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/update_source_editor.js @@ -12,8 +12,7 @@ import { indexPatternService } from '../../../kibana_services'; import { ResolutionEditor } from './resolution_editor'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiSpacer, EuiTitle } from '@elastic/eui'; -import { GlobalFilterCheckbox } from '../../../components/global_filter_checkbox'; +import { EuiPanel, EuiSpacer, EuiTitle } from '@elastic/eui'; import { isMetricCountable } from '../../util/is_metric_countable'; export class UpdateSourceEditor extends Component { @@ -63,11 +62,7 @@ export class UpdateSourceEditor extends Component { this.props.onChange({ propName: 'resolution', value: e }); }; - _onApplyGlobalQueryChange = applyGlobalQuery => { - this.props.onChange({ propName: 'applyGlobalQuery', value: applyGlobalQuery }); - }; - - _renderMetricsEditor() { + _renderMetricsPanel() { const metricsFilter = this.props.renderAs === RENDER_AS.HEATMAP ? metric => { @@ -77,13 +72,13 @@ export class UpdateSourceEditor extends Component { : null; const allowMultipleMetrics = this.props.renderAs !== RENDER_AS.HEATMAP; return ( -
- + +
- + -
+ ); } render() { return ( - - + {this._renderMetricsPanel()} + - {this._renderMetricsEditor()} + + +
+ +
+
+ + +
+ -
); } diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/update_source_editor.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/update_source_editor.js index 2df7dfc3e0764..f0b09f2480084 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/update_source_editor.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/update_source_editor.js @@ -4,14 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Component } from 'react'; +import React, { Component, Fragment } from 'react'; import { MetricsEditor } from '../../../components/metrics_editor'; import { indexPatternService } from '../../../kibana_services'; import { i18n } from '@kbn/i18n'; -import { EuiTitle, EuiSpacer } from '@elastic/eui'; +import { EuiPanel, EuiTitle, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { GlobalFilterCheckbox } from '../../../components/global_filter_checkbox'; export class UpdateSourceEditor extends Component { state = { @@ -56,30 +55,25 @@ export class UpdateSourceEditor extends Component { this.props.onChange({ propName: 'metrics', value: metrics }); }; - _onApplyGlobalQueryChange = applyGlobalQuery => { - this.props.onChange({ propName: 'applyGlobalQuery', value: applyGlobalQuery }); - }; - render() { return ( - <> - -
- -
-
+ + + +
+ +
+
+ + +
- - - +
); } } diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/__snapshots__/update_source_editor.test.js.snap b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/__snapshots__/update_source_editor.test.js.snap index 1e064fdb0dd7d..85c8d0b354a13 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/__snapshots__/update_source_editor.test.js.snap +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/__snapshots__/update_source_editor.test.js.snap @@ -2,344 +2,386 @@ exports[`should enable sort order select when sort field provided 1`] = ` - + + +
+ +
+
+ -
- - + + + - - - - - + - - - - - + + - - - + + + + + + - - + + + +
`; exports[`should render top hits form when useTopHits is true 1`] = ` - + + +
+ +
+
+ -
- - + + + - - - - - + - - - - - - - - + + - - - - - - + + + + + + - - + + + + + + + + + +
`; exports[`should render update source editor 1`] = ` - + + +
+ +
+
+ -
- - + + + - - + - - - - - - - - + + - - - + + + + + + - - + + + +
`; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js index 61b0cad40a0a6..2a47cb2213be1 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js @@ -85,14 +85,12 @@ export class ESSearchSource extends AbstractESSource { source={this} indexPatternId={this._descriptor.indexPatternId} onChange={onChange} - filterByMapBounds={this._descriptor.filterByMapBounds} tooltipFields={this._tooltipFields} sortField={this._descriptor.sortField} sortOrder={this._descriptor.sortOrder} useTopHits={this._descriptor.useTopHits} topHitsSplitField={this._descriptor.topHitsSplitField} topHitsSize={this._descriptor.topHitsSize} - applyGlobalQuery={this._descriptor.applyGlobalQuery} /> ); } @@ -445,6 +443,10 @@ export class ESSearchSource extends AbstractESSource { return _.get(this._descriptor, 'filterByMapBounds', false); } + isFilterByMapBoundsConfigurable() { + return true; + } + async getLeftJoinFields() { const indexPattern = await this.getIndexPattern(); // Left fields are retrieved from _source. diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.js index 1b4e999c29d0a..b7c332b4c96cb 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/update_source_editor.js @@ -9,13 +9,14 @@ import PropTypes from 'prop-types'; import { EuiFormRow, EuiSwitch, - EuiFlexGroup, - EuiFlexItem, EuiSelect, + EuiTitle, + EuiPanel, + EuiSpacer, + EuiHorizontalRule, } from '@elastic/eui'; import { SingleFieldSelect } from '../../../components/single_field_select'; import { TooltipSelector } from '../../../components/tooltip_selector'; -import { GlobalFilterCheckbox } from '../../../components/global_filter_checkbox'; import { indexPatternService } from '../../../kibana_services'; import { i18n } from '@kbn/i18n'; @@ -23,12 +24,12 @@ import { getTermsFields, getSourceFields } from '../../../index_pattern_util'; import { ValidatedRange } from '../../../components/validated_range'; import { SORT_ORDER } from '../../../../common/constants'; import { ESDocField } from '../../fields/es_doc_field'; +import { FormattedMessage } from '@kbn/i18n/react'; export class UpdateSourceEditor extends Component { static propTypes = { indexPatternId: PropTypes.string.isRequired, onChange: PropTypes.func.isRequired, - filterByMapBounds: PropTypes.bool.isRequired, tooltipFields: PropTypes.arrayOf(PropTypes.object).isRequired, sortField: PropTypes.string, sortOrder: PropTypes.string.isRequired, @@ -94,10 +95,6 @@ export class UpdateSourceEditor extends Component { this.props.onChange({ propName: 'tooltipProperties', value: propertyNames }); }; - _onFilterByMapBoundsChange = event => { - this.props.onChange({ propName: 'filterByMapBounds', value: event.target.checked }); - }; - onUseTopHitsChange = event => { this.props.onChange({ propName: 'useTopHits', value: event.target.checked }); }; @@ -118,13 +115,27 @@ export class UpdateSourceEditor extends Component { this.props.onChange({ propName: 'topHitsSize', value: size }); }; - _onApplyGlobalQueryChange = applyGlobalQuery => { - this.props.onChange({ propName: 'applyGlobalQuery', value: applyGlobalQuery }); - }; - renderTopHitsForm() { + const topHitsSwitch = ( + + + + ); + if (!this.props.useTopHits) { - return null; + return topHitsSwitch; } let sizeSlider; @@ -134,7 +145,7 @@ export class UpdateSourceEditor extends Component { label={i18n.translate('xpack.maps.source.esSearch.topHitsSizeLabel', { defaultMessage: 'Documents per entity', })} - display="rowCompressed" + display="columnCompressed" > + {topHitsSwitch} - - - + + +
+ +
+
+ + + + +
+ ); + } + + _renderSortPanel() { + return ( + + +
+ +
+
+ + - - - - - - - - + - - + + {this.renderTopHitsForm()} +
+ ); + } - - - + render() { + return ( + - + {this._renderTooltipsPanel()} + + + {this._renderSortPanel()} + ); diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/vector_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/vector_source.js index e255e2478a37d..a586bc9fb53b2 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/vector_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/vector_source.js @@ -79,6 +79,10 @@ export class AbstractVectorSource extends AbstractSource { return false; } + isFilterByMapBoundsConfigurable() { + return false; + } + isBoundsAware() { return false; } diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 2e7d4233dd7ff..f047e6a506f82 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -6433,7 +6433,6 @@ "xpack.maps.layerControl.tocEntry.hideDetailsButtonTitle": "レイヤー詳細を非表示", "xpack.maps.layerControl.tocEntry.showDetailsButtonAriaLabel": "レイヤー詳細を表示", "xpack.maps.layerControl.tocEntry.showDetailsButtonTitle": "レイヤー詳細を表示", - "xpack.maps.layerPanel.applyGlobalQueryCheckboxLabel": "レイヤーにグローバルフィルターを適用", "xpack.maps.layerPanel.filterEditor.addFilterButtonLabel": "フィルターを追加します", "xpack.maps.layerPanel.filterEditor.editFilterButtonLabel": "フィルターを編集", "xpack.maps.layerPanel.filterEditor.emptyState.description": "フィルターを追加してレイヤーデータを絞ります。", @@ -6468,7 +6467,6 @@ "xpack.maps.layerPanel.settingsPanel.unableToLoadTitle": "レイヤーを読み込めません", "xpack.maps.layerPanel.settingsPanel.visibleZoomLabel": "レイヤー表示のズーム範囲", "xpack.maps.layerPanel.sourceDetailsLabel": "ソースの詳細", - "xpack.maps.layerPanel.sourceSettingsTitle": "ソース設定", "xpack.maps.layerPanel.styleSettingsTitle": "レイヤースタイル", "xpack.maps.layerTocActions.cloneLayerTitle": "レイヤーおクローンを作成", "xpack.maps.layerTocActions.editLayerTitle": "レイヤーを編集", @@ -6690,7 +6688,6 @@ "xpack.maps.layerPanel.settingsPanel.percentageLabel": "%", "xpack.maps.layerPanel.settingsPanel.visibleZoom": "ズームレベル", "xpack.maps.source.esSearch.sortFieldSelectPlaceholder": "ソートフィールドを選択", - "xpack.maps.source.esSearch.sortLabel": "並べ替え", "xpack.maps.toolbarOverlay.drawBoundsLabelShort": "境界を描く", "xpack.maps.toolbarOverlay.drawShapeLabelShort": "図形を描く", "xpack.maps.tooltipSelector.addLabelWithCount": "{count} を追加", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index fd5573901fb00..1be193f83d3bd 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -6435,7 +6435,6 @@ "xpack.maps.layerControl.tocEntry.hideDetailsButtonTitle": "隐藏图层详情", "xpack.maps.layerControl.tocEntry.showDetailsButtonAriaLabel": "显示图层详情", "xpack.maps.layerControl.tocEntry.showDetailsButtonTitle": "显示图层详情", - "xpack.maps.layerPanel.applyGlobalQueryCheckboxLabel": "将全局筛选应用到图层", "xpack.maps.layerPanel.filterEditor.addFilterButtonLabel": "添加筛选", "xpack.maps.layerPanel.filterEditor.editFilterButtonLabel": "编辑筛选", "xpack.maps.layerPanel.filterEditor.emptyState.description": "添加筛选以缩小图层数据范围。", @@ -6470,7 +6469,6 @@ "xpack.maps.layerPanel.settingsPanel.unableToLoadTitle": "无法加载图层", "xpack.maps.layerPanel.settingsPanel.visibleZoomLabel": "图层可见性的缩放范围", "xpack.maps.layerPanel.sourceDetailsLabel": "源详情", - "xpack.maps.layerPanel.sourceSettingsTitle": "源设置", "xpack.maps.layerPanel.styleSettingsTitle": "图层样式", "xpack.maps.layerTocActions.cloneLayerTitle": "克隆图层", "xpack.maps.layerTocActions.editLayerTitle": "编辑图层", @@ -6692,7 +6690,6 @@ "xpack.maps.layerPanel.settingsPanel.percentageLabel": "%", "xpack.maps.layerPanel.settingsPanel.visibleZoom": "缩放级别", "xpack.maps.source.esSearch.sortFieldSelectPlaceholder": "选择排序字段", - "xpack.maps.source.esSearch.sortLabel": "排序", "xpack.maps.toolbarOverlay.drawBoundsLabelShort": "绘制边界", "xpack.maps.toolbarOverlay.drawShapeLabelShort": "绘制形状", "xpack.maps.tooltipSelector.addLabelWithCount": "添加 {count} 个", From 802423da894997d30b8aea99db0bd41187b90149 Mon Sep 17 00:00:00 2001 From: Chris Roberson Date: Wed, 11 Dec 2019 16:34:32 -0500 Subject: [PATCH 29/79] [Monitoring] Fix 7.5 cloud test issues (#51781) * Fix cloud test issues * We don't have to skip for cloud --- .../apis/monitoring/setup/index.js | 5 +++- .../monitoring/enable_monitoring/index.js | 2 +- .../services/monitoring/logstash_pipelines.js | 23 ++++++++++++++----- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/x-pack/test/api_integration/apis/monitoring/setup/index.js b/x-pack/test/api_integration/apis/monitoring/setup/index.js index a6bb46740e940..89e970c8002fd 100644 --- a/x-pack/test/api_integration/apis/monitoring/setup/index.js +++ b/x-pack/test/api_integration/apis/monitoring/setup/index.js @@ -5,7 +5,10 @@ */ export default function ({ loadTestFile }) { - describe('Setup', () => { + describe('Setup', function () { + // Setup mode is not supported in cloud + this.tags(['skipCloud']); + loadTestFile(require.resolve('./collection')); }); } diff --git a/x-pack/test/functional/apps/monitoring/enable_monitoring/index.js b/x-pack/test/functional/apps/monitoring/enable_monitoring/index.js index aa96d71228799..2f6b1a91b7304 100644 --- a/x-pack/test/functional/apps/monitoring/enable_monitoring/index.js +++ b/x-pack/test/functional/apps/monitoring/enable_monitoring/index.js @@ -13,7 +13,7 @@ export default function ({ getService, getPageObjects }) { const clusterOverview = getService('monitoringClusterOverview'); const retry = getService('retry'); - describe('Monitoring is turned off', () => { + describe('Monitoring is turned off', function () { before(async () => { const browser = getService('browser'); await browser.setWindowSize(1600, 1000); diff --git a/x-pack/test/functional/services/monitoring/logstash_pipelines.js b/x-pack/test/functional/services/monitoring/logstash_pipelines.js index 759728555c86a..6740d6352bbf7 100644 --- a/x-pack/test/functional/services/monitoring/logstash_pipelines.js +++ b/x-pack/test/functional/services/monitoring/logstash_pipelines.js @@ -10,6 +10,7 @@ export function MonitoringLogstashPipelinesProvider({ getService, getPageObjects const testSubjects = getService('testSubjects'); const retry = getService('retry'); const PageObjects = getPageObjects(['monitoring']); + const find = getService('find'); const SUBJ_LISTING_PAGE = 'logstashPipelinesListing'; @@ -34,6 +35,12 @@ export function MonitoringLogstashPipelinesProvider({ getService, getPageObjects return PageObjects.monitoring.tableGetRowsFromContainer(SUBJ_TABLE_CONTAINER); } + async waitForTableToFinishLoading() { + await retry.try(async () => { + await find.waitForDeletedByCssSelector('.euiBasicTable-loading', 5000); + }); + } + async getPipelinesAll() { const ids = await testSubjects.getVisibleTextAll(SUBJ_PIPELINES_IDS); const eventsEmittedRates = await testSubjects.getVisibleTextAll(SUBJ_PIPELINES_EVENTS_EMITTED_RATES); @@ -57,21 +64,25 @@ export function MonitoringLogstashPipelinesProvider({ getService, getPageObjects async clickIdCol() { const headerCell = await testSubjects.find(SUBJ_TABLE_SORT_ID_COL); const button = await headerCell.findByTagName('button'); - return button.click(); + await button.click(); + await this.waitForTableToFinishLoading(); } async clickEventsEmittedRateCol() { const headerCell = await testSubjects.find(SUBJ_TABLE_SORT_EVENTS_EMITTED_RATE_COL); const button = await headerCell.findByTagName('button'); - return button.click(); + await button.click(); + await this.waitForTableToFinishLoading(); } - setFilter(text) { - return PageObjects.monitoring.tableSetFilter(SUBJ_SEARCH_BAR, text); + async setFilter(text) { + await PageObjects.monitoring.tableSetFilter(SUBJ_SEARCH_BAR, text); + await this.waitForTableToFinishLoading(); } - clearFilter() { - return PageObjects.monitoring.tableClearFilter(SUBJ_SEARCH_BAR); + async clearFilter() { + await PageObjects.monitoring.tableClearFilter(SUBJ_SEARCH_BAR); + await this.waitForTableToFinishLoading(); } assertNoData() { From 618764355e65854e576c99dd7a7cd53be8ed0631 Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Wed, 11 Dec 2019 17:36:55 -0600 Subject: [PATCH 30/79] [docs] max-old-space-size (#52310) * [docs] max-old-space-size * Update docs/setup/production.asciidoc Co-Authored-By: gchaps <33642766+gchaps@users.noreply.github.com> * Update docs/setup/production.asciidoc Co-Authored-By: gchaps <33642766+gchaps@users.noreply.github.com> * _max_ * Update docs/setup/production.asciidoc Co-Authored-By: Tyler Smalley * max example * move comma * Update production.asciidoc --- docs/setup/production.asciidoc | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/docs/setup/production.asciidoc b/docs/setup/production.asciidoc index 67afe0896a0dd..fed4ba4886bf9 100644 --- a/docs/setup/production.asciidoc +++ b/docs/setup/production.asciidoc @@ -6,6 +6,7 @@ * <> * <> * <> +* <> How you deploy Kibana largely depends on your use case. If you are the only user, you can run Kibana on your local machine and configure it to point to whatever @@ -27,7 +28,7 @@ You can use {stack} {security-features} to control what {es} data users can access through Kibana. When {security-features} are enabled, Kibana users have to log in. They need to -have a role granting <> as well as access +have a role granting <> as well as access to the indices they will be working with in Kibana. If a user loads a Kibana dashboard that accesses data in an index that they @@ -125,4 +126,17 @@ elasticsearch.hosts: -------- Related configurations include `elasticsearch.sniffInterval`, `elasticsearch.sniffOnStart`, and `elasticsearch.sniffOnConnectionFault`. -These can be used to automatically update the list of hosts as a cluster is resized. Parameters can be found on the {kibana-ref}/settings.html[settings page]. \ No newline at end of file +These can be used to automatically update the list of hosts as a cluster is resized. Parameters can be found on the {kibana-ref}/settings.html[settings page]. + +[float] +[[memory]] +=== Memory +Kibana has a default maximum memory limit of 1.4 GB, and in most cases, we recommend leaving this unconfigured. In some scenarios, such as large reporting jobs, +it may make sense to tweak limits to meet more specific requirements. + +You can modify this limit by setting `--max-old-space-size` in the `NODE_OPTIONS` environment variable. For deb and rpm, packages this is passed in via `/etc/default/kibana` and can be appended to the bottom of the file. + +The option accepts a limit in MB: +-------- +NODE_OPTIONS="--max-old-space-size=2048" bin/kibana +-------- From 5014f21cf430e65be8b42ece9622b984fff48fe5 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 11 Dec 2019 16:38:15 -0700 Subject: [PATCH 31/79] Add instructions for setting up remote clusters needed for CCS and CCR (#52796) * Add instructions for setting up remote clusters needed for CCS and CCR * clean up --- CONTRIBUTING.md | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 599cf26970030..06e08c85dafec 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -218,6 +218,7 @@ node scripts/makelogs --auth : > The default username and password combination are `elastic:changeme` > Make sure to execute `node scripts/makelogs` *after* elasticsearch is up and running! + ### Running Elasticsearch Remotely You can save some system resources, and the effort of generating sample data, if you have a remote Elasticsearch cluster to connect to. (**Elasticians: you do! Check with your team about where to find credentials**) @@ -239,6 +240,41 @@ kibana.index: '.{YourGitHubHandle}-kibana' xpack.task_manager.index: '.{YourGitHubHandle}-task-manager-kibana' ``` +### Running remote clusters +Setup remote clusters for cross cluster search (CCS) and cross cluster replication (CCR). + +Start your primary cluster by running: +```bash +yarn es snapshot -E path.data=../data_prod1 +``` + +Start your remote cluster by running: +```bash +yarn es snapshot -E transport.port=9500 -E http.port=9201 -E path.data=../data_prod2 +``` + +Once both clusters are running, start kibana. Kibana will connect to the primary cluster. + +Setup the remote cluster in Kibana from either `Management` -> `Elasticsearch` -> `Remote Clusters` UI or by running the following script in `Console`. +``` +PUT _cluster/settings +{ + "persistent": { + "cluster": { + "remote": { + "cluster_one": { + "seeds": [ + "localhost:9500" + ] + } + } + } + } +} +``` + +Follow the [cross-cluster search](https://www.elastic.co/guide/en/kibana/current/management-cross-cluster-search.html) instructions for setting up index patterns to search across clusters. + ### Running Kibana Start the development server. @@ -506,7 +542,7 @@ yarn test:browser --dev # remove the --dev flag to run them once and close * In System Preferences > Sharing, change your computer name to be something simple, e.g. "computer". * Run Kibana with `yarn start --host=computer.local` (substituting your computer name). * Now you can run your VM, open the browser, and navigate to `http://computer.local:5601` to test Kibana. -* Alternatively you can use browserstack +* Alternatively you can use browserstack #### Running Browser Automation Tests From db2d4bdf11f6c19379fa52a783550b1394a54d5f Mon Sep 17 00:00:00 2001 From: gchaps <33642766+gchaps@users.noreply.github.com> Date: Wed, 11 Dec 2019 16:03:12 -0800 Subject: [PATCH 32/79] [DOCS] Adds example of assigning roles in Reporting (#52757) * [DOCS] Adds example of assigning roles in Reporting * [DOCS] Updates reporting security doc with review comments * [DOCS] Incorporates review comments in reporting doc --- .../images/reporting-privileges-example.png | Bin 0 -> 96808 bytes docs/user/security/reporting.asciidoc | 63 +++++++++++++++--- 2 files changed, 54 insertions(+), 9 deletions(-) create mode 100644 docs/user/security/images/reporting-privileges-example.png diff --git a/docs/user/security/images/reporting-privileges-example.png b/docs/user/security/images/reporting-privileges-example.png new file mode 100644 index 0000000000000000000000000000000000000000..d108fe6634fa2b75d183e2f196a79cd943409412 GIT binary patch literal 96808 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%0DH}s-wzV<6Xpz2pz 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
H2^KW_ciGt5!1!Q3}C)vUTgolr}?6rP#n6ACD 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 EAHA=YYybcN literal 0 HcmV?d00001 diff --git a/docs/user/security/reporting.asciidoc b/docs/user/security/reporting.asciidoc index aaba60ca4b3ca..86599be9af375 100644 --- a/docs/user/security/reporting.asciidoc +++ b/docs/user/security/reporting.asciidoc @@ -9,19 +9,60 @@ To use {reporting} with {security} enabled, you need to <>. If you are automatically generating reports with {ref}/xpack-alerting.html[{watcher}], you also need to configure {watcher} -to trust the {kib} server's certificate. For more information, see +to trust the {kib} server's certificate. +//// +For more information, see <>. +//// [[reporting-app-users]] -To enable users to generate reports, assign them the built-in `reporting_user` -role. Users will also need the appropriate <> to access the objects +To enable users to generate reports, you must assign them the built-in `reporting_user` +role. Users will also need the appropriate <> to access the objects to report on and the {es} indices. -* If you're using the `native` realm, you can assign roles through -**Management > Users** UI in Kibana or with the `user` API. For example, -the following request creates a `reporter` user that has the -`reporting_user` role and the `kibana_user` role: +[float] +[[reporting-roles-management-ui]] +=== If you are using the `native` realm + +You can assign roles through the +*Management* app in Kibana or with the <>. +This example shows how to use *Management* to create a user who has a custom role and the +`reporting_user` role. + +. Go to *Management > Roles*, and click *Create role*. + +. Give the new role a name, for example, `custom_reporting_user`. + +. Specify the indices and privileges. + +Access to data is an index-level privilege, so in *Create role*, +add a line for each index that contains the data for the report and give each +index `read` and `view_index_metadata` privileges. +For more information, see {ref}/security-privileges.html[Security privileges]. ++ +[role="screenshot"] +image::user/security/images/reporting-privileges-example.png["Reporting privileges"] + +. Add space privileges. ++ +Reporting users typically save searches, create +visualizations, and build dashboards. They require a space +that provides read and write privileges in +*Discover*, *Visualize*, and *Dashboard*. + +. Save your new role. + +. Create a user account with the proper roles. ++ +Go to *Management > Users*, add a new user, and assign the user the built-in +`reporting_user` role and your new custom role, `custom_reporting_user`. + +[float] +[[reporting-roles-user-api]] +==== With the user API +This example uses the {ref}/security-api-put-user.html[user API] to create a user who has the +`reporting_user` role and the `kibana_user` role: + [source, sh] --------------------------------------------------------------- POST /_security/user/reporter @@ -32,13 +73,17 @@ POST /_security/user/reporter } --------------------------------------------------------------- -* If you are using an LDAP or Active Directory realm, you can either assign +[float] +=== If you are using an external identity provider + +If you are using an external identity provider, such as +LDAP or Active Directory, you can either assign roles on a per user basis, or assign roles to groups of users. By default, role mappings are configured in {ref}/mapping-roles.html[`config/shield/role_mapping.yml`]. For example, the following snippet assigns the user named Bill Murray the `kibana_user` and `reporting_user` roles: -+ + [source,yaml] -------------------------------------------------------------------------------- kibana_user: From 7ae5e7170ade2c37572b186acb9996dc7777853c Mon Sep 17 00:00:00 2001 From: Dmitry Lemeshko Date: Thu, 12 Dec 2019 01:34:09 +0100 Subject: [PATCH 33/79] update chromedriver to 79 (#52784) --- package.json | 4 ++-- yarn.lock | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 3403e9649f1b0..c9e6bd05f6751 100644 --- a/package.json +++ b/package.json @@ -351,7 +351,7 @@ "@types/redux": "^3.6.31", "@types/redux-actions": "^2.2.1", "@types/request": "^2.48.2", - "@types/selenium-webdriver": "^4.0.3", + "@types/selenium-webdriver": "^4.0.5", "@types/semver": "^5.5.0", "@types/sinon": "^7.0.13", "@types/strip-ansi": "^3.0.0", @@ -377,7 +377,7 @@ "chai": "3.5.0", "chance": "1.0.18", "cheerio": "0.22.0", - "chromedriver": "78.0.1", + "chromedriver": "79.0.0", "classnames": "2.2.6", "dedent": "^0.7.0", "delete-empty": "^2.0.0", diff --git a/yarn.lock b/yarn.lock index 39551aeb5fb68..246586bf7bcff 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3961,10 +3961,10 @@ "@types/tough-cookie" "*" form-data "^2.5.0" -"@types/selenium-webdriver@^4.0.3": - version "4.0.3" - resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-4.0.3.tgz#388f12c464cc1fff5d4c84cb372f19b9ab9b5c81" - integrity sha512-aMKIG1IKwV9/gjhm9uICjvmy4s2SL/bF9fE2WEgLhfdrTLKSIsDMt9M2pTqhZlxllgQPa+EUddtkx4YFTSjadw== +"@types/selenium-webdriver@^4.0.5": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-4.0.5.tgz#23041a4948c82daf2df9836e4d2358fec10d3e24" + integrity sha512-ma1aL1znI3ptEbSQgbywgadrRCJouPIACSfOl/bPwu/TPNSyyE/+o9jZ6+bpDVTtIdksZuVKpq4SR1ip3DRduw== "@types/semver@^5.5.0": version "5.5.0" @@ -7805,10 +7805,10 @@ chrome-trace-event@^1.0.0, chrome-trace-event@^1.0.2: dependencies: tslib "^1.9.0" -chromedriver@78.0.1: - version "78.0.1" - resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-78.0.1.tgz#2db3425a2cba6fcaf1a41d9538b16c3d06fa74a8" - integrity sha512-eOsyFk4xb9EECs1VMrDbxO713qN+Bu1XUE8K9AuePc3839TPdAegg72kpXSzkeNqRNZiHbnJUItIVCLFkDqceA== +chromedriver@79.0.0: + version "79.0.0" + resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-79.0.0.tgz#1660ac29924dfcd847911025593d6b6746aeea35" + integrity sha512-DO29C7ntJfzu6q1vuoWwCON8E9x5xzopt7Q41A7Dr7hBKcdNpGw1l9DTt9b+l1qviOWiJLGsD+jHw21ptEHubA== dependencies: del "^4.1.1" extract-zip "^1.6.7" From 3d103701380237c290c02b91f52e7599d603cd30 Mon Sep 17 00:00:00 2001 From: Aaron Caldwell Date: Wed, 11 Dec 2019 19:14:30 -0700 Subject: [PATCH 34/79] [Maps] Get basic structure of NP client shim in place (#52551) * Move ui routes init to separate file * Add index and general maps plugin template * Add legacy shim. Pass uimodules in as legacy service * Move ts-ignore * Fix N/A ts error on uiModules * Point index file toward legacy file. Minor NP additions --- .../plugins/file_upload/public/plugin.ts | 2 -- x-pack/legacy/plugins/maps/index.js | 2 +- x-pack/legacy/plugins/maps/public/index.ts | 29 +++++++++++++++++ x-pack/legacy/plugins/maps/public/legacy.ts | 27 ++++++++++++++++ x-pack/legacy/plugins/maps/public/plugin.ts | 31 +++++++++++++++++++ .../maps/public/{index.js => routes.js} | 25 --------------- 6 files changed, 88 insertions(+), 28 deletions(-) create mode 100644 x-pack/legacy/plugins/maps/public/index.ts create mode 100644 x-pack/legacy/plugins/maps/public/legacy.ts create mode 100644 x-pack/legacy/plugins/maps/public/plugin.ts rename x-pack/legacy/plugins/maps/public/{index.js => routes.js} (79%) diff --git a/x-pack/legacy/plugins/file_upload/public/plugin.ts b/x-pack/legacy/plugins/file_upload/public/plugin.ts index cc9ebbfc15b39..53b292b02760f 100644 --- a/x-pack/legacy/plugins/file_upload/public/plugin.ts +++ b/x-pack/legacy/plugins/file_upload/public/plugin.ts @@ -6,8 +6,6 @@ import { Plugin, CoreStart } from 'src/core/public'; // @ts-ignore -import { initResources } from './util/indexing_service'; -// @ts-ignore import { JsonUploadAndParse } from './components/json_upload_and_parse'; // @ts-ignore import { initServicesAndConstants } from './kibana_services'; diff --git a/x-pack/legacy/plugins/maps/index.js b/x-pack/legacy/plugins/maps/index.js index e5b3d5c615013..4f5bca6af7feb 100644 --- a/x-pack/legacy/plugins/maps/index.js +++ b/x-pack/legacy/plugins/maps/index.js @@ -28,7 +28,7 @@ export function maps(kibana) { description: i18n.translate('xpack.maps.appDescription', { defaultMessage: 'Map application' }), - main: 'plugins/maps/index', + main: 'plugins/maps/legacy', icon: 'plugins/maps/icon.svg', euiIconType: APP_ICON, }, diff --git a/x-pack/legacy/plugins/maps/public/index.ts b/x-pack/legacy/plugins/maps/public/index.ts new file mode 100644 index 0000000000000..404909c5c51b8 --- /dev/null +++ b/x-pack/legacy/plugins/maps/public/index.ts @@ -0,0 +1,29 @@ +/* + * 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 './kibana_services'; + +// import the uiExports that we want to "use" +import 'uiExports/inspectorViews'; +import 'uiExports/search'; +import 'uiExports/embeddableFactories'; +import 'uiExports/embeddableActions'; +import 'ui/agg_types'; + +import 'ui/kbn_top_nav'; +import 'ui/autoload/all'; +import 'react-vis/dist/style.css'; + +import './angular/services/gis_map_saved_object_loader'; +import './angular/map_controller'; +import './routes'; +// @ts-ignore +import { PluginInitializerContext } from 'kibana/public'; +import { MapsPlugin } from './plugin'; + +export const plugin = (initializerContext: PluginInitializerContext) => { + return new MapsPlugin(); +}; diff --git a/x-pack/legacy/plugins/maps/public/legacy.ts b/x-pack/legacy/plugins/maps/public/legacy.ts new file mode 100644 index 0000000000000..684d7b16fbb3b --- /dev/null +++ b/x-pack/legacy/plugins/maps/public/legacy.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { npSetup, npStart } from 'ui/new_platform'; +// @ts-ignore Untyped Module +import { uiModules } from 'ui/modules'; +import { PluginInitializerContext } from 'kibana/public'; // eslint-disable-line import/order +import { plugin } from '.'; + +const pluginInstance = plugin({} as PluginInitializerContext); + +const setupPlugins = { + __LEGACY: { + uiModules, + }, + plugins: npSetup.plugins, +}; + +const startPlugins = { + plugins: npStart.plugins, +}; + +export const setup = pluginInstance.setup(npSetup.core, setupPlugins); +export const start = pluginInstance.start(npStart.core, startPlugins); diff --git a/x-pack/legacy/plugins/maps/public/plugin.ts b/x-pack/legacy/plugins/maps/public/plugin.ts new file mode 100644 index 0000000000000..4e6d52d20db64 --- /dev/null +++ b/x-pack/legacy/plugins/maps/public/plugin.ts @@ -0,0 +1,31 @@ +/* + * 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, CoreStart } from 'src/core/public'; +// @ts-ignore +import { wrapInI18nContext } from 'ui/i18n'; +// @ts-ignore +import { MapListing } from './components/map_listing'; + +/** + * These are the interfaces with your public contracts. You should export these + * for other plugins to use in _their_ `SetupDeps`/`StartDeps` interfaces. + * @public + */ +export type MapsPluginSetup = ReturnType; +export type MapsPluginStart = ReturnType; + +/** @internal */ +export class MapsPlugin implements Plugin { + public setup(core: any, plugins: any) { + const app = plugins.__LEGACY.uiModules.get('app/maps', ['ngRoute', 'react']); + app.directive('mapListing', function(reactDirective: any) { + return reactDirective(wrapInI18nContext(MapListing)); + }); + } + + public start(core: CoreStart, plugins: any) {} +} diff --git a/x-pack/legacy/plugins/maps/public/index.js b/x-pack/legacy/plugins/maps/public/routes.js similarity index 79% rename from x-pack/legacy/plugins/maps/public/index.js rename to x-pack/legacy/plugins/maps/public/routes.js index 964753f464d95..ce8ae1359d3b6 100644 --- a/x-pack/legacy/plugins/maps/public/index.js +++ b/x-pack/legacy/plugins/maps/public/routes.js @@ -4,40 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -import './kibana_services'; - -import { wrapInI18nContext } from 'ui/i18n'; import { i18n } from '@kbn/i18n'; - -// import the uiExports that we want to "use" -import 'uiExports/inspectorViews'; -import 'uiExports/search'; -import 'uiExports/embeddableFactories'; -import 'uiExports/embeddableActions'; -import 'ui/agg_types'; - import { capabilities } from 'ui/capabilities'; import chrome from 'ui/chrome'; import routes from 'ui/routes'; -import 'ui/kbn_top_nav'; -import { uiModules } from 'ui/modules'; import { docTitle } from 'ui/doc_title'; -import 'ui/autoload/all'; -import 'react-vis/dist/style.css'; - -import './angular/services/gis_map_saved_object_loader'; -import './angular/map_controller'; import listingTemplate from './angular/listing_ng_wrapper.html'; import mapTemplate from './angular/map.html'; -import { MapListing } from './components/map_listing'; import { npStart } from 'ui/new_platform'; -const app = uiModules.get('app/maps', ['ngRoute', 'react']); - -app.directive('mapListing', function (reactDirective) { - return reactDirective(wrapInI18nContext(MapListing)); -}); - routes.enable(); routes From e488d9b02a10d5ffa9a50e736f35fb880d9b37e4 Mon Sep 17 00:00:00 2001 From: Nathan L Smith Date: Wed, 11 Dec 2019 21:45:46 -0600 Subject: [PATCH 35/79] [APM] Make client-side routes static (#52574) * [APM] Make client-side routes static Turn `getRoutes` back into `routes` so we can just import it. Checking for the service map being enabled isn't really necessary since we don't have any links to those routes and the backend routes are already flagged. --- .../app/Main/UpdateBreadcrumbs.test.tsx | 11 +- .../app/Main/route_config/index.tsx | 344 +++++++++--------- .../app/TraceLink/__test__/TraceLink.test.tsx | 30 +- .../apm/public/new-platform/plugin.tsx | 9 +- 4 files changed, 189 insertions(+), 205 deletions(-) diff --git a/x-pack/legacy/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.test.tsx b/x-pack/legacy/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.test.tsx index 97f8c941911b6..5bf8cb8271fa4 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.test.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.test.tsx @@ -7,15 +7,14 @@ import { mount } from 'enzyme'; import React from 'react'; import { MemoryRouter } from 'react-router-dom'; -import { UpdateBreadcrumbs } from './UpdateBreadcrumbs'; -import { getRoutes } from './route_config'; +import { ApmPluginContextValue } from '../../../context/ApmPluginContext'; import { - MockApmPluginContextWrapper, - mockApmPluginContextValue + mockApmPluginContextValue, + MockApmPluginContextWrapper } from '../../../utils/testHelpers'; -import { ApmPluginContextValue } from '../../../context/ApmPluginContext'; +import { routes } from './route_config'; +import { UpdateBreadcrumbs } from './UpdateBreadcrumbs'; -const routes = getRoutes({ serviceMapEnabled: true }); const setBreadcrumbs = jest.fn(); function expectBreadcrumbToMatchSnapshot(route: string, params = '') { diff --git a/x-pack/legacy/plugins/apm/public/components/app/Main/route_config/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/Main/route_config/index.tsx index 1d76a98573617..2f7df3c5a4acd 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Main/route_config/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/Main/route_config/index.tsx @@ -42,187 +42,175 @@ const renderAsRedirectTo = (to: string) => { ); }; -export function getRoutes({ - serviceMapEnabled -}: { - serviceMapEnabled: boolean; -}): BreadcrumbRoute[] { - const routes: BreadcrumbRoute[] = [ - { - exact: true, - path: '/', - render: renderAsRedirectTo('/services'), - breadcrumb: 'APM', - name: RouteName.HOME - }, - { - exact: true, - path: '/services', - component: () => , - breadcrumb: i18n.translate('xpack.apm.breadcrumb.servicesTitle', { - defaultMessage: 'Services' - }), - name: RouteName.SERVICES - }, - { - exact: true, - path: '/traces', - component: () => , - breadcrumb: i18n.translate('xpack.apm.breadcrumb.tracesTitle', { - defaultMessage: 'Traces' - }), - name: RouteName.TRACES - }, - { - exact: true, - path: '/settings', - render: renderAsRedirectTo('/settings/agent-configuration'), - breadcrumb: i18n.translate('xpack.apm.breadcrumb.listSettingsTitle', { - defaultMessage: 'Settings' - }), - name: RouteName.SETTINGS - }, - { - exact: true, - path: '/settings/apm-indices', - component: () => ( - - - - ), - breadcrumb: i18n.translate('xpack.apm.breadcrumb.settings.indicesTitle', { - defaultMessage: 'Indices' - }), - name: RouteName.INDICES - }, - { - exact: true, - path: '/settings/agent-configuration', - component: () => ( - - - - ), - breadcrumb: i18n.translate( - 'xpack.apm.breadcrumb.settings.agentConfigurationTitle', - { - defaultMessage: 'Agent Configuration' - } - ), - name: RouteName.AGENT_CONFIGURATION - }, - { - exact: true, - path: '/services/:serviceName', - breadcrumb: ({ match }) => match.params.serviceName, - render: (props: RouteComponentProps) => - renderAsRedirectTo( - `/services/${props.match.params.serviceName}/transactions` - )(props), - name: RouteName.SERVICE - }, - // errors - { - exact: true, - path: '/services/:serviceName/errors/:groupId', - component: ErrorGroupDetails, - breadcrumb: ({ match }) => match.params.groupId, - name: RouteName.ERROR - }, - { - exact: true, - path: '/services/:serviceName/errors', - component: () => , - breadcrumb: i18n.translate('xpack.apm.breadcrumb.errorsTitle', { - defaultMessage: 'Errors' - }), - name: RouteName.ERRORS - }, - // transactions - { - exact: true, - path: '/services/:serviceName/transactions', - component: () => , - breadcrumb: i18n.translate('xpack.apm.breadcrumb.transactionsTitle', { - defaultMessage: 'Transactions' - }), - name: RouteName.TRANSACTIONS - }, - // metrics - { - exact: true, - path: '/services/:serviceName/metrics', - component: () => , - breadcrumb: metricsBreadcrumb, - name: RouteName.METRICS - }, - // service nodes, only enabled for java agents for now - { - exact: true, - path: '/services/:serviceName/nodes', - component: () => , - breadcrumb: i18n.translate('xpack.apm.breadcrumb.nodesTitle', { - defaultMessage: 'JVMs' - }), - name: RouteName.SERVICE_NODES - }, - // node metrics - { - exact: true, - path: '/services/:serviceName/nodes/:serviceNodeName/metrics', - component: () => , - breadcrumb: ({ location }) => { - const { serviceNodeName } = resolveUrlParams(location, {}); +export const routes: BreadcrumbRoute[] = [ + { + exact: true, + path: '/', + render: renderAsRedirectTo('/services'), + breadcrumb: 'APM', + name: RouteName.HOME + }, + { + exact: true, + path: '/services', + component: () => , + breadcrumb: i18n.translate('xpack.apm.breadcrumb.servicesTitle', { + defaultMessage: 'Services' + }), + name: RouteName.SERVICES + }, + { + exact: true, + path: '/traces', + component: () => , + breadcrumb: i18n.translate('xpack.apm.breadcrumb.tracesTitle', { + defaultMessage: 'Traces' + }), + name: RouteName.TRACES + }, + { + exact: true, + path: '/settings', + render: renderAsRedirectTo('/settings/agent-configuration'), + breadcrumb: i18n.translate('xpack.apm.breadcrumb.listSettingsTitle', { + defaultMessage: 'Settings' + }), + name: RouteName.SETTINGS + }, + { + exact: true, + path: '/settings/apm-indices', + component: () => ( + + + + ), + breadcrumb: i18n.translate('xpack.apm.breadcrumb.settings.indicesTitle', { + defaultMessage: 'Indices' + }), + name: RouteName.INDICES + }, + { + exact: true, + path: '/settings/agent-configuration', + component: () => ( + + + + ), + breadcrumb: i18n.translate( + 'xpack.apm.breadcrumb.settings.agentConfigurationTitle', + { + defaultMessage: 'Agent Configuration' + } + ), + name: RouteName.AGENT_CONFIGURATION + }, + { + exact: true, + path: '/services/:serviceName', + breadcrumb: ({ match }) => match.params.serviceName, + render: (props: RouteComponentProps) => + renderAsRedirectTo( + `/services/${props.match.params.serviceName}/transactions` + )(props), + name: RouteName.SERVICE + }, + // errors + { + exact: true, + path: '/services/:serviceName/errors/:groupId', + component: ErrorGroupDetails, + breadcrumb: ({ match }) => match.params.groupId, + name: RouteName.ERROR + }, + { + exact: true, + path: '/services/:serviceName/errors', + component: () => , + breadcrumb: i18n.translate('xpack.apm.breadcrumb.errorsTitle', { + defaultMessage: 'Errors' + }), + name: RouteName.ERRORS + }, + // transactions + { + exact: true, + path: '/services/:serviceName/transactions', + component: () => , + breadcrumb: i18n.translate('xpack.apm.breadcrumb.transactionsTitle', { + defaultMessage: 'Transactions' + }), + name: RouteName.TRANSACTIONS + }, + // metrics + { + exact: true, + path: '/services/:serviceName/metrics', + component: () => , + breadcrumb: metricsBreadcrumb, + name: RouteName.METRICS + }, + // service nodes, only enabled for java agents for now + { + exact: true, + path: '/services/:serviceName/nodes', + component: () => , + breadcrumb: i18n.translate('xpack.apm.breadcrumb.nodesTitle', { + defaultMessage: 'JVMs' + }), + name: RouteName.SERVICE_NODES + }, + // node metrics + { + exact: true, + path: '/services/:serviceName/nodes/:serviceNodeName/metrics', + component: () => , + breadcrumb: ({ location }) => { + const { serviceNodeName } = resolveUrlParams(location, {}); - if (serviceNodeName === SERVICE_NODE_NAME_MISSING) { - return UNIDENTIFIED_SERVICE_NODES_LABEL; - } + if (serviceNodeName === SERVICE_NODE_NAME_MISSING) { + return UNIDENTIFIED_SERVICE_NODES_LABEL; + } - return serviceNodeName || ''; - }, - name: RouteName.SERVICE_NODE_METRICS + return serviceNodeName || ''; }, - { - exact: true, - path: '/services/:serviceName/transactions/view', - component: TransactionDetails, - breadcrumb: ({ location }) => { - const query = toQuery(location.search); - return query.transactionName as string; - }, - name: RouteName.TRANSACTION_NAME + name: RouteName.SERVICE_NODE_METRICS + }, + { + exact: true, + path: '/services/:serviceName/transactions/view', + component: TransactionDetails, + breadcrumb: ({ location }) => { + const query = toQuery(location.search); + return query.transactionName as string; }, - { - exact: true, - path: '/link-to/trace/:traceId', - component: TraceLink, - breadcrumb: null, - name: RouteName.LINK_TO_TRACE - } - ]; + name: RouteName.TRANSACTION_NAME + }, + { + exact: true, + path: '/link-to/trace/:traceId', + component: TraceLink, + breadcrumb: null, + name: RouteName.LINK_TO_TRACE + }, - if (serviceMapEnabled) { - routes.push( - { - exact: true, - path: '/service-map', - component: () => , - breadcrumb: i18n.translate('xpack.apm.breadcrumb.serviceMapTitle', { - defaultMessage: 'Service Map' - }), - name: RouteName.SERVICE_MAP - }, - { - exact: true, - path: '/services/:serviceName/service-map', - component: () => , - breadcrumb: i18n.translate('xpack.apm.breadcrumb.serviceMapTitle', { - defaultMessage: 'Service Map' - }), - name: RouteName.SINGLE_SERVICE_MAP - } - ); + { + exact: true, + path: '/service-map', + component: () => , + breadcrumb: i18n.translate('xpack.apm.breadcrumb.serviceMapTitle', { + defaultMessage: 'Service Map' + }), + name: RouteName.SERVICE_MAP + }, + { + exact: true, + path: '/services/:serviceName/service-map', + component: () => , + breadcrumb: i18n.translate('xpack.apm.breadcrumb.serviceMapTitle', { + defaultMessage: 'Service Map' + }), + name: RouteName.SINGLE_SERVICE_MAP } - - return routes; -} +]; diff --git a/x-pack/legacy/plugins/apm/public/components/app/TraceLink/__test__/TraceLink.test.tsx b/x-pack/legacy/plugins/apm/public/components/app/TraceLink/__test__/TraceLink.test.tsx index d1254e1e1e2ad..fe58fc39c6cfa 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TraceLink/__test__/TraceLink.test.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/TraceLink/__test__/TraceLink.test.tsx @@ -3,28 +3,28 @@ * 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 { render } from '@testing-library/react'; import { shallow } from 'enzyme'; -import * as urlParamsHooks from '../../../../hooks/useUrlParams'; -import * as hooks from '../../../../hooks/useFetcher'; +import React from 'react'; import { TraceLink } from '../'; +import * as hooks from '../../../../hooks/useFetcher'; +import * as urlParamsHooks from '../../../../hooks/useUrlParams'; import { MockApmPluginContextWrapper } from '../../../../utils/testHelpers'; -import * as routeConfig from '../../Main/route_config'; -import { BreadcrumbRoute } from '../../Main/ProvideBreadcrumbs'; const renderOptions = { wrapper: MockApmPluginContextWrapper }; -jest.spyOn(routeConfig, 'getRoutes').mockReturnValue([ - { - path: '/services/:serviceName/transactions/view', - name: 'transaction_name' - }, - { - path: '/traces', - name: 'traces' - } -] as BreadcrumbRoute[]); +jest.mock('../../Main/route_config', () => ({ + routes: [ + { + path: '/services/:serviceName/transactions/view', + name: 'transaction_name' + }, + { + path: '/traces', + name: 'traces' + } + ] +})); describe('TraceLink', () => { afterAll(() => { diff --git a/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx b/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx index 38dc82f01b386..64784617442ef 100644 --- a/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx +++ b/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx @@ -25,7 +25,7 @@ import { px, unit, units } from '../style/variables'; import { LoadingIndicatorProvider } from '../context/LoadingIndicatorContext'; import { LicenseProvider } from '../context/LicenseContext'; import { UpdateBreadcrumbs } from '../components/app/Main/UpdateBreadcrumbs'; -import { getRoutes } from '../components/app/Main/route_config'; +import { routes } from '../components/app/Main/route_config'; import { ScrollToTopOnPathChange } from '../components/app/Main/ScrollToTopOnPathChange'; import { MatchedRouteProvider } from '../context/MatchedRouteContext'; import { createStaticIndexPattern } from '../services/rest/index_pattern'; @@ -34,7 +34,6 @@ import { setReadonlyBadge } from './updateBadge'; import { featureCatalogueEntry } from './featureCatalogueEntry'; import { getConfigFromInjectedMetadata } from './getConfigFromInjectedMetadata'; import { toggleAppLinkInNav } from './toggleAppLinkInNav'; -import { BreadcrumbRoute } from '../components/app/Main/ProvideBreadcrumbs'; import { ApmPluginContext } from '../context/ApmPluginContext'; export const REACT_APP_ROOT_ID = 'react-apm-root'; @@ -45,7 +44,7 @@ const MainContainer = styled.main` height: 100%; `; -const App = ({ routes }: { routes: BreadcrumbRoute[] }) => { +const App = () => { return ( @@ -115,8 +114,6 @@ export class ApmPlugin // Until then we use a shim to get it from legacy metadata: const packageInfo = metadata as PackageInfo; - const routes = getRoutes(config); - // render APM feedback link in global help menu setHelpExtension(core); setReadonlyBadge(core); @@ -138,7 +135,7 @@ export class ApmPlugin - + From a05fef269ad8d90339bbacae7e8c1e496fb36145 Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Thu, 12 Dec 2019 06:57:27 +0100 Subject: [PATCH 36/79] Disable/enable filter with click+shift on a filter badge (#52751) --- src/plugins/data/public/ui/filter_bar/filter_item.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/plugins/data/public/ui/filter_bar/filter_item.tsx b/src/plugins/data/public/ui/filter_bar/filter_item.tsx index 1921f6672755d..b26bb05f926d5 100644 --- a/src/plugins/data/public/ui/filter_bar/filter_item.tsx +++ b/src/plugins/data/public/ui/filter_bar/filter_item.tsx @@ -20,7 +20,7 @@ import { EuiContextMenu, EuiPopover } from '@elastic/eui'; import { InjectedIntl, injectI18n } from '@kbn/i18n/react'; import classNames from 'classnames'; -import React, { Component } from 'react'; +import React, { Component, MouseEvent } from 'react'; import { IUiSettingsClient } from 'src/core/public'; import { FilterEditor } from './filter_editor'; import { FilterView } from './filter_view'; @@ -46,6 +46,13 @@ class FilterItemUI extends Component { isPopoverOpen: false, }; + private handleBadgeClick = (e: MouseEvent) => { + if (e.shiftKey) { + this.onToggleDisabled(); + } else { + this.togglePopover(); + } + }; public render() { const { filter, id } = this.props; const { negate, disabled } = filter.meta; @@ -73,7 +80,7 @@ class FilterItemUI extends Component { valueLabel={valueLabel} className={classes} iconOnClick={() => this.props.onRemove()} - onClick={this.togglePopover} + onClick={this.handleBadgeClick} data-test-subj={`filter ${dataTestSubjDisabled} ${dataTestSubjKey} ${dataTestSubjValue}`} /> ); From 989a349ba8d06804b0197895578569f561b07ce0 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Thu, 12 Dec 2019 08:31:55 +0100 Subject: [PATCH 37/79] [Discover] Place tooltip at bottom of filter button (#52720) This prevents a hover conflict that makes filtering out value impossible in the last column --- .../discover/angular/doc_table/components/table_row/cell.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/legacy/core_plugins/kibana/public/discover/angular/doc_table/components/table_row/cell.html b/src/legacy/core_plugins/kibana/public/discover/angular/doc_table/components/table_row/cell.html index 77702ed606474..0704016a52bbd 100644 --- a/src/legacy/core_plugins/kibana/public/discover/angular/doc_table/components/table_row/cell.html +++ b/src/legacy/core_plugins/kibana/public/discover/angular/doc_table/components/table_row/cell.html @@ -19,9 +19,9 @@ tooltip-append-to-body="1" data-test-subj="docTableCellFilter" tooltip="{{ ::'kbn.docTable.tableRow.filterForValueButtonTooltip' | i18n: {defaultMessage: 'Filter for value'} }}" + tooltip-placement="bottom" aria-label="{{ ::'kbn.docTable.tableRow.filterForValueButtonAriaLabel' | i18n: {defaultMessage: 'Filter for value'} }}" > - <% } %> From 860be3c3eb6917d0479e0563e45189ab192e1017 Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Thu, 12 Dec 2019 13:36:14 +0100 Subject: [PATCH 38/79] Stabilize dashboard save modal functional test (#52761) --- test/functional/apps/dashboard/dashboard_save.js | 1 + test/functional/page_objects/dashboard_page.js | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/test/functional/apps/dashboard/dashboard_save.js b/test/functional/apps/dashboard/dashboard_save.js index 8e4c4d66b3844..88a1c592ec74e 100644 --- a/test/functional/apps/dashboard/dashboard_save.js +++ b/test/functional/apps/dashboard/dashboard_save.js @@ -55,6 +55,7 @@ export default function ({ getPageObjects }) { await PageObjects.dashboard.clickNewDashboard(); await PageObjects.dashboard.enterDashboardTitleAndClickSave(dashboardName, { waitDialogIsClosed: false }); + await PageObjects.dashboard.ensureDuplicateTitleCallout(); await PageObjects.dashboard.clickSave(); // This is important since saving a new dashboard will cause a refresh of the page. We have to diff --git a/test/functional/page_objects/dashboard_page.js b/test/functional/page_objects/dashboard_page.js index 73424a3df55da..f7b0cf41d30e4 100644 --- a/test/functional/page_objects/dashboard_page.js +++ b/test/functional/page_objects/dashboard_page.js @@ -376,6 +376,10 @@ export function DashboardPageProvider({ getService, getPageObjects }) { } } + async ensureDuplicateTitleCallout() { + await testSubjects.existOrFail('titleDupicateWarnMsg'); + } + /** * @param dashboardTitle {String} */ From ba2e2588a31c06f6b36b1a7671be4d121b719258 Mon Sep 17 00:00:00 2001 From: Chris Davies Date: Thu, 12 Dec 2019 09:18:09 -0500 Subject: [PATCH 39/79] Change ajax_stream to use new-line delimited JSON (#52797) --- .../canvas/ajax_stream/ajax_stream.test.ts | 54 ++++++++++--------- .../public/canvas/ajax_stream/ajax_stream.ts | 23 ++------ .../server/routes/server_functions.ts | 5 +- 3 files changed, 34 insertions(+), 48 deletions(-) diff --git a/src/legacy/core_plugins/interpreter/public/canvas/ajax_stream/ajax_stream.test.ts b/src/legacy/core_plugins/interpreter/public/canvas/ajax_stream/ajax_stream.test.ts index 243c766206d2d..4463758e30bd6 100644 --- a/src/legacy/core_plugins/interpreter/public/canvas/ajax_stream/ajax_stream.test.ts +++ b/src/legacy/core_plugins/interpreter/public/canvas/ajax_stream/ajax_stream.test.ts @@ -26,7 +26,7 @@ describe('ajaxStream', () => { it('pulls items from the stream and calls the handler', async () => { const handler = jest.fn(() => ({})); const { req, sendText, done } = mockRequest(); - const messages = ['{ "hello": "world" }\n', '{ "tis": "fate" }\n'].map(m => `${m.length}:${m}`); + const messages = ['{ "hello": "world" }\n', '{ "tis": "fate" }\n']; const promise = ajaxStream('', {}, req, { url: '/test/endpoint', @@ -43,12 +43,34 @@ describe('ajaxStream', () => { expect(handler).toHaveBeenCalledWith({ tis: 'fate' }); }); + it('handles newlines in values', async () => { + const handler = jest.fn(() => ({})); + const { req, sendText, done } = mockRequest(); + const messages = [ + JSON.stringify({ hello: 'wo\nrld' }), + '\n', + JSON.stringify({ tis: 'fa\nte' }), + '\n', + ]; + + const promise = ajaxStream('', {}, req, { + url: '/test/endpoint', + onResponse: handler, + }); + + messages.forEach(sendText); + done(); + + await promise; + expect(handler).toHaveBeenCalledTimes(2); + expect(handler).toHaveBeenCalledWith({ hello: 'wo\nrld' }); + expect(handler).toHaveBeenCalledWith({ tis: 'fa\nte' }); + }); + it('handles partial messages', async () => { const handler = jest.fn(() => ({})); const { req, sendText, done } = mockRequest(); - const messages = ['{ "hello": "world" }\n', '{ "tis": "fate" }\n'] - .map(m => `${m.length}:${m}`) - .join(''); + const messages = ['{ "hello": "world" }\n', '{ "tis": "fate" }\n'].join(''); const promise = ajaxStream('', {}, req, { url: '/test/endpoint', @@ -117,7 +139,7 @@ describe('ajaxStream', () => { it('rejects if the payload contains invalid JSON', async () => { const handler = jest.fn(() => ({})); const { req, sendText, done } = mockRequest(); - const messages = ['{ waut? }\n'].map(m => `${m.length}:${m}`).join(''); + const messages = ['{ waut? }\n'].join(''); const promise = ajaxStream('', {}, req, { url: '/test/endpoint', @@ -130,32 +152,12 @@ describe('ajaxStream', () => { expect(await promise.then(() => true).catch(() => false)).toBeFalsy(); }); - it('rejects if the delim is invalid', async () => { - const handler = jest.fn(() => ({})); - const { req, sendText, done } = mockRequest(); - const messages = '{ "hi": "there" }'; - - const promise = ajaxStream('', {}, req, { - url: '/test/endpoint', - onResponse: handler, - }); - - sendText(messages); - done(); - - expect(await promise.then(() => true).catch(({ message }) => message)).toMatch( - /invalid stream response/i - ); - }); - it('rejects if the handler throws', async () => { const handler = jest.fn(() => { throw new Error('DOH!'); }); const { req, sendText, done } = mockRequest(); - const messages = ['{ "hello": "world" }\n', '{ "tis": "fate" }\n'] - .map(m => `${m.length}:${m}`) - .join(''); + const messages = ['{ "hello": "world" }\n', '{ "tis": "fate" }\n'].join(''); const promise = ajaxStream('', {}, req, { url: '/test/endpoint', diff --git a/src/legacy/core_plugins/interpreter/public/canvas/ajax_stream/ajax_stream.ts b/src/legacy/core_plugins/interpreter/public/canvas/ajax_stream/ajax_stream.ts index 74e10e2a271bc..867581081f82f 100644 --- a/src/legacy/core_plugins/interpreter/public/canvas/ajax_stream/ajax_stream.ts +++ b/src/legacy/core_plugins/interpreter/public/canvas/ajax_stream/ajax_stream.ts @@ -64,34 +64,19 @@ function processBatchResponseStream(handler: BatchResponseHandler) { return (text: string) => { // While there's text to process... while (index < text.length) { - // Our messages are delimited by colon: len:json - const delim = ':'; + // We're using new line-delimited JSON. + const delim = '\n'; const delimIndex = text.indexOf(delim, index); - const payloadStart = delimIndex + delim.length; // We've got an incomplete batch length if (delimIndex < 0) { return; } - const rawLen = text.slice(index, delimIndex); - const payloadLen = parseInt(rawLen, 10); - const payloadEnd = payloadStart + payloadLen; - - // We've got an invalid batch message (e.g. one without a numeric length: prefix) - if (isNaN(payloadLen)) { - throw new Error(`Invalid stream response length: ${rawLen}`); - } - - // We've got an incomplete batch message - if (text.length < payloadEnd) { - return; - } - - const payload = JSON.parse(text.slice(payloadStart, payloadEnd)); + const payload = JSON.parse(text.slice(index, delimIndex)); handler(payload); - index = payloadEnd; + index = delimIndex + 1; } }; } diff --git a/src/legacy/core_plugins/interpreter/server/routes/server_functions.ts b/src/legacy/core_plugins/interpreter/server/routes/server_functions.ts index 63e59ad613719..e03ad361b5555 100644 --- a/src/legacy/core_plugins/interpreter/server/routes/server_functions.ts +++ b/src/legacy/core_plugins/interpreter/server/routes/server_functions.ts @@ -75,7 +75,7 @@ function runServerFunctions(server: any) { // Send the initial headers. res.writeHead(200, { - 'Content-Type': 'text/plain', + 'Content-Type': 'application/x-ndjson', Connection: 'keep-alive', 'Transfer-Encoding': 'chunked', 'Cache-Control': 'no-cache', @@ -83,8 +83,7 @@ function runServerFunctions(server: any) { // Write a length-delimited response const streamResult = (result: any) => { - const payload = JSON.stringify(result) + '\n'; - res.write(`${payload.length}:${payload}`); + res.write(JSON.stringify(result) + '\n'); }; // Tries to run an interpreter function, and ensures a consistent error payload on failure. From 45563b257459206bd11e0fad66c4ce92b5059f8f Mon Sep 17 00:00:00 2001 From: Rudolf Meijering Date: Thu, 12 Dec 2019 15:27:52 +0100 Subject: [PATCH 40/79] Polish migration.md (#52764) * Polish migration.md - Added saved objects legacy vs NP docs - Moved some data plugin docs into the right table - added table for server-side plugin services and added the features plugin * Missing backticks --- src/core/MIGRATION.md | 126 +++++++++++++++++------------------------- 1 file changed, 50 insertions(+), 76 deletions(-) diff --git a/src/core/MIGRATION.md b/src/core/MIGRATION.md index 2527ffba2cbbd..0e854cd8bb8ef 100644 --- a/src/core/MIGRATION.md +++ b/src/core/MIGRATION.md @@ -9,22 +9,21 @@ - [Challenges on the server](#challenges-on-the-server) - [Challenges in the browser](#challenges-in-the-browser) - [Plan of action](#plan-of-action) - - [Shared application plugins](#shared-application-plugins) - [Server-side plan of action](#server-side-plan-of-action) - [De-couple from hapi.js server and request objects](#de-couple-from-hapijs-server-and-request-objects) - [Introduce new plugin definition shim](#introduce-new-plugin-definition-shim) - [Switch to new platform services](#switch-to-new-platform-services) - [Migrate to the new plugin system](#migrate-to-the-new-plugin-system) - [Browser-side plan of action](#browser-side-plan-of-action) - - [1. Create a plugin definition file](#1-create-a-plugin-definition-file) - - [2. Export all static code and types from `public/index.ts`](#2-export-all-static-code-and-types-from-publicindexts) - - [3. Export your runtime contract](#3-export-your-runtime-contract) - - [4. Move "owned" UI modules into your plugin and expose them from your public contract](#4-move-owned-ui-modules-into-your-plugin-and-expose-them-from-your-public-contract) - - [5. Provide plugin extension points decoupled from angular.js](#5-provide-plugin-extension-points-decoupled-from-angularjs) - - [6. Move all webpack alias imports into uiExport entry files](#6-move-all-webpack-alias-imports-into-uiexport-entry-files) - - [7. Switch to new platform services](#7-switch-to-new-platform-services) - - [8. Migrate to the new plugin system](#8-migrate-to-the-new-plugin-system) - - [Bonus: Tips for complex migration scenarios](#bonus-tips-for-complex-migration-scenarios) + - [1. Create a plugin definition file](#1-create-a-plugin-definition-file) + - [2. Export all static code and types from `public/index.ts`](#2-export-all-static-code-and-types-from-publicindexts) + - [3. Export your runtime contract](#3-export-your-runtime-contract) + - [4. Move "owned" UI modules into your plugin and expose them from your public contract](#4-move-owned-ui-modules-into-your-plugin-and-expose-them-from-your-public-contract) + - [5. Provide plugin extension points decoupled from angular.js](#5-provide-plugin-extension-points-decoupled-from-angularjs) + - [6. Move all webpack alias imports into uiExport entry files](#6-move-all-webpack-alias-imports-into-uiexport-entry-files) + - [7. Switch to new platform services](#7-switch-to-new-platform-services) + - [8. Migrate to the new plugin system](#8-migrate-to-the-new-plugin-system) + - [Bonus: Tips for complex migration scenarios](#bonus-tips-for-complex-migration-scenarios) - [Frequently asked questions](#frequently-asked-questions) - [Is migrating a plugin an all-or-nothing thing?](#is-migrating-a-plugin-an-all-or-nothing-thing) - [Do plugins need to be converted to TypeScript?](#do-plugins-need-to-be-converted-to-typescript) @@ -42,6 +41,7 @@ - [Plugins for shared application services](#plugins-for-shared-application-services) - [Server-side](#server-side) - [Core services](#core-services-1) + - [Plugin services](#plugin-services) - [UI Exports](#ui-exports) - [How to](#how-to) - [Configure plugin](#configure-plugin) @@ -325,43 +325,6 @@ First, decouple your plugin's business logic from the dependencies that are not Once those things are finished for any given plugin, it can officially be switched to the new plugin system. -### Shared application plugins - -Some services have been already moved to the new platform. - -Below you can find their new locations: - -| Service | Old place | New place in the NP | -| --------------- | ----------------------------------------- | --------------------------------------------------- | -| *FieldFormats* | ui/registry/field_formats | plugins/data/public | - -The `FieldFormats` service has been moved to the `data` plugin in the New Platform. If your plugin has any imports from `ui/registry/field_formats`, you'll need to update your imports as follows: - -Use it in your New Platform plugin: - -```ts -class MyPlugin { - setup (core, { data }) { - data.fieldFormats.register(myFieldFormat); - // ... - } - start (core, { data }) { - data.fieldFormats.getType(myFieldFormatId); - // ... - } -} -``` - -Or, in your legacy platform plugin, consume it through the `ui/new_platform` module: - -```ts -import { npSetup, npStart } from 'ui/new_platform'; - -npSetup.plugins.data.fieldFormats.register(myFieldFormat); -npStart.plugins.data.fieldFormats.getType(myFieldFormatId); -// ... -``` - ## Server-side plan of action Legacy server-side plugins access functionality from core and other plugins at runtime via function arguments, which is similar to how they must be architected to use the new plugin system. This greatly simplifies the plan of action for migrating server-side plugins. @@ -1191,25 +1154,26 @@ import { setup, start } from '../core_plugins/embeddables/public/legacy'; import { setup, start } from '../core_plugins/visualizations/public/legacy'; ``` -| Legacy Platform | New Platform | Notes | -| ------------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `import 'ui/apply_filters'` | N/A. Replaced by triggering an APPLY_FILTER_TRIGGER trigger. | Directive is deprecated. | -| `import 'ui/filter_bar'` | `import { FilterBar } from '../data/public'` | Directive is deprecated. | -| `import 'ui/query_bar'` | `import { QueryStringInput } from '../data/public'` | Directives are deprecated. | -| `import 'ui/search_bar'` | `import { SearchBar } from '../data/public'` | Directive is deprecated. | -| `import 'ui/kbn_top_nav'` | `import { TopNavMenu } from '../navigation/public'` | Directive is still available in `ui/kbn_top_nav`. | -| `ui/saved_objects/components/saved_object_finder` | `import { SavedObjectFinder } from '../kibana_react/public'` | | -| `core_plugins/interpreter` | `data.expressions` | still in progress | -| `ui/courier` | `data.search` | still in progress | -| `ui/embeddable` | `embeddables` | still in progress | -| `ui/filter_manager` | `data.filter` | -- | -| `ui/index_patterns` | `data.indexPatterns` | still in progress | -| `ui/registry/feature_catalogue` | `home.featureCatalogue.register` | Must add `home` as a dependency in your kibana.json. | -| `ui/registry/vis_types` | `visualizations.types` | -- | -| `ui/vis` | `visualizations.types` | -- | -| `ui/share` | `share` | `showShareContextMenu` is now called `toggleShareContextMenu`, `ShareContextMenuExtensionsRegistryProvider` is now called `register` | -| `ui/vis/vis_factory` | `visualizations.types` | -- | -| `ui/vis/vis_filters` | `visualizations.filters` | -- | +| Legacy Platform | New Platform | Notes | +| ------------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ | +| `import 'ui/apply_filters'` | N/A. Replaced by triggering an APPLY_FILTER_TRIGGER trigger. | Directive is deprecated. | +| `import 'ui/filter_bar'` | `import { FilterBar } from '../data/public'` | Directive is deprecated. | +| `import 'ui/query_bar'` | `import { QueryStringInput } from '../data/public'` | Directives are deprecated. | +| `import 'ui/search_bar'` | `import { SearchBar } from '../data/public'` | Directive is deprecated. | +| `import 'ui/kbn_top_nav'` | `import { TopNavMenu } from '../navigation/public'` | Directive is still available in `ui/kbn_top_nav`. | +| `ui/saved_objects/components/saved_object_finder` | `import { SavedObjectFinder } from '../kibana_react/public'` | | +| `core_plugins/interpreter` | `data.expressions` | still in progress | +| `ui/courier` | `data.search` | still in progress | +| `ui/embeddable` | `embeddables` | still in progress | +| `ui/filter_manager` | `data.filter` | -- | +| `ui/index_patterns` | `data.indexPatterns` | still in progress | +| `ui/registry/field_formats` | `data.fieldFormats` | | +| `ui/registry/feature_catalogue` | `home.featureCatalogue.register` | Must add `home` as a dependency in your kibana.json. | +| `ui/registry/vis_types` | `visualizations.types` | -- | +| `ui/vis` | `visualizations.types` | -- | +| `ui/share` | `share` | `showShareContextMenu` is now called `toggleShareContextMenu`, `ShareContextMenuExtensionsRegistryProvider` is now called `register` | +| `ui/vis/vis_factory` | `visualizations.types` | -- | +| `ui/vis/vis_filters` | `visualizations.filters` | -- | | `ui/utils/parse_es_interval` | `import { parseEsInterval } from '../data/public'` | `parseEsInterval`, `ParsedInterval`, `InvalidEsCalendarIntervalError`, `InvalidEsIntervalFormatError` items were moved to the `Data Plugin` as a static code | #### Server-side @@ -1218,17 +1182,27 @@ import { setup, start } from '../core_plugins/visualizations/public/legacy'; In server code, `core` can be accessed from either `server.newPlatform` or `kbnServer.newPlatform`. There are not currently very many services available on the server-side: -| Legacy Platform | New Platform | Notes | -| -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | -| `server.config()` | [`initializerContext.config.create()`](/docs/development/core/server/kibana-plugin-server.plugininitializercontext.config.md) | Must also define schema. See _[how to configure plugin](#configure-plugin)_ | -| `server.route` | [`core.http.createRouter`](/docs/development/core/server/kibana-plugin-server.httpservicesetup.createrouter.md) | [Examples](./MIGRATION_EXAMPLES.md#route-registration) | -| `request.getBasePath()` | [`core.http.basePath.get`](/docs/development/core/server/kibana-plugin-server.httpservicesetup.basepath.md) | | -| `server.plugins.elasticsearch.getCluster('data')` | [`core.elasticsearch.dataClient$`](/docs/development/core/server/kibana-plugin-server.elasticsearchservicesetup.dataclient_.md) | Handlers will also include a pre-configured client | -| `server.plugins.elasticsearch.getCluster('admin')` | [`core.elasticsearch.adminClient$`](/docs/development/core/server/kibana-plugin-server.elasticsearchservicesetup.adminclient_.md) | Handlers will also include a pre-configured client | -| `xpackMainPlugin.info.feature(pluginID).registerLicenseCheckResultsGenerator` | [`x-pack licensing plugin`](/x-pack/plugins/licensing/README.md) | | +| Legacy Platform | New Platform | Notes | +| ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | +| `server.config()` | [`initializerContext.config.create()`](/docs/development/core/server/kibana-plugin-server.plugininitializercontext.config.md) | Must also define schema. See _[how to configure plugin](#configure-plugin)_ | +| `server.route` | [`core.http.createRouter`](/docs/development/core/server/kibana-plugin-server.httpservicesetup.createrouter.md) | [Examples](./MIGRATION_EXAMPLES.md#route-registration) | +| `request.getBasePath()` | [`core.http.basePath.get`](/docs/development/core/server/kibana-plugin-server.httpservicesetup.basepath.md) | | +| `server.plugins.elasticsearch.getCluster('data')` | [`core.elasticsearch.dataClient$`](/docs/development/core/server/kibana-plugin-server.elasticsearchservicesetup.dataclient_.md) | Handlers will also include a pre-configured client | +| `server.plugins.elasticsearch.getCluster('admin')` | [`core.elasticsearch.adminClient$`](/docs/development/core/server/kibana-plugin-server.elasticsearchservicesetup.adminclient_.md) | Handlers will also include a pre-configured client | +| `xpackMainPlugin.info.feature(pluginID).registerLicenseCheckResultsGenerator` | [`x-pack licensing plugin`](/x-pack/plugins/licensing/README.md) | | +| `server.savedObjects.setScopedSavedObjectsClientFactory` | [`core.savedObjects.setClientFactory`](/docs/development/core/server/kibana-plugin-server.savedobjectsservicesetup.setclientfactory.md) | | +| `server.savedObjects.addScopedSavedObjectsClientWrapperFactory` | [`core.savedObjects.addClientWrapper`](/docs/development/core/server/kibana-plugin-server.savedobjectsservicesetup.addclientwrapper.md) | | +| `server.savedObjects.getSavedObjectsRepository` | [`core.savedObjects.createInternalRepository`](/docs/development/core/server/kibana-plugin-server.savedobjectsservicesetup.createinternalrepository.md) [`core.savedObjects.createScopedRepository`](/docs/development/core/server/kibana-plugin-server.savedobjectsservicesetup.createscopedrepository.md) | | +| `server.savedObjects.getScopedSavedObjectsClient` | [`core.savedObjects.getScopedClient`](/docs/development/core/server/kibana-plugin-server.savedobjectsservicestart.getscopedclient.md) | | +| `request.getSavedObjectsClient` | [`context.core.savedObjects.client`](/docs/development/core/server/kibana-plugin-server.requesthandlercontext.core.md) | | _See also: [Server's CoreSetup API Docs](/docs/development/core/server/kibana-plugin-server.coresetup.md)_ +##### Plugin services +| Legacy Platform | New Platform | Notes | +| ------------------------------------------- | ------------------------------------------------------------------------------ | ----- | +| `server.plugins.xpack_main.registerFeature` | [`plugins.features.registerFeature`](x-pack/plugins/features/server/plugin.ts) | | + #### UI Exports The legacy platform uses a set of "uiExports" to inject modules from one plugin into other plugins. This mechansim is not necessary in the New Platform because all plugins are executed on the page at once (though only one application) is rendered at a time. @@ -1249,7 +1223,7 @@ This table shows where these uiExports have moved to in the New Platform. In mos | `fieldFormatEditors` | | | | `fieldFormats` | | | | `hacks` | n/a | Just run the code in your plugin's `start` method. | -| `home` | [`plugins.home.featureCatalogue.register`](./src/plugins/home/public/feature_catalogue) | Must add `home` as a dependency in your kibana.json. | +| `home` | [`plugins.home.featureCatalogue.register`](./src/plugins/home/public/feature_catalogue) | Must add `home` as a dependency in your kibana.json. | | `indexManagement` | | Should be an API on the indexManagement plugin. | | `injectDefaultVars` | n/a | Plugins will only be able to "whitelist" config values for the frontend. See [#41990](https://github.com/elastic/kibana/issues/41990) | | `inspectorViews` | | Should be an API on the data (?) plugin. | @@ -1267,7 +1241,7 @@ This table shows where these uiExports have moved to in the New Platform. In mos | `styleSheetPaths` | | | | `taskDefinitions` | | Should be an API on the taskManager plugin. | | `uiCapabilities` | [`core.application.register`](/docs/development/core/public/kibana-plugin-public.applicationsetup.register.md) | | -| `uiSettingDefaults` | [`core.uiSettings.register`](/docs/development/core/server/kibana-plugin-server.uisettingsservicesetup.md) | | +| `uiSettingDefaults` | [`core.uiSettings.register`](/docs/development/core/server/kibana-plugin-server.uisettingsservicesetup.md) | | | `validations` | | Part of SavedObjects, see [#33587](https://github.com/elastic/kibana/issues/33587) | | `visEditorTypes` | | | | `visTypeEnhancers` | | | From f8ba2fdd78d75e85df2df2d14c35c24e76fd9778 Mon Sep 17 00:00:00 2001 From: Thomas Watson Date: Thu, 12 Dec 2019 16:00:07 +0100 Subject: [PATCH 41/79] Hide stderr git output during APM agent configuration (#52878) --- config/apm.js | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/config/apm.js b/config/apm.js index 8efbbf87487e3..0cfcd759f163b 100644 --- a/config/apm.js +++ b/config/apm.js @@ -42,19 +42,22 @@ const { join } = require('path'); const { execSync } = require('child_process'); const merge = require('lodash.merge'); -module.exports = merge({ - active: false, - serverUrl: 'https://f1542b814f674090afd914960583265f.apm.us-central1.gcp.cloud.es.io:443', - // The secretToken below is intended to be hardcoded in this file even though - // it makes it public. This is not a security/privacy issue. Normally we'd - // instead disable the need for a secretToken in the APM Server config where - // the data is transmitted to, but due to how it's being hosted, it's easier, - // for now, to simply leave it in. - secretToken: 'R0Gjg46pE9K9wGestd', - globalLabels: {}, - centralConfig: false, - logUncaughtExceptions: true -}, devConfig()); +module.exports = merge( + { + active: false, + serverUrl: 'https://f1542b814f674090afd914960583265f.apm.us-central1.gcp.cloud.es.io:443', + // The secretToken below is intended to be hardcoded in this file even though + // it makes it public. This is not a security/privacy issue. Normally we'd + // instead disable the need for a secretToken in the APM Server config where + // the data is transmitted to, but due to how it's being hosted, it's easier, + // for now, to simply leave it in. + secretToken: 'R0Gjg46pE9K9wGestd', + globalLabels: {}, + centralConfig: false, + logUncaughtExceptions: true, + }, + devConfig() +); const rev = gitRev(); if (rev !== null) module.exports.globalLabels.git_rev = rev; @@ -66,7 +69,10 @@ try { function gitRev() { try { - return execSync('git rev-parse --short HEAD', { encoding: 'utf-8' }).trim(); + return execSync('git rev-parse --short HEAD', { + encoding: 'utf-8', + stdio: ['ignore', 'pipe', 'ignore'], + }).trim(); } catch (e) { return null; } From 2caf640d4824a43ad57de79f3424cb4063e9a03d Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Thu, 12 Dec 2019 08:00:44 -0700 Subject: [PATCH 42/79] [Data Plugin]: Remove `export *` for common code from public/server index files (#52821) --- .../data/common/es_query/es_query/index.ts | 2 - .../{utils => filters}/get_display_value.ts | 0 .../get_index_pattern_from_filter.test.ts | 0 .../get_index_pattern_from_filter.ts | 0 .../data/common/es_query/filters/index.ts | 7 +- src/plugins/data/common/es_query/index.ts | 3 +- .../common/es_query/kuery/functions/is.js | 2 +- .../common/es_query/kuery/functions/range.js | 2 +- ...et_time_zone_from_settings.ts => utils.ts} | 0 .../data/common/es_query/utils/index.ts | 22 ------ src/plugins/data/public/index.ts | 68 +++++++++++++++++-- .../apply_filter_popover_content.tsx | 4 +- .../ui/filter_bar/filter_editor/index.tsx | 4 +- .../data/public/ui/filter_bar/filter_item.tsx | 4 +- src/plugins/data/server/index.ts | 64 +++++++++++++++-- .../components/description_step/index.tsx | 3 +- 16 files changed, 136 insertions(+), 49 deletions(-) rename src/plugins/data/common/es_query/{utils => filters}/get_display_value.ts (100%) rename src/plugins/data/common/es_query/{utils => filters}/get_index_pattern_from_filter.test.ts (100%) rename src/plugins/data/common/es_query/{utils => filters}/get_index_pattern_from_filter.ts (100%) rename src/plugins/data/common/es_query/{utils/get_time_zone_from_settings.ts => utils.ts} (100%) delete mode 100644 src/plugins/data/common/es_query/utils/index.ts diff --git a/src/plugins/data/common/es_query/es_query/index.ts b/src/plugins/data/common/es_query/es_query/index.ts index 82cbc543e19db..39b10be4c75b3 100644 --- a/src/plugins/data/common/es_query/es_query/index.ts +++ b/src/plugins/data/common/es_query/es_query/index.ts @@ -20,7 +20,5 @@ export { buildEsQuery, EsQueryConfig } from './build_es_query'; export { buildQueryFromFilters } from './from_filters'; export { luceneStringToDsl } from './lucene_string_to_dsl'; -export { migrateFilter } from './migrate_filter'; export { decorateQuery } from './decorate_query'; -export { filterMatchesIndex } from './filter_matches_index'; export { getEsQueryConfig } from './get_es_query_config'; diff --git a/src/plugins/data/common/es_query/utils/get_display_value.ts b/src/plugins/data/common/es_query/filters/get_display_value.ts similarity index 100% rename from src/plugins/data/common/es_query/utils/get_display_value.ts rename to src/plugins/data/common/es_query/filters/get_display_value.ts diff --git a/src/plugins/data/common/es_query/utils/get_index_pattern_from_filter.test.ts b/src/plugins/data/common/es_query/filters/get_index_pattern_from_filter.test.ts similarity index 100% rename from src/plugins/data/common/es_query/utils/get_index_pattern_from_filter.test.ts rename to src/plugins/data/common/es_query/filters/get_index_pattern_from_filter.test.ts diff --git a/src/plugins/data/common/es_query/utils/get_index_pattern_from_filter.ts b/src/plugins/data/common/es_query/filters/get_index_pattern_from_filter.ts similarity index 100% rename from src/plugins/data/common/es_query/utils/get_index_pattern_from_filter.ts rename to src/plugins/data/common/es_query/filters/get_index_pattern_from_filter.ts diff --git a/src/plugins/data/common/es_query/filters/index.ts b/src/plugins/data/common/es_query/filters/index.ts index 403ff2b79b55f..990d588359442 100644 --- a/src/plugins/data/common/es_query/filters/index.ts +++ b/src/plugins/data/common/es_query/filters/index.ts @@ -21,13 +21,14 @@ import { omit, get } from 'lodash'; import { Filter } from './meta_filter'; export * from './build_filters'; -export * from './get_filter_params'; -export * from './get_filter_field'; - export * from './custom_filter'; export * from './exists_filter'; export * from './geo_bounding_box_filter'; export * from './geo_polygon_filter'; +export * from './get_display_value'; +export * from './get_filter_field'; +export * from './get_filter_params'; +export * from './get_index_pattern_from_filter'; export * from './match_all_filter'; export * from './meta_filter'; export * from './missing_filter'; diff --git a/src/plugins/data/common/es_query/index.ts b/src/plugins/data/common/es_query/index.ts index 937fe09903b6b..e585fda8aff80 100644 --- a/src/plugins/data/common/es_query/index.ts +++ b/src/plugins/data/common/es_query/index.ts @@ -19,6 +19,5 @@ import * as esQuery from './es_query'; import * as esFilters from './filters'; import * as esKuery from './kuery'; -import * as utils from './utils'; -export { esFilters, esQuery, utils, esKuery }; +export { esFilters, esQuery, esKuery }; diff --git a/src/plugins/data/common/es_query/kuery/functions/is.js b/src/plugins/data/common/es_query/kuery/functions/is.js index 4f2f298c4707d..120dd9352d9a4 100644 --- a/src/plugins/data/common/es_query/kuery/functions/is.js +++ b/src/plugins/data/common/es_query/kuery/functions/is.js @@ -20,7 +20,7 @@ import { get, isUndefined } from 'lodash'; import { getPhraseScript } from '../../filters'; import { getFields } from './utils/get_fields'; -import { getTimeZoneFromSettings } from '../../utils/get_time_zone_from_settings'; +import { getTimeZoneFromSettings } from '../../utils'; import { getFullFieldNameNode } from './utils/get_full_field_name_node'; import * as ast from '../ast'; diff --git a/src/plugins/data/common/es_query/kuery/functions/range.js b/src/plugins/data/common/es_query/kuery/functions/range.js index 80181cfc003f1..d5eba8e20253e 100644 --- a/src/plugins/data/common/es_query/kuery/functions/range.js +++ b/src/plugins/data/common/es_query/kuery/functions/range.js @@ -22,7 +22,7 @@ import { nodeTypes } from '../node_types'; import * as ast from '../ast'; import { getRangeScript } from '../../filters'; import { getFields } from './utils/get_fields'; -import { getTimeZoneFromSettings } from '../../utils/get_time_zone_from_settings'; +import { getTimeZoneFromSettings } from '../../utils'; import { getFullFieldNameNode } from './utils/get_full_field_name_node'; export function buildNodeParams(fieldName, params) { diff --git a/src/plugins/data/common/es_query/utils/get_time_zone_from_settings.ts b/src/plugins/data/common/es_query/utils.ts similarity index 100% rename from src/plugins/data/common/es_query/utils/get_time_zone_from_settings.ts rename to src/plugins/data/common/es_query/utils.ts diff --git a/src/plugins/data/common/es_query/utils/index.ts b/src/plugins/data/common/es_query/utils/index.ts deleted file mode 100644 index 79856c9e0267e..0000000000000 --- a/src/plugins/data/common/es_query/utils/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export * from './get_time_zone_from_settings'; -export * from './get_index_pattern_from_filter'; -export * from './get_display_value'; diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index e54278698a05a..967887764237d 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -22,19 +22,75 @@ export function plugin(initializerContext: PluginInitializerContext) { return new DataPublicPlugin(initializerContext); } -export * from '../common'; +/** + * Types to be shared externally + * @public + */ +export { IRequestTypesMap, IResponseTypesMap } from './search'; +export * from './types'; +export { + // field formats + ContentType, // only used in agg_type + FIELD_FORMAT_IDS, + IFieldFormat, + IFieldFormatId, + IFieldFormatType, + // index patterns + IIndexPattern, + IFieldType, + IFieldSubType, + // kbn field types + ES_FIELD_TYPES, + KBN_FIELD_TYPES, + // query + Query, + // timefilter + RefreshInterval, + TimeRange, +} from '../common'; +/** + * Static code to be shared externally + * @public + */ export * from './autocomplete_provider'; export * from './field_formats_provider'; export * from './index_patterns'; - -export * from './types'; - -export { IRequestTypesMap, IResponseTypesMap } from './search'; export * from './search'; export * from './query'; - export * from './ui'; +export { + // es query + esFilters, + esKuery, + esQuery, + // field formats + BoolFormat, + BytesFormat, + ColorFormat, + DateFormat, + DateNanosFormat, + DEFAULT_CONVERTER_COLOR, + DurationFormat, + FieldFormat, + getHighlightRequest, // only used in search source + IpFormat, + NumberFormat, + PercentFormat, + RelativeDateFormat, + SourceFormat, + StaticLookupFormat, + StringFormat, + TEXT_CONTEXT_TYPE, // only used in agg_types + TruncateFormat, + UrlFormat, + // index patterns + isFilterable, + // kbn field types + castEsToKbnFieldTypeName, + getKbnFieldType, + getKbnTypeNames, +} from '../common'; // Export plugin after all other imports import { DataPublicPlugin } from './plugin'; diff --git a/src/plugins/data/public/ui/apply_filters/apply_filter_popover_content.tsx b/src/plugins/data/public/ui/apply_filters/apply_filter_popover_content.tsx index affbb8acecb20..92582ef1d15c2 100644 --- a/src/plugins/data/public/ui/apply_filters/apply_filter_popover_content.tsx +++ b/src/plugins/data/public/ui/apply_filters/apply_filter_popover_content.tsx @@ -30,7 +30,7 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { Component } from 'react'; -import { mapAndFlattenFilters, esFilters, utils, IIndexPattern } from '../..'; +import { mapAndFlattenFilters, esFilters, IIndexPattern } from '../..'; import { FilterLabel } from '../filter_bar'; interface Props { @@ -56,7 +56,7 @@ export class ApplyFiltersPopoverContent extends Component { }; } private getLabel(filter: esFilters.Filter) { - const valueLabel = utils.getDisplayValueFromFilter(filter, this.props.indexPatterns); + const valueLabel = esFilters.getDisplayValueFromFilter(filter, this.props.indexPatterns); return ; } diff --git a/src/plugins/data/public/ui/filter_bar/filter_editor/index.tsx b/src/plugins/data/public/ui/filter_bar/filter_editor/index.tsx index 12da4cbab02da..b058d231b8306 100644 --- a/src/plugins/data/public/ui/filter_bar/filter_editor/index.tsx +++ b/src/plugins/data/public/ui/filter_bar/filter_editor/index.tsx @@ -48,7 +48,7 @@ import { Operator } from './lib/filter_operators'; import { PhraseValueInput } from './phrase_value_input'; import { PhrasesValuesInput } from './phrases_values_input'; import { RangeValueInput } from './range_value_input'; -import { esFilters, utils, IIndexPattern, IFieldType } from '../../..'; +import { esFilters, IIndexPattern, IFieldType } from '../../..'; interface Props { filter: esFilters.Filter; @@ -371,7 +371,7 @@ class FilterEditorUI extends Component { } private getIndexPatternFromFilter() { - return utils.getIndexPatternFromFilter(this.props.filter, this.props.indexPatterns); + return esFilters.getIndexPatternFromFilter(this.props.filter, this.props.indexPatterns); } private getFieldFromFilter() { diff --git a/src/plugins/data/public/ui/filter_bar/filter_item.tsx b/src/plugins/data/public/ui/filter_bar/filter_item.tsx index b26bb05f926d5..788663041fd03 100644 --- a/src/plugins/data/public/ui/filter_bar/filter_item.tsx +++ b/src/plugins/data/public/ui/filter_bar/filter_item.tsx @@ -24,7 +24,7 @@ import React, { Component, MouseEvent } from 'react'; import { IUiSettingsClient } from 'src/core/public'; import { FilterEditor } from './filter_editor'; import { FilterView } from './filter_view'; -import { esFilters, utils, IIndexPattern } from '../..'; +import { esFilters, IIndexPattern } from '../..'; interface Props { id: string; @@ -67,7 +67,7 @@ class FilterItemUI extends Component { this.props.className ); - const valueLabel = utils.getDisplayValueFromFilter(filter, this.props.indexPatterns); + const valueLabel = esFilters.getDisplayValueFromFilter(filter, this.props.indexPatterns); const dataTestSubjKey = filter.meta.key ? `filter-key-${filter.meta.key}` : ''; const dataTestSubjValue = filter.meta.value ? `filter-value-${valueLabel}` : ''; const dataTestSubjDisabled = `filter-${ diff --git a/src/plugins/data/server/index.ts b/src/plugins/data/server/index.ts index 81906a63bd49d..022eb0ae50295 100644 --- a/src/plugins/data/server/index.ts +++ b/src/plugins/data/server/index.ts @@ -24,14 +24,70 @@ export function plugin(initializerContext: PluginInitializerContext) { return new DataServerPlugin(initializerContext); } -export { DataServerPlugin as Plugin }; +/** + * Types to be shared externally + * @public + */ +export { IRequestTypesMap, IResponseTypesMap } from './search'; +export { + // field formats + FIELD_FORMAT_IDS, + IFieldFormat, + IFieldFormatId, + IFieldFormatType, + // index patterns + IIndexPattern, + IFieldType, + IFieldSubType, + // kbn field types + ES_FIELD_TYPES, + KBN_FIELD_TYPES, + // query + Query, + // timefilter + RefreshInterval, + TimeRange, +} from '../common'; + +/** + * Static code to be shared externally + * @public + */ export { IndexPatternsFetcher, FieldDescriptor, shouldReadFieldFromDocValues, } from './index_patterns'; - export * from './search'; -export * from '../common'; +export { + // es query + esFilters, + esKuery, + esQuery, + // field formats + BoolFormat, + BytesFormat, + ColorFormat, + DateFormat, + DateNanosFormat, + DEFAULT_CONVERTER_COLOR, + DurationFormat, + FieldFormat, + IpFormat, + NumberFormat, + PercentFormat, + RelativeDateFormat, + SourceFormat, + StaticLookupFormat, + StringFormat, + TruncateFormat, + UrlFormat, + // index patterns + isFilterable, + // kbn field types + castEsToKbnFieldTypeName, + getKbnFieldType, + getKbnTypeNames, +} from '../common'; -export { IRequestTypesMap, IResponseTypesMap } from './search'; +export { DataServerPlugin as Plugin }; diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/description_step/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/description_step/index.tsx index 29e1bc228e066..e6fec597ed8ea 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/description_step/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/create_rule/components/description_step/index.tsx @@ -22,7 +22,6 @@ import { IIndexPattern, esFilters, Query, - utils, } from '../../../../../../../../../../src/plugins/data/public'; import { FilterLabel } from './filter_label'; @@ -126,7 +125,7 @@ const getDescriptionItem = ( From 4be168ce27311e13fc17cf4d779f9dc28f254940 Mon Sep 17 00:00:00 2001 From: Pedro Luiz Cabral Salomon Prado Date: Thu, 12 Dec 2019 12:03:10 -0300 Subject: [PATCH 43/79] [Watcher] Removed overwritten property (#49998) --- .../public/np_ready/application/models/action/index_action.js | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/legacy/plugins/watcher/public/np_ready/application/models/action/index_action.js b/x-pack/legacy/plugins/watcher/public/np_ready/application/models/action/index_action.js index 7276ef59a3fc3..de84951cc3d27 100644 --- a/x-pack/legacy/plugins/watcher/public/np_ready/application/models/action/index_action.js +++ b/x-pack/legacy/plugins/watcher/public/np_ready/application/models/action/index_action.js @@ -35,7 +35,6 @@ export class IndexAction extends BaseAction { const result = super.upstreamJson; Object.assign(result, { - index: this.index, index: { index: this.index, } From 0279eb7b1c9d137ba70b814582b60c8a39d94a67 Mon Sep 17 00:00:00 2001 From: Thomas Watson Date: Thu, 12 Dec 2019 16:05:00 +0100 Subject: [PATCH 44/79] Ensure APM agent config file path respects CWD (#52880) --- src/apm.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/apm.js b/src/apm.js index 04a70ee71c53e..5effefaccd029 100644 --- a/src/apm.js +++ b/src/apm.js @@ -25,15 +25,13 @@ module.exports = function (serviceName = name) { if (process.env.kbnWorkerType === 'optmzr') return; const conf = { - serviceName: `${serviceName}-${version.replace(/\./g, '_')}` + serviceName: `${serviceName}-${version.replace(/\./g, '_')}`, }; - if (configFileExists()) conf.configFile = 'config/apm.js'; + const configFile = join(__dirname, '..', 'config', 'apm.js'); + + if (existsSync(configFile)) conf.configFile = configFile; else conf.active = false; require('elastic-apm-node').start(conf); }; - -function configFileExists() { - return existsSync(join(__dirname, '..', 'config', 'apm.js')); -} From 21334e7b15c52ea94b288c16a3c45d769a86a132 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 12 Dec 2019 16:15:39 +0100 Subject: [PATCH 45/79] [Console] Fix load from remote (#52814) * Fix load remote state * Clean up variable usage, add comment, move forceRetokenize to private method * Optimize sequence of checking hash on initial load --- .../editor/legacy/console_editor/editor.tsx | 77 +++++++++++++++---- .../application/hooks/use_set_input_editor.ts | 13 ++-- .../legacy_core_editor/legacy_core_editor.ts | 35 +++++---- 3 files changed, 90 insertions(+), 35 deletions(-) diff --git a/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.tsx b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.tsx index 442ed330e9b7a..a52c15c20c902 100644 --- a/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.tsx +++ b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.tsx @@ -20,6 +20,11 @@ import React, { CSSProperties, useCallback, useEffect, useRef, useState } from 'react'; import { EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { debounce } from 'lodash'; + +// Node v5 querystring for browser. +// @ts-ignore +import * as qs from 'querystring-browser'; import { EuiIcon, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { useServicesContext, useEditorReadContext } from '../../../../contexts'; @@ -80,17 +85,64 @@ function EditorUI() { useEffect(() => { editorInstanceRef.current = senseEditor.create(editorRef.current!); + const editor = editorInstanceRef.current; + + const readQueryParams = () => { + const [, queryString] = (window.location.hash || '').split('?'); + return qs.parse(queryString || ''); + }; + + const loadBufferFromRemote = (url: string) => { + if (/^https?:\/\//.test(url)) { + const loadFrom: Record = { + url, + // Having dataType here is required as it doesn't allow jQuery to `eval` content + // coming from the external source thereby preventing XSS attack. + dataType: 'text', + kbnXsrfToken: false, + }; + + if (/https?:\/\/api\.github\.com/.test(url)) { + loadFrom.headers = { Accept: 'application/vnd.github.v3.raw' }; + } - const { content: text } = history.getSavedEditorState() || { - content: DEFAULT_INPUT_VALUE, + // Fire and forget. + $.ajax(loadFrom).done(async data => { + const coreEditor = editor.getCoreEditor(); + await editor.update(data, true); + editor.moveToNextRequestEdge(false); + coreEditor.clearSelection(); + editor.highlightCurrentRequestsAndUpdateActionBar(); + coreEditor.getContainer().focus(); + }); + } }; - editorInstanceRef.current.update(text); + + // Support for loading a console snippet from a remote source, like support docs. + const onHashChange = debounce(() => { + const { load_from: url } = readQueryParams(); + if (!url) { + return; + } + loadBufferFromRemote(url); + }, 200); + window.addEventListener('hashchange', onHashChange); + + const initialQueryParams = readQueryParams(); + if (initialQueryParams.load_from) { + loadBufferFromRemote(initialQueryParams.load_from); + } else { + const { content: text } = history.getSavedEditorState() || { + content: DEFAULT_INPUT_VALUE, + }; + editor.update(text); + } function setupAutosave() { let timer: number; const saveDelay = 500; - editorInstanceRef.current!.getCoreEditor().on('change', () => { + editor.getCoreEditor().on('change', () => { if (timer) { clearTimeout(timer); } @@ -100,35 +152,34 @@ function EditorUI() { function saveCurrentState() { try { - const content = editorInstanceRef.current!.getCoreEditor().getValue(); + const content = editor.getCoreEditor().getValue(); history.updateCurrentState(content); } catch (e) { // Ignoring saving error } } - setInputEditor(editorInstanceRef.current); + setInputEditor(editor); setTextArea(editorRef.current!.querySelector('textarea')); mappings.retrieveAutoCompleteInfo(); - const unsubscribeResizer = subscribeResizeChecker( - editorRef.current!, - editorInstanceRef.current.getCoreEditor() - ); + const unsubscribeResizer = subscribeResizeChecker(editorRef.current!, editor.getCoreEditor()); setupAutosave(); return () => { unsubscribeResizer(); mappings.clearSubscriptions(); + window.removeEventListener('hashchange', onHashChange); }; }, [history, setInputEditor]); useEffect(() => { - applyCurrentSettings(editorInstanceRef.current!.getCoreEditor(), settings); + const { current: editor } = editorInstanceRef; + applyCurrentSettings(editor!.getCoreEditor(), settings); // Preserve legacy focus behavior after settings have updated. - editorInstanceRef - .current!.getCoreEditor() + editor! + .getCoreEditor() .getContainer() .focus(); }, [settings]); diff --git a/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_set_input_editor.ts b/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_set_input_editor.ts index 672f3e269ead9..fbd53762c27e6 100644 --- a/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_set_input_editor.ts +++ b/src/legacy/core_plugins/console/public/np_ready/application/hooks/use_set_input_editor.ts @@ -16,15 +16,18 @@ * specific language governing permissions and limitations * under the License. */ - +import { useCallback } from 'react'; import { useEditorActionContext } from '../contexts/editor_context'; import { instance as registry } from '../contexts/editor_context/editor_registry'; export const useSetInputEditor = () => { const dispatch = useEditorActionContext(); - return (editor: any) => { - dispatch({ type: 'setInputEditor', payload: editor }); - registry.setInputEditor(editor); - }; + return useCallback( + (editor: any) => { + dispatch({ type: 'setInputEditor', payload: editor }); + registry.setInputEditor(editor); + }, + [dispatch] + ); }; diff --git a/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/legacy_core_editor.ts b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/legacy_core_editor.ts index 621f4eeb0163e..608c73335b3e5 100644 --- a/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/legacy_core_editor.ts +++ b/src/legacy/core_plugins/console/public/np_ready/application/models/legacy_core_editor/legacy_core_editor.ts @@ -104,25 +104,12 @@ export class LegacyCoreEditor implements CoreEditor { return this.editor.getValue(); } - setValue(text: string, forceRetokenize: boolean): Promise { + async setValue(text: string, forceRetokenize: boolean): Promise { const session = this.editor.getSession(); session.setValue(text); - return new Promise(resolve => { - if (!forceRetokenize) { - // resolve immediately - resolve(); - return; - } - - // force update of tokens, but not on this thread to allow for ace rendering. - setTimeout(function() { - let i; - for (i = 0; i < session.getLength(); i++) { - session.getTokens(i); - } - resolve(); - }); - }); + if (forceRetokenize) { + await this.forceRetokenize(); + } } getLineValue(lineNumber: number): string { @@ -241,6 +228,20 @@ export class LegacyCoreEditor implements CoreEditor { return Boolean((this.editor as any).completer && (this.editor as any).completer.activated); } + private forceRetokenize() { + const session = this.editor.getSession(); + return new Promise(resolve => { + // force update of tokens, but not on this thread to allow for ace rendering. + setTimeout(function() { + let i; + for (i = 0; i < session.getLength(); i++) { + session.getTokens(i); + } + resolve(); + }); + }); + } + // eslint-disable-next-line @typescript-eslint/camelcase private DO_NOT_USE_onPaste(text: string) { if (text && curl.detectCURL(text)) { From 0c6516f1bc1818ab29393592f56cf045c9704029 Mon Sep 17 00:00:00 2001 From: patrykkopycinski Date: Thu, 12 Dec 2019 16:29:59 +0100 Subject: [PATCH 46/79] Add babel-plugin-styled-components to webpack config (#52862) --- package.json | 2 +- packages/kbn-babel-preset/package.json | 1 + packages/kbn-babel-preset/webpack_preset.js | 8 +++++++- x-pack/package.json | 2 +- yarn.lock | 19 ++++++++++++++----- 5 files changed, 24 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index c9e6bd05f6751..72f8b404617bc 100644 --- a/package.json +++ b/package.json @@ -355,7 +355,7 @@ "@types/semver": "^5.5.0", "@types/sinon": "^7.0.13", "@types/strip-ansi": "^3.0.0", - "@types/styled-components": "^4.4.0", + "@types/styled-components": "^4.4.1", "@types/supertest": "^2.0.5", "@types/supertest-as-promised": "^2.0.38", "@types/testing-library__react": "^9.1.2", diff --git a/packages/kbn-babel-preset/package.json b/packages/kbn-babel-preset/package.json index e554859928c0b..c8bb4a568c500 100644 --- a/packages/kbn-babel-preset/package.json +++ b/packages/kbn-babel-preset/package.json @@ -14,6 +14,7 @@ "@babel/preset-typescript": "^7.3.3", "babel-plugin-add-module-exports": "^1.0.2", "babel-plugin-filter-imports": "^3.0.0", + "babel-plugin-styled-components": "^1.10.6", "babel-plugin-transform-define": "^1.3.1", "babel-plugin-typescript-strip-namespaces": "^1.1.1" } diff --git a/packages/kbn-babel-preset/webpack_preset.js b/packages/kbn-babel-preset/webpack_preset.js index def848f4154bb..e6a8bd81b602e 100644 --- a/packages/kbn-babel-preset/webpack_preset.js +++ b/packages/kbn-babel-preset/webpack_preset.js @@ -33,6 +33,12 @@ module.exports = () => { plugins: [ require.resolve('@babel/plugin-transform-modules-commonjs'), require.resolve('@babel/plugin-syntax-dynamic-import'), - ] + [ + require.resolve('babel-plugin-styled-components'), + { + fileName: false, + }, + ], + ], }; }; diff --git a/x-pack/package.json b/x-pack/package.json index 4f806c6252f3f..06406f76af7af 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -98,7 +98,7 @@ "@types/reduce-reducers": "^0.3.0", "@types/redux-actions": "^2.2.1", "@types/sinon": "^7.0.13", - "@types/styled-components": "^4.4.0", + "@types/styled-components": "^4.4.1", "@types/supertest": "^2.0.5", "@types/tar-fs": "^1.16.1", "@types/tinycolor2": "^1.4.1", diff --git a/yarn.lock b/yarn.lock index 246586bf7bcff..d2606c3ce6bc7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3420,6 +3420,14 @@ resolved "https://registry.yarnpkg.com/@types/hoek/-/hoek-4.1.3.tgz#d1982d48fb0d2a0e5d7e9d91838264d8e428d337" integrity sha1-0ZgtSPsNKg5dfp2Rg4Jk2OQo0zc= +"@types/hoist-non-react-statics@*": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" + integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== + dependencies: + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + "@types/indent-string@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/indent-string/-/indent-string-3.0.0.tgz#9ebb391ceda548926f5819ad16405349641b999f" @@ -4012,11 +4020,12 @@ dependencies: "@types/node" "*" -"@types/styled-components@^4.4.0": - version "4.4.0" - resolved "https://registry.yarnpkg.com/@types/styled-components/-/styled-components-4.4.0.tgz#15a3d59533fd3a5bd013db4a7c4422ec542c59d2" - integrity sha512-QFl+w3hQJNHE64Or3PXMFpC3HAQDiuQLi5o9m1XPEwYWfgCZtAribO5ksjxnO8U0LG8Parh0ESCgVxo4VfxlHg== +"@types/styled-components@^4.4.1": + version "4.4.1" + resolved "https://registry.yarnpkg.com/@types/styled-components/-/styled-components-4.4.1.tgz#bc40cf5ce0708032f4b148b04ab3c470d3e74026" + integrity sha512-cQXT4pkAkM0unk/s26UBrJx9RmJ2rNUn2aDTgzp1rtu+tTkScebE78jbxNWhlqkA43XF3d41CcDlyl9Ldotm2g== dependencies: + "@types/hoist-non-react-statics" "*" "@types/react" "*" "@types/react-native" "*" csstype "^2.2.0" @@ -6184,7 +6193,7 @@ babel-plugin-react-docgen@^3.0.0: resolved "https://registry.yarnpkg.com/babel-plugin-require-context-hook-babel7/-/babel-plugin-require-context-hook-babel7-1.0.0.tgz#1273d4cee7e343d0860966653759a45d727e815d" integrity sha512-kez0BAN/cQoyO1Yu1nre1bQSYZEF93Fg7VQiBHFfMWuaZTy7vJSTT4FY68FwHTYG53Nyt0A7vpSObSVxwweQeQ== -"babel-plugin-styled-components@>= 1": +"babel-plugin-styled-components@>= 1", babel-plugin-styled-components@^1.10.6: version "1.10.6" resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-1.10.6.tgz#f8782953751115faf09a9f92431436912c34006b" integrity sha512-gyQj/Zf1kQti66100PhrCRjI5ldjaze9O0M3emXRPAN80Zsf8+e1thpTpaXJXVHXtaM4/+dJEgZHyS9Its+8SA== From 1489c32a1daf3e43ac2af93bf872ccaa60beae77 Mon Sep 17 00:00:00 2001 From: Brian Seeders Date: Thu, 12 Dec 2019 10:58:18 -0500 Subject: [PATCH 47/79] Print out agent debugging links during CI (#52812) --- vars/agentInfo.groovy | 42 ++++++++++++++++++++++++++++++++++++++ vars/kibanaPipeline.groovy | 2 ++ 2 files changed, 44 insertions(+) create mode 100644 vars/agentInfo.groovy diff --git a/vars/agentInfo.groovy b/vars/agentInfo.groovy new file mode 100644 index 0000000000000..b53ed23f81ff0 --- /dev/null +++ b/vars/agentInfo.groovy @@ -0,0 +1,42 @@ +def print() { + try { + def startTime = sh(script: "date -d '-3 minutes' -Iseconds | sed s/+/%2B/", returnStdout: true).trim() + def endTime = sh(script: "date -d '+1 hour 30 minutes' -Iseconds | sed s/+/%2B/", returnStdout: true).trim() + + def resourcesUrl = + ( + "https://infra-stats.elastic.co/app/kibana#/visualize/edit/8bd92360-1b92-11ea-b719-aba04518cc34" + + "?_g=(time:(from:'${startTime}',to:'${endTime}'))" + + "&_a=(query:'host.name:${env.NODE_NAME}')" + ) + .replaceAll("'", '%27') // Need to escape ' because of the shell echo below, but can't really replace "'" with "\'" because of groovy sandbox + .replaceAll(/\)$/, '%29') // This is just here because the URL parsing in the Jenkins console doesn't work right + + def logsStartTime = sh(script: "date -d '-3 minutes' +%s", returnStdout: true).trim() + def logsUrl = + ( + "https://infra-stats.elastic.co/app/infra#/logs" + + "?_g=()&flyoutOptions=(flyoutId:!n,flyoutVisibility:hidden,surroundingLogsId:!n)" + + "&logFilter=(expression:'host.name:${env.NODE_NAME}',kind:kuery)" + + "&logPosition=(position:(time:${logsStartTime}000),streamLive:!f)" + ) + .replaceAll("'", '%27') + .replaceAll('\\)', '%29') + + sh script: """ + set +x + echo 'Resource Graph:' + echo '${resourcesUrl}' + echo '' + echo 'Agent Logs:' + echo '${logsUrl}' + echo '' + echo 'SSH Command:' + echo "ssh -F ssh_config \$(hostname --ip-address)" + """, label: "Worker/Agent/Node debug links" + } catch(ex) { + print ex.toString() + } +} + +return this diff --git a/vars/kibanaPipeline.groovy b/vars/kibanaPipeline.groovy index dbb33f2766dac..18f214554b444 100644 --- a/vars/kibanaPipeline.groovy +++ b/vars/kibanaPipeline.groovy @@ -116,6 +116,8 @@ def legacyJobRunner(name) { def jobRunner(label, useRamDisk, closure) { node(label) { + agentInfo.print() + if (useRamDisk) { // Move to a temporary workspace, so that we can symlink the real workspace into /dev/shm def originalWorkspace = env.WORKSPACE From c5bf708c55ef2a360e1b30178bce89089009527d Mon Sep 17 00:00:00 2001 From: Maja Grubic Date: Thu, 12 Dec 2019 16:07:25 +0000 Subject: [PATCH 48/79] [Dashboard] Add visualization from dasbhoard empty screen (#52670) * [Dashboard] Add visualization from dasbhoard empty screen * Fixing linting errors * Fixing i18n error * Fixing unit test that was causing typecheck failure --- .../dashboard_empty_screen.test.tsx.snap | 74 ++- .../__tests__/dashboard_empty_screen.test.tsx | 11 + .../dashboard/dashboard_app_controller.tsx | 33 +- .../dashboard/dashboard_empty_screen.tsx | 32 +- .../dashboard_empty_screen_constants.tsx | 6 + .../__snapshots__/new_vis_modal.test.tsx.snap | 628 +++++++++++++++++- .../visualize/wizard/new_vis_modal.test.tsx | 31 + .../public/visualize/wizard/new_vis_modal.tsx | 6 +- .../embeddable/grid/_dashboard_grid.scss | 2 +- .../viewport/_dashboard_viewport.scss | 1 - .../apps/dashboard/empty_dashboard.js | 8 + .../services/dashboard/visualizations.js | 8 +- 12 files changed, 773 insertions(+), 67 deletions(-) diff --git a/src/legacy/core_plugins/kibana/public/dashboard/__tests__/__snapshots__/dashboard_empty_screen.test.tsx.snap b/src/legacy/core_plugins/kibana/public/dashboard/__tests__/__snapshots__/dashboard_empty_screen.test.tsx.snap index 8410040a0100d..4ea658bcd03ef 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/__tests__/__snapshots__/dashboard_empty_screen.test.tsx.snap +++ b/src/legacy/core_plugins/kibana/public/dashboard/__tests__/__snapshots__/dashboard_empty_screen.test.tsx.snap @@ -306,40 +306,56 @@ exports[`DashboardEmptyScreen renders correctly with visualize paragraph 1`] = ` className="euiSpacer euiSpacer--m" /> - -
-

- - visit the Visualize app - , - } - } +

- + + + + Create new + + + + +

diff --git a/src/legacy/core_plugins/kibana/public/dashboard/__tests__/dashboard_empty_screen.test.tsx b/src/legacy/core_plugins/kibana/public/dashboard/__tests__/dashboard_empty_screen.test.tsx index 69bdcf59bb227..653e7d4215eef 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/__tests__/dashboard_empty_screen.test.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/__tests__/dashboard_empty_screen.test.tsx @@ -47,4 +47,15 @@ describe('DashboardEmptyScreen', () => { const paragraph = findTestSubject(component, 'linkToVisualizeParagraph'); expect(paragraph.length).toBe(0); }); + + test('when specified, prop onVisualizeClick is called correctly', () => { + const onVisualizeClick = jest.fn(); + const component = mountComponent({ + ...defaultProps, + ...{ showLinkToVisualize: true, onVisualizeClick }, + }); + const button = findTestSubject(component, 'addVisualizationButton'); + button.simulate('click'); + expect(onVisualizeClick).toHaveBeenCalled(); + }); }); diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx index fd49b26e0d948..d8496ebb5cdbc 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx @@ -21,7 +21,7 @@ import _ from 'lodash'; import { i18n } from '@kbn/i18n'; import React from 'react'; import angular from 'angular'; -import { uniq, noop } from 'lodash'; +import { uniq } from 'lodash'; import { Subscription } from 'rxjs'; import { DashboardEmptyScreen, DashboardEmptyScreenProps } from './dashboard_empty_screen'; @@ -53,6 +53,7 @@ import { ErrorEmbeddable, ViewMode, openAddPanelFlyout, + EmbeddableFactoryNotFoundError, } from '../../../embeddable_api/public/np_ready/public'; import { DashboardAppState, NavAction, ConfirmModalFn, SavedDashboardPanel } from './types'; @@ -145,16 +146,20 @@ export class DashboardAppController { } $scope.showSaveQuery = dashboardCapabilities.saveQuery as boolean; - $scope.getShouldShowEditHelp = () => + const getShouldShowEditHelp = () => !dashboardStateManager.getPanels().length && dashboardStateManager.getIsEditMode() && !dashboardConfig.getHideWriteControls(); - $scope.getShouldShowViewHelp = () => + const getShouldShowViewHelp = () => !dashboardStateManager.getPanels().length && dashboardStateManager.getIsViewMode() && !dashboardConfig.getHideWriteControls(); + const addVisualization = () => { + navActions[TopNavIds.VISUALIZE](); + }; + const updateIndexPatterns = (container?: DashboardContainer) => { if (!container || isErrorEmbeddable(container)) { return; @@ -189,7 +194,7 @@ export class DashboardAppController { showLinkToVisualize: shouldShowEditHelp, }; if (shouldShowEditHelp) { - emptyScreenProps.onVisualizeClick = noop; + emptyScreenProps.onVisualizeClick = addVisualization; } return emptyScreenProps; }; @@ -205,8 +210,8 @@ export class DashboardAppController { if (dashboardContainer && !isErrorEmbeddable(dashboardContainer)) { expandedPanelId = dashboardContainer.getInput().expandedPanelId; } - const shouldShowEditHelp = $scope.getShouldShowEditHelp(); - const shouldShowViewHelp = $scope.getShouldShowViewHelp(); + const shouldShowEditHelp = getShouldShowEditHelp(); + const shouldShowViewHelp = getShouldShowViewHelp(); return { id: dashboardStateManager.savedDashboard.id || '', filters: queryFilter.getFilters(), @@ -261,8 +266,8 @@ export class DashboardAppController { dashboardContainer = container; dashboardContainer.renderEmpty = () => { - const shouldShowEditHelp = $scope.getShouldShowEditHelp(); - const shouldShowViewHelp = $scope.getShouldShowViewHelp(); + const shouldShowEditHelp = getShouldShowEditHelp(); + const shouldShowViewHelp = getShouldShowViewHelp(); const isEmptyState = shouldShowEditHelp || shouldShowViewHelp; return isEmptyState ? ( @@ -759,7 +764,17 @@ export class DashboardAppController { } }; - navActions[TopNavIds.VISUALIZE] = async () => {}; + navActions[TopNavIds.VISUALIZE] = async () => { + const type = 'visualization'; + const factory = embeddables.getEmbeddableFactory(type); + if (!factory) { + throw new EmbeddableFactoryNotFoundError(type); + } + const explicitInput = await factory.getExplicitInput(); + if (dashboardContainer) { + await dashboardContainer.addNewEmbeddable(type, explicitInput); + } + }; navActions[TopNavIds.OPTIONS] = anchorElement => { showOptionsPopover({ diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen.tsx b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen.tsx index 234228ba4166a..2fc78d64d0a0c 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen.tsx @@ -17,7 +17,7 @@ * under the License. */ import React from 'react'; -import { I18nProvider, FormattedMessage } from '@kbn/i18n/react'; +import { I18nProvider } from '@kbn/i18n/react'; import { EuiIcon, EuiLink, @@ -26,6 +26,7 @@ import { EuiPageBody, EuiPage, EuiText, + EuiButton, } from '@elastic/eui'; import * as constants from './dashboard_empty_screen_constants'; @@ -38,23 +39,20 @@ export interface DashboardEmptyScreenProps { export function DashboardEmptyScreen({ showLinkToVisualize, onLinkClick, + onVisualizeClick, }: DashboardEmptyScreenProps) { const linkToVisualizeParagraph = ( - -

- - {constants.visualizeAppLinkTest} - - ), - }} - /> -

-
+

+ + {constants.createNewVisualizationButton} + +

); const paragraph = ( description1: string, @@ -96,7 +94,7 @@ export function DashboardEmptyScreen({ ); return ( - + diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen_constants.tsx b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen_constants.tsx index 0f510375aaf59..03004f6270fef 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen_constants.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_empty_screen_constants.tsx @@ -76,3 +76,9 @@ export const visualizeAppLinkTest: string = i18n.translate( defaultMessage: 'visit the Visualize app', } ); +export const createNewVisualizationButton: string = i18n.translate( + 'kbn.dashboard.createNewVisualizationButton', + { + defaultMessage: 'Create new', + } +); diff --git a/src/legacy/core_plugins/kibana/public/visualize/wizard/__snapshots__/new_vis_modal.test.tsx.snap b/src/legacy/core_plugins/kibana/public/visualize/wizard/__snapshots__/new_vis_modal.test.tsx.snap index 04b7cddc75289..ca6b872c73f8f 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/wizard/__snapshots__/new_vis_modal.test.tsx.snap +++ b/src/legacy/core_plugins/kibana/public/visualize/wizard/__snapshots__/new_vis_modal.test.tsx.snap @@ -242,13 +242,70 @@ exports[`NewVisModal filter for visualization types should render as expected 1` aria-live="polite" class="euiScreenReaderOnly" > - 1 type found + 2 types found +

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

+
+ + + Vis with alias Url + + } + onBlur={[Function]} + onClick={[Function]} + onFocus={[Function]} + onMouseEnter={[Function]} + onMouseLeave={[Function]} + role="menuitem" + > + + { + const { location } = window; const defaultVisTypeParams = { hidden: false, visualization: class Controller { @@ -51,6 +52,12 @@ describe('NewVisModal', () => { stage: 'production', ...defaultVisTypeParams, }, + { + name: 'visWithAliasUrl', + title: 'Vis with alias Url', + stage: 'production', + aliasUrl: '/aliasUrl', + }, ]; const visTypes: TypesStart = { get: (id: string) => { @@ -69,6 +76,10 @@ describe('NewVisModal', () => { jest.clearAllMocks(); }); + afterAll(() => { + window.location = location; + }); + it('should render as expected', () => { const wrapper = mountWithIntl( { visButton.simulate('click'); expect(window.location.assign).toBeCalledWith('#/visualize/create?type=vis&foo=true&bar=42'); }); + + it('closes if visualization with aliasUrl and addToDashboard in editorParams', () => { + const onClose = jest.fn(); + window.location.assign = jest.fn(); + const wrapper = mountWithIntl( + + ); + const visButton = wrapper.find('button[data-test-subj="visType-visWithAliasUrl"]'); + visButton.simulate('click'); + expect(window.location.assign).toBeCalledWith('testbasepath/aliasUrl'); + expect(onClose).toHaveBeenCalled(); + }); }); describe('filter for visualization types', () => { diff --git a/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx b/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx index 0402265610fb1..e84797302589d 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx +++ b/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx @@ -132,8 +132,10 @@ class NewVisModal extends React.Component { @@ -54,6 +56,12 @@ export default function ({ getService, getPageObjects }) { expect(isAddPanelOpen).to.be(true); }); + it('should add new visualization from dashboard', async () => { + await testSubjects.click('addVisualizationButton'); + await dashboardVisualizations.createAndAddMarkdown({ name: 'Dashboard Test Markdown', markdown: 'Markdown text' }, false); + await PageObjects.dashboard.waitForRenderComplete(); + await dashboardExpect.markdownWithValuesExists(['Markdown text']); + }); }); } diff --git a/test/functional/services/dashboard/visualizations.js b/test/functional/services/dashboard/visualizations.js index 8cde98861ca88..97433a1e4923c 100644 --- a/test/functional/services/dashboard/visualizations.js +++ b/test/functional/services/dashboard/visualizations.js @@ -73,14 +73,16 @@ export function DashboardVisualizationProvider({ getService, getPageObjects }) { await dashboardAddPanel.addSavedSearch(name); } - async createAndAddMarkdown({ name, markdown }) { + async createAndAddMarkdown({ name, markdown }, checkForAddPanel = true) { log.debug(`createAndAddMarkdown(${markdown})`); const inViewMode = await PageObjects.dashboard.getIsInViewMode(); if (inViewMode) { await PageObjects.dashboard.switchToEditMode(); } - await dashboardAddPanel.ensureAddPanelIsShowing(); - await dashboardAddPanel.clickAddNewEmbeddableLink('visualization'); + if (checkForAddPanel) { + await dashboardAddPanel.ensureAddPanelIsShowing(); + await dashboardAddPanel.clickAddNewEmbeddableLink('visualization'); + } await PageObjects.visualize.clickMarkdownWidget(); await PageObjects.visualize.setMarkdownTxt(markdown); await PageObjects.visualize.clickGo(); From 06eeb59da3d1057adb22460e24011b0694d35609 Mon Sep 17 00:00:00 2001 From: Wylie Conlon Date: Thu, 12 Dec 2019 11:22:27 -0500 Subject: [PATCH 49/79] [Lens] Fix sort crash (#52694) --- .../indexpattern_plugin/state_helpers.test.ts | 15 +++++++++++---- .../public/indexpattern_plugin/state_helpers.ts | 9 ++++----- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/state_helpers.test.ts b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/state_helpers.test.ts index ad3d3f3816262..28486c8201da0 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/state_helpers.test.ts +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/state_helpers.test.ts @@ -32,8 +32,8 @@ describe('state_helpers', () => { operationType: 'terms', sourceField: 'source', params: { - orderBy: { type: 'alphabetical' }, - orderDirection: 'asc', + orderBy: { type: 'column', columnId: 'col2' }, + orderDirection: 'desc', size: 5, }, }; @@ -65,11 +65,18 @@ describe('state_helpers', () => { expect( deleteColumn({ state, columnId: 'col2', layerId: 'first' }).layers.first.columns ).toEqual({ - col1: termsColumn, + col1: { + ...termsColumn, + params: { + ...termsColumn.params, + orderBy: { type: 'alphabetical' }, + orderDirection: 'asc', + }, + }, }); }); - it('should execute adjustments for other columns', () => { + it('should adjust when deleting other columns', () => { const termsColumn: TermsIndexPatternColumn = { label: 'Top values of source', dataType: 'string', diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/state_helpers.ts b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/state_helpers.ts index db44d73a00337..f56f8089ea586 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/state_helpers.ts +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/state_helpers.ts @@ -124,11 +124,10 @@ export function deleteColumn({ layerId: string; columnId: string; }): IndexPatternPrivateState { - const newColumns = adjustColumnReferencesForChangedColumn( - state.layers[layerId].columns, - columnId - ); - delete newColumns[columnId]; + const hypotheticalColumns = { ...state.layers[layerId].columns }; + delete hypotheticalColumns[columnId]; + + const newColumns = adjustColumnReferencesForChangedColumn(hypotheticalColumns, columnId); return { ...state, From 85aea35c944abf3bb8d315cb599d0e19ce58ed1f Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Thu, 12 Dec 2019 17:35:22 +0100 Subject: [PATCH 50/79] Deangularize and typescriptify ui/saved_object (#51562) --- .../__tests__/get_saved_dashboard_mock.ts | 2 +- .../dashboard/dashboard_app_controller.tsx | 4 +- .../kibana/public/dashboard/legacy_imports.ts | 2 +- .../public/dashboard/lib/save_dashboard.ts | 4 +- .../saved_dashboard/saved_dashboard.d.ts | 2 +- .../saved_dashboard/saved_dashboards.js | 5 +- .../__tests__/directives/discover_field.js | 2 +- .../__tests__/directives/field_chooser.js | 2 +- .../__tests__/action_add_filter.js | 2 +- .../__tests__/action_set_predecessor_count.js | 2 +- .../__tests__/action_set_query_parameters.js | 2 +- .../__tests__/action_set_successor_count.js | 2 +- .../doc_table/__tests__/lib/rows_headers.js | 2 +- .../public/discover/helpers/build_services.ts | 37 +- .../kibana/public/discover/plugin.ts | 4 +- .../discover/saved_searches/_saved_search.js | 72 --- .../discover/saved_searches/_saved_search.ts | 71 +++ .../saved_searches/{index.js => index.ts} | 0 .../{saved_searches.js => saved_searches.ts} | 35 +- .../embeddable/visualize_embeddable.ts | 2 +- .../saved_visualizations/_saved_vis.js | 24 +- .../saved_visualizations.js | 10 +- .../timelion/public/services/saved_sheets.js | 5 +- .../__tests__/find_object_by_title.js | 2 +- .../saved_objects/__tests__/saved_object.js | 78 +-- .../{saved_object.d.ts => constants.ts} | 32 +- .../saved_objects/helpers/apply_es_resp.ts | 82 +++ .../helpers/build_saved_object.ts | 126 ++++ .../helpers/check_for_duplicate_title.ts | 69 +++ .../helpers/confirm_modal_promise.tsx | 59 ++ .../saved_objects/helpers/create_source.ts | 85 +++ .../display_duplicate_title_confirm_modal.ts | 49 ++ .../{ => helpers}/find_object_by_title.ts | 28 +- .../helpers/hydrate_index_pattern.ts | 55 ++ .../helpers/initialize_saved_object.ts | 59 ++ .../helpers/parse_search_source.ts | 97 ++++ .../helpers/save_saved_object.ts | 128 +++++ .../helpers/serialize_saved_object.ts | 98 ++++ src/legacy/ui/public/saved_objects/index.ts | 3 +- .../ui/public/saved_objects/saved_object.js | 541 ------------------ .../ui/public/saved_objects/saved_object.ts | 63 ++ ...bject_loader.js => saved_object_loader.ts} | 88 +-- src/legacy/ui/public/saved_objects/types.ts | 90 +++ .../plugins/graph/public/types/persistence.ts | 2 +- .../services/gis_map_saved_object_loader.js | 8 +- 45 files changed, 1297 insertions(+), 838 deletions(-) delete mode 100644 src/legacy/core_plugins/kibana/public/discover/saved_searches/_saved_search.js create mode 100644 src/legacy/core_plugins/kibana/public/discover/saved_searches/_saved_search.ts rename src/legacy/core_plugins/kibana/public/discover/saved_searches/{index.js => index.ts} (100%) rename src/legacy/core_plugins/kibana/public/discover/saved_searches/{saved_searches.js => saved_searches.ts} (60%) rename src/legacy/ui/public/saved_objects/{saved_object.d.ts => constants.ts} (55%) create mode 100644 src/legacy/ui/public/saved_objects/helpers/apply_es_resp.ts create mode 100644 src/legacy/ui/public/saved_objects/helpers/build_saved_object.ts create mode 100644 src/legacy/ui/public/saved_objects/helpers/check_for_duplicate_title.ts create mode 100644 src/legacy/ui/public/saved_objects/helpers/confirm_modal_promise.tsx create mode 100644 src/legacy/ui/public/saved_objects/helpers/create_source.ts create mode 100644 src/legacy/ui/public/saved_objects/helpers/display_duplicate_title_confirm_modal.ts rename src/legacy/ui/public/saved_objects/{ => helpers}/find_object_by_title.ts (75%) create mode 100644 src/legacy/ui/public/saved_objects/helpers/hydrate_index_pattern.ts create mode 100644 src/legacy/ui/public/saved_objects/helpers/initialize_saved_object.ts create mode 100644 src/legacy/ui/public/saved_objects/helpers/parse_search_source.ts create mode 100644 src/legacy/ui/public/saved_objects/helpers/save_saved_object.ts create mode 100644 src/legacy/ui/public/saved_objects/helpers/serialize_saved_object.ts delete mode 100644 src/legacy/ui/public/saved_objects/saved_object.js create mode 100644 src/legacy/ui/public/saved_objects/saved_object.ts rename src/legacy/ui/public/saved_objects/{saved_object_loader.js => saved_object_loader.ts} (60%) create mode 100644 src/legacy/ui/public/saved_objects/types.ts diff --git a/src/legacy/core_plugins/kibana/public/dashboard/__tests__/get_saved_dashboard_mock.ts b/src/legacy/core_plugins/kibana/public/dashboard/__tests__/get_saved_dashboard_mock.ts index 01468eadffb84..bf7135098ea74 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/__tests__/get_saved_dashboard_mock.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/__tests__/get_saved_dashboard_mock.ts @@ -41,5 +41,5 @@ export function getSavedDashboardMock( getQuery: () => ({ query: '', language: 'kuery' }), getFilters: () => [], ...config, - }; + } as SavedObjectDashboard; } diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx index d8496ebb5cdbc..24b64a88998f4 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx @@ -35,7 +35,7 @@ import { State, AppStateClass as TAppStateClass, KbnUrl, - SaveOptions, + SavedObjectSaveOpts, unhashUrl, } from './legacy_imports'; import { FilterStateManager, IndexPattern } from '../../../data/public'; @@ -608,7 +608,7 @@ export class DashboardAppController { * @return {Promise} * @resolved {String} - The id of the doc */ - function save(saveOptions: SaveOptions): Promise { + function save(saveOptions: SavedObjectSaveOpts): Promise { return saveDashboard(angular.toJson, timefilter, dashboardStateManager, saveOptions) .then(function(id) { if (id) { diff --git a/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts b/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts index af0a833399a52..adae063a1470b 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts @@ -30,7 +30,7 @@ export const legacyChrome = chrome; export { State } from 'ui/state_management/state'; export { AppState } from 'ui/state_management/app_state'; export { AppStateClass } from 'ui/state_management/app_state'; -export { SaveOptions } from 'ui/saved_objects/saved_object'; +export { SavedObjectSaveOpts } from 'ui/saved_objects/types'; export { npSetup, npStart } from 'ui/new_platform'; export { SavedObjectRegistryProvider } from 'ui/saved_objects'; export { IPrivate } from 'ui/private'; diff --git a/src/legacy/core_plugins/kibana/public/dashboard/lib/save_dashboard.ts b/src/legacy/core_plugins/kibana/public/dashboard/lib/save_dashboard.ts index e0d82373d3ad9..e322677433ce6 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/lib/save_dashboard.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/lib/save_dashboard.ts @@ -18,7 +18,7 @@ */ import { TimefilterContract } from 'src/plugins/data/public'; -import { SaveOptions } from '../legacy_imports'; +import { SavedObjectSaveOpts } from '../legacy_imports'; import { updateSavedDashboard } from './update_saved_dashboard'; import { DashboardStateManager } from '../dashboard_state_manager'; @@ -34,7 +34,7 @@ export function saveDashboard( toJson: (obj: any) => string, timeFilter: TimefilterContract, dashboardStateManager: DashboardStateManager, - saveOptions: SaveOptions + saveOptions: SavedObjectSaveOpts ): Promise { dashboardStateManager.saveState(); diff --git a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.d.ts b/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.d.ts index 4c417ed2954d3..20544fa97fdb0 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.d.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.d.ts @@ -17,7 +17,7 @@ * under the License. */ -import { SavedObject } from 'ui/saved_objects/saved_object'; +import { SavedObject } from 'ui/saved_objects/types'; import { SearchSourceContract } from '../../../../../ui/public/courier'; import { esFilters, Query, RefreshInterval } from '../../../../../../plugins/data/public'; diff --git a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboards.js b/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboards.js index 9b7d036590f1d..6b561c18a5d42 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboards.js +++ b/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboards.js @@ -22,6 +22,7 @@ import './saved_dashboard'; import { uiModules } from 'ui/modules'; import { SavedObjectLoader, SavedObjectsClientProvider } from 'ui/saved_objects'; import { savedObjectManagementRegistry } from '../../management/saved_object_registry'; +import { npStart } from '../../../../../ui/public/new_platform'; const module = uiModules.get('app/dashboard'); @@ -35,7 +36,7 @@ savedObjectManagementRegistry.register({ }); // This is the only thing that gets injected into controllers -module.service('savedDashboards', function (Private, SavedDashboard, kbnUrl, chrome) { +module.service('savedDashboards', function (Private, SavedDashboard) { const savedObjectClient = Private(SavedObjectsClientProvider); - return new SavedObjectLoader(SavedDashboard, kbnUrl, chrome, savedObjectClient); + return new SavedObjectLoader(SavedDashboard, savedObjectClient, npStart.core.chrome); }); diff --git a/src/legacy/core_plugins/kibana/public/discover/__tests__/directives/discover_field.js b/src/legacy/core_plugins/kibana/public/discover/__tests__/directives/discover_field.js index 92df04c536e43..5c6ba86455588 100644 --- a/src/legacy/core_plugins/kibana/public/discover/__tests__/directives/discover_field.js +++ b/src/legacy/core_plugins/kibana/public/discover/__tests__/directives/discover_field.js @@ -32,7 +32,7 @@ describe('discoverField', function () { let $scope; let indexPattern; let $elem; - beforeEach(() => pluginInstance.initializeServices(true)); + beforeEach(() => pluginInstance.initializeServices()); beforeEach(() => pluginInstance.initializeInnerAngular()); beforeEach(ngMock.module('app/discover')); beforeEach(ngMock.inject(function (Private, $rootScope, $compile) { diff --git a/src/legacy/core_plugins/kibana/public/discover/__tests__/directives/field_chooser.js b/src/legacy/core_plugins/kibana/public/discover/__tests__/directives/field_chooser.js index 34c6483349af6..a707402ff92b0 100644 --- a/src/legacy/core_plugins/kibana/public/discover/__tests__/directives/field_chooser.js +++ b/src/legacy/core_plugins/kibana/public/discover/__tests__/directives/field_chooser.js @@ -70,7 +70,7 @@ describe('discover field chooser directives', function () { on-remove-field="removeField" > `); - beforeEach(() => pluginInstance.initializeServices(true)); + beforeEach(() => pluginInstance.initializeServices()); beforeEach(() => pluginInstance.initializeInnerAngular()); beforeEach(ngMock.module('app/discover', ($provide) => { diff --git a/src/legacy/core_plugins/kibana/public/discover/angular/context/query_parameters/__tests__/action_add_filter.js b/src/legacy/core_plugins/kibana/public/discover/angular/context/query_parameters/__tests__/action_add_filter.js index 645ca32924ede..aa3c260eed52d 100644 --- a/src/legacy/core_plugins/kibana/public/discover/angular/context/query_parameters/__tests__/action_add_filter.js +++ b/src/legacy/core_plugins/kibana/public/discover/angular/context/query_parameters/__tests__/action_add_filter.js @@ -27,7 +27,7 @@ import { npStart } from 'ui/new_platform'; describe('context app', function () { beforeEach(() => pluginInstance.initializeInnerAngular()); - beforeEach(() => pluginInstance.initializeServices(true)); + beforeEach(() => pluginInstance.initializeServices()); beforeEach(ngMock.module('app/discover')); beforeEach(ngMock.module(function createServiceStubs($provide) { $provide.value('indexPatterns', createIndexPatternsStub()); diff --git a/src/legacy/core_plugins/kibana/public/discover/angular/context/query_parameters/__tests__/action_set_predecessor_count.js b/src/legacy/core_plugins/kibana/public/discover/angular/context/query_parameters/__tests__/action_set_predecessor_count.js index a8bef6fe75c79..e1821eada79ed 100644 --- a/src/legacy/core_plugins/kibana/public/discover/angular/context/query_parameters/__tests__/action_set_predecessor_count.js +++ b/src/legacy/core_plugins/kibana/public/discover/angular/context/query_parameters/__tests__/action_set_predecessor_count.js @@ -26,7 +26,7 @@ import { getQueryParameterActions } from '../actions'; describe('context app', function () { beforeEach(() => pluginInstance.initializeInnerAngular()); - beforeEach(() => pluginInstance.initializeServices(true)); + beforeEach(() => pluginInstance.initializeServices()); beforeEach(ngMock.module('app/discover')); describe('action setPredecessorCount', function () { diff --git a/src/legacy/core_plugins/kibana/public/discover/angular/context/query_parameters/__tests__/action_set_query_parameters.js b/src/legacy/core_plugins/kibana/public/discover/angular/context/query_parameters/__tests__/action_set_query_parameters.js index a43a8a11a7bf8..348ea2c55790a 100644 --- a/src/legacy/core_plugins/kibana/public/discover/angular/context/query_parameters/__tests__/action_set_query_parameters.js +++ b/src/legacy/core_plugins/kibana/public/discover/angular/context/query_parameters/__tests__/action_set_query_parameters.js @@ -27,7 +27,7 @@ import { getQueryParameterActions } from '../actions'; describe('context app', function () { beforeEach(() => pluginInstance.initializeInnerAngular()); - beforeEach(() => pluginInstance.initializeServices(true)); + beforeEach(() => pluginInstance.initializeServices()); beforeEach(ngMock.module('app/discover')); describe('action setQueryParameters', function () { diff --git a/src/legacy/core_plugins/kibana/public/discover/angular/context/query_parameters/__tests__/action_set_successor_count.js b/src/legacy/core_plugins/kibana/public/discover/angular/context/query_parameters/__tests__/action_set_successor_count.js index 4bbd462aaa4b0..c03158722347b 100644 --- a/src/legacy/core_plugins/kibana/public/discover/angular/context/query_parameters/__tests__/action_set_successor_count.js +++ b/src/legacy/core_plugins/kibana/public/discover/angular/context/query_parameters/__tests__/action_set_successor_count.js @@ -27,7 +27,7 @@ import { getQueryParameterActions } from '../actions'; describe('context app', function () { beforeEach(() => pluginInstance.initializeInnerAngular()); - beforeEach(() => pluginInstance.initializeServices(true)); + beforeEach(() => pluginInstance.initializeServices()); beforeEach(ngMock.module('app/discover')); describe('action setSuccessorCount', function () { diff --git a/src/legacy/core_plugins/kibana/public/discover/angular/doc_table/__tests__/lib/rows_headers.js b/src/legacy/core_plugins/kibana/public/discover/angular/doc_table/__tests__/lib/rows_headers.js index 666261610fa7c..c8e8e216d0dea 100644 --- a/src/legacy/core_plugins/kibana/public/discover/angular/doc_table/__tests__/lib/rows_headers.js +++ b/src/legacy/core_plugins/kibana/public/discover/angular/doc_table/__tests__/lib/rows_headers.js @@ -37,7 +37,7 @@ describe('Doc Table', function () { let fakeRowVals; let stubFieldFormatConverter; - beforeEach(() => pluginInstance.initializeServices(true)); + beforeEach(() => pluginInstance.initializeServices()); beforeEach(() => pluginInstance.initializeInnerAngular()); beforeEach(ngMock.module('app/discover')); beforeEach( diff --git a/src/legacy/core_plugins/kibana/public/discover/helpers/build_services.ts b/src/legacy/core_plugins/kibana/public/discover/helpers/build_services.ts index b72bd27a31cf9..14ea4e99b0de4 100644 --- a/src/legacy/core_plugins/kibana/public/discover/helpers/build_services.ts +++ b/src/legacy/core_plugins/kibana/public/discover/helpers/build_services.ts @@ -25,14 +25,12 @@ import { IUiSettingsClient, } from 'kibana/public'; import * as docViewsRegistry from 'ui/registry/doc_views'; -import chromeLegacy from 'ui/chrome'; -import { IPrivate } from 'ui/private'; import { FilterManager, TimefilterContract, IndexPatternsContract } from 'src/plugins/data/public'; // @ts-ignore import { createSavedSearchesService } from '../saved_searches/saved_searches'; // @ts-ignore -import { createSavedSearchFactory } from '../saved_searches/_saved_search'; import { DiscoverStartPlugins } from '../plugin'; +import { DataStart } from '../../../../data/public'; import { EuiUtilsStart } from '../../../../../../plugins/eui_utils/public'; import { SavedSearch } from '../types'; import { SharePluginStart } from '../../../../../../plugins/share/public'; @@ -42,6 +40,7 @@ export interface DiscoverServices { capabilities: Capabilities; chrome: ChromeStart; core: CoreStart; + data: DataStart; docLinks: DocLinksStart; docViewsRegistry: docViewsRegistry.DocViewsRegistry; eui_utils: EuiUtilsStart; @@ -52,35 +51,19 @@ export interface DiscoverServices { share: SharePluginStart; timefilter: TimefilterContract; toastNotifications: ToastsStart; - // legacy getSavedSearchById: (id: string) => Promise; getSavedSearchUrlById: (id: string) => Promise; uiSettings: IUiSettingsClient; } - -export async function buildGlobalAngularServices() { - const injector = await chromeLegacy.dangerouslyGetActiveInjector(); - const Private = injector.get('Private'); - const kbnUrl = injector.get('kbnUrl'); - const SavedSearchFactory = createSavedSearchFactory(Private); - const service = createSavedSearchesService(Private, SavedSearchFactory, kbnUrl, chromeLegacy); - return { - getSavedSearchById: async (id: string) => service.get(id), - getSavedSearchUrlById: async (id: string) => service.urlFor(id), +export async function buildServices(core: CoreStart, plugins: DiscoverStartPlugins) { + const services = { + savedObjectsClient: core.savedObjects.client, + indexPatterns: plugins.data.indexPatterns, + chrome: core.chrome, + overlays: core.overlays, }; -} - -export async function buildServices(core: CoreStart, plugins: DiscoverStartPlugins, test: false) { - const globalAngularServices = !test - ? await buildGlobalAngularServices() - : { - getSavedSearchById: async (id: string) => void id, - getSavedSearchUrlById: async (id: string) => void id, - State: null, - }; - + const savedObjectService = createSavedSearchesService(services); return { - ...globalAngularServices, addBasePath: core.http.basePath.prepend, capabilities: core.application.capabilities, chrome: core.chrome, @@ -90,6 +73,8 @@ export async function buildServices(core: CoreStart, plugins: DiscoverStartPlugi docViewsRegistry, eui_utils: plugins.eui_utils, filterManager: plugins.data.query.filterManager, + getSavedSearchById: async (id: string) => savedObjectService.get(id), + getSavedSearchUrlById: async (id: string) => savedObjectService.urlFor(id), indexPatterns: plugins.data.indexPatterns, inspector: plugins.inspector, // @ts-ignore diff --git a/src/legacy/core_plugins/kibana/public/discover/plugin.ts b/src/legacy/core_plugins/kibana/public/discover/plugin.ts index 6679e8a3b8826..a5a1ead93188a 100644 --- a/src/legacy/core_plugins/kibana/public/discover/plugin.ts +++ b/src/legacy/core_plugins/kibana/public/discover/plugin.ts @@ -106,11 +106,11 @@ export class DiscoverPlugin implements Plugin { this.innerAngularInitialized = true; }; - this.initializeServices = async (test = false) => { + this.initializeServices = async () => { if (this.servicesInitialized) { return; } - const services = await buildServices(core, plugins, test); + const services = await buildServices(core, plugins); setServices(services); this.servicesInitialized = true; }; diff --git a/src/legacy/core_plugins/kibana/public/discover/saved_searches/_saved_search.js b/src/legacy/core_plugins/kibana/public/discover/saved_searches/_saved_search.js deleted file mode 100644 index db2b2b5b22af7..0000000000000 --- a/src/legacy/core_plugins/kibana/public/discover/saved_searches/_saved_search.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { createLegacyClass } from 'ui/utils/legacy_class'; -import { SavedObjectProvider } from 'ui/saved_objects/saved_object'; - -import { uiModules } from 'ui/modules'; - -const module = uiModules.get('discover/saved_searches', []); - -export function createSavedSearchFactory(Private) { - const SavedObject = Private(SavedObjectProvider); - createLegacyClass(SavedSearch).inherits(SavedObject); - function SavedSearch(id) { - SavedObject.call(this, { - type: SavedSearch.type, - mapping: SavedSearch.mapping, - searchSource: SavedSearch.searchSource, - id: id, - defaults: { - title: '', - description: '', - columns: [], - hits: 0, - sort: [], - version: 1, - }, - }); - - this.showInRecentlyAccessed = true; - } - - SavedSearch.type = 'search'; - - SavedSearch.mapping = { - title: 'text', - description: 'text', - hits: 'integer', - columns: 'keyword', - sort: 'keyword', - version: 'integer', - }; - - // Order these fields to the top, the rest are alphabetical - SavedSearch.fieldOrder = ['title', 'description']; - - SavedSearch.searchSource = true; - - SavedSearch.prototype.getFullPath = function () { - return `/app/kibana#/discover/${this.id}`; - }; - - return SavedSearch; -} - -module.factory('SavedSearch', createSavedSearchFactory); diff --git a/src/legacy/core_plugins/kibana/public/discover/saved_searches/_saved_search.ts b/src/legacy/core_plugins/kibana/public/discover/saved_searches/_saved_search.ts new file mode 100644 index 0000000000000..113d13287bd12 --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/discover/saved_searches/_saved_search.ts @@ -0,0 +1,71 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { SavedObjectKibanaServices } from 'ui/saved_objects/types'; +import { createSavedObjectClass } from 'ui/saved_objects/saved_object'; + +export function createSavedSearchClass(services: SavedObjectKibanaServices) { + const SavedObjectClass = createSavedObjectClass(services); + + class SavedSearch extends SavedObjectClass { + public static type: string = 'search'; + public static mapping = { + title: 'text', + description: 'text', + hits: 'integer', + columns: 'keyword', + sort: 'keyword', + version: 'integer', + }; + // Order these fields to the top, the rest are alphabetical + public static fieldOrder = ['title', 'description']; + public static searchSource = true; + + public id: string; + public showInRecentlyAccessed: boolean; + + constructor(id: string) { + super({ + id, + type: 'search', + mapping: { + title: 'text', + description: 'text', + hits: 'integer', + columns: 'keyword', + sort: 'keyword', + version: 'integer', + }, + searchSource: true, + defaults: { + title: '', + description: '', + columns: [], + hits: 0, + sort: [], + version: 1, + }, + }); + this.showInRecentlyAccessed = true; + this.id = id; + this.getFullPath = () => `/app/kibana#/discover/${String(id)}`; + } + } + + return SavedSearch; +} diff --git a/src/legacy/core_plugins/kibana/public/discover/saved_searches/index.js b/src/legacy/core_plugins/kibana/public/discover/saved_searches/index.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/saved_searches/index.js rename to src/legacy/core_plugins/kibana/public/discover/saved_searches/index.ts diff --git a/src/legacy/core_plugins/kibana/public/discover/saved_searches/saved_searches.js b/src/legacy/core_plugins/kibana/public/discover/saved_searches/saved_searches.ts similarity index 60% rename from src/legacy/core_plugins/kibana/public/discover/saved_searches/saved_searches.js rename to src/legacy/core_plugins/kibana/public/discover/saved_searches/saved_searches.ts index 7ebcba903cc7f..46fdd3a7baedc 100644 --- a/src/legacy/core_plugins/kibana/public/discover/saved_searches/saved_searches.js +++ b/src/legacy/core_plugins/kibana/public/discover/saved_searches/saved_searches.ts @@ -16,12 +16,14 @@ * specific language governing permissions and limitations * under the License. */ - -import './_saved_search'; +import { npStart } from 'ui/new_platform'; +// @ts-ignore import { uiModules } from 'ui/modules'; -import { SavedObjectLoader, SavedObjectsClientProvider } from 'ui/saved_objects'; +import { SavedObjectLoader } from 'ui/saved_objects'; +import { SavedObjectKibanaServices } from 'ui/saved_objects/types'; +// @ts-ignore import { savedObjectManagementRegistry } from '../../management/saved_object_registry'; - +import { createSavedSearchClass } from './_saved_search'; // Register this service with the saved object registry so it can be // edited by the object editor. @@ -30,9 +32,13 @@ savedObjectManagementRegistry.register({ title: 'searches', }); -export function createSavedSearchesService(Private, SavedSearch, kbnUrl, chrome) { - const savedObjectClient = Private(SavedObjectsClientProvider); - const savedSearchLoader = new SavedObjectLoader(SavedSearch, kbnUrl, chrome, savedObjectClient); +export function createSavedSearchesService(services: SavedObjectKibanaServices) { + const SavedSearchClass = createSavedSearchClass(services); + const savedSearchLoader = new SavedObjectLoader( + SavedSearchClass, + services.savedObjectsClient, + services.chrome + ); // Customize loader properties since adding an 's' on type doesn't work for type 'search' . savedSearchLoader.loaderProperties = { name: 'searches', @@ -40,11 +46,18 @@ export function createSavedSearchesService(Private, SavedSearch, kbnUrl, chrome) nouns: 'saved searches', }; - savedSearchLoader.urlFor = (id) => { - return kbnUrl.eval('#/discover/{{id}}', { id: id }); - }; + savedSearchLoader.urlFor = (id: string) => `#/discover/${encodeURIComponent(id)}`; return savedSearchLoader; } +// this is needed for saved object management const module = uiModules.get('discover/saved_searches'); -module.service('savedSearches', createSavedSearchesService); +module.service('savedSearches', () => { + const services = { + savedObjectsClient: npStart.core.savedObjects.client, + indexPatterns: npStart.plugins.data.indexPatterns, + chrome: npStart.core.chrome, + overlays: npStart.core.overlays, + }; + return createSavedSearchesService(services); +}); diff --git a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts index 7ab60f8867c38..8e414984a0c08 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts @@ -22,7 +22,7 @@ import { PersistedState } from 'ui/persisted_state'; import { Subscription } from 'rxjs'; import * as Rx from 'rxjs'; import { buildPipeline } from 'ui/visualize/loader/pipeline_helpers'; -import { SavedObject } from 'ui/saved_objects/saved_object'; +import { SavedObject } from 'ui/saved_objects/types'; import { Vis } from 'ui/vis'; import { queryGeohashBounds } from 'ui/visualize/loader/utils'; import { getTableAggs } from 'ui/visualize/loader/pipeline_helpers/utilities'; diff --git a/src/legacy/core_plugins/kibana/public/visualize/saved_visualizations/_saved_vis.js b/src/legacy/core_plugins/kibana/public/visualize/saved_visualizations/_saved_vis.js index ae4b4d1c779df..a30973ab6a461 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/saved_visualizations/_saved_vis.js +++ b/src/legacy/core_plugins/kibana/public/visualize/saved_visualizations/_saved_vis.js @@ -38,7 +38,7 @@ import { uiModules .get('app/visualize') - .factory('SavedVis', function (Promise, savedSearches, Private) { + .factory('SavedVis', function (savedSearches, Private) { const SavedObject = Private(SavedObjectProvider); createLegacyClass(SavedVis).inherits(SavedObject); function SavedVis(opts) { @@ -95,18 +95,15 @@ uiModules return `/app/kibana#${VisualizeConstants.EDIT_PATH}/${this.id}`; }; - SavedVis.prototype._afterEsResp = function () { + SavedVis.prototype._afterEsResp = async function () { const self = this; - return self._getLinkedSavedSearch() - .then(function () { - self.searchSource.setField('size', 0); - - return self.vis ? self._updateVis() : self._createVis(); - }); + await self._getLinkedSavedSearch(); + self.searchSource.setField('size', 0); + return self.vis ? self._updateVis() : self._createVis(); }; - SavedVis.prototype._getLinkedSavedSearch = Promise.method(function () { + SavedVis.prototype._getLinkedSavedSearch = async function () { const self = this; const linkedSearch = !!self.savedSearchId; const current = self.savedSearch; @@ -122,13 +119,10 @@ uiModules } if (linkedSearch) { - return savedSearches.get(self.savedSearchId) - .then(function (savedSearch) { - self.savedSearch = savedSearch; - self.searchSource.setParent(self.savedSearch.searchSource); - }); + self.savedSearch = await savedSearches.get(self.savedSearchId); + self.searchSource.setParent(self.savedSearch.searchSource); } - }); + }; SavedVis.prototype._createVis = function () { const self = this; diff --git a/src/legacy/core_plugins/kibana/public/visualize/saved_visualizations/saved_visualizations.js b/src/legacy/core_plugins/kibana/public/visualize/saved_visualizations/saved_visualizations.js index c391eb872e29d..dd12b7e38798f 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/saved_visualizations/saved_visualizations.js +++ b/src/legacy/core_plugins/kibana/public/visualize/saved_visualizations/saved_visualizations.js @@ -24,6 +24,7 @@ import { savedObjectManagementRegistry } from '../../management/saved_object_reg import { start as visualizations } from '../../../../visualizations/public/np_ready/public/legacy'; import { createVisualizeEditUrl } from '../visualize_constants'; import { findListItems } from './find_list_items'; +import { npStart } from '../../../../../ui/public/new_platform'; const app = uiModules.get('app/visualize'); @@ -34,14 +35,13 @@ savedObjectManagementRegistry.register({ title: 'visualizations', }); -app.service('savedVisualizations', function (SavedVis, Private, kbnUrl, chrome) { +app.service('savedVisualizations', function (SavedVis, Private) { const visTypes = visualizations.types; const savedObjectClient = Private(SavedObjectsClientProvider); const saveVisualizationLoader = new SavedObjectLoader( SavedVis, - kbnUrl, - chrome, - savedObjectClient + savedObjectClient, + npStart.core.chrome ); saveVisualizationLoader.mapHitSource = function (source, id) { @@ -73,7 +73,7 @@ app.service('savedVisualizations', function (SavedVis, Private, kbnUrl, chrome) }; saveVisualizationLoader.urlFor = function (id) { - return kbnUrl.eval('#/visualize/edit/{{id}}', { id: id }); + return `#/visualize/edit/${encodeURIComponent(id)}`; }; // This behaves similarly to find, except it returns visualizations that are diff --git a/src/legacy/core_plugins/timelion/public/services/saved_sheets.js b/src/legacy/core_plugins/timelion/public/services/saved_sheets.js index d303069e74dea..86cde9e06240a 100644 --- a/src/legacy/core_plugins/timelion/public/services/saved_sheets.js +++ b/src/legacy/core_plugins/timelion/public/services/saved_sheets.js @@ -21,6 +21,7 @@ import { SavedObjectLoader, SavedObjectsClientProvider } from 'ui/saved_objects' import { savedObjectManagementRegistry } from 'plugins/kibana/management/saved_object_registry'; import { uiModules } from 'ui/modules'; import './_saved_sheet.js'; +import { npStart } from '../../../../ui/public/new_platform'; const module = uiModules.get('app/sheet'); @@ -32,9 +33,9 @@ savedObjectManagementRegistry.register({ }); // This is the only thing that gets injected into controllers -module.service('savedSheets', function (Private, SavedSheet, kbnUrl, chrome) { +module.service('savedSheets', function (Private, SavedSheet, kbnUrl) { const savedObjectClient = Private(SavedObjectsClientProvider); - const savedSheetLoader = new SavedObjectLoader(SavedSheet, kbnUrl, chrome, savedObjectClient); + const savedSheetLoader = new SavedObjectLoader(SavedSheet, savedObjectClient, npStart.core.chrome); savedSheetLoader.urlFor = function (id) { return kbnUrl.eval('#/{{id}}', { id: id }); }; diff --git a/src/legacy/ui/public/saved_objects/__tests__/find_object_by_title.js b/src/legacy/ui/public/saved_objects/__tests__/find_object_by_title.js index 766ed44a4c0fe..ccd2ba6a6c510 100644 --- a/src/legacy/ui/public/saved_objects/__tests__/find_object_by_title.js +++ b/src/legacy/ui/public/saved_objects/__tests__/find_object_by_title.js @@ -19,7 +19,7 @@ import sinon from 'sinon'; import expect from '@kbn/expect'; -import { findObjectByTitle } from '../find_object_by_title'; +import { findObjectByTitle } from '../helpers/find_object_by_title'; import { SimpleSavedObject } from '../../../../../core/public'; describe('findObjectByTitle', () => { diff --git a/src/legacy/ui/public/saved_objects/__tests__/saved_object.js b/src/legacy/ui/public/saved_objects/__tests__/saved_object.js index 56124a047ba6d..55d0f800ae7ff 100644 --- a/src/legacy/ui/public/saved_objects/__tests__/saved_object.js +++ b/src/legacy/ui/public/saved_objects/__tests__/saved_object.js @@ -22,7 +22,7 @@ import expect from '@kbn/expect'; import sinon from 'sinon'; import Bluebird from 'bluebird'; -import { SavedObjectProvider } from '../saved_object'; +import { createSavedObjectClass } from '../saved_object'; import StubIndexPattern from 'test_utils/stub_index_pattern'; import { SavedObjectsClientProvider } from '../saved_objects_client_provider'; import { InvalidJSONProperty } from '../../../../../plugins/kibana_utils/public'; @@ -97,9 +97,9 @@ describe('Saved Object', function () { ); beforeEach(ngMock.inject(function (es, Private, $window) { - SavedObject = Private(SavedObjectProvider); - esDataStub = es; savedObjectsClientStub = Private(SavedObjectsClientProvider); + SavedObject = createSavedObjectClass({ savedObjectsClient: savedObjectsClientStub }); + esDataStub = es; window = $window; })); @@ -110,66 +110,6 @@ describe('Saved Object', function () { sinon.stub(esDataStub, 'create').returns(Bluebird.reject(mock409FetchError)); } - describe('when true', function () { - it('requests confirmation and updates on yes response', function () { - stubESResponse(getMockedDocResponse('myId')); - return createInitializedSavedObject({ type: 'dashboard', id: 'myId' }).then(savedObject => { - const createStub = sinon.stub(savedObjectsClientStub, 'create'); - createStub.onFirstCall().returns(Bluebird.reject(mock409FetchError)); - createStub.onSecondCall().returns(Bluebird.resolve({ id: 'myId' })); - - stubConfirmOverwrite(); - - savedObject.lastSavedTitle = 'original title'; - savedObject.title = 'new title'; - return savedObject.save({ confirmOverwrite: true }) - .then(() => { - expect(window.confirm.called).to.be(true); - expect(savedObject.id).to.be('myId'); - expect(savedObject.isSaving).to.be(false); - expect(savedObject.lastSavedTitle).to.be('new title'); - expect(savedObject.title).to.be('new title'); - }); - }); - }); - - it('does not update on no response', function () { - stubESResponse(getMockedDocResponse('HI')); - return createInitializedSavedObject({ type: 'dashboard', id: 'HI' }).then(savedObject => { - window.confirm = sinon.stub().returns(false); - - sinon.stub(savedObjectsClientStub, 'create').returns(Bluebird.reject(mock409FetchError)); - - savedObject.lastSavedTitle = 'original title'; - savedObject.title = 'new title'; - return savedObject.save({ confirmOverwrite: true }) - .then(() => { - expect(savedObject.id).to.be('HI'); - expect(savedObject.isSaving).to.be(false); - expect(savedObject.lastSavedTitle).to.be('original title'); - expect(savedObject.title).to.be('new title'); - }); - }); - }); - - it('handles create failures', function () { - stubESResponse(getMockedDocResponse('myId')); - return createInitializedSavedObject({ type: 'dashboard', id: 'myId' }).then(savedObject => { - stubConfirmOverwrite(); - - sinon.stub(savedObjectsClientStub, 'create').returns(Bluebird.reject(mock409FetchError)); - - return savedObject.save({ confirmOverwrite: true }) - .then(() => { - expect(true).to.be(false); // Force failure, the save should not succeed. - }) - .catch(() => { - expect(window.confirm.called).to.be(true); - }); - }); - }); - }); - it('when false does not request overwrite', function () { const mockDocResponse = getMockedDocResponse('myId'); stubESResponse(mockDocResponse); @@ -691,18 +631,6 @@ describe('Saved Object', function () { }); }); - it('init is called', function () { - const initCallback = sinon.spy(); - const config = { - type: 'dashboard', - init: initCallback - }; - - return createInitializedSavedObject(config).then(() => { - expect(initCallback.called).to.be(true); - }); - }); - describe('searchSource', function () { it('when true, creates index', function () { const indexPatternId = 'testIndexPattern'; diff --git a/src/legacy/ui/public/saved_objects/saved_object.d.ts b/src/legacy/ui/public/saved_objects/constants.ts similarity index 55% rename from src/legacy/ui/public/saved_objects/saved_object.d.ts rename to src/legacy/ui/public/saved_objects/constants.ts index dc6496eacfcbe..e1684aa1d19d5 100644 --- a/src/legacy/ui/public/saved_objects/saved_object.d.ts +++ b/src/legacy/ui/public/saved_objects/constants.ts @@ -16,15 +16,25 @@ * specific language governing permissions and limitations * under the License. */ +import { i18n } from '@kbn/i18n'; -export interface SaveOptions { - confirmOverwrite: boolean; - isTitleDuplicateConfirmed: boolean; - onTitleDuplicate: () => void; -} - -export interface SavedObject { - save: (saveOptions: SaveOptions) => Promise; - copyOnSave: boolean; - id?: string; -} +/** + * An error message to be used when the user rejects a confirm overwrite. + * @type {string} + */ +export const OVERWRITE_REJECTED = i18n.translate( + 'common.ui.savedObjects.overwriteRejectedDescription', + { + defaultMessage: 'Overwrite confirmation was rejected', + } +); +/** + * An error message to be used when the user rejects a confirm save with duplicate title. + * @type {string} + */ +export const SAVE_DUPLICATE_REJECTED = i18n.translate( + 'common.ui.savedObjects.saveDuplicateRejectedDescription', + { + defaultMessage: 'Save with duplicate title confirmation was rejected', + } +); diff --git a/src/legacy/ui/public/saved_objects/helpers/apply_es_resp.ts b/src/legacy/ui/public/saved_objects/helpers/apply_es_resp.ts new file mode 100644 index 0000000000000..77f504d108076 --- /dev/null +++ b/src/legacy/ui/public/saved_objects/helpers/apply_es_resp.ts @@ -0,0 +1,82 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import _ from 'lodash'; +import { EsResponse, SavedObject, SavedObjectConfig } from 'ui/saved_objects/types'; +import { parseSearchSource } from 'ui/saved_objects/helpers/parse_search_source'; +import { expandShorthand, SavedObjectNotFound } from '../../../../../plugins/kibana_utils/public'; +import { IndexPattern } from '../../../../core_plugins/data/public'; + +/** + * A given response of and ElasticSearch containing a plain saved object is applied to the given + * savedObject + */ +export async function applyESResp( + resp: EsResponse, + savedObject: SavedObject, + config: SavedObjectConfig +) { + const mapping = expandShorthand(config.mapping); + const esType = config.type || ''; + savedObject._source = _.cloneDeep(resp._source); + const injectReferences = config.injectReferences; + const hydrateIndexPattern = savedObject.hydrateIndexPattern!; + if (typeof resp.found === 'boolean' && !resp.found) { + throw new SavedObjectNotFound(esType, savedObject.id || ''); + } + + const meta = resp._source.kibanaSavedObjectMeta || {}; + delete resp._source.kibanaSavedObjectMeta; + + if (!config.indexPattern && savedObject._source.indexPattern) { + config.indexPattern = savedObject._source.indexPattern as IndexPattern; + delete savedObject._source.indexPattern; + } + + // assign the defaults to the response + _.defaults(savedObject._source, savedObject.defaults); + + // transform the source using _deserializers + _.forOwn(mapping, (fieldMapping, fieldName) => { + if (fieldMapping._deserialize && typeof fieldName === 'string') { + savedObject._source[fieldName] = fieldMapping._deserialize( + savedObject._source[fieldName] as string + ); + } + }); + + // Give obj all of the values in _source.fields + _.assign(savedObject, savedObject._source); + savedObject.lastSavedTitle = savedObject.title; + + try { + await parseSearchSource(savedObject, esType, meta.searchSourceJSON, resp.references); + await hydrateIndexPattern(); + if (injectReferences && resp.references && resp.references.length > 0) { + injectReferences(savedObject, resp.references); + } + if (typeof config.afterESResp === 'function') { + await config.afterESResp.call(savedObject); + } + return savedObject; + } catch (e) { + // eslint-disable-next-line no-console + console.error(e); + throw e; + } +} diff --git a/src/legacy/ui/public/saved_objects/helpers/build_saved_object.ts b/src/legacy/ui/public/saved_objects/helpers/build_saved_object.ts new file mode 100644 index 0000000000000..a436f70f31ffe --- /dev/null +++ b/src/legacy/ui/public/saved_objects/helpers/build_saved_object.ts @@ -0,0 +1,126 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import _ from 'lodash'; +import { SearchSource } from 'ui/courier'; +import { hydrateIndexPattern } from './hydrate_index_pattern'; +import { intializeSavedObject } from './initialize_saved_object'; +import { serializeSavedObject } from './serialize_saved_object'; + +import { + EsResponse, + SavedObject, + SavedObjectConfig, + SavedObjectKibanaServices, + SavedObjectSaveOpts, +} from '../types'; +import { applyESResp } from './apply_es_resp'; +import { saveSavedObject } from './save_saved_object'; + +export function buildSavedObject( + savedObject: SavedObject, + config: SavedObjectConfig = {}, + services: SavedObjectKibanaServices +) { + const { indexPatterns, savedObjectsClient } = services; + // type name for this object, used as the ES-type + const esType = config.type || ''; + + savedObject.getDisplayName = () => esType; + + // NOTE: this.type (not set in this file, but somewhere else) is the sub type, e.g. 'area' or + // 'data table', while esType is the more generic type - e.g. 'visualization' or 'saved search'. + savedObject.getEsType = () => esType; + + /** + * Flips to true during a save operation, and back to false once the save operation + * completes. + * @type {boolean} + */ + savedObject.isSaving = false; + savedObject.defaults = config.defaults || {}; + // optional search source which this object configures + savedObject.searchSource = config.searchSource ? new SearchSource() : undefined; + // the id of the document + savedObject.id = config.id || void 0; + // the migration version of the document, should only be set on imports + savedObject.migrationVersion = config.migrationVersion; + // Whether to create a copy when the object is saved. This should eventually go away + // in favor of a better rename/save flow. + savedObject.copyOnSave = false; + + /** + * After creation or fetching from ES, ensure that the searchSources index indexPattern + * is an bonafide IndexPattern object. + * + * @return {Promise} + */ + savedObject.hydrateIndexPattern = (id?: string) => + hydrateIndexPattern(id || '', savedObject, indexPatterns, config); + /** + * Asynchronously initialize this object - will only run + * once even if called multiple times. + * + * @return {Promise} + * @resolved {SavedObject} + */ + savedObject.init = _.once(() => intializeSavedObject(savedObject, savedObjectsClient, config)); + + savedObject.applyESResp = (resp: EsResponse) => applyESResp(resp, savedObject, config); + + /** + * Serialize this object + * @return {Object} + */ + savedObject._serialize = () => serializeSavedObject(savedObject, config); + + /** + * Returns true if the object's original title has been changed. New objects return false. + * @return {boolean} + */ + savedObject.isTitleChanged = () => + savedObject._source && savedObject._source.title !== savedObject.title; + + savedObject.creationOpts = (opts: Record = {}) => ({ + id: savedObject.id, + migrationVersion: savedObject.migrationVersion, + ...opts, + }); + + savedObject.save = async (opts: SavedObjectSaveOpts) => { + try { + const result = await saveSavedObject(savedObject, config, opts, services); + return Promise.resolve(result); + } catch (e) { + return Promise.reject(e); + } + }; + + savedObject.destroy = () => {}; + + /** + * Delete this object from Elasticsearch + * @return {promise} + */ + savedObject.delete = () => { + if (!savedObject.id) { + return Promise.reject(new Error('Deleting a saved Object requires type and id')); + } + return savedObjectsClient.delete(esType, savedObject.id); + }; +} diff --git a/src/legacy/ui/public/saved_objects/helpers/check_for_duplicate_title.ts b/src/legacy/ui/public/saved_objects/helpers/check_for_duplicate_title.ts new file mode 100644 index 0000000000000..5c1c1d0d9a851 --- /dev/null +++ b/src/legacy/ui/public/saved_objects/helpers/check_for_duplicate_title.ts @@ -0,0 +1,69 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { SavedObject, SavedObjectKibanaServices } from '../types'; +import { findObjectByTitle } from './find_object_by_title'; +import { SAVE_DUPLICATE_REJECTED } from '../constants'; +import { displayDuplicateTitleConfirmModal } from './display_duplicate_title_confirm_modal'; + +/** + * check for an existing SavedObject with the same title in ES + * returns Promise when it's no duplicate, or the modal displaying the warning + * that's there's a duplicate is confirmed, else it returns a rejected Promise + * @param savedObject + * @param isTitleDuplicateConfirmed + * @param onTitleDuplicate + * @param services + */ +export async function checkForDuplicateTitle( + savedObject: SavedObject, + isTitleDuplicateConfirmed: boolean, + onTitleDuplicate: (() => void) | undefined, + services: SavedObjectKibanaServices +): Promise { + const { savedObjectsClient, overlays } = services; + // Don't check for duplicates if user has already confirmed save with duplicate title + if (isTitleDuplicateConfirmed) { + return true; + } + + // Don't check if the user isn't updating the title, otherwise that would become very annoying to have + // to confirm the save every time, except when copyOnSave is true, then we do want to check. + if (savedObject.title === savedObject.lastSavedTitle && !savedObject.copyOnSave) { + return true; + } + + const duplicate = await findObjectByTitle( + savedObjectsClient, + savedObject.getEsType(), + savedObject.title + ); + + if (!duplicate || duplicate.id === savedObject.id) { + return true; + } + + if (onTitleDuplicate) { + onTitleDuplicate(); + return Promise.reject(new Error(SAVE_DUPLICATE_REJECTED)); + } + + // TODO: make onTitleDuplicate a required prop and remove UI components from this class + // Need to leave here until all users pass onTitleDuplicate. + return displayDuplicateTitleConfirmModal(savedObject, overlays); +} diff --git a/src/legacy/ui/public/saved_objects/helpers/confirm_modal_promise.tsx b/src/legacy/ui/public/saved_objects/helpers/confirm_modal_promise.tsx new file mode 100644 index 0000000000000..1e0a4f4ebe47f --- /dev/null +++ b/src/legacy/ui/public/saved_objects/helpers/confirm_modal_promise.tsx @@ -0,0 +1,59 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { OverlayStart } from 'kibana/public'; +import { i18n } from '@kbn/i18n'; +import { EuiConfirmModal } from '@elastic/eui'; +import { toMountPoint } from '../../../../../plugins/kibana_react/public'; + +export function confirmModalPromise( + message = '', + title = '', + confirmBtnText = '', + overlays: OverlayStart +): Promise { + return new Promise((resolve, reject) => { + const cancelButtonText = i18n.translate( + 'common.ui.savedObjects.confirmModal.cancelButtonLabel', + { + defaultMessage: 'Cancel', + } + ); + + const modal = overlays.openModal( + toMountPoint( + { + modal.close(); + reject(); + }} + onConfirm={() => { + modal.close(); + resolve(true); + }} + confirmButtonText={confirmBtnText} + cancelButtonText={cancelButtonText} + title={title} + > + {message} + + ) + ); + }); +} diff --git a/src/legacy/ui/public/saved_objects/helpers/create_source.ts b/src/legacy/ui/public/saved_objects/helpers/create_source.ts new file mode 100644 index 0000000000000..1818671cecebe --- /dev/null +++ b/src/legacy/ui/public/saved_objects/helpers/create_source.ts @@ -0,0 +1,85 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import _ from 'lodash'; +import { i18n } from '@kbn/i18n'; +import { SavedObject, SavedObjectKibanaServices } from 'ui/saved_objects/types'; +import { SavedObjectAttributes } from 'kibana/public'; +import { OVERWRITE_REJECTED } from 'ui/saved_objects/constants'; +import { confirmModalPromise } from './confirm_modal_promise'; + +/** + * Attempts to create the current object using the serialized source. If an object already + * exists, a warning message requests an overwrite confirmation. + * @param source - serialized version of this object (return value from this._serialize()) + * What will be indexed into elasticsearch. + * @param savedObject - savedObject + * @param esType - type of the saved object + * @param options - options to pass to the saved object create method + * @param services - provides Kibana services savedObjectsClient and overlays + * @returns {Promise} - A promise that is resolved with the objects id if the object is + * successfully indexed. If the overwrite confirmation was rejected, an error is thrown with + * a confirmRejected = true parameter so that case can be handled differently than + * a create or index error. + * @resolved {SavedObject} + */ +export async function createSource( + source: SavedObjectAttributes, + savedObject: SavedObject, + esType: string, + options = {}, + services: SavedObjectKibanaServices +) { + const { savedObjectsClient, overlays } = services; + try { + return await savedObjectsClient.create(esType, source, options); + } catch (err) { + // record exists, confirm overwriting + if (_.get(err, 'res.status') === 409) { + const confirmMessage = i18n.translate( + 'common.ui.savedObjects.confirmModal.overwriteConfirmationMessage', + { + defaultMessage: 'Are you sure you want to overwrite {title}?', + values: { title: savedObject.title }, + } + ); + + const title = i18n.translate('common.ui.savedObjects.confirmModal.overwriteTitle', { + defaultMessage: 'Overwrite {name}?', + values: { name: savedObject.getDisplayName() }, + }); + const confirmButtonText = i18n.translate( + 'common.ui.savedObjects.confirmModal.overwriteButtonLabel', + { + defaultMessage: 'Overwrite', + } + ); + + return confirmModalPromise(confirmMessage, title, confirmButtonText, overlays) + .then(() => + savedObjectsClient.create( + esType, + source, + savedObject.creationOpts({ overwrite: true, ...options }) + ) + ) + .catch(() => Promise.reject(new Error(OVERWRITE_REJECTED))); + } + return await Promise.reject(err); + } +} diff --git a/src/legacy/ui/public/saved_objects/helpers/display_duplicate_title_confirm_modal.ts b/src/legacy/ui/public/saved_objects/helpers/display_duplicate_title_confirm_modal.ts new file mode 100644 index 0000000000000..36882db72d56c --- /dev/null +++ b/src/legacy/ui/public/saved_objects/helpers/display_duplicate_title_confirm_modal.ts @@ -0,0 +1,49 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { i18n } from '@kbn/i18n'; +import { OverlayStart } from 'kibana/public'; +import { SAVE_DUPLICATE_REJECTED } from '../constants'; +import { confirmModalPromise } from './confirm_modal_promise'; +import { SavedObject } from '../types'; + +export function displayDuplicateTitleConfirmModal( + savedObject: SavedObject, + overlays: OverlayStart +): Promise { + const confirmMessage = i18n.translate( + 'common.ui.savedObjects.confirmModal.saveDuplicateConfirmationMessage', + { + defaultMessage: `A {name} with the title '{title}' already exists. Would you like to save anyway?`, + values: { title: savedObject.title, name: savedObject.getDisplayName() }, + } + ); + + const confirmButtonText = i18n.translate( + 'common.ui.savedObjects.confirmModal.saveDuplicateButtonLabel', + { + defaultMessage: 'Save {name}', + values: { name: savedObject.getDisplayName() }, + } + ); + try { + return confirmModalPromise(confirmMessage, '', confirmButtonText, overlays); + } catch (_) { + return Promise.reject(new Error(SAVE_DUPLICATE_REJECTED)); + } +} diff --git a/src/legacy/ui/public/saved_objects/find_object_by_title.ts b/src/legacy/ui/public/saved_objects/helpers/find_object_by_title.ts similarity index 75% rename from src/legacy/ui/public/saved_objects/find_object_by_title.ts rename to src/legacy/ui/public/saved_objects/helpers/find_object_by_title.ts index d6f11bcb80956..373800f576627 100644 --- a/src/legacy/ui/public/saved_objects/find_object_by_title.ts +++ b/src/legacy/ui/public/saved_objects/helpers/find_object_by_title.ts @@ -17,7 +17,6 @@ * under the License. */ -import { find } from 'lodash'; import { SavedObjectAttributes } from 'src/core/server'; import { SavedObjectsClientContract } from 'src/core/public'; import { SimpleSavedObject } from 'src/core/public'; @@ -30,30 +29,23 @@ import { SimpleSavedObject } from 'src/core/public'; * @param title {string} * @returns {Promise} */ -export function findObjectByTitle( +export async function findObjectByTitle( savedObjectsClient: SavedObjectsClientContract, type: string, title: string ): Promise | void> { if (!title) { - return Promise.resolve(); + return; } // Elastic search will return the most relevant results first, which means exact matches should come // first, and so we shouldn't need to request everything. Using 10 just to be on the safe side. - return savedObjectsClient - .find({ - type, - perPage: 10, - search: `"${title}"`, - searchFields: ['title'], - fields: ['title'], - }) - .then(response => { - const match = find(response.savedObjects, obj => { - return obj.get('title').toLowerCase() === title.toLowerCase(); - }); - - return match; - }); + const response = await savedObjectsClient.find({ + type, + perPage: 10, + search: `"${title}"`, + searchFields: ['title'], + fields: ['title'], + }); + return response.savedObjects.find(obj => obj.get('title').toLowerCase() === title.toLowerCase()); } diff --git a/src/legacy/ui/public/saved_objects/helpers/hydrate_index_pattern.ts b/src/legacy/ui/public/saved_objects/helpers/hydrate_index_pattern.ts new file mode 100644 index 0000000000000..a78b3f97e884b --- /dev/null +++ b/src/legacy/ui/public/saved_objects/helpers/hydrate_index_pattern.ts @@ -0,0 +1,55 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { SavedObject, SavedObjectConfig } from '../types'; +import { IndexPatternsContract } from '../../../../../plugins/data/public'; + +/** + * After creation or fetching from ES, ensure that the searchSources index indexPattern + * is an bonafide IndexPattern object. + * + * @return {Promise} + */ +export async function hydrateIndexPattern( + id: string, + savedObject: SavedObject, + indexPatterns: IndexPatternsContract, + config: SavedObjectConfig +) { + const clearSavedIndexPattern = !!config.clearSavedIndexPattern; + const indexPattern = config.indexPattern; + + if (!savedObject.searchSource) { + return null; + } + + if (clearSavedIndexPattern) { + savedObject.searchSource!.setField('index', undefined); + return null; + } + + const index = id || indexPattern || savedObject.searchSource!.getOwnField('index'); + + if (typeof index !== 'string' || !index) { + return null; + } + + const indexObj = await indexPatterns.get(index); + savedObject.searchSource!.setField('index', indexObj); + return indexObj; +} diff --git a/src/legacy/ui/public/saved_objects/helpers/initialize_saved_object.ts b/src/legacy/ui/public/saved_objects/helpers/initialize_saved_object.ts new file mode 100644 index 0000000000000..c5ea31e0784aa --- /dev/null +++ b/src/legacy/ui/public/saved_objects/helpers/initialize_saved_object.ts @@ -0,0 +1,59 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import _ from 'lodash'; +import { SavedObjectsClientContract } from 'kibana/public'; +import { SavedObject, SavedObjectConfig } from '../types'; + +/** + * Initialize saved object + */ +export async function intializeSavedObject( + savedObject: SavedObject, + savedObjectsClient: SavedObjectsClientContract, + config: SavedObjectConfig +) { + const esType = config.type; + // ensure that the esType is defined + if (!esType) throw new Error('You must define a type name to use SavedObject objects.'); + + if (!savedObject.id) { + // just assign the defaults and be done + _.assign(savedObject, savedObject.defaults); + await savedObject.hydrateIndexPattern!(); + if (typeof config.afterESResp === 'function') { + await config.afterESResp.call(savedObject); + } + return savedObject; + } + + const resp = await savedObjectsClient.get(esType, savedObject.id); + const respMapped = { + _id: resp.id, + _type: resp.type, + _source: _.cloneDeep(resp.attributes), + references: resp.references, + found: !!resp._version, + }; + await savedObject.applyESResp(respMapped); + if (typeof config.init === 'function') { + await config.init.call(savedObject); + } + + return savedObject; +} diff --git a/src/legacy/ui/public/saved_objects/helpers/parse_search_source.ts b/src/legacy/ui/public/saved_objects/helpers/parse_search_source.ts new file mode 100644 index 0000000000000..8c52b7cfa0dbf --- /dev/null +++ b/src/legacy/ui/public/saved_objects/helpers/parse_search_source.ts @@ -0,0 +1,97 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import _ from 'lodash'; +import { migrateLegacyQuery } from 'ui/utils/migrate_legacy_query'; +import { SavedObject } from '../types'; +import { InvalidJSONProperty } from '../../../../../plugins/kibana_utils/public'; + +export function parseSearchSource( + savedObject: SavedObject, + esType: string, + searchSourceJson: string, + references: any[] +) { + if (!savedObject.searchSource) return; + + // if we have a searchSource, set its values based on the searchSourceJson field + let searchSourceValues: Record; + try { + searchSourceValues = JSON.parse(searchSourceJson); + } catch (e) { + throw new InvalidJSONProperty( + `Invalid JSON in ${esType} "${savedObject.id}". ${e.message} JSON: ${searchSourceJson}` + ); + } + + // This detects a scenario where documents with invalid JSON properties have been imported into the saved object index. + // (This happened in issue #20308) + if (!searchSourceValues || typeof searchSourceValues !== 'object') { + throw new InvalidJSONProperty(`Invalid searchSourceJSON in ${esType} "${savedObject.id}".`); + } + + // Inject index id if a reference is saved + if (searchSourceValues.indexRefName) { + const reference = references.find( + (ref: Record) => ref.name === searchSourceValues.indexRefName + ); + if (!reference) { + throw new Error( + `Could not find reference for ${ + searchSourceValues.indexRefName + } on ${savedObject.getEsType()} ${savedObject.id}` + ); + } + searchSourceValues.index = reference.id; + delete searchSourceValues.indexRefName; + } + + if (searchSourceValues.filter) { + searchSourceValues.filter.forEach((filterRow: any) => { + if (!filterRow.meta || !filterRow.meta.indexRefName) { + return; + } + const reference = references.find((ref: any) => ref.name === filterRow.meta.indexRefName); + if (!reference) { + throw new Error( + `Could not find reference for ${ + filterRow.meta.indexRefName + } on ${savedObject.getEsType()}` + ); + } + filterRow.meta.index = reference.id; + delete filterRow.meta.indexRefName; + }); + } + + const searchSourceFields = savedObject.searchSource.getFields(); + const fnProps = _.transform( + searchSourceFields, + function(dynamic: Record, val: any, name: string | undefined) { + if (_.isFunction(val) && name) dynamic[name] = val; + }, + {} + ); + + savedObject.searchSource.setFields(_.defaults(searchSourceValues, fnProps)); + const query = savedObject.searchSource.getOwnField('query'); + + if (typeof query !== 'undefined') { + savedObject.searchSource.setField('query', migrateLegacyQuery(query)); + } +} diff --git a/src/legacy/ui/public/saved_objects/helpers/save_saved_object.ts b/src/legacy/ui/public/saved_objects/helpers/save_saved_object.ts new file mode 100644 index 0000000000000..bd6daa1832a25 --- /dev/null +++ b/src/legacy/ui/public/saved_objects/helpers/save_saved_object.ts @@ -0,0 +1,128 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { + SavedObject, + SavedObjectConfig, + SavedObjectKibanaServices, + SavedObjectSaveOpts, +} from '../types'; +import { OVERWRITE_REJECTED, SAVE_DUPLICATE_REJECTED } from '../constants'; +import { createSource } from './create_source'; +import { checkForDuplicateTitle } from './check_for_duplicate_title'; + +/** + * @param error {Error} the error + * @return {boolean} + */ +function isErrorNonFatal(error: { message: string }) { + if (!error) return false; + return error.message === OVERWRITE_REJECTED || error.message === SAVE_DUPLICATE_REJECTED; +} + +/** + * Saves this object. + * + * @param {string} [esType] + * @param {SavedObject} [savedObject] + * @param {SavedObjectConfig} [config] + * @param {object} [options={}] + * @property {boolean} [options.confirmOverwrite=false] - If true, attempts to create the source so it + * can confirm an overwrite if a document with the id already exists. + * @property {boolean} [options.isTitleDuplicateConfirmed=false] - If true, save allowed with duplicate title + * @property {func} [options.onTitleDuplicate] - function called if duplicate title exists. + * When not provided, confirm modal will be displayed asking user to confirm or cancel save. + * @param {SavedObjectKibanaServices} [services] + * @return {Promise} + * @resolved {String} - The id of the doc + */ +export async function saveSavedObject( + savedObject: SavedObject, + config: SavedObjectConfig, + { + confirmOverwrite = false, + isTitleDuplicateConfirmed = false, + onTitleDuplicate, + }: SavedObjectSaveOpts = {}, + services: SavedObjectKibanaServices +): Promise { + const { savedObjectsClient, chrome } = services; + + const esType = config.type || ''; + const extractReferences = config.extractReferences; + // Save the original id in case the save fails. + const originalId = savedObject.id; + // Read https://github.com/elastic/kibana/issues/9056 and + // https://github.com/elastic/kibana/issues/9012 for some background into why this copyOnSave variable + // exists. + // The goal is to move towards a better rename flow, but since our users have been conditioned + // to expect a 'save as' flow during a rename, we are keeping the logic the same until a better + // UI/UX can be worked out. + if (savedObject.copyOnSave) { + delete savedObject.id; + } + + // Here we want to extract references and set them within "references" attribute + let { attributes, references } = savedObject._serialize(); + if (extractReferences) { + ({ attributes, references } = extractReferences({ attributes, references })); + } + if (!references) throw new Error('References not returned from extractReferences'); + + try { + await checkForDuplicateTitle( + savedObject, + isTitleDuplicateConfirmed, + onTitleDuplicate, + services + ); + savedObject.isSaving = true; + const resp = confirmOverwrite + ? await createSource( + attributes, + savedObject, + esType, + savedObject.creationOpts({ references }), + services + ) + : await savedObjectsClient.create( + esType, + attributes, + savedObject.creationOpts({ references, overwrite: true }) + ); + + savedObject.id = resp.id; + if (savedObject.showInRecentlyAccessed && savedObject.getFullPath) { + chrome.recentlyAccessed.add( + savedObject.getFullPath(), + savedObject.title, + String(savedObject.id) + ); + } + savedObject.isSaving = false; + savedObject.lastSavedTitle = savedObject.title; + return savedObject.id; + } catch (err) { + savedObject.isSaving = false; + savedObject.id = originalId; + if (isErrorNonFatal(err)) { + return ''; + } + return Promise.reject(err); + } +} diff --git a/src/legacy/ui/public/saved_objects/helpers/serialize_saved_object.ts b/src/legacy/ui/public/saved_objects/helpers/serialize_saved_object.ts new file mode 100644 index 0000000000000..ca780f8f9584d --- /dev/null +++ b/src/legacy/ui/public/saved_objects/helpers/serialize_saved_object.ts @@ -0,0 +1,98 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import _ from 'lodash'; +import angular from 'angular'; +import { SavedObject, SavedObjectConfig } from '../types'; +import { expandShorthand } from '../../../../../plugins/kibana_utils/public'; + +export function serializeSavedObject(savedObject: SavedObject, config: SavedObjectConfig) { + // mapping definition for the fields that this object will expose + const mapping = expandShorthand(config.mapping); + const attributes = {} as Record; + const references = []; + + _.forOwn(mapping, (fieldMapping, fieldName) => { + if (typeof fieldName !== 'string') { + return; + } + // @ts-ignore + const savedObjectFieldVal = savedObject[fieldName]; + if (savedObjectFieldVal != null) { + attributes[fieldName] = fieldMapping._serialize + ? fieldMapping._serialize(savedObjectFieldVal) + : savedObjectFieldVal; + } + }); + + if (savedObject.searchSource) { + let searchSourceFields: Record = _.omit(savedObject.searchSource.getFields(), [ + 'sort', + 'size', + ]); + if (searchSourceFields.index) { + // searchSourceFields.index will normally be an IndexPattern, but can be a string in two scenarios: + // (1) `init()` (and by extension `hydrateIndexPattern()`) hasn't been called on Saved Object + // (2) The IndexPattern doesn't exist, so we fail to resolve it in `hydrateIndexPattern()` + const indexId = + typeof searchSourceFields.index === 'string' + ? searchSourceFields.index + : searchSourceFields.index.id; + const refName = 'kibanaSavedObjectMeta.searchSourceJSON.index'; + references.push({ + name: refName, + type: 'index-pattern', + id: indexId, + }); + searchSourceFields = { + ...searchSourceFields, + indexRefName: refName, + index: undefined, + }; + } + if (searchSourceFields.filter) { + searchSourceFields = { + ...searchSourceFields, + filter: searchSourceFields.filter.map((filterRow: any, i: number) => { + if (!filterRow.meta || !filterRow.meta.index) { + return filterRow; + } + const refName = `kibanaSavedObjectMeta.searchSourceJSON.filter[${i}].meta.index`; + references.push({ + name: refName, + type: 'index-pattern', + id: filterRow.meta.index, + }); + return { + ...filterRow, + meta: { + ...filterRow.meta, + indexRefName: refName, + index: undefined, + }, + }; + }), + }; + } + attributes.kibanaSavedObjectMeta = { + searchSourceJSON: angular.toJson(searchSourceFields), + }; + } + + return { attributes, references }; +} diff --git a/src/legacy/ui/public/saved_objects/index.ts b/src/legacy/ui/public/saved_objects/index.ts index 8076213f62e9a..3c77a02c608c6 100644 --- a/src/legacy/ui/public/saved_objects/index.ts +++ b/src/legacy/ui/public/saved_objects/index.ts @@ -19,6 +19,5 @@ export { SavedObjectRegistryProvider } from './saved_object_registry'; export { SavedObjectsClientProvider } from './saved_objects_client_provider'; -// @ts-ignore export { SavedObjectLoader } from './saved_object_loader'; -export { findObjectByTitle } from './find_object_by_title'; +export { findObjectByTitle } from './helpers/find_object_by_title'; diff --git a/src/legacy/ui/public/saved_objects/saved_object.js b/src/legacy/ui/public/saved_objects/saved_object.js deleted file mode 100644 index 1db651ad9308f..0000000000000 --- a/src/legacy/ui/public/saved_objects/saved_object.js +++ /dev/null @@ -1,541 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * @name SavedObject - * - * NOTE: SavedObject seems to track a reference to an object in ES, - * and surface methods for CRUD functionality (save and delete). This seems - * similar to how Backbone Models work. - * - * This class seems to interface with ES primarily through the es Angular - * service and the saved object api. - */ - -import angular from 'angular'; -import _ from 'lodash'; - - -import { InvalidJSONProperty, SavedObjectNotFound, expandShorthand } from '../../../../plugins/kibana_utils/public'; - -import { SearchSource } from '../courier'; -import { findObjectByTitle } from './find_object_by_title'; -import { SavedObjectsClientProvider } from './saved_objects_client_provider'; -import { migrateLegacyQuery } from '../utils/migrate_legacy_query'; -import { npStart } from 'ui/new_platform'; -import { i18n } from '@kbn/i18n'; - -/** - * An error message to be used when the user rejects a confirm overwrite. - * @type {string} - */ -const OVERWRITE_REJECTED = i18n.translate('common.ui.savedObjects.overwriteRejectedDescription', { - defaultMessage: 'Overwrite confirmation was rejected' -}); - -/** - * An error message to be used when the user rejects a confirm save with duplicate title. - * @type {string} - */ -const SAVE_DUPLICATE_REJECTED = i18n.translate('common.ui.savedObjects.saveDuplicateRejectedDescription', { - defaultMessage: 'Save with duplicate title confirmation was rejected' -}); - -/** - * @param error {Error} the error - * @return {boolean} - */ -function isErrorNonFatal(error) { - if (!error) return false; - return error.message === OVERWRITE_REJECTED || error.message === SAVE_DUPLICATE_REJECTED; -} - -export function SavedObjectProvider(Promise, Private, confirmModalPromise, indexPatterns) { - const savedObjectsClient = Private(SavedObjectsClientProvider); - - /** - * The SavedObject class is a base class for saved objects loaded from the server and - * provides additional functionality besides loading/saving/deleting/etc. - * - * It is overloaded and configured to provide type-aware functionality. - * To just retrieve the attributes of saved objects, it is recommended to use SavedObjectLoader - * which returns instances of SimpleSavedObject which don't introduce additional type-specific complexity. - * @param {*} config - */ - function SavedObject(config) { - if (!_.isObject(config)) config = {}; - - /************ - * Initialize config vars - ************/ - - // type name for this object, used as the ES-type - const esType = config.type; - - this.getDisplayName = function () { - return esType; - }; - - // NOTE: this.type (not set in this file, but somewhere else) is the sub type, e.g. 'area' or - // 'data table', while esType is the more generic type - e.g. 'visualization' or 'saved search'. - this.getEsType = function () { - return esType; - }; - - /** - * Flips to true during a save operation, and back to false once the save operation - * completes. - * @type {boolean} - */ - this.isSaving = false; - this.defaults = config.defaults || {}; - - // mapping definition for the fields that this object will expose - const mapping = expandShorthand(config.mapping); - - const afterESResp = config.afterESResp || _.noop; - const customInit = config.init || _.noop; - const extractReferences = config.extractReferences; - const injectReferences = config.injectReferences; - - // optional search source which this object configures - this.searchSource = config.searchSource ? new SearchSource() : undefined; - - // the id of the document - this.id = config.id || void 0; - - // the migration version of the document, should only be set on imports - this.migrationVersion = config.migrationVersion; - - // Whether to create a copy when the object is saved. This should eventually go away - // in favor of a better rename/save flow. - this.copyOnSave = false; - - const parseSearchSource = (searchSourceJson, references) => { - if (!this.searchSource) return; - - // if we have a searchSource, set its values based on the searchSourceJson field - let searchSourceValues; - try { - searchSourceValues = JSON.parse(searchSourceJson); - } catch (e) { - throw new InvalidJSONProperty( - `Invalid JSON in ${esType} "${this.id}". ${e.message} JSON: ${searchSourceJson}` - ); - } - - // This detects a scenario where documents with invalid JSON properties have been imported into the saved object index. - // (This happened in issue #20308) - if (!searchSourceValues || typeof searchSourceValues !== 'object') { - throw new InvalidJSONProperty(`Invalid searchSourceJSON in ${esType} "${this.id}".`); - } - - // Inject index id if a reference is saved - if (searchSourceValues.indexRefName) { - const reference = references.find(reference => reference.name === searchSourceValues.indexRefName); - if (!reference) { - throw new Error(`Could not find reference for ${searchSourceValues.indexRefName} on ${this.getEsType()} ${this.id}`); - } - searchSourceValues.index = reference.id; - delete searchSourceValues.indexRefName; - } - - if (searchSourceValues.filter) { - searchSourceValues.filter.forEach((filterRow) => { - if (!filterRow.meta || !filterRow.meta.indexRefName) { - return; - } - const reference = references.find(reference => reference.name === filterRow.meta.indexRefName); - if (!reference) { - throw new Error(`Could not find reference for ${filterRow.meta.indexRefName} on ${this.getEsType()}`); - } - filterRow.meta.index = reference.id; - delete filterRow.meta.indexRefName; - }); - } - - const searchSourceFields = this.searchSource.getFields(); - const fnProps = _.transform(searchSourceFields, function (dynamic, val, name) { - if (_.isFunction(val)) dynamic[name] = val; - }, {}); - - this.searchSource.setFields(_.defaults(searchSourceValues, fnProps)); - - if (!_.isUndefined(this.searchSource.getOwnField('query'))) { - this.searchSource.setField('query', migrateLegacyQuery(this.searchSource.getOwnField('query'))); - } - }; - - /** - * After creation or fetching from ES, ensure that the searchSources index indexPattern - * is an bonafide IndexPattern object. - * - * @return {Promise} - */ - this.hydrateIndexPattern = (id) => { - if (!this.searchSource) { - return Promise.resolve(null); - } - - if (config.clearSavedIndexPattern) { - this.searchSource.setField('index', null); - return Promise.resolve(null); - } - - let index = id || config.indexPattern || this.searchSource.getOwnField('index'); - - if (!index) { - return Promise.resolve(null); - } - - // If index is not an IndexPattern object at this point, then it's a string id of an index. - if (typeof index === 'string') { - index = indexPatterns.get(index); - } - - // At this point index will either be an IndexPattern, if cached, or a promise that - // will return an IndexPattern, if not cached. - return Promise.resolve(index).then(indexPattern => { - this.searchSource.setField('index', indexPattern); - }); - }; - - /** - * Asynchronously initialize this object - will only run - * once even if called multiple times. - * - * @return {Promise} - * @resolved {SavedObject} - */ - this.init = _.once(() => { - // ensure that the esType is defined - if (!esType) throw new Error('You must define a type name to use SavedObject objects.'); - - return Promise.resolve() - .then(() => { - // If there is not id, then there is no document to fetch from elasticsearch - if (!this.id) { - // just assign the defaults and be done - _.assign(this, this.defaults); - return this.hydrateIndexPattern().then(() => { - return afterESResp.call(this); - }); - } - - // fetch the object from ES - return savedObjectsClient.get(esType, this.id) - .then(resp => { - // temporary compatability for savedObjectsClient - return { - _id: resp.id, - _type: resp.type, - _source: _.cloneDeep(resp.attributes), - references: resp.references, - found: resp._version ? true : false - }; - }) - .then(this.applyESResp) - .catch(this.applyEsResp); - }) - .then(() => customInit.call(this)) - .then(() => this); - }); - - - this.applyESResp = (resp) => { - this._source = _.cloneDeep(resp._source); - - if (resp.found != null && !resp.found) { - throw new SavedObjectNotFound(esType, this.id); - } - - const meta = resp._source.kibanaSavedObjectMeta || {}; - delete resp._source.kibanaSavedObjectMeta; - - if (!config.indexPattern && this._source.indexPattern) { - config.indexPattern = this._source.indexPattern; - delete this._source.indexPattern; - } - - // assign the defaults to the response - _.defaults(this._source, this.defaults); - - // transform the source using _deserializers - _.forOwn(mapping, (fieldMapping, fieldName) => { - if (fieldMapping._deserialize) { - this._source[fieldName] = fieldMapping._deserialize(this._source[fieldName], resp, fieldName, fieldMapping); - } - }); - - // Give obj all of the values in _source.fields - _.assign(this, this._source); - this.lastSavedTitle = this.title; - - return Promise.try(() => { - parseSearchSource(meta.searchSourceJSON, resp.references); - return this.hydrateIndexPattern(); - }).then(() => { - if (injectReferences && resp.references && resp.references.length > 0) { - injectReferences(this, resp.references); - } - return this; - }).then(() => { - return Promise.cast(afterESResp.call(this, resp)); - }); - }; - - /** - * Serialize this object - * - * @return {Object} - */ - this._serialize = () => { - const attributes = {}; - const references = []; - - _.forOwn(mapping, (fieldMapping, fieldName) => { - if (this[fieldName] != null) { - attributes[fieldName] = (fieldMapping._serialize) - ? fieldMapping._serialize(this[fieldName]) - : this[fieldName]; - } - }); - - if (this.searchSource) { - let searchSourceFields = _.omit(this.searchSource.getFields(), ['sort', 'size']); - if (searchSourceFields.index) { - // searchSourceFields.index will normally be an IndexPattern, but can be a string in two scenarios: - // (1) `init()` (and by extension `hydrateIndexPattern()`) hasn't been called on this Saved Object - // (2) The IndexPattern doesn't exist, so we fail to resolve it in `hydrateIndexPattern()` - const indexId = typeof (searchSourceFields.index) === 'string' ? searchSourceFields.index : searchSourceFields.index.id; - const refName = 'kibanaSavedObjectMeta.searchSourceJSON.index'; - references.push({ - name: refName, - type: 'index-pattern', - id: indexId, - }); - searchSourceFields = { - ...searchSourceFields, - indexRefName: refName, - index: undefined, - }; - } - if (searchSourceFields.filter) { - searchSourceFields = { - ...searchSourceFields, - filter: searchSourceFields.filter.map((filterRow, i) => { - if (!filterRow.meta || !filterRow.meta.index) { - return filterRow; - } - const refName = `kibanaSavedObjectMeta.searchSourceJSON.filter[${i}].meta.index`; - references.push({ - name: refName, - type: 'index-pattern', - id: filterRow.meta.index, - }); - return { - ...filterRow, - meta: { - ...filterRow.meta, - indexRefName: refName, - index: undefined, - } - }; - }), - }; - } - attributes.kibanaSavedObjectMeta = { - searchSourceJSON: angular.toJson(searchSourceFields) - }; - } - - return { attributes, references }; - }; - - /** - * Returns true if the object's original title has been changed. New objects return false. - * @return {boolean} - */ - this.isTitleChanged = () => { - return this._source && this._source.title !== this.title; - }; - - this.creationOpts = (opts = {}) => ({ - id: this.id, - migrationVersion: this.migrationVersion, - ...opts, - }); - - /** - * Attempts to create the current object using the serialized source. If an object already - * exists, a warning message requests an overwrite confirmation. - * @param source - serialized version of this object (return value from this._serialize()) - * What will be indexed into elasticsearch. - * @param options - options to pass to the saved object create method - * @returns {Promise} - A promise that is resolved with the objects id if the object is - * successfully indexed. If the overwrite confirmation was rejected, an error is thrown with - * a confirmRejected = true parameter so that case can be handled differently than - * a create or index error. - * @resolved {SavedObject} - */ - const createSource = (source, options = {}) => { - return savedObjectsClient.create(esType, source, options) - .catch(err => { - // record exists, confirm overwriting - if (_.get(err, 'res.status') === 409) { - const confirmMessage = i18n.translate('common.ui.savedObjects.confirmModal.overwriteConfirmationMessage', { - defaultMessage: 'Are you sure you want to overwrite {title}?', - values: { title: this.title } - }); - - return confirmModalPromise(confirmMessage, { - confirmButtonText: i18n.translate('common.ui.savedObjects.confirmModal.overwriteButtonLabel', { - defaultMessage: 'Overwrite', - }), - title: i18n.translate('common.ui.savedObjects.confirmModal.overwriteTitle', { - defaultMessage: 'Overwrite {name}?', - values: { name: this.getDisplayName() } - }), - }) - .then(() => savedObjectsClient.create(esType, source, this.creationOpts({ overwrite: true, ...options }))) - .catch(() => Promise.reject(new Error(OVERWRITE_REJECTED))); - } - return Promise.reject(err); - }); - }; - - const displayDuplicateTitleConfirmModal = () => { - const confirmMessage = i18n.translate('common.ui.savedObjects.confirmModal.saveDuplicateConfirmationMessage', { - defaultMessage: `A {name} with the title '{title}' already exists. Would you like to save anyway?`, - values: { title: this.title, name: this.getDisplayName() } - }); - - return confirmModalPromise(confirmMessage, { - confirmButtonText: i18n.translate('common.ui.savedObjects.confirmModal.saveDuplicateButtonLabel', { - defaultMessage: 'Save {name}', - values: { name: this.getDisplayName() } - }) - }) - .catch(() => Promise.reject(new Error(SAVE_DUPLICATE_REJECTED))); - }; - - const checkForDuplicateTitle = (isTitleDuplicateConfirmed, onTitleDuplicate) => { - // Don't check for duplicates if user has already confirmed save with duplicate title - if (isTitleDuplicateConfirmed) { - return Promise.resolve(); - } - - // Don't check if the user isn't updating the title, otherwise that would become very annoying to have - // to confirm the save every time, except when copyOnSave is true, then we do want to check. - if (this.title === this.lastSavedTitle && !this.copyOnSave) { - return Promise.resolve(); - } - - return findObjectByTitle(savedObjectsClient, this.getEsType(), this.title) - .then(duplicate => { - if (!duplicate) return true; - if (duplicate.id === this.id) return true; - - if (onTitleDuplicate) { - onTitleDuplicate(); - return Promise.reject(new Error(SAVE_DUPLICATE_REJECTED)); - } - - // TODO: make onTitleDuplicate a required prop and remove UI components from this class - // Need to leave here until all users pass onTitleDuplicate. - return displayDuplicateTitleConfirmModal(); - }); - }; - - /** - * Saves this object. - * - * @param {object} [options={}] - * @property {boolean} [options.confirmOverwrite=false] - If true, attempts to create the source so it - * can confirm an overwrite if a document with the id already exists. - * @property {boolean} [options.isTitleDuplicateConfirmed=false] - If true, save allowed with duplicate title - * @property {func} [options.onTitleDuplicate] - function called if duplicate title exists. - * When not provided, confirm modal will be displayed asking user to confirm or cancel save. - * @return {Promise} - * @resolved {String} - The id of the doc - */ - this.save = ({ confirmOverwrite = false, isTitleDuplicateConfirmed = false, onTitleDuplicate } = {}) => { - // Save the original id in case the save fails. - const originalId = this.id; - // Read https://github.com/elastic/kibana/issues/9056 and - // https://github.com/elastic/kibana/issues/9012 for some background into why this copyOnSave variable - // exists. - // The goal is to move towards a better rename flow, but since our users have been conditioned - // to expect a 'save as' flow during a rename, we are keeping the logic the same until a better - // UI/UX can be worked out. - if (this.copyOnSave) { - this.id = null; - } - - // Here we want to extract references and set them within "references" attribute - let { attributes, references } = this._serialize(); - if (extractReferences) { - ({ attributes, references } = extractReferences({ attributes, references })); - } - if (!references) throw new Error('References not returned from extractReferences'); - - this.isSaving = true; - - return checkForDuplicateTitle(isTitleDuplicateConfirmed, onTitleDuplicate) - .then(() => { - if (confirmOverwrite) { - return createSource(attributes, this.creationOpts({ references })); - } else { - return savedObjectsClient.create(esType, attributes, this.creationOpts({ references, overwrite: true })); - } - }) - .then((resp) => { - this.id = resp.id; - }) - .then(() => { - if (this.showInRecentlyAccessed && this.getFullPath) { - npStart.core.chrome.recentlyAccessed.add(this.getFullPath(), this.title, this.id); - } - this.isSaving = false; - this.lastSavedTitle = this.title; - return this.id; - }) - .catch((err) => { - this.isSaving = false; - this.id = originalId; - if (isErrorNonFatal(err)) { - return; - } - return Promise.reject(err); - }); - }; - - this.destroy = () => {}; - - /** - * Delete this object from Elasticsearch - * @return {promise} - */ - this.delete = () => { - return savedObjectsClient.delete(esType, this.id); - }; - } - - return SavedObject; -} diff --git a/src/legacy/ui/public/saved_objects/saved_object.ts b/src/legacy/ui/public/saved_objects/saved_object.ts new file mode 100644 index 0000000000000..91182e67aac0d --- /dev/null +++ b/src/legacy/ui/public/saved_objects/saved_object.ts @@ -0,0 +1,63 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * @name SavedObject + * + * NOTE: SavedObject seems to track a reference to an object in ES, + * and surface methods for CRUD functionality (save and delete). This seems + * similar to how Backbone Models work. + * + * This class seems to interface with ES primarily through the es Angular + * service and the saved object api. + */ +import { npStart } from 'ui/new_platform'; +import { SavedObject, SavedObjectConfig, SavedObjectKibanaServices } from './types'; +import { buildSavedObject } from './helpers/build_saved_object'; + +export function createSavedObjectClass(services: SavedObjectKibanaServices) { + /** + * The SavedObject class is a base class for saved objects loaded from the server and + * provides additional functionality besides loading/saving/deleting/etc. + * + * It is overloaded and configured to provide type-aware functionality. + * To just retrieve the attributes of saved objects, it is recommended to use SavedObjectLoader + * which returns instances of SimpleSavedObject which don't introduce additional type-specific complexity. + * @param {*} config + */ + class SavedObjectClass { + constructor(config: SavedObjectConfig = {}) { + // @ts-ignore + const self: SavedObject = this; + buildSavedObject(self, config, services); + } + } + + return SavedObjectClass as new (config: SavedObjectConfig) => SavedObject; +} +// the old angular way, should be removed once no longer used +export function SavedObjectProvider() { + const services = { + savedObjectsClient: npStart.core.savedObjects.client, + indexPatterns: npStart.plugins.data.indexPatterns, + chrome: npStart.core.chrome, + overlays: npStart.core.overlays, + }; + return createSavedObjectClass(services); +} diff --git a/src/legacy/ui/public/saved_objects/saved_object_loader.js b/src/legacy/ui/public/saved_objects/saved_object_loader.ts similarity index 60% rename from src/legacy/ui/public/saved_objects/saved_object_loader.js rename to src/legacy/ui/public/saved_objects/saved_object_loader.ts index 434ce0d8b0caa..eb880ce5380c0 100644 --- a/src/legacy/ui/public/saved_objects/saved_object_loader.js +++ b/src/legacy/ui/public/saved_objects/saved_object_loader.ts @@ -16,7 +16,8 @@ * specific language governing permissions and limitations * under the License. */ - +import { SavedObject } from 'ui/saved_objects/types'; +import { ChromeStart, SavedObjectsClientContract, SavedObjectsFindOptions } from 'kibana/public'; import { StringUtils } from '../utils/string_utils'; /** @@ -28,20 +29,25 @@ import { StringUtils } from '../utils/string_utils'; * to avoid pulling in extra functionality which isn't used. */ export class SavedObjectLoader { - constructor(SavedObjectClass, kbnUrl, chrome, savedObjectClient) { + private readonly Class: (id: string) => SavedObject; + public type: string; + public lowercaseType: string; + public loaderProperties: Record; + + constructor( + SavedObjectClass: any, + private readonly savedObjectsClient: SavedObjectsClientContract, + private readonly chrome: ChromeStart + ) { this.type = SavedObjectClass.type; this.Class = SavedObjectClass; this.lowercaseType = this.type.toLowerCase(); - this.kbnUrl = kbnUrl; - this.chrome = chrome; this.loaderProperties = { - name: `${ this.lowercaseType }s`, + name: `${this.lowercaseType}s`, noun: StringUtils.upperFirst(this.type), - nouns: `${ this.lowercaseType }s`, + nouns: `${this.lowercaseType}s`, }; - - this.savedObjectsClient = savedObjectClient; } /** @@ -50,27 +56,38 @@ export class SavedObjectLoader { * @param id * @returns {Promise} */ - get(id) { - return (new this.Class(id)).init(); + async get(id: string) { + // @ts-ignore + const obj = new this.Class(id); + return obj.init(); } - urlFor(id) { - return this.kbnUrl.eval(`#/${ this.lowercaseType }/{{id}}`, { id: id }); + urlFor(id: string) { + return `#/${this.lowercaseType}/${encodeURIComponent(id)}`; } - delete(ids) { - ids = !Array.isArray(ids) ? [ids] : ids; + async delete(ids: string | string[]) { + const idsUsed = !Array.isArray(ids) ? [ids] : ids; - const deletions = ids.map(id => { + const deletions = idsUsed.map(id => { + // @ts-ignore const savedObject = new this.Class(id); return savedObject.delete(); }); + await Promise.all(deletions); - return Promise.all(deletions).then(() => { - if (this.chrome) { - this.chrome.untrackNavLinksForDeletedSavedObjects(ids); - } - }); + const coreNavLinks = this.chrome.navLinks; + /** + * Modify last url for deleted saved objects to avoid loading pages with "Could not locate..." + */ + coreNavLinks + .getAll() + .filter( + link => + link.linkToLastSubUrl && + idsUsed.find(deletedId => link.url && link.url.includes(deletedId)) !== undefined + ) + .forEach(link => coreNavLinks.update(link.id, { url: link.baseUrl })); } /** @@ -80,7 +97,7 @@ export class SavedObjectLoader { * @param id * @returns {source} The modified source object, with an id and url field. */ - mapHitSource(source, id) { + mapHitSource(source: Record, id: string) { source.id = id; source.url = this.urlFor(id); return source; @@ -92,7 +109,7 @@ export class SavedObjectLoader { * @param hit * @returns {hit.attributes} The modified hit.attributes object, with an id and url field. */ - mapSavedObjectApiHits(hit) { + mapSavedObjectApiHits(hit: { attributes: Record; id: string }) { return this.mapHitSource(hit.attributes, hit.id); } @@ -100,13 +117,14 @@ export class SavedObjectLoader { * TODO: Rather than use a hardcoded limit, implement pagination. See * https://github.com/elastic/kibana/issues/8044 for reference. * - * @param searchString + * @param search * @param size + * @param fields * @returns {Promise} */ - findAll(search = '', size = 100, fields) { - return this.savedObjectsClient.find( - { + findAll(search: string = '', size: number = 100, fields?: string[]) { + return this.savedObjectsClient + .find({ type: this.lowercaseType, search: search ? `${search}*` : undefined, perPage: size, @@ -114,20 +132,20 @@ export class SavedObjectLoader { searchFields: ['title^3', 'description'], defaultSearchOperator: 'AND', fields, - }).then((resp) => { - return { - total: resp.total, - hits: resp.savedObjects - .map((savedObject) => this.mapSavedObjectApiHits(savedObject)) - }; - }); + } as SavedObjectsFindOptions) + .then(resp => { + return { + total: resp.total, + hits: resp.savedObjects.map(savedObject => this.mapSavedObjectApiHits(savedObject)), + }; + }); } - find(search = '', size = 100) { + find(search: string = '', size: number = 100) { return this.findAll(search, size).then(resp => { return { total: resp.total, - hits: resp.hits.filter(savedObject => !savedObject.error) + hits: resp.hits.filter(savedObject => !savedObject.error), }; }); } diff --git a/src/legacy/ui/public/saved_objects/types.ts b/src/legacy/ui/public/saved_objects/types.ts new file mode 100644 index 0000000000000..bccf73917882a --- /dev/null +++ b/src/legacy/ui/public/saved_objects/types.ts @@ -0,0 +1,90 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { ChromeStart, OverlayStart, SavedObjectsClientContract } from 'kibana/public'; +import { SearchSource, SearchSourceContract } from 'ui/courier'; +import { SavedObjectAttributes, SavedObjectReference } from 'kibana/server'; +import { IndexPatternsContract } from '../../../../plugins/data/public'; +import { IndexPattern } from '../../../core_plugins/data/public'; + +export interface SavedObject { + _serialize: () => { attributes: SavedObjectAttributes; references: SavedObjectReference[] }; + _source: Record; + applyESResp: (resp: EsResponse) => Promise; + copyOnSave: boolean; + creationOpts: (opts: SavedObjectCreationOpts) => Record; + defaults: any; + delete?: () => Promise<{}>; + destroy?: () => void; + getDisplayName: () => string; + getEsType: () => string; + getFullPath: () => string; + hydrateIndexPattern?: (id?: string) => Promise; + id?: string; + init?: () => Promise; + isSaving: boolean; + isTitleChanged: () => boolean; + lastSavedTitle: string; + migrationVersion?: Record; + save: (saveOptions: SavedObjectSaveOpts) => Promise; + searchSource?: SearchSourceContract; + showInRecentlyAccessed: boolean; + title: string; +} + +export interface SavedObjectSaveOpts { + confirmOverwrite?: boolean; + isTitleDuplicateConfirmed?: boolean; + onTitleDuplicate?: () => void; +} + +export interface SavedObjectCreationOpts { + references?: SavedObjectReference[]; + overwrite?: boolean; +} + +export interface SavedObjectKibanaServices { + savedObjectsClient: SavedObjectsClientContract; + indexPatterns: IndexPatternsContract; + chrome: ChromeStart; + overlays: OverlayStart; +} + +export interface SavedObjectConfig { + afterESResp?: () => any; + clearSavedIndexPattern?: boolean; + defaults?: any; + extractReferences?: (opts: { + attributes: SavedObjectAttributes; + references: SavedObjectReference[]; + }) => { + attributes: SavedObjectAttributes; + references: SavedObjectReference[]; + }; + id?: string; + init?: () => void; + indexPattern?: IndexPattern; + injectReferences?: any; + mapping?: any; + migrationVersion?: Record; + path?: string; + searchSource?: SearchSource | boolean; + type?: string; +} + +export type EsResponse = Record; diff --git a/x-pack/legacy/plugins/graph/public/types/persistence.ts b/x-pack/legacy/plugins/graph/public/types/persistence.ts index 9c59b7057fe67..7883e81fb9b8e 100644 --- a/x-pack/legacy/plugins/graph/public/types/persistence.ts +++ b/x-pack/legacy/plugins/graph/public/types/persistence.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SavedObject } from 'ui/saved_objects/saved_object'; +import { SavedObject } from 'ui/saved_objects/types'; import { AdvancedSettings, UrlTemplate, WorkspaceField } from './app_state'; import { WorkspaceNode, WorkspaceEdge } from './workspace_state'; diff --git a/x-pack/legacy/plugins/maps/public/angular/services/gis_map_saved_object_loader.js b/x-pack/legacy/plugins/maps/public/angular/services/gis_map_saved_object_loader.js index fdf5172fea8ca..cff6fe878c9fc 100644 --- a/x-pack/legacy/plugins/maps/public/angular/services/gis_map_saved_object_loader.js +++ b/x-pack/legacy/plugins/maps/public/angular/services/gis_map_saved_object_loader.js @@ -6,12 +6,12 @@ import './saved_gis_map'; import { uiModules } from 'ui/modules'; -import { SavedObjectLoader, SavedObjectsClientProvider } from 'ui/saved_objects'; +import { SavedObjectLoader } from 'ui/saved_objects'; +import { npStart } from '../../../../../../../src/legacy/ui/public/new_platform'; const module = uiModules.get('app/maps'); // This is the only thing that gets injected into controllers -module.service('gisMapSavedObjectLoader', function (Private, SavedGisMap, kbnUrl, chrome) { - const savedObjectClient = Private(SavedObjectsClientProvider); - return new SavedObjectLoader(SavedGisMap, kbnUrl, chrome, savedObjectClient); +module.service('gisMapSavedObjectLoader', function (SavedGisMap) { + return new SavedObjectLoader(SavedGisMap, npStart.core.savedObjects.client, npStart.core.chrome); }); From c8b42f09deecf39bf904afb58576fa8912aa84ed Mon Sep 17 00:00:00 2001 From: Spencer Date: Thu, 12 Dec 2019 10:15:23 -0700 Subject: [PATCH 51/79] require yarn 1.21.1 to avoid binary planting vuln (#52899) --- package.json | 2 +- x-pack/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 72f8b404617bc..e8f50ecb46f9a 100644 --- a/package.json +++ b/package.json @@ -468,6 +468,6 @@ }, "engines": { "node": "10.15.2", - "yarn": "^1.10.1" + "yarn": "^1.21.1" } } diff --git a/x-pack/package.json b/x-pack/package.json index 06406f76af7af..52f90c5809e26 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -345,7 +345,7 @@ "xregexp": "4.2.4" }, "engines": { - "yarn": "^1.10.1" + "yarn": "^1.21.1" }, "workspaces": { "nohoist": [ From 065ca6e0417912bfea4761845bfc3215374d091b Mon Sep 17 00:00:00 2001 From: spalger Date: Thu, 12 Dec 2019 11:13:06 -0700 Subject: [PATCH 52/79] skip flaky suite (#36011) --- x-pack/test/functional/apps/maps/layer_errors.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/functional/apps/maps/layer_errors.js b/x-pack/test/functional/apps/maps/layer_errors.js index 142ea7c4bf025..36a6e48eb88ef 100644 --- a/x-pack/test/functional/apps/maps/layer_errors.js +++ b/x-pack/test/functional/apps/maps/layer_errors.js @@ -65,7 +65,8 @@ export default function ({ getPageObjects }) { }); }); - describe('EMSFileSource with missing EMS id', () => { + // FLAKY: https://github.com/elastic/kibana/issues/36011 + describe.skip('EMSFileSource with missing EMS id', () => { const MISSING_EMS_ID = 'idThatDoesNotExitForEMSFileSource'; const LAYER_NAME = 'EMS_vector_shapes'; From af1a876f212a3d8a0e4d247e5bc8bf820ef80393 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 12 Dec 2019 19:16:32 +0100 Subject: [PATCH 53/79] [ML] Color Range Legend component (#52794) Introduces ColorRangeLegend, a reusable component to display a color range legend to go along with color coded table cells or visualizations such as heatmaps. --- .../_color_range_legend.scss | 18 ++ .../components/color_range_legend/_index.scss | 1 + .../color_range_legend/color_range_legend.tsx | 153 ++++++++++++++ .../components/color_range_legend/index.ts | 14 ++ .../use_color_range.test.ts | 59 ++++++ .../color_range_legend/use_color_range.ts | 188 ++++++++++++++++++ .../components/exploration/exploration.tsx | 107 +++++----- .../plugins/ml/public/application/index.scss | 1 + 8 files changed, 485 insertions(+), 56 deletions(-) create mode 100644 x-pack/legacy/plugins/ml/public/application/components/color_range_legend/_color_range_legend.scss create mode 100644 x-pack/legacy/plugins/ml/public/application/components/color_range_legend/_index.scss create mode 100644 x-pack/legacy/plugins/ml/public/application/components/color_range_legend/color_range_legend.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/components/color_range_legend/index.ts create mode 100644 x-pack/legacy/plugins/ml/public/application/components/color_range_legend/use_color_range.test.ts create mode 100644 x-pack/legacy/plugins/ml/public/application/components/color_range_legend/use_color_range.ts diff --git a/x-pack/legacy/plugins/ml/public/application/components/color_range_legend/_color_range_legend.scss b/x-pack/legacy/plugins/ml/public/application/components/color_range_legend/_color_range_legend.scss new file mode 100644 index 0000000000000..b164e605a2488 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/components/color_range_legend/_color_range_legend.scss @@ -0,0 +1,18 @@ +/* Overrides for d3/svg default styles */ +.mlColorRangeLegend { + text { + @include fontSize($euiFontSizeXS - 2px); + fill: $euiColorDarkShade; + } + + .axis path { + fill: none; + stroke: none; + } + + .axis line { + fill: none; + stroke: $euiColorMediumShade; + shape-rendering: crispEdges; + } +} diff --git a/x-pack/legacy/plugins/ml/public/application/components/color_range_legend/_index.scss b/x-pack/legacy/plugins/ml/public/application/components/color_range_legend/_index.scss new file mode 100644 index 0000000000000..c7cd3faac0dcf --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/components/color_range_legend/_index.scss @@ -0,0 +1 @@ +@import 'color_range_legend'; diff --git a/x-pack/legacy/plugins/ml/public/application/components/color_range_legend/color_range_legend.tsx b/x-pack/legacy/plugins/ml/public/application/components/color_range_legend/color_range_legend.tsx new file mode 100644 index 0000000000000..d6f0d347a57ec --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/components/color_range_legend/color_range_legend.tsx @@ -0,0 +1,153 @@ +/* + * 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, { useEffect, useRef, FC } from 'react'; +import d3 from 'd3'; + +import { EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; + +const COLOR_RANGE_RESOLUTION = 10; + +interface ColorRangeLegendProps { + colorRange: (d: number) => string; + justifyTicks?: boolean; + showTicks?: boolean; + title?: string; + width?: number; +} + +/** + * Component to render a legend for color ranges to be used for color coding + * table cells and visualizations. + * + * This current version supports normalized value ranges (0-1) only. + * + * @param props ColorRangeLegendProps + */ +export const ColorRangeLegend: FC = ({ + colorRange, + justifyTicks = false, + showTicks = true, + title, + width = 250, +}) => { + const d3Container = useRef(null); + + const scale = d3.range(COLOR_RANGE_RESOLUTION + 1).map(d => ({ + offset: (d / COLOR_RANGE_RESOLUTION) * 100, + stopColor: colorRange(d / COLOR_RANGE_RESOLUTION), + })); + + useEffect(() => { + if (d3Container.current === null) { + return; + } + + const wrapperHeight = 32; + const wrapperWidth = width; + + // top: 2 — adjust vertical alignment with title text + // bottom: 20 — room for axis ticks and labels + // left/right: 1 — room for first and last axis tick + // when justifyTicks is enabled, the left margin is increased to not cut off the first tick label + const margin = { top: 2, bottom: 20, left: justifyTicks || !showTicks ? 1 : 4, right: 1 }; + + const legendWidth = wrapperWidth - margin.left - margin.right; + const legendHeight = wrapperHeight - margin.top - margin.bottom; + + // remove, then redraw the legend + d3.select(d3Container.current) + .selectAll('*') + .remove(); + + const wrapper = d3 + .select(d3Container.current) + .classed('mlColorRangeLegend', true) + .attr('width', wrapperWidth) + .attr('height', wrapperHeight) + .append('g') + .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); + + // append gradient bar + const gradient = wrapper + .append('defs') + .append('linearGradient') + .attr('id', 'mlColorRangeGradient') + .attr('x1', '0%') + .attr('y1', '0%') + .attr('x2', '100%') + .attr('y2', '0%') + .attr('spreadMethod', 'pad'); + + scale.forEach(function(d) { + gradient + .append('stop') + .attr('offset', `${d.offset}%`) + .attr('stop-color', d.stopColor) + .attr('stop-opacity', 1); + }); + + wrapper + .append('rect') + .attr('x1', 0) + .attr('y1', 0) + .attr('width', legendWidth) + .attr('height', legendHeight) + .style('fill', 'url(#mlColorRangeGradient)'); + + const axisScale = d3.scale + .linear() + .domain([0, 1]) + .range([0, legendWidth]); + + // Using this formatter ensures we get e.g. `0` and not `0.0`, but still `0.1`, `0.2` etc. + const tickFormat = d3.format(''); + const legendAxis = d3.svg + .axis() + .scale(axisScale) + .orient('bottom') + .tickFormat(tickFormat) + .tickSize(legendHeight + 4) + .ticks(legendWidth / 40); + + wrapper + .append('g') + .attr('class', 'legend axis') + .attr('transform', 'translate(0, 0)') + .call(legendAxis); + + // Adjust the alignment of the first and last tick text + // so that the tick labels don't overflow the color range. + if (justifyTicks || !showTicks) { + const text = wrapper.selectAll('text')[0]; + if (text.length > 1) { + d3.select(text[0]).style('text-anchor', 'start'); + d3.select(text[text.length - 1]).style('text-anchor', 'end'); + } + } + + if (!showTicks) { + wrapper.selectAll('.axis line').style('display', 'none'); + } + }, [JSON.stringify(scale), d3Container.current]); + + if (title === undefined) { + return ; + } + + return ( + + + + {title} + + + + + + + ); +}; diff --git a/x-pack/legacy/plugins/ml/public/application/components/color_range_legend/index.ts b/x-pack/legacy/plugins/ml/public/application/components/color_range_legend/index.ts new file mode 100644 index 0000000000000..93a1ec40f1d5e --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/components/color_range_legend/index.ts @@ -0,0 +1,14 @@ +/* + * 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 { ColorRangeLegend } from './color_range_legend'; +export { + colorRangeOptions, + colorRangeScaleOptions, + useColorRange, + COLOR_RANGE, + COLOR_RANGE_SCALE, +} from './use_color_range'; diff --git a/x-pack/legacy/plugins/ml/public/application/components/color_range_legend/use_color_range.test.ts b/x-pack/legacy/plugins/ml/public/application/components/color_range_legend/use_color_range.test.ts new file mode 100644 index 0000000000000..f047ae800266b --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/components/color_range_legend/use_color_range.test.ts @@ -0,0 +1,59 @@ +/* + * 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 { influencerColorScaleFactory } from './use_color_range'; + +jest.mock('../../contexts/ui/use_ui_chrome_context'); + +describe('useColorRange', () => { + test('influencerColorScaleFactory(1)', () => { + const influencerColorScale = influencerColorScaleFactory(1); + + expect(influencerColorScale(0)).toBe(0); + expect(influencerColorScale(0.1)).toBe(0.1); + expect(influencerColorScale(0.2)).toBe(0.2); + expect(influencerColorScale(0.3)).toBe(0.3); + expect(influencerColorScale(0.4)).toBe(0.4); + expect(influencerColorScale(0.5)).toBe(0.5); + expect(influencerColorScale(0.6)).toBe(0.6); + expect(influencerColorScale(0.7)).toBe(0.7); + expect(influencerColorScale(0.8)).toBe(0.8); + expect(influencerColorScale(0.9)).toBe(0.9); + expect(influencerColorScale(1)).toBe(1); + }); + + test('influencerColorScaleFactory(2)', () => { + const influencerColorScale = influencerColorScaleFactory(2); + + expect(influencerColorScale(0)).toBe(0); + expect(influencerColorScale(0.1)).toBe(0); + expect(influencerColorScale(0.2)).toBe(0); + expect(influencerColorScale(0.3)).toBe(0); + expect(influencerColorScale(0.4)).toBe(0); + expect(influencerColorScale(0.5)).toBe(0); + expect(influencerColorScale(0.6)).toBe(0.04999999999999999); + expect(influencerColorScale(0.7)).toBe(0.09999999999999998); + expect(influencerColorScale(0.8)).toBe(0.15000000000000002); + expect(influencerColorScale(0.9)).toBe(0.2); + expect(influencerColorScale(1)).toBe(0.25); + }); + + test('influencerColorScaleFactory(3)', () => { + const influencerColorScale = influencerColorScaleFactory(3); + + expect(influencerColorScale(0)).toBe(0); + expect(influencerColorScale(0.1)).toBe(0); + expect(influencerColorScale(0.2)).toBe(0); + expect(influencerColorScale(0.3)).toBe(0); + expect(influencerColorScale(0.4)).toBe(0.05000000000000003); + expect(influencerColorScale(0.5)).toBe(0.125); + expect(influencerColorScale(0.6)).toBe(0.2); + expect(influencerColorScale(0.7)).toBe(0.27499999999999997); + expect(influencerColorScale(0.8)).toBe(0.35000000000000003); + expect(influencerColorScale(0.9)).toBe(0.425); + expect(influencerColorScale(1)).toBe(0.5); + }); +}); diff --git a/x-pack/legacy/plugins/ml/public/application/components/color_range_legend/use_color_range.ts b/x-pack/legacy/plugins/ml/public/application/components/color_range_legend/use_color_range.ts new file mode 100644 index 0000000000000..f9c5e6ff81f9e --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/components/color_range_legend/use_color_range.ts @@ -0,0 +1,188 @@ +/* + * 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 d3 from 'd3'; + +import euiThemeLight from '@elastic/eui/dist/eui_theme_light.json'; +import euiThemeDark from '@elastic/eui/dist/eui_theme_dark.json'; + +import { i18n } from '@kbn/i18n'; + +import { useUiChromeContext } from '../../contexts/ui/use_ui_chrome_context'; + +/** + * Custom color scale factory that takes the amount of feature influencers + * into account to adjust the contrast of the color range. This is used for + * color coding for outlier detection where the amount of feature influencers + * affects the threshold from which the influencers value can actually be + * considered influential. + * + * @param n number of influencers + * @returns a function suitable as a preprocessor for d3.scale.linear() + */ +export const influencerColorScaleFactory = (n: number) => (t: number) => { + // for 1 influencer or less we fall back to a plain linear scale. + if (n <= 1) { + return t; + } + + if (t < 1 / n) { + return 0; + } + if (t < 3 / n) { + return (n / 4) * (t - 1 / n); + } + return 0.5 + (t - 3 / n); +}; + +export enum COLOR_RANGE_SCALE { + LINEAR = 'linear', + INFLUENCER = 'influencer', + SQRT = 'sqrt', +} + +/** + * Color range scale options in the format for EuiSelect's options prop. + */ +export const colorRangeScaleOptions = [ + { + value: COLOR_RANGE_SCALE.LINEAR, + text: i18n.translate('xpack.ml.components.colorRangeLegend.linearScaleLabel', { + defaultMessage: 'Linear', + }), + }, + { + value: COLOR_RANGE_SCALE.INFLUENCER, + text: i18n.translate('xpack.ml.components.colorRangeLegend.influencerScaleLabel', { + defaultMessage: 'Influencer custom scale', + }), + }, + { + value: COLOR_RANGE_SCALE.SQRT, + text: i18n.translate('xpack.ml.components.colorRangeLegend.sqrtScaleLabel', { + defaultMessage: 'Sqrt', + }), + }, +]; + +export enum COLOR_RANGE { + BLUE = 'blue', + RED = 'red', + RED_GREEN = 'red-green', + GREEN_RED = 'green-red', + YELLOW_GREEN_BLUE = 'yellow-green-blue', +} + +/** + * Color range options in the format for EuiSelect's options prop. + */ +export const colorRangeOptions = [ + { + value: COLOR_RANGE.BLUE, + text: i18n.translate('xpack.ml.components.colorRangeLegend.blueColorRangeLabel', { + defaultMessage: 'Blue', + }), + }, + { + value: COLOR_RANGE.RED, + text: i18n.translate('xpack.ml.components.colorRangeLegend.redColorRangeLabel', { + defaultMessage: 'Red', + }), + }, + { + value: COLOR_RANGE.RED_GREEN, + text: i18n.translate('xpack.ml.components.colorRangeLegend.redGreenColorRangeLabel', { + defaultMessage: 'Red - Green', + }), + }, + { + value: COLOR_RANGE.GREEN_RED, + text: i18n.translate('xpack.ml.components.colorRangeLegend.greenRedColorRangeLabel', { + defaultMessage: 'Green - Red', + }), + }, + { + value: COLOR_RANGE.YELLOW_GREEN_BLUE, + text: i18n.translate('xpack.ml.components.colorRangeLegend.yellowGreenBlueColorRangeLabel', { + defaultMessage: 'Yellow - Green - Blue', + }), + }, +]; + +/** + * A custom Yellow-Green-Blue color range to demonstrate the support + * for more complex ranges with more than two colors. + */ +const coloursYGB = [ + '#FFFFDD', + '#AAF191', + '#80D385', + '#61B385', + '#3E9583', + '#217681', + '#285285', + '#1F2D86', + '#000086', +]; +const colourRangeYGB = d3.range(0, 1, 1.0 / (coloursYGB.length - 1)); +colourRangeYGB.push(1); + +const colorDomains = { + [COLOR_RANGE.BLUE]: [0, 1], + [COLOR_RANGE.RED]: [0, 1], + [COLOR_RANGE.RED_GREEN]: [0, 1], + [COLOR_RANGE.GREEN_RED]: [0, 1], + [COLOR_RANGE.YELLOW_GREEN_BLUE]: colourRangeYGB, +}; + +/** + * Custom hook to get a d3 based color range to be used for color coding in table cells. + * + * @param colorRange COLOR_RANGE enum. + * @param colorRangeScale COLOR_RANGE_SCALE enum. + * @param featureCount + */ +export const useColorRange = ( + colorRange = COLOR_RANGE.BLUE, + colorRangeScale = COLOR_RANGE_SCALE.LINEAR, + featureCount = 1 +) => { + const euiTheme = useUiChromeContext() + .getUiSettingsClient() + .get('theme:darkMode') + ? euiThemeDark + : euiThemeLight; + + const colorRanges = { + [COLOR_RANGE.BLUE]: [d3.rgb(euiTheme.euiColorEmptyShade), d3.rgb(euiTheme.euiColorVis1)], + [COLOR_RANGE.RED]: [d3.rgb(euiTheme.euiColorEmptyShade), d3.rgb(euiTheme.euiColorDanger)], + [COLOR_RANGE.RED_GREEN]: ['red', 'green'], + [COLOR_RANGE.GREEN_RED]: ['green', 'red'], + [COLOR_RANGE.YELLOW_GREEN_BLUE]: coloursYGB, + }; + + const linearScale = d3.scale + .linear() + .domain(colorDomains[colorRange]) + // typings for .range() incorrectly don't allow passing in a color extent. + // @ts-ignore + .range(colorRanges[colorRange]); + const influencerColorScale = influencerColorScaleFactory(featureCount); + const influencerScaleLinearWrapper = (n: number) => linearScale(influencerColorScale(n)); + + const scaleTypes = { + [COLOR_RANGE_SCALE.LINEAR]: linearScale, + [COLOR_RANGE_SCALE.INFLUENCER]: influencerScaleLinearWrapper, + [COLOR_RANGE_SCALE.SQRT]: d3.scale + .sqrt() + .domain(colorDomains[colorRange]) + // typings for .range() incorrectly don't allow passing in a color extent. + // @ts-ignore + .range(colorRanges[colorRange]), + }; + + return scaleTypes[colorRangeScale]; +}; diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration/exploration.tsx b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration/exploration.tsx index c4bba08353d84..31e6d409b1c4f 100644 --- a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration/exploration.tsx +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration/exploration.tsx @@ -4,13 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { FC, Fragment, useEffect, useState } from 'react'; +import React, { FC, useEffect, useState } from 'react'; import moment from 'moment-timezone'; import { i18n } from '@kbn/i18n'; -import d3 from 'd3'; - import { EuiBadge, EuiButtonIcon, @@ -18,7 +16,6 @@ import { EuiCheckbox, EuiFlexGroup, EuiFlexItem, - EuiFormRow, EuiPanel, EuiPopover, EuiPopoverTitle, @@ -30,9 +27,12 @@ import { Query, } from '@elastic/eui'; -import euiThemeLight from '@elastic/eui/dist/eui_theme_light.json'; -import euiThemeDark from '@elastic/eui/dist/eui_theme_dark.json'; - +import { + useColorRange, + ColorRangeLegend, + COLOR_RANGE, + COLOR_RANGE_SCALE, +} from '../../../../../components/color_range_legend'; import { ColumnType, mlInMemoryTableBasicFactory, @@ -41,8 +41,6 @@ import { SORT_DIRECTION, } from '../../../../../components/ml_in_memory_table'; -import { useUiChromeContext } from '../../../../../contexts/ui/use_ui_chrome_context'; - import { formatHumanReadableDateTimeSeconds } from '../../../../../util/date_utils'; import { ml } from '../../../../../services/ml_api_service'; @@ -67,16 +65,6 @@ import { import { getTaskStateBadge } from '../../../analytics_management/components/analytics_list/columns'; import { SavedSearchQuery } from '../../../../../contexts/kibana'; -const customColorScaleFactory = (n: number) => (t: number) => { - if (t < 1 / n) { - return 0; - } - if (t < 3 / n) { - return (n / 4) * (t - 1 / n); - } - return 0.5 + (t - 3 / n); -}; - const FEATURE_INFLUENCE = 'feature_influence'; interface GetDataFrameAnalyticsResponse { @@ -102,6 +90,16 @@ interface Props { jobStatus: DATA_FRAME_TASK_STATE; } +const getFeatureCount = (jobConfig?: DataFrameAnalyticsConfig, tableItems: TableItem[] = []) => { + if (jobConfig === undefined || tableItems.length === 0) { + return 0; + } + + return Object.keys(tableItems[0]).filter(key => + key.includes(`${jobConfig.dest.results_field}.${FEATURE_INFLUENCE}.`) + ).length; +}; + export const Exploration: FC = React.memo(({ jobId, jobStatus }) => { const [jobConfig, setJobConfig] = useState(undefined); @@ -126,12 +124,6 @@ export const Exploration: FC = React.memo(({ jobId, jobStatus }) => { })(); }, []); - const euiTheme = useUiChromeContext() - .getUiSettingsClient() - .get('theme:darkMode') - ? euiThemeDark - : euiThemeLight; - const [selectedFields, setSelectedFields] = useState([] as EsFieldName[]); const [isColumnsPopoverVisible, setColumnsPopoverVisible] = useState(false); @@ -169,23 +161,13 @@ export const Exploration: FC = React.memo(({ jobId, jobStatus }) => { const columns: Array> = []; - if (jobConfig !== undefined && selectedFields.length > 0 && tableItems.length > 0) { - // table cell color coding takes into account: - // - whether the theme is dark/light - // - the number of analysis features - // based on that - const cellBgColorScale = d3.scale - .linear() - .domain([0, 1]) - // typings for .range() incorrectly don't allow passing in a color extent. - // @ts-ignore - .range([d3.rgb(euiTheme.euiColorEmptyShade), d3.rgb(euiTheme.euiColorVis1)]); - const featureCount = Object.keys(tableItems[0]).filter(key => - key.includes(`${jobConfig.dest.results_field}.${FEATURE_INFLUENCE}.`) - ).length; - const customScale = customColorScaleFactory(featureCount); - const cellBgColor = (n: number) => cellBgColorScale(customScale(n)); + const cellBgColor = useColorRange( + COLOR_RANGE.BLUE, + COLOR_RANGE_SCALE.INFLUENCER, + getFeatureCount(jobConfig, tableItems) + ); + if (jobConfig !== undefined && selectedFields.length > 0 && tableItems.length > 0) { columns.push( ...selectedFields.sort(sortColumns(tableItems[0], jobConfig.dest.results_field)).map(k => { const column: ColumnType = { @@ -504,21 +486,34 @@ export const Exploration: FC = React.memo(({ jobId, jobStatus }) => { )} {(columns.length > 0 || searchQuery !== defaultSearchQuery) && sortField !== '' && ( - - {tableItems.length === SEARCH_SIZE && ( - + + + + {tableItems.length === SEARCH_SIZE && ( + + {i18n.translate( + 'xpack.ml.dataframe.analytics.exploration.documentsShownHelpText', + { + defaultMessage: 'Showing first {searchSize} documents', + values: { searchSize: SEARCH_SIZE }, + } + )} + )} - > - - - )} - + + + + + = React.memo(({ jobId, jobStatus }) => { search={search} error={tableError} /> - + )} ); diff --git a/x-pack/legacy/plugins/ml/public/application/index.scss b/x-pack/legacy/plugins/ml/public/application/index.scss index dbcdf288b6a85..ecef2bbf9a597 100644 --- a/x-pack/legacy/plugins/ml/public/application/index.scss +++ b/x-pack/legacy/plugins/ml/public/application/index.scss @@ -28,6 +28,7 @@ @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/color_range_legend/index'; @import 'components/controls/index'; @import 'components/entity_cell/index'; @import 'components/field_title_bar/index'; From 79a85286460ddd581428aa515d3bcf9676a2f998 Mon Sep 17 00:00:00 2001 From: Bill McConaghy Date: Thu, 12 Dec 2019 13:41:10 -0500 Subject: [PATCH 54/79] fixing CODEOWNERS file (#52919) --- .github/CODEOWNERS | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 338fbf2e359b7..36a2cda841fa8 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -97,15 +97,19 @@ /x-pack/plugins/security/ @elastic/kibana-security /x-pack/test/api_integration/apis/security/ @elastic/kibana-security -# Kibana Stack Services -/src/dev/i18n @elastic/kibana-stack-services -/packages/kbn-analytics/ @elastic/kibana-stack-services -/src/legacy/core_plugins/ui_metric/ @elastic/kibana-stack-services -/src/plugins/usage_collection/ @elastic/kibana-stack-services -/x-pack/legacy/plugins/telemetry @elastic/kibana-stack-services -/x-pack/legacy/plugins/alerting @elastic/kibana-stack-services -/x-pack/legacy/plugins/actions @elastic/kibana-stack-services -/x-pack/legacy/plugins/task_manager @elastic/kibana-stack-services +# Kibana Localization +/src/dev/i18n @elastic/kibana-localization + +# Pulse +/packages/kbn-analytics/ @elastic/pulse +/src/legacy/core_plugins/ui_metric/ @elastic/pulse +/src/plugins/usage_collection/ @elastic/pulse +/x-pack/legacy/plugins/telemetry @elastic/pulse + +# Kibana Alerting Services +/x-pack/legacy/plugins/alerting @elastic/kibana-alerting-services +/x-pack/legacy/plugins/actions @elastic/kibana-alerting-services +/x-pack/legacy/plugins/task_manager @elastic/kibana-alerting-services # Design **/*.scss @elastic/kibana-design From 0cd5bb0ca97fcd91961ef3e67a6bbe3c5f8c96df Mon Sep 17 00:00:00 2001 From: Melissa Alvarez Date: Thu, 12 Dec 2019 12:02:04 -0700 Subject: [PATCH 55/79] [ML] DF Analytics: create classification jobs results view (#52584) * wip: create classification results page + table and evaluate panel * enable view link for classification jobs * wip: fetch classification eval data * wip: display confusion matrix in datagrid * evaluate panel: add heatmap for cells and doc count * Update use of loadEvalData in expanded row component * Add metric type for evaluate endpoint and fix localization error * handle no incorrect prediction classes case for confusion matrix. remove unused translation * setCellProps needs to be called from a lifecycle method - wrap in useEffect * TypeScript improvements * fix datagrid column resize affecting results table * allow custom prediction field for classification jobs * ensure values are rounded correctly and add tooltip * temp workaroun for datagrid width issues --- .../data_frame_analytics/_index.scss | 1 + .../data_frame_analytics/common/analytics.ts | 186 +++++-- .../data_frame_analytics/common/fields.ts | 57 ++- .../data_frame_analytics/common/index.ts | 2 + .../_classification_exploration.scss | 4 + .../classification_exploration/_index.scss | 1 + .../classification_exploration.tsx | 120 +++++ .../column_data.tsx | 80 +++ .../evaluate_panel.tsx | 343 +++++++++++++ .../classification_exploration/index.ts | 7 + .../results_table.tsx | 481 ++++++++++++++++++ .../use_explore_data.ts | 156 ++++++ .../error_callout.tsx | 0 .../components/error_callout/index.ts | 7 + .../components/loading_panel/index.ts | 7 + .../loading_panel/loading_panel.tsx | 14 + .../regression_exploration/evaluate_panel.tsx | 107 ++-- .../regression_exploration.tsx | 17 +- .../regression_exploration/results_table.tsx | 4 +- .../use_explore_data.ts | 5 - .../pages/analytics_exploration/page.tsx | 4 + .../components/analytics_list/actions.tsx | 5 +- .../analytics_list/expanded_row.tsx | 20 +- .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 25 files changed, 1514 insertions(+), 116 deletions(-) create mode 100644 x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/_classification_exploration.scss create mode 100644 x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/_index.scss create mode 100644 x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/classification_exploration.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/column_data.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_panel.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/index.ts create mode 100644 x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/results_table.tsx create mode 100644 x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/use_explore_data.ts rename x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/{regression_exploration => error_callout}/error_callout.tsx (100%) create mode 100644 x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/error_callout/index.ts create mode 100644 x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/loading_panel/index.ts create mode 100644 x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/loading_panel/loading_panel.tsx diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/_index.scss b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/_index.scss index c231c405b5369..962d3f4c7bd54 100644 --- a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/_index.scss +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/_index.scss @@ -1,5 +1,6 @@ @import 'pages/analytics_exploration/components/exploration/index'; @import 'pages/analytics_exploration/components/regression_exploration/index'; +@import 'pages/analytics_exploration/components/classification_exploration/index'; @import 'pages/analytics_management/components/analytics_list/index'; @import 'pages/analytics_management/components/create_analytics_form/index'; @import 'pages/analytics_management/components/create_analytics_flyout/index'; diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/common/analytics.ts b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/common/analytics.ts index 0642c1fbe6186..cadc1f01c6dda 100644 --- a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/common/analytics.ts +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/common/analytics.ts @@ -35,6 +35,7 @@ interface ClassificationAnalysis { dependent_variable: string; training_percent?: number; num_top_classes?: string; + prediction_field_name?: string; }; } @@ -74,13 +75,33 @@ export interface RegressionEvaluateResponse { }; } +export interface PredictedClass { + predicted_class: string; + count: number; +} + +export interface ConfusionMatrix { + actual_class: string; + actual_class_doc_count: number; + predicted_classes: PredictedClass[]; + other_predicted_class_doc_count: number; +} + +export interface ClassificationEvaluateResponse { + classification: { + multiclass_confusion_matrix: { + confusion_matrix: ConfusionMatrix[]; + }; + }; +} + interface GenericAnalysis { [key: string]: Record; } interface LoadEvaluateResult { success: boolean; - eval: RegressionEvaluateResponse | null; + eval: RegressionEvaluateResponse | ClassificationEvaluateResponse | null; error: string | null; } @@ -109,6 +130,7 @@ export const getAnalysisType = (analysis: AnalysisConfig) => { export const getDependentVar = (analysis: AnalysisConfig) => { let depVar = ''; + if (isRegressionAnalysis(analysis)) { depVar = analysis.regression.dependent_variable; } @@ -124,17 +146,26 @@ export const getPredictionFieldName = (analysis: AnalysisConfig) => { let predictionFieldName; if (isRegressionAnalysis(analysis) && analysis.regression.prediction_field_name !== undefined) { predictionFieldName = analysis.regression.prediction_field_name; + } else if ( + isClassificationAnalysis(analysis) && + analysis.classification.prediction_field_name !== undefined + ) { + predictionFieldName = analysis.classification.prediction_field_name; } return predictionFieldName; }; -export const getPredictedFieldName = (resultsField: string, analysis: AnalysisConfig) => { +export const getPredictedFieldName = ( + resultsField: string, + analysis: AnalysisConfig, + forSort?: boolean +) => { // default is 'ml' const predictionFieldName = getPredictionFieldName(analysis); const defaultPredictionField = `${getDependentVar(analysis)}_prediction`; const predictedField = `${resultsField}.${ predictionFieldName ? predictionFieldName : defaultPredictionField - }`; + }${isClassificationAnalysis(analysis) && !forSort ? '.keyword' : ''}`; return predictedField; }; @@ -153,13 +184,32 @@ export const isClassificationAnalysis = (arg: any): arg is ClassificationAnalysi return keys.length === 1 && keys[0] === ANALYSIS_CONFIG_TYPE.CLASSIFICATION; }; -export const isRegressionResultsSearchBoolQuery = ( - arg: any -): arg is RegressionResultsSearchBoolQuery => { +export const isResultsSearchBoolQuery = (arg: any): arg is ResultsSearchBoolQuery => { const keys = Object.keys(arg); return keys.length === 1 && keys[0] === 'bool'; }; +export const isRegressionEvaluateResponse = (arg: any): arg is RegressionEvaluateResponse => { + const keys = Object.keys(arg); + return ( + keys.length === 1 && + keys[0] === ANALYSIS_CONFIG_TYPE.REGRESSION && + arg?.regression?.mean_squared_error !== undefined && + arg?.regression?.r_squared !== undefined + ); +}; + +export const isClassificationEvaluateResponse = ( + arg: any +): arg is ClassificationEvaluateResponse => { + const keys = Object.keys(arg); + return ( + keys.length === 1 && + keys[0] === ANALYSIS_CONFIG_TYPE.CLASSIFICATION && + arg?.classification?.multiclass_confusion_matrix !== undefined + ); +}; + export interface DataFrameAnalyticsConfig { id: DataFrameAnalyticsId; // Description attribute is not supported yet @@ -254,17 +304,14 @@ export function getValuesFromResponse(response: RegressionEvaluateResponse) { return { meanSquaredError, rSquared }; } -interface RegressionResultsSearchBoolQuery { +interface ResultsSearchBoolQuery { bool: Dictionary; } -interface RegressionResultsSearchTermQuery { +interface ResultsSearchTermQuery { term: Dictionary; } -export type RegressionResultsSearchQuery = - | RegressionResultsSearchBoolQuery - | RegressionResultsSearchTermQuery - | SavedSearchQuery; +export type ResultsSearchQuery = ResultsSearchBoolQuery | ResultsSearchTermQuery | SavedSearchQuery; export function getEvalQueryBody({ resultsField, @@ -274,16 +321,16 @@ export function getEvalQueryBody({ }: { resultsField: string; isTraining: boolean; - searchQuery?: RegressionResultsSearchQuery; + searchQuery?: ResultsSearchQuery; ignoreDefaultQuery?: boolean; }) { - let query: RegressionResultsSearchQuery = { + let query: ResultsSearchQuery = { term: { [`${resultsField}.is_training`]: { value: isTraining } }, }; if (searchQuery !== undefined && ignoreDefaultQuery === true) { query = searchQuery; - } else if (searchQuery !== undefined && isRegressionResultsSearchBoolQuery(searchQuery)) { + } else if (searchQuery !== undefined && isResultsSearchBoolQuery(searchQuery)) { const searchQueryClone = cloneDeep(searchQuery); searchQueryClone.bool.must.push(query); query = searchQueryClone; @@ -291,6 +338,27 @@ export function getEvalQueryBody({ return query; } +interface EvaluateMetrics { + classification: { + multiclass_confusion_matrix: object; + }; + regression: { + r_squared: object; + mean_squared_error: object; + }; +} + +interface LoadEvalDataConfig { + isTraining: boolean; + index: string; + dependentVariable: string; + resultsField: string; + predictionFieldName?: string; + searchQuery?: ResultsSearchQuery; + ignoreDefaultQuery?: boolean; + jobType: ANALYSIS_CONFIG_TYPE; +} + export const loadEvalData = async ({ isTraining, index, @@ -299,34 +367,38 @@ export const loadEvalData = async ({ predictionFieldName, searchQuery, ignoreDefaultQuery, -}: { - isTraining: boolean; - index: string; - dependentVariable: string; - resultsField: string; - predictionFieldName?: string; - searchQuery?: RegressionResultsSearchQuery; - ignoreDefaultQuery?: boolean; -}) => { + jobType, +}: LoadEvalDataConfig) => { const results: LoadEvaluateResult = { success: false, eval: null, error: null }; const defaultPredictionField = `${dependentVariable}_prediction`; - const predictedField = `${resultsField}.${ + let predictedField = `${resultsField}.${ predictionFieldName ? predictionFieldName : defaultPredictionField }`; + if (jobType === ANALYSIS_CONFIG_TYPE.CLASSIFICATION) { + predictedField = `${predictedField}.keyword`; + } + const query = getEvalQueryBody({ resultsField, isTraining, searchQuery, ignoreDefaultQuery }); + const metrics: EvaluateMetrics = { + classification: { + multiclass_confusion_matrix: {}, + }, + regression: { + r_squared: {}, + mean_squared_error: {}, + }, + }; + const config = { index, query, evaluation: { - regression: { + [jobType]: { actual_field: dependentVariable, predicted_field: predictedField, - metrics: { - r_squared: {}, - mean_squared_error: {}, - }, + metrics: metrics[jobType as keyof EvaluateMetrics], }, }, }; @@ -341,3 +413,57 @@ export const loadEvalData = async ({ return results; } }; + +interface TrackTotalHitsSearchResponse { + hits: { + total: { + value: number; + relation: string; + }; + hits: any[]; + }; +} + +interface LoadDocsCountConfig { + ignoreDefaultQuery?: boolean; + isTraining: boolean; + searchQuery: SavedSearchQuery; + resultsField: string; + destIndex: string; +} + +interface LoadDocsCountResponse { + docsCount: number | null; + success: boolean; +} + +export const loadDocsCount = async ({ + ignoreDefaultQuery = true, + isTraining, + searchQuery, + resultsField, + destIndex, +}: LoadDocsCountConfig): Promise => { + const query = getEvalQueryBody({ resultsField, isTraining, ignoreDefaultQuery, searchQuery }); + + try { + const body: SearchQuery = { + track_total_hits: true, + query, + }; + + const resp: TrackTotalHitsSearchResponse = await ml.esSearch({ + index: destIndex, + size: 0, + body, + }); + + const docsCount = resp.hits.total && resp.hits.total.value; + return { docsCount, success: docsCount !== undefined }; + } catch (e) { + return { + docsCount: null, + success: false, + }; + } +}; diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/common/fields.ts b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/common/fields.ts index 5621d77f66469..216836db4ccbc 100644 --- a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/common/fields.ts +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/common/fields.ts @@ -77,7 +77,7 @@ export const sortRegressionResultsFields = ( ) => { const dependentVariable = getDependentVar(jobConfig.analysis); const resultsField = jobConfig.dest.results_field; - const predictedField = getPredictedFieldName(resultsField, jobConfig.analysis); + const predictedField = getPredictedFieldName(resultsField, jobConfig.analysis, true); if (a === `${resultsField}.is_training`) { return -1; } @@ -96,6 +96,14 @@ export const sortRegressionResultsFields = ( if (b === dependentVariable) { return 1; } + + if (a === `${resultsField}.prediction_probability`) { + return -1; + } + if (b === `${resultsField}.prediction_probability`) { + return 1; + } + return a.localeCompare(b); }; @@ -107,7 +115,7 @@ export const sortRegressionResultsColumns = ( ) => (a: string, b: string) => { const dependentVariable = getDependentVar(jobConfig.analysis); const resultsField = jobConfig.dest.results_field; - const predictedField = getPredictedFieldName(resultsField, jobConfig.analysis); + const predictedField = getPredictedFieldName(resultsField, jobConfig.analysis, true); const typeofA = typeof obj[a]; const typeofB = typeof obj[b]; @@ -136,6 +144,14 @@ export const sortRegressionResultsColumns = ( return 1; } + if (a === `${resultsField}.prediction_probability`) { + return -1; + } + + if (b === `${resultsField}.prediction_probability`) { + return 1; + } + if (typeofA !== 'string' && typeofB === 'string') { return 1; } @@ -184,6 +200,43 @@ export function getFlattenedFields(obj: EsDocSource, resultsField: string): EsFi return flatDocFields.filter(f => f !== ML__ID_COPY); } +export const getDefaultClassificationFields = ( + docs: EsDoc[], + jobConfig: DataFrameAnalyticsConfig +): EsFieldName[] => { + if (docs.length === 0) { + return []; + } + const resultsField = jobConfig.dest.results_field; + const newDocFields = getFlattenedFields(docs[0]._source, resultsField); + return newDocFields + .filter(k => { + if (k === `${resultsField}.is_training`) { + return true; + } + // predicted value of dependent variable + if (k === getPredictedFieldName(resultsField, jobConfig.analysis, true)) { + return true; + } + // actual value of dependent variable + if (k === getDependentVar(jobConfig.analysis)) { + return true; + } + + if (k === `${resultsField}.prediction_probability`) { + return true; + } + + if (k.split('.')[0] === resultsField) { + return false; + } + + return docs.some(row => row._source[k] !== null); + }) + .sort((a, b) => sortRegressionResultsFields(a, b, jobConfig)) + .slice(0, DEFAULT_REGRESSION_COLUMNS); +}; + export const getDefaultRegressionFields = ( docs: EsDoc[], jobConfig: DataFrameAnalyticsConfig diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/common/index.ts b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/common/index.ts index 02a1c30259cce..f7794af8b5861 100644 --- a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/common/index.ts +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/common/index.ts @@ -20,6 +20,7 @@ export { RegressionEvaluateResponse, getValuesFromResponse, loadEvalData, + loadDocsCount, Eval, getPredictedFieldName, INDEX_STATUS, @@ -31,6 +32,7 @@ export { export { getDefaultSelectableFields, getDefaultRegressionFields, + getDefaultClassificationFields, getFlattenedFields, sortColumns, sortRegressionResultsColumns, diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/_classification_exploration.scss b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/_classification_exploration.scss new file mode 100644 index 0000000000000..1141dddf398b0 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/_classification_exploration.scss @@ -0,0 +1,4 @@ +.euiFormRow.mlDataFrameAnalyticsClassification__actualLabel { + padding-top: $euiSize * 4; +} + diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/_index.scss b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/_index.scss new file mode 100644 index 0000000000000..88edd92951d41 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/_index.scss @@ -0,0 +1 @@ +@import 'classification_exploration'; diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/classification_exploration.tsx b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/classification_exploration.tsx new file mode 100644 index 0000000000000..f424ebee58120 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/classification_exploration.tsx @@ -0,0 +1,120 @@ +/* + * 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, Fragment, useState, useEffect } from 'react'; +import { EuiCallOut, EuiPanel, EuiSpacer, EuiTitle } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { ml } from '../../../../../services/ml_api_service'; +import { DataFrameAnalyticsConfig } from '../../../../common'; +import { EvaluatePanel } from './evaluate_panel'; +import { ResultsTable } from './results_table'; +import { DATA_FRAME_TASK_STATE } from '../../../analytics_management/components/analytics_list/common'; +import { ResultsSearchQuery, defaultSearchQuery } from '../../../../common/analytics'; +import { LoadingPanel } from '../loading_panel'; + +interface GetDataFrameAnalyticsResponse { + count: number; + data_frame_analytics: DataFrameAnalyticsConfig[]; +} + +export const ExplorationTitle: React.FC<{ jobId: string }> = ({ jobId }) => ( + + + {i18n.translate('xpack.ml.dataframe.analytics.classificationExploration.tableJobIdTitle', { + defaultMessage: 'Destination index for classification job ID {jobId}', + values: { jobId }, + })} + + +); + +interface Props { + jobId: string; + jobStatus: DATA_FRAME_TASK_STATE; +} + +export const ClassificationExploration: FC = ({ jobId, jobStatus }) => { + const [jobConfig, setJobConfig] = useState(undefined); + const [isLoadingJobConfig, setIsLoadingJobConfig] = useState(false); + const [jobConfigErrorMessage, setJobConfigErrorMessage] = useState(undefined); + const [searchQuery, setSearchQuery] = useState(defaultSearchQuery); + + const loadJobConfig = async () => { + setIsLoadingJobConfig(true); + try { + const analyticsConfigs: GetDataFrameAnalyticsResponse = await ml.dataFrameAnalytics.getDataFrameAnalytics( + jobId + ); + if ( + Array.isArray(analyticsConfigs.data_frame_analytics) && + analyticsConfigs.data_frame_analytics.length > 0 + ) { + setJobConfig(analyticsConfigs.data_frame_analytics[0]); + setIsLoadingJobConfig(false); + } else { + setJobConfigErrorMessage( + i18n.translate( + 'xpack.ml.dataframe.analytics.classificationExploration.jobConfigurationNoResultsMessage', + { + defaultMessage: 'No results found.', + } + ) + ); + } + } catch (e) { + if (e.message !== undefined) { + setJobConfigErrorMessage(e.message); + } else { + setJobConfigErrorMessage(JSON.stringify(e)); + } + setIsLoadingJobConfig(false); + } + }; + + useEffect(() => { + loadJobConfig(); + }, []); + + if (jobConfigErrorMessage !== undefined) { + return ( + + + + +

{jobConfigErrorMessage}

+
+
+ ); + } + + return ( + + {isLoadingJobConfig === true && jobConfig === undefined && } + {isLoadingJobConfig === false && jobConfig !== undefined && ( + + )} + + {isLoadingJobConfig === true && jobConfig === undefined && } + {isLoadingJobConfig === false && jobConfig !== undefined && ( + + )} + + ); +}; diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/column_data.tsx b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/column_data.tsx new file mode 100644 index 0000000000000..5a08dd159affb --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/column_data.tsx @@ -0,0 +1,80 @@ +/* + * 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 { ConfusionMatrix, PredictedClass } from '../../../../common/analytics'; + +interface ColumnData { + actual_class: string; + actual_class_doc_count: number; + predicted_class?: string; + count?: number; + error_count?: number; +} + +export function getColumnData(confusionMatrixData: ConfusionMatrix[]) { + const colData: Partial = []; + + confusionMatrixData.forEach((classData: any) => { + const correctlyPredictedClass = classData.predicted_classes.find( + (pc: PredictedClass) => pc.predicted_class === classData.actual_class + ); + const incorrectlyPredictedClass = classData.predicted_classes.find( + (pc: PredictedClass) => pc.predicted_class !== classData.actual_class + ); + + let accuracy; + if (correctlyPredictedClass !== undefined) { + accuracy = correctlyPredictedClass.count / classData.actual_class_doc_count; + // round to 2 decimal places without converting to string; + accuracy = Math.round(accuracy * 100) / 100; + } + + let error; + if (incorrectlyPredictedClass !== undefined) { + error = incorrectlyPredictedClass.count / classData.actual_class_doc_count; + error = Math.round(error * 100) / 100; + } + + let col: any = { + actual_class: classData.actual_class, + actual_class_doc_count: classData.actual_class_doc_count, + }; + + if (correctlyPredictedClass !== undefined) { + col = { + ...col, + predicted_class: correctlyPredictedClass.predicted_class, + [correctlyPredictedClass.predicted_class]: accuracy, + count: correctlyPredictedClass.count, + accuracy, + }; + } + + if (incorrectlyPredictedClass !== undefined) { + col = { + ...col, + [incorrectlyPredictedClass.predicted_class]: error, + error_count: incorrectlyPredictedClass.count, + }; + } + + colData.push(col); + }); + + const columns: any = [ + { + id: 'actual_class', + display: , + }, + ]; + + colData.forEach((data: any) => { + columns.push({ id: data.predicted_class }); + }); + + return { columns, columnData: colData }; +} diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_panel.tsx b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_panel.tsx new file mode 100644 index 0000000000000..ddf52943c2feb --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_panel.tsx @@ -0,0 +1,343 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC, useState, useEffect, Fragment } from 'react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { + EuiDataGrid, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiIconTip, + EuiPanel, + EuiSpacer, + EuiText, + EuiTitle, +} from '@elastic/eui'; +import { ErrorCallout } from '../error_callout'; +import { + getDependentVar, + getPredictionFieldName, + loadEvalData, + loadDocsCount, + DataFrameAnalyticsConfig, +} from '../../../../common'; +import { getTaskStateBadge } from '../../../analytics_management/components/analytics_list/columns'; +import { DATA_FRAME_TASK_STATE } from '../../../analytics_management/components/analytics_list/common'; +import { + isResultsSearchBoolQuery, + isClassificationEvaluateResponse, + ConfusionMatrix, + ResultsSearchQuery, + ANALYSIS_CONFIG_TYPE, +} from '../../../../common/analytics'; +import { LoadingPanel } from '../loading_panel'; +import { getColumnData } from './column_data'; + +const defaultPanelWidth = 500; + +interface Props { + jobConfig: DataFrameAnalyticsConfig; + jobStatus: DATA_FRAME_TASK_STATE; + searchQuery: ResultsSearchQuery; +} + +export const EvaluatePanel: FC = ({ jobConfig, jobStatus, searchQuery }) => { + const [isLoading, setIsLoading] = useState(false); + const [confusionMatrixData, setConfusionMatrixData] = useState([]); + const [columns, setColumns] = useState([]); + const [columnsData, setColumnsData] = useState([]); + const [popoverContents, setPopoverContents] = useState([]); + const [docsCount, setDocsCount] = useState(null); + const [error, setError] = useState(null); + const [panelWidth, setPanelWidth] = useState(defaultPanelWidth); + + // Column visibility + const [visibleColumns, setVisibleColumns] = useState(() => + columns.map(({ id }: { id: string }) => id) + ); + + const index = jobConfig.dest.index; + const dependentVariable = getDependentVar(jobConfig.analysis); + const predictionFieldName = getPredictionFieldName(jobConfig.analysis); + // default is 'ml' + const resultsField = jobConfig.dest.results_field; + + const loadData = async ({ + isTrainingClause, + ignoreDefaultQuery = true, + }: { + isTrainingClause: { query: string; operator: string }; + ignoreDefaultQuery?: boolean; + }) => { + setIsLoading(true); + + const evalData = await loadEvalData({ + isTraining: false, + index, + dependentVariable, + resultsField, + predictionFieldName, + searchQuery, + ignoreDefaultQuery, + jobType: ANALYSIS_CONFIG_TYPE.CLASSIFICATION, + }); + + const docsCountResp = await loadDocsCount({ + isTraining: false, + searchQuery, + resultsField, + destIndex: jobConfig.dest.index, + }); + + if ( + evalData.success === true && + evalData.eval && + isClassificationEvaluateResponse(evalData.eval) + ) { + const confusionMatrix = + evalData.eval?.classification?.multiclass_confusion_matrix?.confusion_matrix; + setError(null); + setConfusionMatrixData(confusionMatrix || []); + setIsLoading(false); + } else { + setIsLoading(false); + setConfusionMatrixData([]); + setError(evalData.error); + } + + if (docsCountResp.success === true) { + setDocsCount(docsCountResp.docsCount); + } else { + setDocsCount(null); + } + }; + + const resizeHandler = () => { + const tablePanelWidth: number = + document.getElementById('mlDataFrameAnalyticsTableResultsPanel')?.clientWidth || + defaultPanelWidth; + // Keep the evaluate panel width slightly smaller than the results table + // to ensure results table can resize correctly. Temporary workaround DataGrid issue with flex + const newWidth = tablePanelWidth - 8; + setPanelWidth(newWidth); + }; + + useEffect(() => { + window.addEventListener('resize', resizeHandler); + resizeHandler(); + return () => { + window.removeEventListener('resize', resizeHandler); + }; + }, []); + + useEffect(() => { + if (confusionMatrixData.length > 0) { + const { columns: derivedColumns, columnData } = getColumnData(confusionMatrixData); + // Initialize all columns as visible + setVisibleColumns(() => derivedColumns.map(({ id }: { id: string }) => id)); + setColumns(derivedColumns); + setColumnsData(columnData); + setPopoverContents({ + numeric: ({ + cellContentsElement, + children, + }: { + cellContentsElement: any; + children: any; + }) => { + const rowIndex = children?.props?.rowIndex; + const colId = children?.props?.columnId; + const gridItem = columnData[rowIndex]; + + if (gridItem !== undefined) { + const count = colId === gridItem.actual_class ? gridItem.count : gridItem.error_count; + return `${count} / ${gridItem.actual_class_doc_count} * 100 = ${cellContentsElement.textContent}`; + } + + return cellContentsElement.textContent; + }, + }); + } + }, [confusionMatrixData]); + + useEffect(() => { + const hasIsTrainingClause = + isResultsSearchBoolQuery(searchQuery) && + searchQuery.bool.must.filter( + (clause: any) => clause.match && clause.match[`${resultsField}.is_training`] !== undefined + ); + const isTrainingClause = + hasIsTrainingClause && + hasIsTrainingClause[0] && + hasIsTrainingClause[0].match[`${resultsField}.is_training`]; + + loadData({ isTrainingClause }); + }, [JSON.stringify(searchQuery)]); + + const renderCellValue = ({ + rowIndex, + columnId, + setCellProps, + }: { + rowIndex: number; + columnId: string; + setCellProps: any; + }) => { + const cellValue = columnsData[rowIndex][columnId]; + // eslint-disable-next-line react-hooks/rules-of-hooks + useEffect(() => { + setCellProps({ + style: { + backgroundColor: `rgba(0, 179, 164, ${cellValue})`, + }, + }); + }, [rowIndex, columnId, setCellProps]); + return ( + {typeof cellValue === 'number' ? `${Math.round(cellValue * 100)}%` : cellValue} + ); + }; + + if (isLoading === true) { + return ; + } + + return ( + + + + + + + + {i18n.translate( + 'xpack.ml.dataframe.analytics.classificationExploration.evaluateJobIdTitle', + { + defaultMessage: 'Evaluation of classification job ID {jobId}', + values: { jobId: jobConfig.id }, + } + )} + + + + + {getTaskStateBadge(jobStatus)} + + + + {error !== null && ( + + + + )} + {error === null && ( + + + + + + {i18n.translate( + 'xpack.ml.dataframe.analytics.classificationExploration.confusionMatrixHelpText', + { + defaultMessage: 'Normalized confusion matrix', + } + )} + + + + + + + + {docsCount !== null && ( + + + + + + )} + {/* BEGIN TABLE ELEMENTS */} + + + + + + + + + {columns.length > 0 && columnsData.length > 0 && ( + + + + + + + + + + + + + + + + + + + + + + + )} + + + + + )} + {/* END TABLE ELEMENTS */} + + + ); +}; diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/index.ts b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/index.ts new file mode 100644 index 0000000000000..4c75d8315b230 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/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 { ClassificationExploration } from './classification_exploration'; diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/results_table.tsx b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/results_table.tsx new file mode 100644 index 0000000000000..1be158499a3f4 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/results_table.tsx @@ -0,0 +1,481 @@ +/* + * 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, { Fragment, FC, useEffect, useState } from 'react'; +import moment from 'moment-timezone'; + +import { i18n } from '@kbn/i18n'; +import { + EuiBadge, + EuiButtonIcon, + EuiCallOut, + EuiCheckbox, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiPanel, + EuiPopover, + EuiPopoverTitle, + EuiProgress, + EuiSpacer, + EuiText, + EuiToolTip, + Query, +} from '@elastic/eui'; + +import { Query as QueryType } from '../../../analytics_management/components/analytics_list/common'; + +import { + ColumnType, + mlInMemoryTableBasicFactory, + OnTableChangeArg, + SortingPropType, + SORT_DIRECTION, +} from '../../../../../components/ml_in_memory_table'; + +import { formatHumanReadableDateTimeSeconds } from '../../../../../util/date_utils'; +import { SavedSearchQuery } from '../../../../../contexts/kibana'; + +import { + sortRegressionResultsColumns, + sortRegressionResultsFields, + toggleSelectedField, + DataFrameAnalyticsConfig, + EsFieldName, + EsDoc, + MAX_COLUMNS, + getPredictedFieldName, + INDEX_STATUS, + SEARCH_SIZE, + defaultSearchQuery, +} from '../../../../common'; +import { getTaskStateBadge } from '../../../analytics_management/components/analytics_list/columns'; +import { DATA_FRAME_TASK_STATE } from '../../../analytics_management/components/analytics_list/common'; + +import { useExploreData, TableItem } from './use_explore_data'; +import { ExplorationTitle } from './classification_exploration'; + +const PAGE_SIZE_OPTIONS = [5, 10, 25, 50]; + +const MlInMemoryTableBasic = mlInMemoryTableBasicFactory(); +interface Props { + jobConfig: DataFrameAnalyticsConfig; + jobStatus: DATA_FRAME_TASK_STATE; + setEvaluateSearchQuery: React.Dispatch>; +} + +export const ResultsTable: FC = React.memo( + ({ jobConfig, jobStatus, setEvaluateSearchQuery }) => { + const [pageIndex, setPageIndex] = useState(0); + const [pageSize, setPageSize] = useState(25); + const [selectedFields, setSelectedFields] = useState([] as EsFieldName[]); + const [isColumnsPopoverVisible, setColumnsPopoverVisible] = useState(false); + const [searchQuery, setSearchQuery] = useState(defaultSearchQuery); + const [searchError, setSearchError] = useState(undefined); + const [searchString, setSearchString] = useState(undefined); + + function toggleColumnsPopover() { + setColumnsPopoverVisible(!isColumnsPopoverVisible); + } + + function closeColumnsPopover() { + setColumnsPopoverVisible(false); + } + + function toggleColumn(column: EsFieldName) { + if (tableItems.length > 0 && jobConfig !== undefined) { + // spread to a new array otherwise the component wouldn't re-render + setSelectedFields([...toggleSelectedField(selectedFields, column)]); + } + } + + const { + errorMessage, + loadExploreData, + sortField, + sortDirection, + status, + tableItems, + } = useExploreData(jobConfig, selectedFields, setSelectedFields); + + let docFields: EsFieldName[] = []; + let docFieldsCount = 0; + if (tableItems.length > 0) { + docFields = Object.keys(tableItems[0]); + docFields.sort((a, b) => sortRegressionResultsFields(a, b, jobConfig)); + docFieldsCount = docFields.length; + } + + const columns: Array> = []; + + if (jobConfig !== undefined && selectedFields.length > 0 && tableItems.length > 0) { + columns.push( + ...selectedFields.sort(sortRegressionResultsColumns(tableItems[0], jobConfig)).map(k => { + const column: ColumnType = { + field: k, + name: k, + sortable: true, + truncateText: true, + }; + + const render = (d: any, fullItem: EsDoc) => { + if (Array.isArray(d) && d.every(item => typeof item === 'string')) { + // If the cells data is an array of strings, return as a comma separated list. + // The list will get limited to 5 items with `…` at the end if there's more in the original array. + return `${d.slice(0, 5).join(', ')}${d.length > 5 ? ', …' : ''}`; + } else if (Array.isArray(d)) { + // If the cells data is an array of e.g. objects, display a 'array' badge with a + // tooltip that explains that this type of field is not supported in this table. + return ( + + + {i18n.translate( + 'xpack.ml.dataframe.analytics.classificationExploration.indexArrayBadgeContent', + { + defaultMessage: 'array', + } + )} + + + ); + } else if (typeof d === 'object' && d !== null) { + // If the cells data is an object, display a 'object' badge with a + // tooltip that explains that this type of field is not supported in this table. + return ( + + + {i18n.translate( + 'xpack.ml.dataframe.analytics.classificationExploration.indexObjectBadgeContent', + { + defaultMessage: 'object', + } + )} + + + ); + } + + return d; + }; + + let columnType; + + if (tableItems.length > 0) { + columnType = typeof tableItems[0][k]; + } + + if (typeof columnType !== 'undefined') { + switch (columnType) { + case 'boolean': + column.dataType = 'boolean'; + break; + case 'Date': + column.align = 'right'; + column.render = (d: any) => + formatHumanReadableDateTimeSeconds(moment(d).unix() * 1000); + break; + case 'number': + column.dataType = 'number'; + column.render = render; + break; + default: + column.render = render; + break; + } + } else { + column.render = render; + } + + return column; + }) + ); + } + + useEffect(() => { + if (jobConfig !== undefined) { + const predictedFieldName = getPredictedFieldName( + jobConfig.dest.results_field, + jobConfig.analysis + ); + const predictedFieldSelected = selectedFields.includes(predictedFieldName); + + const field = predictedFieldSelected ? predictedFieldName : selectedFields[0]; + const direction = predictedFieldSelected ? SORT_DIRECTION.DESC : SORT_DIRECTION.ASC; + loadExploreData({ field, direction, searchQuery }); + } + }, [JSON.stringify(searchQuery)]); + + useEffect(() => { + // by default set the sorting to descending on the prediction field (`_prediction`). + // if that's not available sort ascending on the first column. + // also check if the current sorting field is still available. + if (jobConfig !== undefined && columns.length > 0 && !selectedFields.includes(sortField)) { + const predictedFieldName = getPredictedFieldName( + jobConfig.dest.results_field, + jobConfig.analysis + ); + const predictedFieldSelected = selectedFields.includes(predictedFieldName); + + const field = predictedFieldSelected ? predictedFieldName : selectedFields[0]; + const direction = predictedFieldSelected ? SORT_DIRECTION.DESC : SORT_DIRECTION.ASC; + loadExploreData({ field, direction, searchQuery }); + } + }, [jobConfig, columns.length, sortField, sortDirection, tableItems.length]); + + let sorting: SortingPropType = false; + let onTableChange; + + if (columns.length > 0 && sortField !== '' && sortField !== undefined) { + sorting = { + sort: { + field: sortField, + direction: sortDirection, + }, + }; + + onTableChange = ({ + page = { index: 0, size: 10 }, + sort = { field: sortField, direction: sortDirection }, + }: OnTableChangeArg) => { + const { index, size } = page; + setPageIndex(index); + setPageSize(size); + + if (sort.field !== sortField || sort.direction !== sortDirection) { + loadExploreData({ ...sort, searchQuery }); + } + }; + } + + const pagination = { + initialPageIndex: pageIndex, + initialPageSize: pageSize, + totalItemCount: tableItems.length, + pageSizeOptions: PAGE_SIZE_OPTIONS, + hidePerPageOptions: false, + }; + + const onQueryChange = ({ query, error }: { query: QueryType; error: any }) => { + if (error) { + setSearchError(error.message); + } else { + try { + const esQueryDsl = Query.toESQuery(query); + setSearchQuery(esQueryDsl); + setSearchString(query.text); + setSearchError(undefined); + // set query for use in evaluate panel + setEvaluateSearchQuery(esQueryDsl); + } catch (e) { + setSearchError(e.toString()); + } + } + }; + + const search = { + onChange: onQueryChange, + defaultQuery: searchString, + box: { + incremental: false, + placeholder: i18n.translate( + 'xpack.ml.dataframe.analytics.regressionExploration.searchBoxPlaceholder', + { + defaultMessage: 'E.g. avg>0.5', + } + ), + }, + filters: [ + { + type: 'field_value_toggle_group', + field: `${jobConfig.dest.results_field}.is_training`, + items: [ + { + value: false, + name: i18n.translate( + 'xpack.ml.dataframe.analytics.regressionExploration.isTestingLabel', + { + defaultMessage: 'Testing', + } + ), + }, + { + value: true, + name: i18n.translate( + 'xpack.ml.dataframe.analytics.regressionExploration.isTrainingLabel', + { + defaultMessage: 'Training', + } + ), + }, + ], + }, + ], + }; + + if (jobConfig === undefined) { + return null; + } + // if it's a searchBar syntax error leave the table visible so they can try again + if (status === INDEX_STATUS.ERROR && !errorMessage.includes('parsing_exception')) { + return ( + + + + + + + {getTaskStateBadge(jobStatus)} + + + +

{errorMessage}

+
+
+ ); + } + + const tableError = + status === INDEX_STATUS.ERROR && errorMessage.includes('parsing_exception') + ? errorMessage + : searchError; + + return ( + + + + + + + + + {getTaskStateBadge(jobStatus)} + + + + + + + {docFieldsCount > MAX_COLUMNS && ( + + {i18n.translate( + 'xpack.ml.dataframe.analytics.regressionExploration.fieldSelection', + { + defaultMessage: + '{selectedFieldsLength, number} of {docFieldsCount, number} {docFieldsCount, plural, one {field} other {fields}} selected', + values: { selectedFieldsLength: selectedFields.length, docFieldsCount }, + } + )} + + )} + + + + + } + isOpen={isColumnsPopoverVisible} + closePopover={closeColumnsPopover} + ownFocus + > + + {i18n.translate( + 'xpack.ml.dataframe.analytics.regressionExploration.selectFieldsPopoverTitle', + { + defaultMessage: 'Select fields', + } + )} + +
+ {docFields.map(d => ( + toggleColumn(d)} + disabled={selectedFields.includes(d) && selectedFields.length === 1} + /> + ))} +
+
+
+
+
+
+
+ {status === INDEX_STATUS.LOADING && } + {status !== INDEX_STATUS.LOADING && ( + + )} + {(columns.length > 0 || searchQuery !== defaultSearchQuery) && ( + + {tableItems.length === SEARCH_SIZE && ( + + + + )} + + + + )} +
+ ); + } +); diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/use_explore_data.ts b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/use_explore_data.ts new file mode 100644 index 0000000000000..ba12fcab98a36 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/use_explore_data.ts @@ -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. + */ +/* + * 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, { useEffect, useState } from 'react'; + +import { SearchResponse } from 'elasticsearch'; + +import { SortDirection, SORT_DIRECTION } from '../../../../../components/ml_in_memory_table'; + +import { ml } from '../../../../../services/ml_api_service'; +import { getNestedProperty } from '../../../../../util/object_utils'; +import { SavedSearchQuery } from '../../../../../contexts/kibana'; + +import { + getDefaultClassificationFields, + getFlattenedFields, + DataFrameAnalyticsConfig, + EsFieldName, + getPredictedFieldName, + INDEX_STATUS, + SEARCH_SIZE, + defaultSearchQuery, + SearchQuery, +} from '../../../../common'; + +export type TableItem = Record; + +interface LoadExploreDataArg { + field: string; + direction: SortDirection; + searchQuery: SavedSearchQuery; +} +export interface UseExploreDataReturnType { + errorMessage: string; + loadExploreData: (arg: LoadExploreDataArg) => void; + sortField: EsFieldName; + sortDirection: SortDirection; + status: INDEX_STATUS; + tableItems: TableItem[]; +} + +export const useExploreData = ( + jobConfig: DataFrameAnalyticsConfig | undefined, + selectedFields: EsFieldName[], + setSelectedFields: React.Dispatch> +): UseExploreDataReturnType => { + const [errorMessage, setErrorMessage] = useState(''); + const [status, setStatus] = useState(INDEX_STATUS.UNUSED); + const [tableItems, setTableItems] = useState([]); + const [sortField, setSortField] = useState(''); + const [sortDirection, setSortDirection] = useState(SORT_DIRECTION.ASC); + + const loadExploreData = async ({ field, direction, searchQuery }: LoadExploreDataArg) => { + if (jobConfig !== undefined) { + setErrorMessage(''); + setStatus(INDEX_STATUS.LOADING); + + try { + const resultsField = jobConfig.dest.results_field; + const body: SearchQuery = { + query: searchQuery, + }; + + if (field !== undefined) { + body.sort = [ + { + [field]: { + order: direction, + }, + }, + ]; + } + + const resp: SearchResponse = await ml.esSearch({ + index: jobConfig.dest.index, + size: SEARCH_SIZE, + body, + }); + + setSortField(field); + setSortDirection(direction); + + const docs = resp.hits.hits; + + if (docs.length === 0) { + setTableItems([]); + setStatus(INDEX_STATUS.LOADED); + return; + } + + if (selectedFields.length === 0) { + const newSelectedFields = getDefaultClassificationFields(docs, jobConfig); + setSelectedFields(newSelectedFields); + } + + // Create a version of the doc's source with flattened field names. + // This avoids confusion later on if a field name has dots in its name + // or is a nested fields when displaying it via EuiInMemoryTable. + const flattenedFields = getFlattenedFields(docs[0]._source, resultsField); + const transformedTableItems = docs.map(doc => { + const item: TableItem = {}; + flattenedFields.forEach(ff => { + item[ff] = getNestedProperty(doc._source, ff); + if (item[ff] === undefined) { + // If the attribute is undefined, it means it was not a nested property + // but had dots in its actual name. This selects the property by its + // full name and assigns it to `item[ff]`. + item[ff] = doc._source[`"${ff}"`]; + } + if (item[ff] === undefined) { + const parts = ff.split('.'); + if (parts[0] === resultsField && parts.length >= 2) { + parts.shift(); + if (doc._source[resultsField] !== undefined) { + item[ff] = doc._source[resultsField][parts.join('.')]; + } + } + } + }); + return item; + }); + + setTableItems(transformedTableItems); + setStatus(INDEX_STATUS.LOADED); + } catch (e) { + if (e.message !== undefined) { + setErrorMessage(e.message); + } else { + setErrorMessage(JSON.stringify(e)); + } + setTableItems([]); + setStatus(INDEX_STATUS.ERROR); + } + } + }; + + useEffect(() => { + if (jobConfig !== undefined) { + loadExploreData({ + field: getPredictedFieldName(jobConfig.dest.results_field, jobConfig.analysis), + direction: SORT_DIRECTION.DESC, + searchQuery: defaultSearchQuery, + }); + } + }, [jobConfig && jobConfig.id]); + + return { errorMessage, loadExploreData, sortField, sortDirection, status, tableItems }; +}; diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/error_callout.tsx b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/error_callout/error_callout.tsx similarity index 100% rename from x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/error_callout.tsx rename to x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/error_callout/error_callout.tsx diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/error_callout/index.ts b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/error_callout/index.ts new file mode 100644 index 0000000000000..4f86d0d061c97 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/error_callout/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 { ErrorCallout } from './error_callout'; diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/loading_panel/index.ts b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/loading_panel/index.ts new file mode 100644 index 0000000000000..40b9e000d6b07 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/loading_panel/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 { LoadingPanel } from './loading_panel'; diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/loading_panel/loading_panel.tsx b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/loading_panel/loading_panel.tsx new file mode 100644 index 0000000000000..f71fbc944f0ed --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/loading_panel/loading_panel.tsx @@ -0,0 +1,14 @@ +/* + * 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 { EuiLoadingSpinner, EuiPanel } from '@elastic/eui'; + +export const LoadingPanel: FC = () => ( + + + +); diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/evaluate_panel.tsx b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/evaluate_panel.tsx index d877ed40e587d..a8a015c6ef345 100644 --- a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/evaluate_panel.tsx +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/evaluate_panel.tsx @@ -8,40 +8,30 @@ import React, { FC, Fragment, useEffect, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui'; -import { ErrorCallout } from './error_callout'; +import { ErrorCallout } from '../error_callout'; import { getValuesFromResponse, getDependentVar, getPredictionFieldName, loadEvalData, + loadDocsCount, Eval, DataFrameAnalyticsConfig, } from '../../../../common'; -import { ml } from '../../../../../services/ml_api_service'; import { getTaskStateBadge } from '../../../analytics_management/components/analytics_list/columns'; import { DATA_FRAME_TASK_STATE } from '../../../analytics_management/components/analytics_list/common'; import { EvaluateStat } from './evaluate_stat'; import { - getEvalQueryBody, - isRegressionResultsSearchBoolQuery, - RegressionResultsSearchQuery, - SearchQuery, + isResultsSearchBoolQuery, + isRegressionEvaluateResponse, + ResultsSearchQuery, + ANALYSIS_CONFIG_TYPE, } from '../../../../common/analytics'; interface Props { jobConfig: DataFrameAnalyticsConfig; jobStatus: DATA_FRAME_TASK_STATE; - searchQuery: RegressionResultsSearchQuery; -} - -interface TrackTotalHitsSearchResponse { - hits: { - total: { - value: number; - relation: string; - }; - hits: any[]; - }; + searchQuery: ResultsSearchQuery; } const defaultEval: Eval = { meanSquaredError: '', rSquared: '', error: null }; @@ -60,40 +50,6 @@ export const EvaluatePanel: FC = ({ jobConfig, jobStatus, searchQuery }) // default is 'ml' const resultsField = jobConfig.dest.results_field; - const loadDocsCount = async ({ - ignoreDefaultQuery = true, - isTraining, - }: { - ignoreDefaultQuery?: boolean; - isTraining: boolean; - }): Promise<{ - docsCount: number | null; - success: boolean; - }> => { - const query = getEvalQueryBody({ resultsField, isTraining, ignoreDefaultQuery, searchQuery }); - - try { - const body: SearchQuery = { - track_total_hits: true, - query, - }; - - const resp: TrackTotalHitsSearchResponse = await ml.esSearch({ - index: jobConfig.dest.index, - size: 0, - body, - }); - - const docsCount = resp.hits.total && resp.hits.total.value; - return { docsCount, success: true }; - } catch (e) { - return { - docsCount: null, - success: false, - }; - } - }; - const loadGeneralizationData = async (ignoreDefaultQuery: boolean = true) => { setIsLoadingGeneralization(true); @@ -105,9 +61,14 @@ export const EvaluatePanel: FC = ({ jobConfig, jobStatus, searchQuery }) predictionFieldName, searchQuery, ignoreDefaultQuery, + jobType: ANALYSIS_CONFIG_TYPE.REGRESSION, }); - if (genErrorEval.success === true && genErrorEval.eval) { + if ( + genErrorEval.success === true && + genErrorEval.eval && + isRegressionEvaluateResponse(genErrorEval.eval) + ) { const { meanSquaredError, rSquared } = getValuesFromResponse(genErrorEval.eval); setGeneralizationEval({ meanSquaredError, @@ -136,9 +97,14 @@ export const EvaluatePanel: FC = ({ jobConfig, jobStatus, searchQuery }) predictionFieldName, searchQuery, ignoreDefaultQuery, + jobType: ANALYSIS_CONFIG_TYPE.REGRESSION, }); - if (trainingErrorEval.success === true && trainingErrorEval.eval) { + if ( + trainingErrorEval.success === true && + trainingErrorEval.eval && + isRegressionEvaluateResponse(trainingErrorEval.eval) + ) { const { meanSquaredError, rSquared } = getValuesFromResponse(trainingErrorEval.eval); setTrainingEval({ meanSquaredError, @@ -165,7 +131,13 @@ export const EvaluatePanel: FC = ({ jobConfig, jobStatus, searchQuery }) if (isTrainingClause !== undefined && isTrainingClause.query === 'false') { loadGeneralizationData(); - const docsCountResp = await loadDocsCount({ isTraining: false }); + const docsCountResp = await loadDocsCount({ + isTraining: false, + searchQuery, + resultsField, + destIndex: jobConfig.dest.index, + }); + if (docsCountResp.success === true) { setGeneralizationDocsCount(docsCountResp.docsCount); } else { @@ -182,7 +154,13 @@ export const EvaluatePanel: FC = ({ jobConfig, jobStatus, searchQuery }) // searchBar query is filtering for training data loadTrainingData(); - const docsCountResp = await loadDocsCount({ isTraining: true }); + const docsCountResp = await loadDocsCount({ + isTraining: true, + searchQuery, + resultsField, + destIndex: jobConfig.dest.index, + }); + if (docsCountResp.success === true) { setTrainingDocsCount(docsCountResp.docsCount); } else { @@ -201,6 +179,9 @@ export const EvaluatePanel: FC = ({ jobConfig, jobStatus, searchQuery }) const genDocsCountResp = await loadDocsCount({ ignoreDefaultQuery: false, isTraining: false, + searchQuery, + resultsField, + destIndex: jobConfig.dest.index, }); if (genDocsCountResp.success === true) { setGeneralizationDocsCount(genDocsCountResp.docsCount); @@ -212,6 +193,9 @@ export const EvaluatePanel: FC = ({ jobConfig, jobStatus, searchQuery }) const trainDocsCountResp = await loadDocsCount({ ignoreDefaultQuery: false, isTraining: true, + searchQuery, + resultsField, + destIndex: jobConfig.dest.index, }); if (trainDocsCountResp.success === true) { setTrainingDocsCount(trainDocsCountResp.docsCount); @@ -223,7 +207,7 @@ export const EvaluatePanel: FC = ({ jobConfig, jobStatus, searchQuery }) useEffect(() => { const hasIsTrainingClause = - isRegressionResultsSearchBoolQuery(searchQuery) && + isResultsSearchBoolQuery(searchQuery) && searchQuery.bool.must.filter( (clause: any) => clause.match && clause.match[`${resultsField}.is_training`] !== undefined ); @@ -241,10 +225,13 @@ export const EvaluatePanel: FC = ({ jobConfig, jobStatus, searchQuery }) - {i18n.translate('xpack.ml.dataframe.analytics.regressionExploration.jobIdTitle', { - defaultMessage: 'Regression job ID {jobId}', - values: { jobId: jobConfig.id }, - })} + {i18n.translate( + 'xpack.ml.dataframe.analytics.regressionExploration.evaluateJobIdTitle', + { + defaultMessage: 'Evaluation of regression job ID {jobId}', + values: { jobId: jobConfig.id }, + } + )} diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/regression_exploration.tsx b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/regression_exploration.tsx index 2f7ff4feed2a8..12a41e1e7d851 100644 --- a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/regression_exploration.tsx +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/regression_exploration.tsx @@ -5,31 +5,26 @@ */ import React, { FC, Fragment, useState, useEffect } from 'react'; -import { EuiCallOut, EuiLoadingSpinner, EuiPanel, EuiSpacer, EuiTitle } from '@elastic/eui'; +import { EuiCallOut, EuiPanel, EuiSpacer, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ml } from '../../../../../services/ml_api_service'; import { DataFrameAnalyticsConfig } from '../../../../common'; import { EvaluatePanel } from './evaluate_panel'; import { ResultsTable } from './results_table'; import { DATA_FRAME_TASK_STATE } from '../../../analytics_management/components/analytics_list/common'; -import { RegressionResultsSearchQuery, defaultSearchQuery } from '../../../../common/analytics'; +import { ResultsSearchQuery, defaultSearchQuery } from '../../../../common/analytics'; +import { LoadingPanel } from '../loading_panel'; interface GetDataFrameAnalyticsResponse { count: number; data_frame_analytics: DataFrameAnalyticsConfig[]; } -const LoadingPanel: FC = () => ( - - - -); - export const ExplorationTitle: React.FC<{ jobId: string }> = ({ jobId }) => ( - {i18n.translate('xpack.ml.dataframe.analytics.regressionExploration.jobIdTitle', { - defaultMessage: 'Regression job ID {jobId}', + {i18n.translate('xpack.ml.dataframe.analytics.regressionExploration.tableJobIdTitle', { + defaultMessage: 'Destination index for regression job ID {jobId}', values: { jobId }, })} @@ -45,7 +40,7 @@ export const RegressionExploration: FC = ({ jobId, jobStatus }) => { const [jobConfig, setJobConfig] = useState(undefined); const [isLoadingJobConfig, setIsLoadingJobConfig] = useState(false); const [jobConfigErrorMessage, setJobConfigErrorMessage] = useState(undefined); - const [searchQuery, setSearchQuery] = useState(defaultSearchQuery); + const [searchQuery, setSearchQuery] = useState(defaultSearchQuery); const loadJobConfig = async () => { setIsLoadingJobConfig(true); diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/results_table.tsx b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/results_table.tsx index 37c2e40c89c3c..1828297365f7a 100644 --- a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/results_table.tsx +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/results_table.tsx @@ -60,6 +60,8 @@ import { ExplorationTitle } from './regression_exploration'; const PAGE_SIZE_OPTIONS = [5, 10, 25, 50]; +const MlInMemoryTableBasic = mlInMemoryTableBasicFactory(); + interface Props { jobConfig: DataFrameAnalyticsConfig; jobStatus: DATA_FRAME_TASK_STATE; @@ -363,8 +365,6 @@ export const ResultsTable: FC = React.memo( ? errorMessage : searchError; - const MlInMemoryTableBasic = mlInMemoryTableBasicFactory(); - return ( diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/use_explore_data.ts b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/use_explore_data.ts index 3a83ad238d0e1..8e9cf45c14ec7 100644 --- a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/use_explore_data.ts +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/use_explore_data.ts @@ -3,11 +3,6 @@ * 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, { useEffect, useState } from 'react'; diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/page.tsx b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/page.tsx index b3d13db0a3550..b00a38e2b5f65 100644 --- a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/page.tsx +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/page.tsx @@ -24,6 +24,7 @@ import { NavigationMenu } from '../../../components/navigation_menu'; import { Exploration } from './components/exploration'; import { RegressionExploration } from './components/regression_exploration'; +import { ClassificationExploration } from './components/classification_exploration'; import { ANALYSIS_CONFIG_TYPE } from '../../common/analytics'; import { DATA_FRAME_TASK_STATE } from '../analytics_management/components/analytics_list/common'; @@ -72,6 +73,9 @@ export const Page: FC<{ {analysisType === ANALYSIS_CONFIG_TYPE.REGRESSION && ( )} + {analysisType === ANALYSIS_CONFIG_TYPE.CLASSIFICATION && ( + + )} diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/actions.tsx b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/actions.tsx index e189c961ccbc9..fc3c00cbcf3e3 100644 --- a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/actions.tsx +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/actions.tsx @@ -17,6 +17,7 @@ import { getAnalysisType, isRegressionAnalysis, isOutlierAnalysis, + isClassificationAnalysis, } from '../../../../common/analytics'; import { getResultsUrl, isDataFrameAnalyticsRunning, DataFrameAnalyticsListRow } from './common'; @@ -31,7 +32,9 @@ export const AnalyticsViewAction = { const analysisType = getAnalysisType(item.config.analysis); const jobStatus = item.stats.state; const isDisabled = - !isRegressionAnalysis(item.config.analysis) && !isOutlierAnalysis(item.config.analysis); + !isRegressionAnalysis(item.config.analysis) && + !isOutlierAnalysis(item.config.analysis) && + !isClassificationAnalysis(item.config.analysis); const url = getResultsUrl(item.id, analysisType, jobStatus); return ( diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row.tsx b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row.tsx index 91b73307ef56c..8772be698bf58 100644 --- a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row.tsx +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/expanded_row.tsx @@ -25,7 +25,11 @@ import { Eval, } from '../../../../common'; import { isCompletedAnalyticsJob } from './common'; -import { isRegressionAnalysis } from '../../../../common/analytics'; +import { + isRegressionAnalysis, + ANALYSIS_CONFIG_TYPE, + isRegressionEvaluateResponse, +} from '../../../../common/analytics'; import { ExpandedRowMessagesPane } from './expanded_row_messages_pane'; function getItemDescription(value: any) { @@ -81,9 +85,14 @@ export const ExpandedRow: FC = ({ item }) => { dependentVariable, resultsField, predictionFieldName, + jobType: ANALYSIS_CONFIG_TYPE.REGRESSION, }); - if (genErrorEval.success === true && genErrorEval.eval) { + if ( + genErrorEval.success === true && + genErrorEval.eval && + isRegressionEvaluateResponse(genErrorEval.eval) + ) { const { meanSquaredError, rSquared } = getValuesFromResponse(genErrorEval.eval); setGeneralizationEval({ meanSquaredError, @@ -106,9 +115,14 @@ export const ExpandedRow: FC = ({ item }) => { dependentVariable, resultsField, predictionFieldName, + jobType: ANALYSIS_CONFIG_TYPE.REGRESSION, }); - if (trainingErrorEval.success === true && trainingErrorEval.eval) { + if ( + trainingErrorEval.success === true && + trainingErrorEval.eval && + isRegressionEvaluateResponse(trainingErrorEval.eval) + ) { const { meanSquaredError, rSquared } = getValuesFromResponse(trainingErrorEval.eval); setTrainingEval({ meanSquaredError, diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index f047e6a506f82..18bfbff786edc 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -7864,7 +7864,6 @@ "xpack.ml.dataframe.analytics.regressionExploration.evaluateError": "データの読み込み中にエラーが発生しました。", "xpack.ml.dataframe.analytics.regressionExploration.generalError": "データの読み込み中にエラーが発生しました。", "xpack.ml.dataframe.analytics.regressionExploration.generalizationErrorTitle": "一般化エラー", - "xpack.ml.dataframe.analytics.regressionExploration.jobIdTitle": "ジョブ ID {jobId}", "xpack.ml.dataframe.analytics.regressionExploration.meanSquaredErrorText": "平均二乗エラー", "xpack.ml.dataframe.analytics.regressionExploration.noDataCalloutBody": "インデックスのクエリが結果を返しませんでした。ジョブが完了済みで、インデックスにドキュメントがあることを確認してください。", "xpack.ml.dataframe.analytics.regressionExploration.noDataCalloutTitle": "空のインデックスクエリ結果。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 1be193f83d3bd..7f55866c17a17 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -7957,7 +7957,6 @@ "xpack.ml.dataframe.analytics.regressionExploration.evaluateError": "加载数据时出错。", "xpack.ml.dataframe.analytics.regressionExploration.generalError": "加载数据时出错。", "xpack.ml.dataframe.analytics.regressionExploration.generalizationErrorTitle": "泛化误差", - "xpack.ml.dataframe.analytics.regressionExploration.jobIdTitle": "作业 ID {jobId}", "xpack.ml.dataframe.analytics.regressionExploration.meanSquaredErrorText": "均方误差", "xpack.ml.dataframe.analytics.regressionExploration.noDataCalloutBody": "该索引的查询未返回结果。请确保作业已完成且索引包含文档。", "xpack.ml.dataframe.analytics.regressionExploration.noDataCalloutTitle": "空的索引查询结果。", From deee1c08e98afb2081d5774b161731140390fc92 Mon Sep 17 00:00:00 2001 From: Melissa Alvarez Date: Thu, 12 Dec 2019 12:05:31 -0700 Subject: [PATCH 56/79] [ML] DF Analytics creation: ensure advanced editor can be validated when empty (#52831) * Check for undefined analysis config before validating * update tests --- .../use_create_analytics_form/reducer.test.ts | 2 +- .../hooks/use_create_analytics_form/reducer.ts | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.test.ts b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.test.ts index 7db9420396a9a..754f7a1136a97 100644 --- a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.test.ts +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.test.ts @@ -20,7 +20,7 @@ type SourceIndex = DataFrameAnalyticsConfig['source']['index']; const getMockState = ({ index, - modelMemoryLimit, + modelMemoryLimit = '100mb', }: { index: SourceIndex; modelMemoryLimit?: string; diff --git a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.ts b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.ts index eda80ca64c86f..06c8a6c6a8846 100644 --- a/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.ts +++ b/x-pack/legacy/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.ts @@ -56,7 +56,7 @@ const getSourceIndexString = (state: State) => { }; export const validateAdvancedEditor = (state: State): State => { - const { jobIdEmpty, jobIdValid, jobIdExists, createIndexPattern } = state.form; + const { jobIdEmpty, jobIdValid, jobIdExists, jobType, createIndexPattern } = state.form; const { jobConfig } = state; state.advancedEditorMessages = []; @@ -85,14 +85,25 @@ export const validateAdvancedEditor = (state: State): State => { const destinationIndexPatternTitleExists = state.indexPatternsMap[destinationIndexName] !== undefined; const mml = jobConfig.model_memory_limit; - const modelMemoryLimitEmpty = mml === ''; + const modelMemoryLimitEmpty = mml === '' || mml === undefined; if (!modelMemoryLimitEmpty && mml !== undefined) { const { valid } = validateModelMemoryLimitUnits(mml); state.form.modelMemoryLimitUnitValid = valid; } let dependentVariableEmpty = false; - if (isRegressionAnalysis(jobConfig.analysis) || isClassificationAnalysis(jobConfig.analysis)) { + + if ( + jobConfig.analysis === undefined && + (jobType === JOB_TYPES.CLASSIFICATION || jobType === JOB_TYPES.REGRESSION) + ) { + dependentVariableEmpty = true; + } + + if ( + jobConfig.analysis !== undefined && + (isRegressionAnalysis(jobConfig.analysis) || isClassificationAnalysis(jobConfig.analysis)) + ) { const dependentVariableName = getDependentVar(jobConfig.analysis) || ''; dependentVariableEmpty = dependentVariableName === ''; } From 2d3698972b80d22ac258b3d79f775037279026b4 Mon Sep 17 00:00:00 2001 From: Josh Dover Date: Thu, 12 Dec 2019 13:21:35 -0600 Subject: [PATCH 57/79] Add getStartServices API (#50231) --- .../core/public/kibana-plugin-public.app.md | 2 +- .../public/kibana-plugin-public.app.mount.md | 9 ++- .../kibana-plugin-public.applicationsetup.md | 2 +- ...c.applicationsetup.registermountcontext.md | 10 ++- .../kibana-plugin-public.applicationstart.md | 2 +- ...c.applicationstart.registermountcontext.md | 10 ++- .../public/kibana-plugin-public.appmount.md | 13 ++++ .../kibana-plugin-public.appmountcontext.md | 6 +- ...kibana-plugin-public.appmountdeprecated.md | 22 ++++++ .../kibana-plugin-public.coresetup.context.md | 4 ++ ...lugin-public.coresetup.getstartservices.md | 17 +++++ .../public/kibana-plugin-public.coresetup.md | 8 ++- .../kibana-plugin-public.legacycoresetup.md | 2 +- .../core/public/kibana-plugin-public.md | 4 +- .../kibana-plugin-public.plugin.setup.md | 4 +- .../application/application_service.test.tsx | 36 +++++++--- .../application/application_service.tsx | 35 +++++++--- src/core/public/application/index.ts | 2 + .../integration_tests/router.test.tsx | 4 +- src/core/public/application/types.ts | 69 ++++++++++++++----- .../public/application/ui/app_container.tsx | 4 +- src/core/public/application/ui/app_router.tsx | 4 +- src/core/public/core_system.ts | 4 +- src/core/public/index.ts | 30 ++++++-- src/core/public/legacy/legacy_service.test.ts | 14 ++++ src/core/public/legacy/legacy_service.ts | 7 ++ src/core/public/mocks.ts | 4 ++ src/core/public/plugins/plugin.test.ts | 27 ++++++++ src/core/public/plugins/plugin.ts | 15 +++- src/core/public/plugins/plugin_context.ts | 1 + .../public/plugins/plugins_service.test.ts | 1 + src/core/public/public.api.md | 23 +++++-- .../local_application_service.ts | 12 +++- .../public/new_platform/new_platform.test.ts | 20 ++++++ .../ui/public/new_platform/new_platform.ts | 15 ++-- src/plugins/dev_tools/public/application.tsx | 15 ++-- .../plugins/core_plugin_b/public/plugin.tsx | 4 ++ .../core_plugin_legacy/public/index.ts | 4 +- .../test_suites/core_plugins/ui_plugins.ts | 17 ++++- 39 files changed, 388 insertions(+), 94 deletions(-) create mode 100644 docs/development/core/public/kibana-plugin-public.appmount.md create mode 100644 docs/development/core/public/kibana-plugin-public.appmountdeprecated.md create mode 100644 docs/development/core/public/kibana-plugin-public.coresetup.getstartservices.md diff --git a/docs/development/core/public/kibana-plugin-public.app.md b/docs/development/core/public/kibana-plugin-public.app.md index c500c080a5feb..edab4f88497f6 100644 --- a/docs/development/core/public/kibana-plugin-public.app.md +++ b/docs/development/core/public/kibana-plugin-public.app.md @@ -17,5 +17,5 @@ export interface App extends AppBase | Property | Type | Description | | --- | --- | --- | | [chromeless](./kibana-plugin-public.app.chromeless.md) | boolean | Hide the UI chrome when the application is mounted. Defaults to false. Takes precedence over chrome service visibility settings. | -| [mount](./kibana-plugin-public.app.mount.md) | (context: AppMountContext, params: AppMountParameters) => AppUnmount | Promise<AppUnmount> | A mount function called when the user navigates to this app's route. | +| [mount](./kibana-plugin-public.app.mount.md) | AppMount | AppMountDeprecated | A mount function called when the user navigates to this app's route. May have signature of [AppMount](./kibana-plugin-public.appmount.md) or [AppMountDeprecated](./kibana-plugin-public.appmountdeprecated.md). | diff --git a/docs/development/core/public/kibana-plugin-public.app.mount.md b/docs/development/core/public/kibana-plugin-public.app.mount.md index dda06b035db4a..151fb7baeb138 100644 --- a/docs/development/core/public/kibana-plugin-public.app.mount.md +++ b/docs/development/core/public/kibana-plugin-public.app.mount.md @@ -4,10 +4,15 @@ ## App.mount property -A mount function called when the user navigates to this app's route. +A mount function called when the user navigates to this app's route. May have signature of [AppMount](./kibana-plugin-public.appmount.md) or [AppMountDeprecated](./kibana-plugin-public.appmountdeprecated.md). Signature: ```typescript -mount: (context: AppMountContext, params: AppMountParameters) => AppUnmount | Promise; +mount: AppMount | AppMountDeprecated; ``` + +## Remarks + +When function has two arguments, it will be called with a [context](./kibana-plugin-public.appmountcontext.md) as the first argument. This behavior is \*\*deprecated\*\*, and consumers should instead use [CoreSetup.getStartServices()](./kibana-plugin-public.coresetup.getstartservices.md). + diff --git a/docs/development/core/public/kibana-plugin-public.applicationsetup.md b/docs/development/core/public/kibana-plugin-public.applicationsetup.md index b53873bc0fb8a..a63de399c2ecb 100644 --- a/docs/development/core/public/kibana-plugin-public.applicationsetup.md +++ b/docs/development/core/public/kibana-plugin-public.applicationsetup.md @@ -16,5 +16,5 @@ export interface ApplicationSetup | Method | Description | | --- | --- | | [register(app)](./kibana-plugin-public.applicationsetup.register.md) | Register an mountable application to the system. | -| [registerMountContext(contextName, provider)](./kibana-plugin-public.applicationsetup.registermountcontext.md) | Register a context provider for application mounting. Will only be available to applications that depend on the plugin that registered this context. | +| [registerMountContext(contextName, provider)](./kibana-plugin-public.applicationsetup.registermountcontext.md) | Register a context provider for application mounting. Will only be available to applications that depend on the plugin that registered this context. Deprecated, use [CoreSetup.getStartServices()](./kibana-plugin-public.coresetup.getstartservices.md). | diff --git a/docs/development/core/public/kibana-plugin-public.applicationsetup.registermountcontext.md b/docs/development/core/public/kibana-plugin-public.applicationsetup.registermountcontext.md index f264ba500ed6e..275ba431bc7e7 100644 --- a/docs/development/core/public/kibana-plugin-public.applicationsetup.registermountcontext.md +++ b/docs/development/core/public/kibana-plugin-public.applicationsetup.registermountcontext.md @@ -4,12 +4,16 @@ ## ApplicationSetup.registerMountContext() method -Register a context provider for application mounting. Will only be available to applications that depend on the plugin that registered this context. +> Warning: This API is now obsolete. +> +> + +Register a context provider for application mounting. Will only be available to applications that depend on the plugin that registered this context. Deprecated, use [CoreSetup.getStartServices()](./kibana-plugin-public.coresetup.getstartservices.md). Signature: ```typescript -registerMountContext(contextName: T, provider: IContextProvider): void; +registerMountContext(contextName: T, provider: IContextProvider): void; ``` ## Parameters @@ -17,7 +21,7 @@ registerMountContext(contextName: T, provider: | Parameter | Type | Description | | --- | --- | --- | | contextName | T | The key of [AppMountContext](./kibana-plugin-public.appmountcontext.md) this provider's return value should be attached to. | -| provider | IContextProvider<App['mount'], T> | A [IContextProvider](./kibana-plugin-public.icontextprovider.md) function | +| provider | IContextProvider<AppMountDeprecated, T> | A [IContextProvider](./kibana-plugin-public.icontextprovider.md) function | Returns: diff --git a/docs/development/core/public/kibana-plugin-public.applicationstart.md b/docs/development/core/public/kibana-plugin-public.applicationstart.md index 2a60ff449e44e..4baa4565ff7b0 100644 --- a/docs/development/core/public/kibana-plugin-public.applicationstart.md +++ b/docs/development/core/public/kibana-plugin-public.applicationstart.md @@ -23,5 +23,5 @@ export interface ApplicationStart | --- | --- | | [getUrlForApp(appId, options)](./kibana-plugin-public.applicationstart.geturlforapp.md) | Returns a relative URL to a given app, including the global base path. | | [navigateToApp(appId, options)](./kibana-plugin-public.applicationstart.navigatetoapp.md) | Navigiate to a given app | -| [registerMountContext(contextName, provider)](./kibana-plugin-public.applicationstart.registermountcontext.md) | Register a context provider for application mounting. Will only be available to applications that depend on the plugin that registered this context. | +| [registerMountContext(contextName, provider)](./kibana-plugin-public.applicationstart.registermountcontext.md) | Register a context provider for application mounting. Will only be available to applications that depend on the plugin that registered this context. Deprecated, use [CoreSetup.getStartServices()](./kibana-plugin-public.coresetup.getstartservices.md). | diff --git a/docs/development/core/public/kibana-plugin-public.applicationstart.registermountcontext.md b/docs/development/core/public/kibana-plugin-public.applicationstart.registermountcontext.md index 62821fcbb92ba..c15a23fe82b21 100644 --- a/docs/development/core/public/kibana-plugin-public.applicationstart.registermountcontext.md +++ b/docs/development/core/public/kibana-plugin-public.applicationstart.registermountcontext.md @@ -4,12 +4,16 @@ ## ApplicationStart.registerMountContext() method -Register a context provider for application mounting. Will only be available to applications that depend on the plugin that registered this context. +> Warning: This API is now obsolete. +> +> + +Register a context provider for application mounting. Will only be available to applications that depend on the plugin that registered this context. Deprecated, use [CoreSetup.getStartServices()](./kibana-plugin-public.coresetup.getstartservices.md). Signature: ```typescript -registerMountContext(contextName: T, provider: IContextProvider): void; +registerMountContext(contextName: T, provider: IContextProvider): void; ``` ## Parameters @@ -17,7 +21,7 @@ registerMountContext(contextName: T, provider: | Parameter | Type | Description | | --- | --- | --- | | contextName | T | The key of [AppMountContext](./kibana-plugin-public.appmountcontext.md) this provider's return value should be attached to. | -| provider | IContextProvider<App['mount'], T> | A [IContextProvider](./kibana-plugin-public.icontextprovider.md) function | +| provider | IContextProvider<AppMountDeprecated, T> | A [IContextProvider](./kibana-plugin-public.icontextprovider.md) function | Returns: diff --git a/docs/development/core/public/kibana-plugin-public.appmount.md b/docs/development/core/public/kibana-plugin-public.appmount.md new file mode 100644 index 0000000000000..25faa7be30b68 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.appmount.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [AppMount](./kibana-plugin-public.appmount.md) + +## AppMount type + +A mount function called when the user navigates to this app's route. + +Signature: + +```typescript +export declare type AppMount = (params: AppMountParameters) => AppUnmount | Promise; +``` diff --git a/docs/development/core/public/kibana-plugin-public.appmountcontext.md b/docs/development/core/public/kibana-plugin-public.appmountcontext.md index 68a1c27b11836..2f8c0553d0b38 100644 --- a/docs/development/core/public/kibana-plugin-public.appmountcontext.md +++ b/docs/development/core/public/kibana-plugin-public.appmountcontext.md @@ -4,7 +4,11 @@ ## AppMountContext interface -The context object received when applications are mounted to the DOM. +> Warning: This API is now obsolete. +> +> + +The context object received when applications are mounted to the DOM. Deprecated, use [CoreSetup.getStartServices()](./kibana-plugin-public.coresetup.getstartservices.md). Signature: diff --git a/docs/development/core/public/kibana-plugin-public.appmountdeprecated.md b/docs/development/core/public/kibana-plugin-public.appmountdeprecated.md new file mode 100644 index 0000000000000..936642abcc97a --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.appmountdeprecated.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [AppMountDeprecated](./kibana-plugin-public.appmountdeprecated.md) + +## AppMountDeprecated type + +> Warning: This API is now obsolete. +> +> + +A mount function called when the user navigates to this app's route. + +Signature: + +```typescript +export declare type AppMountDeprecated = (context: AppMountContext, params: AppMountParameters) => AppUnmount | Promise; +``` + +## Remarks + +When function has two arguments, it will be called with a [context](./kibana-plugin-public.appmountcontext.md) as the first argument. This behavior is \*\*deprecated\*\*, and consumers should instead use [CoreSetup.getStartServices()](./kibana-plugin-public.coresetup.getstartservices.md). + diff --git a/docs/development/core/public/kibana-plugin-public.coresetup.context.md b/docs/development/core/public/kibana-plugin-public.coresetup.context.md index e56ecb92074c4..f2a891c6c674e 100644 --- a/docs/development/core/public/kibana-plugin-public.coresetup.context.md +++ b/docs/development/core/public/kibana-plugin-public.coresetup.context.md @@ -4,6 +4,10 @@ ## CoreSetup.context property +> Warning: This API is now obsolete. +> +> + [ContextSetup](./kibana-plugin-public.contextsetup.md) Signature: diff --git a/docs/development/core/public/kibana-plugin-public.coresetup.getstartservices.md b/docs/development/core/public/kibana-plugin-public.coresetup.getstartservices.md new file mode 100644 index 0000000000000..b89d98b0a9ed5 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-public.coresetup.getstartservices.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [CoreSetup](./kibana-plugin-public.coresetup.md) > [getStartServices](./kibana-plugin-public.coresetup.getstartservices.md) + +## CoreSetup.getStartServices() method + +Allows plugins to get access to APIs available in start inside async handlers, such as [App.mount](./kibana-plugin-public.app.mount.md). Promise will not resolve until Core and plugin dependencies have completed `start`. + +Signature: + +```typescript +getStartServices(): Promise<[CoreStart, TPluginsStart]>; +``` +Returns: + +`Promise<[CoreStart, TPluginsStart]>` + diff --git a/docs/development/core/public/kibana-plugin-public.coresetup.md b/docs/development/core/public/kibana-plugin-public.coresetup.md index 8314bde7b95f0..7d75782df2e32 100644 --- a/docs/development/core/public/kibana-plugin-public.coresetup.md +++ b/docs/development/core/public/kibana-plugin-public.coresetup.md @@ -9,7 +9,7 @@ Core services exposed to the `Plugin` setup lifecycle Signature: ```typescript -export interface CoreSetup +export interface CoreSetup ``` ## Properties @@ -24,3 +24,9 @@ export interface CoreSetup | [notifications](./kibana-plugin-public.coresetup.notifications.md) | NotificationsSetup | [NotificationsSetup](./kibana-plugin-public.notificationssetup.md) | | [uiSettings](./kibana-plugin-public.coresetup.uisettings.md) | IUiSettingsClient | [IUiSettingsClient](./kibana-plugin-public.iuisettingsclient.md) | +## Methods + +| Method | Description | +| --- | --- | +| [getStartServices()](./kibana-plugin-public.coresetup.getstartservices.md) | Allows plugins to get access to APIs available in start inside async handlers, such as [App.mount](./kibana-plugin-public.app.mount.md). Promise will not resolve until Core and plugin dependencies have completed start. | + diff --git a/docs/development/core/public/kibana-plugin-public.legacycoresetup.md b/docs/development/core/public/kibana-plugin-public.legacycoresetup.md index f704bc65d12a5..a753300437c1c 100644 --- a/docs/development/core/public/kibana-plugin-public.legacycoresetup.md +++ b/docs/development/core/public/kibana-plugin-public.legacycoresetup.md @@ -13,7 +13,7 @@ Setup interface exposed to the legacy platform via the `ui/new_platform` module. Signature: ```typescript -export interface LegacyCoreSetup extends CoreSetup +export interface LegacyCoreSetup extends CoreSetup ``` ## Properties diff --git a/docs/development/core/public/kibana-plugin-public.md b/docs/development/core/public/kibana-plugin-public.md index 22b6f7faf2daa..c599e1eaa14fe 100644 --- a/docs/development/core/public/kibana-plugin-public.md +++ b/docs/development/core/public/kibana-plugin-public.md @@ -26,7 +26,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | [AppBase](./kibana-plugin-public.appbase.md) | | | [ApplicationSetup](./kibana-plugin-public.applicationsetup.md) | | | [ApplicationStart](./kibana-plugin-public.applicationstart.md) | | -| [AppMountContext](./kibana-plugin-public.appmountcontext.md) | The context object received when applications are mounted to the DOM. | +| [AppMountContext](./kibana-plugin-public.appmountcontext.md) | The context object received when applications are mounted to the DOM. Deprecated, use [CoreSetup.getStartServices()](./kibana-plugin-public.coresetup.getstartservices.md). | | [AppMountParameters](./kibana-plugin-public.appmountparameters.md) | | | [Capabilities](./kibana-plugin-public.capabilities.md) | The read-only set of capabilities available for the current UI session. Capabilities are simple key-value pairs of (string, boolean), where the string denotes the capability ID, and the boolean is a flag indicating if the capability is enabled or disabled. | | [ChromeBadge](./kibana-plugin-public.chromebadge.md) | | @@ -98,6 +98,8 @@ The plugin integrates with the core system via lifecycle events: `setup` | Type Alias | Description | | --- | --- | +| [AppMount](./kibana-plugin-public.appmount.md) | A mount function called when the user navigates to this app's route. | +| [AppMountDeprecated](./kibana-plugin-public.appmountdeprecated.md) | A mount function called when the user navigates to this app's route. | | [AppUnmount](./kibana-plugin-public.appunmount.md) | A function called when an application should be unmounted from the page. This function should be synchronous. | | [ChromeBreadcrumb](./kibana-plugin-public.chromebreadcrumb.md) | | | [ChromeHelpExtensionMenuCustomLink](./kibana-plugin-public.chromehelpextensionmenucustomlink.md) | | diff --git a/docs/development/core/public/kibana-plugin-public.plugin.setup.md b/docs/development/core/public/kibana-plugin-public.plugin.setup.md index 56855b02cfbad..f058bc8d86fbc 100644 --- a/docs/development/core/public/kibana-plugin-public.plugin.setup.md +++ b/docs/development/core/public/kibana-plugin-public.plugin.setup.md @@ -7,14 +7,14 @@ Signature: ```typescript -setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise; +setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise; ``` ## Parameters | Parameter | Type | Description | | --- | --- | --- | -| core | CoreSetup | | +| core | CoreSetup<TPluginsStart> | | | plugins | TPluginsSetup | | Returns: diff --git a/src/core/public/application/application_service.test.tsx b/src/core/public/application/application_service.test.tsx index 19a208aeefb37..32634572466a6 100644 --- a/src/core/public/application/application_service.test.tsx +++ b/src/core/public/application/application_service.test.tsx @@ -32,9 +32,9 @@ describe('#setup()', () => { const service = new ApplicationService(); const context = contextServiceMock.createSetupContract(); const setup = service.setup({ context }); - setup.register(Symbol(), { id: 'app1' } as any); + setup.register(Symbol(), { id: 'app1', mount: jest.fn() } as any); expect(() => - setup.register(Symbol(), { id: 'app1' } as any) + setup.register(Symbol(), { id: 'app1', mount: jest.fn() } as any) ).toThrowErrorMatchingInlineSnapshot( `"An application is already registered with the id \\"app1\\""` ); @@ -51,6 +51,18 @@ describe('#setup()', () => { setup.register(Symbol(), { id: 'app1' } as any) ).toThrowErrorMatchingInlineSnapshot(`"Applications cannot be registered after \\"setup\\""`); }); + + it('logs a warning when registering a deprecated app mount', async () => { + const consoleWarnSpy = jest.spyOn(console, 'warn'); + const service = new ApplicationService(); + const context = contextServiceMock.createSetupContract(); + const setup = service.setup({ context }); + setup.register(Symbol(), { id: 'app1', mount: (ctx: any, params: any) => {} } as any); + expect(consoleWarnSpy).toHaveBeenCalledWith( + `App [app1] is using deprecated mount context. Use core.getStartServices() instead.` + ); + consoleWarnSpy.mockRestore(); + }); }); describe('registerLegacyApp', () => { @@ -100,7 +112,7 @@ describe('#start()', () => { const service = new ApplicationService(); const context = contextServiceMock.createSetupContract(); const setup = service.setup({ context }); - setup.register(Symbol(), { id: 'app1' } as any); + setup.register(Symbol(), { id: 'app1', mount: jest.fn() } as any); setup.registerLegacyApp({ id: 'app2' } as any); const http = httpServiceMock.createStartContract(); @@ -108,12 +120,13 @@ describe('#start()', () => { const startContract = await service.start({ http, injectedMetadata }); expect(startContract.availableApps).toMatchInlineSnapshot(` - Map { - "app1" => Object { - "id": "app1", - }, - } - `); + Map { + "app1" => Object { + "id": "app1", + "mount": [MockFunction], + }, + } + `); expect(startContract.availableLegacyApps).toMatchInlineSnapshot(` Map { "app2" => Object { @@ -127,14 +140,15 @@ describe('#start()', () => { const service = new ApplicationService(); const context = contextServiceMock.createSetupContract(); const setup = service.setup({ context }); - setup.register(Symbol(), { id: 'app1' } as any); + const app1 = { id: 'app1', mount: jest.fn() }; + setup.register(Symbol(), app1 as any); const http = httpServiceMock.createStartContract(); const injectedMetadata = injectedMetadataServiceMock.createStartContract(); await service.start({ http, injectedMetadata }); expect(MockCapabilitiesService.start).toHaveBeenCalledWith({ - apps: new Map([['app1', { id: 'app1' }]]), + apps: new Map([['app1', app1]]), legacyApps: new Map(), http, }); diff --git a/src/core/public/application/application_service.tsx b/src/core/public/application/application_service.tsx index 45ca7f3fe7f7b..df00c84028e6f 100644 --- a/src/core/public/application/application_service.tsx +++ b/src/core/public/application/application_service.tsx @@ -29,7 +29,8 @@ import { ContextSetup, IContextContainer } from '../context'; import { App, LegacyApp, - AppMounter, + AppMount, + AppMountDeprecated, InternalApplicationSetup, InternalApplicationStart, } from './types'; @@ -50,7 +51,7 @@ interface StartDeps { interface AppBox { app: App; - mount: AppMounter; + mount: AppMount; } /** @@ -61,7 +62,7 @@ export class ApplicationService { private readonly apps$ = new BehaviorSubject>(new Map()); private readonly legacyApps$ = new BehaviorSubject>(new Map()); private readonly capabilities = new CapabilitiesService(); - private mountContext?: IContextContainer; + private mountContext?: IContextContainer; public setup({ context }: SetupDeps): InternalApplicationSetup { this.mountContext = context.createContextContainer(); @@ -75,10 +76,21 @@ export class ApplicationService { throw new Error(`Applications cannot be registered after "setup"`); } - const appBox: AppBox = { - app, - mount: this.mountContext!.createHandler(plugin, app.mount), - }; + let appBox: AppBox; + if (isAppMountDeprecated(app.mount)) { + // eslint-disable-next-line no-console + console.warn( + `App [${app.id}] is using deprecated mount context. Use core.getStartServices() instead.` + ); + + appBox = { + app, + mount: this.mountContext!.createHandler(plugin, app.mount), + }; + } else { + appBox = { app, mount: app.mount }; + } + this.apps$.next(new Map([...this.apps$.value.entries(), [app.id, appBox]])); }, registerLegacyApp: (app: LegacyApp) => { @@ -146,7 +158,7 @@ export class ApplicationService { } // Filter only available apps and map to just the mount function. - const appMounters = new Map( + const appMounts = new Map( [...this.apps$.value] .filter(([id]) => availableApps.has(id)) .map(([id, { mount }]) => [id, mount]) @@ -154,7 +166,7 @@ export class ApplicationService { return ( path ? `/app/${appId}/${path.replace(/^\//, '')}` // Remove preceding slash from path if present : `/app/${appId}`; + +function isAppMountDeprecated(mount: (...args: any[]) => any): mount is AppMountDeprecated { + // Mount functions with two arguments are assumed to expect deprecated `context` object. + return mount.length === 2; +} diff --git a/src/core/public/application/index.ts b/src/core/public/application/index.ts index ae25b54cf07a8..9c4427c772a5e 100644 --- a/src/core/public/application/index.ts +++ b/src/core/public/application/index.ts @@ -22,6 +22,8 @@ export { Capabilities } from './capabilities'; export { App, AppBase, + AppMount, + AppMountDeprecated, AppUnmount, AppMountContext, AppMountParameters, diff --git a/src/core/public/application/integration_tests/router.test.tsx b/src/core/public/application/integration_tests/router.test.tsx index 593858851d387..81aef5204c7e2 100644 --- a/src/core/public/application/integration_tests/router.test.tsx +++ b/src/core/public/application/integration_tests/router.test.tsx @@ -24,7 +24,7 @@ import { BehaviorSubject } from 'rxjs'; import { I18nProvider } from '@kbn/i18n/react'; -import { AppMounter, LegacyApp, AppMountParameters } from '../types'; +import { AppMount, LegacyApp, AppMountParameters } from '../types'; import { httpServiceMock } from '../../http/http_service.mock'; import { AppRouter, AppNotFound } from '../ui'; @@ -35,7 +35,7 @@ const createMountHandler = (htmlString: string) => }); describe('AppContainer', () => { - let apps: Map, Parameters>>; + let apps: Map, Parameters>>; let legacyApps: Map; let history: History; let router: ReactWrapper; diff --git a/src/core/public/application/types.ts b/src/core/public/application/types.ts index a031ab6070413..72460b07900da 100644 --- a/src/core/public/application/types.ts +++ b/src/core/public/application/types.ts @@ -75,12 +75,14 @@ export interface AppBase { */ export interface App extends AppBase { /** - * A mount function called when the user navigates to this app's route. - * @param context The mount context for this app. - * @param targetDomElement An HTMLElement to mount the application onto. - * @returns An unmounting function that will be called to unmount the application. + * A mount function called when the user navigates to this app's route. May have signature of {@link AppMount} or + * {@link AppMountDeprecated}. + * + * @remarks + * When function has two arguments, it will be called with a {@link AppMountContext | context} as the first argument. + * This behavior is **deprecated**, and consumers should instead use {@link CoreSetup.getStartServices}. */ - mount: (context: AppMountContext, params: AppMountParameters) => AppUnmount | Promise; + mount: AppMount | AppMountDeprecated; /** * Hide the UI chrome when the application is mounted. Defaults to `false`. @@ -97,7 +99,39 @@ export interface LegacyApp extends AppBase { } /** - * The context object received when applications are mounted to the DOM. + * A mount function called when the user navigates to this app's route. + * + * @param params {@link AppMountParameters} + * @returns An unmounting function that will be called to unmount the application. See {@link AppUnmount}. + * + * @public + */ +export type AppMount = (params: AppMountParameters) => AppUnmount | Promise; + +/** + * A mount function called when the user navigates to this app's route. + * + * @remarks + * When function has two arguments, it will be called with a {@link AppMountContext | context} as the first argument. + * This behavior is **deprecated**, and consumers should instead use {@link CoreSetup.getStartServices}. + * + * @param context The mount context for this app. Deprecated, use {@link CoreSetup.getStartServices}. + * @param params {@link AppMountParameters} + * @returns An unmounting function that will be called to unmount the application. See {@link AppUnmount}. + * + * @deprecated + * @public + */ +export type AppMountDeprecated = ( + context: AppMountContext, + params: AppMountParameters +) => AppUnmount | Promise; + +/** + * The context object received when applications are mounted to the DOM. Deprecated, use + * {@link CoreSetup.getStartServices}. + * + * @deprecated * @public */ export interface AppMountContext { @@ -192,9 +226,6 @@ export interface AppMountParameters { */ export type AppUnmount = () => void; -/** @internal */ -export type AppMounter = (params: AppMountParameters) => Promise; - /** @public */ export interface ApplicationSetup { /** @@ -205,14 +236,15 @@ export interface ApplicationSetup { /** * Register a context provider for application mounting. Will only be available to applications that depend on the - * plugin that registered this context. + * plugin that registered this context. Deprecated, use {@link CoreSetup.getStartServices}. * + * @deprecated * @param contextName - The key of {@link AppMountContext} this provider's return value should be attached to. * @param provider - A {@link IContextProvider} function */ registerMountContext( contextName: T, - provider: IContextProvider + provider: IContextProvider ): void; } @@ -234,8 +266,9 @@ export interface InternalApplicationSetup { /** * Register a context provider for application mounting. Will only be available to applications that depend on the - * plugin that registered this context. + * plugin that registered this context. Deprecated, use {@link CoreSetup.getStartServices}. * + * @deprecated * @param pluginOpaqueId - The opaque ID of the plugin that is registering the context. * @param contextName - The key of {@link AppMountContext} this provider's return value should be attached to. * @param provider - A {@link IContextProvider} function @@ -243,7 +276,7 @@ export interface InternalApplicationSetup { registerMountContext( pluginOpaqueId: PluginOpaqueId, contextName: T, - provider: IContextProvider + provider: IContextProvider ): void; } @@ -272,15 +305,16 @@ export interface ApplicationStart { /** * Register a context provider for application mounting. Will only be available to applications that depend on the - * plugin that registered this context. + * plugin that registered this context. Deprecated, use {@link CoreSetup.getStartServices}. * + * @deprecated * @param pluginOpaqueId - The opaque ID of the plugin that is registering the context. * @param contextName - The key of {@link AppMountContext} this provider's return value should be attached to. * @param provider - A {@link IContextProvider} function */ registerMountContext( contextName: T, - provider: IContextProvider + provider: IContextProvider ): void; } @@ -301,8 +335,9 @@ export interface InternalApplicationStart /** * Register a context provider for application mounting. Will only be available to applications that depend on the - * plugin that registered this context. + * plugin that registered this context. Deprecated, use {@link CoreSetup.getStartServices}. * + * @deprecated * @param pluginOpaqueId - The opaque ID of the plugin that is registering the context. * @param contextName - The key of {@link AppMountContext} this provider's return value should be attached to. * @param provider - A {@link IContextProvider} function @@ -310,7 +345,7 @@ export interface InternalApplicationStart registerMountContext( pluginOpaqueId: PluginOpaqueId, contextName: T, - provider: IContextProvider + provider: IContextProvider ): void; // Internal APIs diff --git a/src/core/public/application/ui/app_container.tsx b/src/core/public/application/ui/app_container.tsx index 876cd3aa3a3d3..9c2bb30e79503 100644 --- a/src/core/public/application/ui/app_container.tsx +++ b/src/core/public/application/ui/app_container.tsx @@ -21,12 +21,12 @@ import React from 'react'; import { RouteComponentProps } from 'react-router-dom'; import { Subject } from 'rxjs'; -import { LegacyApp, AppMounter, AppUnmount } from '../types'; +import { LegacyApp, AppMount, AppUnmount } from '../types'; import { HttpStart } from '../../http'; import { AppNotFound } from './app_not_found_screen'; interface Props extends RouteComponentProps<{ appId: string }> { - apps: ReadonlyMap; + apps: ReadonlyMap; legacyApps: ReadonlyMap; basePath: HttpStart['basePath']; currentAppId$: Subject; diff --git a/src/core/public/application/ui/app_router.tsx b/src/core/public/application/ui/app_router.tsx index b574bf16278e2..67701a33dabf4 100644 --- a/src/core/public/application/ui/app_router.tsx +++ b/src/core/public/application/ui/app_router.tsx @@ -22,12 +22,12 @@ import React from 'react'; import { Router, Route } from 'react-router-dom'; import { Subject } from 'rxjs'; -import { LegacyApp, AppMounter } from '../types'; +import { LegacyApp, AppMount } from '../types'; import { AppContainer } from './app_container'; import { HttpStart } from '../../http'; interface Props { - apps: ReadonlyMap; + apps: ReadonlyMap; legacyApps: ReadonlyMap; basePath: HttpStart['basePath']; currentAppId$: Subject; diff --git a/src/core/public/core_system.ts b/src/core/public/core_system.ts index 4818484b00819..abc4c144356e8 100644 --- a/src/core/public/core_system.ts +++ b/src/core/public/core_system.ts @@ -64,7 +64,7 @@ export interface CoreContext { } /** @internal */ -export interface InternalCoreSetup extends Omit { +export interface InternalCoreSetup extends Omit { application: InternalApplicationSetup; injectedMetadata: InjectedMetadataSetup; } @@ -253,11 +253,11 @@ export class CoreSystem { docLinks, http, i18n, + injectedMetadata: pick(injectedMetadata, ['getInjectedVar']), notifications, overlays, savedObjects, uiSettings, - injectedMetadata: pick(injectedMetadata, ['getInjectedVar']), })); const core: InternalCoreStart = { diff --git a/src/core/public/index.ts b/src/core/public/index.ts index 035cbcca86ac7..f53bf44bcdcfd 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -79,7 +79,17 @@ import { export { CoreContext, CoreSystem } from './core_system'; export { RecursiveReadonly } from '../utils'; -export { App, AppBase, AppUnmount, AppMountContext, AppMountParameters } from './application'; +export { + ApplicationSetup, + ApplicationStart, + App, + AppBase, + AppMount, + AppMountDeprecated, + AppUnmount, + AppMountContext, + AppMountParameters, +} from './application'; export { SavedObjectsBatchResponse, @@ -145,10 +155,13 @@ export { MountPoint, UnmountCallback } from './types'; * navigation in the generated docs until there's a fix for * https://github.com/Microsoft/web-build-tools/issues/1237 */ -export interface CoreSetup { +export interface CoreSetup { /** {@link ApplicationSetup} */ application: ApplicationSetup; - /** {@link ContextSetup} */ + /** + * {@link ContextSetup} + * @deprecated + */ context: ContextSetup; /** {@link FatalErrorsSetup} */ fatalErrors: FatalErrorsSetup; @@ -167,6 +180,13 @@ export interface CoreSetup { injectedMetadata: { getInjectedVar: (name: string, defaultValue?: any) => unknown; }; + + /** + * Allows plugins to get access to APIs available in start inside async + * handlers, such as {@link App.mount}. Promise will not resolve until Core + * and plugin dependencies have completed `start`. + */ + getStartServices(): Promise<[CoreStart, TPluginsStart]>; } /** @@ -218,7 +238,7 @@ export interface CoreStart { * @public * @deprecated */ -export interface LegacyCoreSetup extends CoreSetup { +export interface LegacyCoreSetup extends CoreSetup { /** @deprecated */ injectedMetadata: InjectedMetadataSetup; } @@ -239,8 +259,6 @@ export interface LegacyCoreStart extends CoreStart { } export { - ApplicationSetup, - ApplicationStart, Capabilities, ChromeBadge, ChromeBrand, diff --git a/src/core/public/legacy/legacy_service.test.ts b/src/core/public/legacy/legacy_service.test.ts index 37e07af0a7da5..9dd24f9e4a7a3 100644 --- a/src/core/public/legacy/legacy_service.test.ts +++ b/src/core/public/legacy/legacy_service.test.ts @@ -169,6 +169,20 @@ describe('#start()', () => { expect(mockUiNewPlatformStart).toHaveBeenCalledWith(expect.any(Object), {}); }); + it('resolves getStartServices with core and plugin APIs', async () => { + const legacyPlatform = new LegacyPlatformService({ + ...defaultParams, + }); + + legacyPlatform.setup(defaultSetupDeps); + legacyPlatform.start(defaultStartDeps); + + const { getStartServices } = mockUiNewPlatformSetup.mock.calls[0][0]; + const [coreStart, pluginsStart] = await getStartServices(); + expect(coreStart).toEqual(expect.any(Object)); + expect(pluginsStart).toBe(defaultStartDeps.plugins); + }); + describe('useLegacyTestHarness = false', () => { it('passes the targetDomElement to ui/chrome', () => { const legacyPlatform = new LegacyPlatformService({ diff --git a/src/core/public/legacy/legacy_service.ts b/src/core/public/legacy/legacy_service.ts index 22e315f9e1b03..a4fdd86de5311 100644 --- a/src/core/public/legacy/legacy_service.ts +++ b/src/core/public/legacy/legacy_service.ts @@ -18,6 +18,8 @@ */ import angular from 'angular'; +import { first } from 'rxjs/operators'; +import { Subject } from 'rxjs'; import { InternalCoreSetup, InternalCoreStart } from '../core_system'; import { LegacyCoreSetup, LegacyCoreStart, MountPoint } from '../'; @@ -55,6 +57,8 @@ export class LegacyPlatformService { public readonly legacyId = Symbol(); private bootstrapModule?: BootstrapModule; private targetDomElement?: HTMLElement; + private readonly startDependencies$ = new Subject<[LegacyCoreStart, object]>(); + private readonly startDependencies = this.startDependencies$.pipe(first()).toPromise(); constructor(private readonly params: LegacyPlatformParams) {} @@ -75,6 +79,7 @@ export class LegacyPlatformService { const legacyCore: LegacyCoreSetup = { ...core, + getStartServices: () => this.startDependencies, application: { register: notSupported(`core.application.register()`), registerMountContext: notSupported(`core.application.registerMountContext()`), @@ -120,6 +125,8 @@ export class LegacyPlatformService { }, }; + this.startDependencies$.next([legacyCore, plugins]); + // Inject parts of the new platform into parts of the legacy platform // so that legacy APIs/modules can mimic their new platform counterparts require('ui/new_platform').__start__(legacyCore, plugins); diff --git a/src/core/public/mocks.ts b/src/core/public/mocks.ts index 644df259b8e24..43c8aa6f1d6b9 100644 --- a/src/core/public/mocks.ts +++ b/src/core/public/mocks.ts @@ -46,6 +46,9 @@ function createCoreSetupMock({ basePath = '' } = {}) { application: applicationServiceMock.createSetupContract(), context: contextServiceMock.createSetupContract(), fatalErrors: fatalErrorsServiceMock.createSetupContract(), + getStartServices: jest.fn, object]>, []>(() => + Promise.resolve([createCoreStartMock({ basePath }), {}]) + ), http: httpServiceMock.createSetupContract({ basePath }), notifications: notificationServiceMock.createSetupContract(), uiSettings: uiSettingsServiceMock.createSetupContract(), @@ -75,6 +78,7 @@ function createCoreStartMock({ basePath = '' } = {}) { return mock; } + function pluginInitializerContextMock() { const mock: PluginInitializerContext = { opaqueId: Symbol(), diff --git a/src/core/public/plugins/plugin.test.ts b/src/core/public/plugins/plugin.test.ts index 85de5c6620cc1..111ee93dd699b 100644 --- a/src/core/public/plugins/plugin.test.ts +++ b/src/core/public/plugins/plugin.test.ts @@ -106,6 +106,33 @@ describe('PluginWrapper', () => { expect(mockPlugin.start).toHaveBeenCalledWith(context, deps); }); + test("`start` resolves `startDependencies` Promise after plugin's start", async () => { + expect.assertions(2); + + let startDependenciesResolved = false; + mockPluginLoader.mockResolvedValueOnce(() => ({ + setup: jest.fn(), + start: async () => { + // Add small delay to ensure startDependencies is not resolved until after the plugin instance's start resolves. + await new Promise(resolve => setTimeout(resolve, 10)); + expect(startDependenciesResolved).toBe(false); + }, + })); + await plugin.load(addBasePath); + await plugin.setup({} as any, {} as any); + const context = { any: 'thing' } as any; + const deps = { otherDep: 'value' }; + + // Add promise callback prior to calling `start` to ensure calls in `setup` will not resolve before `start` is + // called. + const startDependenciesCheck = plugin.startDependencies.then(res => { + startDependenciesResolved = true; + expect(res).toEqual([context, deps]); + }); + await plugin.start(context, deps); + await startDependenciesCheck; + }); + test('`stop` fails if plugin is not setup up', async () => { expect(() => plugin.stop()).toThrowErrorMatchingInlineSnapshot( `"Plugin \\"plugin-a\\" can't be stopped since it isn't set up."` diff --git a/src/core/public/plugins/plugin.ts b/src/core/public/plugins/plugin.ts index 05268bbfcdd05..e880627e352c8 100644 --- a/src/core/public/plugins/plugin.ts +++ b/src/core/public/plugins/plugin.ts @@ -17,6 +17,8 @@ * under the License. */ +import { Subject } from 'rxjs'; +import { first } from 'rxjs/operators'; import { DiscoveredPlugin, PluginOpaqueId } from '../../server'; import { PluginInitializerContext } from './plugin_context'; import { loadPluginBundle } from './plugin_loader'; @@ -33,7 +35,7 @@ export interface Plugin< TPluginsSetup extends object = object, TPluginsStart extends object = object > { - setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise; + setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise; start(core: CoreStart, plugins: TPluginsStart): TStart | Promise; stop?(): void; } @@ -70,6 +72,9 @@ export class PluginWrapper< private initializer?: PluginInitializer; private instance?: Plugin; + private readonly startDependencies$ = new Subject<[CoreStart, TPluginsStart]>(); + public readonly startDependencies = this.startDependencies$.pipe(first()).toPromise(); + constructor( public readonly discoveredPlugin: DiscoveredPlugin, public readonly opaqueId: PluginOpaqueId, @@ -100,7 +105,7 @@ export class PluginWrapper< * @param plugins The dictionary where the key is the dependency name and the value * is the contract returned by the dependency's `setup` function. */ - public async setup(setupContext: CoreSetup, plugins: TPluginsSetup) { + public async setup(setupContext: CoreSetup, plugins: TPluginsSetup) { this.instance = await this.createPluginInstance(); return await this.instance.setup(setupContext, plugins); @@ -118,7 +123,11 @@ export class PluginWrapper< throw new Error(`Plugin "${this.name}" can't be started since it isn't set up.`); } - return await this.instance.start(startContext, plugins); + const startContract = await this.instance.start(startContext, plugins); + + this.startDependencies$.next([startContext, plugins]); + + return startContract; } /** diff --git a/src/core/public/plugins/plugin_context.ts b/src/core/public/plugins/plugin_context.ts index f77ddd8f2f696..848f46605d4de 100644 --- a/src/core/public/plugins/plugin_context.ts +++ b/src/core/public/plugins/plugin_context.ts @@ -107,6 +107,7 @@ export function createPluginSetupContext< injectedMetadata: { getInjectedVar: deps.injectedMetadata.getInjectedVar, }, + getStartServices: () => plugin.startDependencies, }; } diff --git a/src/core/public/plugins/plugins_service.test.ts b/src/core/public/plugins/plugins_service.test.ts index 2983d7583cb49..281778f9420dd 100644 --- a/src/core/public/plugins/plugins_service.test.ts +++ b/src/core/public/plugins/plugins_service.test.ts @@ -98,6 +98,7 @@ describe('PluginsService', () => { mockSetupContext = { ...mockSetupDeps, application: expect.any(Object), + getStartServices: expect.any(Function), }; mockStartDeps = { application: applicationServiceMock.createInternalStartContract(), diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index 157f0bab466b0..b745c23d52212 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -19,7 +19,7 @@ import { UserProvidedValues as UserProvidedValues_2 } from 'src/core/server/type // @public export interface App extends AppBase { chromeless?: boolean; - mount: (context: AppMountContext, params: AppMountParameters) => AppUnmount | Promise; + mount: AppMount | AppMountDeprecated; } // @public (undocumented) @@ -37,7 +37,8 @@ export interface AppBase { // @public (undocumented) export interface ApplicationSetup { register(app: App): void; - registerMountContext(contextName: T, provider: IContextProvider): void; + // @deprecated + registerMountContext(contextName: T, provider: IContextProvider): void; } // @public (undocumented) @@ -50,10 +51,14 @@ export interface ApplicationStart { path?: string; state?: any; }): void; - registerMountContext(contextName: T, provider: IContextProvider): void; + // @deprecated + registerMountContext(contextName: T, provider: IContextProvider): void; } // @public +export type AppMount = (params: AppMountParameters) => AppUnmount | Promise; + +// @public @deprecated export interface AppMountContext { core: { application: Pick; @@ -71,6 +76,9 @@ export interface AppMountContext { }; } +// @public @deprecated +export type AppMountDeprecated = (context: AppMountContext, params: AppMountParameters) => AppUnmount | Promise; + // @public (undocumented) export interface AppMountParameters { appBasePath: string; @@ -275,13 +283,14 @@ export interface CoreContext { } // @public -export interface CoreSetup { +export interface CoreSetup { // (undocumented) application: ApplicationSetup; - // (undocumented) + // @deprecated (undocumented) context: ContextSetup; // (undocumented) fatalErrors: FatalErrorsSetup; + getStartServices(): Promise<[CoreStart, TPluginsStart]>; // (undocumented) http: HttpSetup; // @deprecated @@ -653,7 +662,7 @@ export interface IUiSettingsClient { } // @public @deprecated -export interface LegacyCoreSetup extends CoreSetup { +export interface LegacyCoreSetup extends CoreSetup { // Warning: (ae-forgotten-export) The symbol "InjectedMetadataSetup" needs to be exported by the entry point index.d.ts // // @deprecated (undocumented) @@ -749,7 +758,7 @@ export interface PackageInfo { // @public export interface Plugin { // (undocumented) - setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise; + setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise; // (undocumented) start(core: CoreStart, plugins: TPluginsStart): TStart | Promise; // (undocumented) diff --git a/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts b/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts index e5bfd88ea7637..cd3e0d2fd9f89 100644 --- a/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts +++ b/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts @@ -17,7 +17,7 @@ * under the License. */ -import { App, AppUnmount } from 'kibana/public'; +import { App, AppUnmount, AppMountDeprecated } from 'kibana/public'; import { UIRoutes } from 'ui/routes'; import { ILocationService, IScope } from 'angular'; import { npStart } from 'ui/new_platform'; @@ -68,7 +68,10 @@ export class LocalApplicationService { isUnmounted = true; }); (async () => { - unmountHandler = await app.mount({ core: npStart.core }, { element, appBasePath: '' }); + const params = { element, appBasePath: '' }; + unmountHandler = isAppMountDeprecated(app.mount) + ? await app.mount({ core: npStart.core }, params) + : await app.mount(params); // immediately unmount app if scope got destroyed in the meantime if (isUnmounted) { unmountHandler(); @@ -90,3 +93,8 @@ export class LocalApplicationService { } export const localApplicationService = new LocalApplicationService(); + +function isAppMountDeprecated(mount: (...args: any[]) => any): mount is AppMountDeprecated { + // Mount functions with two arguments are assumed to expect deprecated `context` object. + return mount.length === 2; +} diff --git a/src/legacy/ui/public/new_platform/new_platform.test.ts b/src/legacy/ui/public/new_platform/new_platform.test.ts index e5d5cd0a87776..cd1af311d4eff 100644 --- a/src/legacy/ui/public/new_platform/new_platform.test.ts +++ b/src/legacy/ui/public/new_platform/new_platform.test.ts @@ -58,6 +58,26 @@ describe('ui/new_platform', () => { const scopeMock = { $on: jest.fn() }; const elementMock = [document.createElement('div')]; + controller(scopeMock, elementMock); + expect(mountMock).toHaveBeenCalledWith({ + element: elementMock[0], + appBasePath: '/test/base/path/app/test', + }); + }); + + test('controller calls deprecated context app.mount when invoked', () => { + const unmountMock = jest.fn(); + // Two arguments changes how this is called. + const mountMock = jest.fn((context, params) => unmountMock); + legacyAppRegister({ + id: 'test', + title: 'Test', + mount: mountMock, + }); + const controller = setRootControllerMock.mock.calls[0][1]; + const scopeMock = { $on: jest.fn() }; + const elementMock = [document.createElement('div')]; + controller(scopeMock, elementMock); expect(mountMock).toHaveBeenCalledWith(expect.any(Object), { element: elementMock[0], diff --git a/src/legacy/ui/public/new_platform/new_platform.ts b/src/legacy/ui/public/new_platform/new_platform.ts index c0b2d6d913257..d80d11e1b1bdd 100644 --- a/src/legacy/ui/public/new_platform/new_platform.ts +++ b/src/legacy/ui/public/new_platform/new_platform.ts @@ -20,7 +20,7 @@ import { IScope } from 'angular'; import { IUiActionsStart, IUiActionsSetup } from 'src/plugins/ui_actions/public'; import { IEmbeddableStart, IEmbeddableSetup } from 'src/plugins/embeddable/public'; -import { LegacyCoreSetup, LegacyCoreStart, App } from '../../../../core/public'; +import { LegacyCoreSetup, LegacyCoreStart, App, AppMountDeprecated } from '../../../../core/public'; import { Plugin as DataPlugin } from '../../../../plugins/data/public'; import { Plugin as ExpressionsPlugin } from '../../../../plugins/expressions/public'; import { @@ -111,13 +111,18 @@ export const legacyAppRegister = (app: App) => { // Root controller cannot return a Promise so use an internal async function and call it immediately (async () => { - const unmount = await app.mount( - { core: npStart.core }, - { element, appBasePath: npSetup.core.http.basePath.prepend(`/app/${app.id}`) } - ); + const params = { element, appBasePath: npSetup.core.http.basePath.prepend(`/app/${app.id}`) }; + const unmount = isAppMountDeprecated(app.mount) + ? await app.mount({ core: npStart.core }, params) + : await app.mount(params); $scope.$on('$destroy', () => { unmount(); }); })(); }); }; + +function isAppMountDeprecated(mount: (...args: any[]) => any): mount is AppMountDeprecated { + // Mount functions with two arguments are assumed to expect deprecated `context` object. + return mount.length === 2; +} diff --git a/src/plugins/dev_tools/public/application.tsx b/src/plugins/dev_tools/public/application.tsx index b3c6bb592f378..be142f2cc74e6 100644 --- a/src/plugins/dev_tools/public/application.tsx +++ b/src/plugins/dev_tools/public/application.tsx @@ -25,7 +25,7 @@ import * as React from 'react'; import ReactDOM from 'react-dom'; import { useEffect, useRef } from 'react'; -import { AppMountContext } from 'kibana/public'; +import { AppMountContext, AppMountDeprecated } from 'kibana/public'; import { DevTool } from './plugin'; interface DevToolsWrapperProps { @@ -91,10 +91,10 @@ function DevToolsWrapper({ if (mountedTool.current) { mountedTool.current.unmountHandler(); } - const unmountHandler = await activeDevTool.mount(appMountContext, { - element, - appBasePath: '', - }); + const params = { element, appBasePath: '' }; + const unmountHandler = isAppMountDeprecated(activeDevTool.mount) + ? await activeDevTool.mount(appMountContext, params) + : await activeDevTool.mount(params); mountedTool.current = { devTool: activeDevTool, mountpoint: element, @@ -182,3 +182,8 @@ export function renderApp( return () => ReactDOM.unmountComponentAtNode(element); } + +function isAppMountDeprecated(mount: (...args: any[]) => any): mount is AppMountDeprecated { + // Mount functions with two arguments are assumed to expect deprecated `context` object. + return mount.length === 2; +} diff --git a/test/plugin_functional/plugins/core_plugin_b/public/plugin.tsx b/test/plugin_functional/plugins/core_plugin_b/public/plugin.tsx index 56cc1cb4ab425..5c8e1d03d5a4a 100644 --- a/test/plugin_functional/plugins/core_plugin_b/public/plugin.tsx +++ b/test/plugin_functional/plugins/core_plugin_b/public/plugin.tsx @@ -24,6 +24,7 @@ declare global { interface Window { corePluginB?: string; hasAccessToInjectedMetadata?: boolean; + receivedStartServices?: boolean; env?: PluginInitializerContext['env']; } } @@ -40,6 +41,9 @@ export class CorePluginBPlugin public setup(core: CoreSetup, deps: CorePluginBDeps) { window.corePluginB = `Plugin A said: ${deps.core_plugin_a.getGreeting()}`; window.hasAccessToInjectedMetadata = 'getInjectedVar' in core.injectedMetadata; + core.getStartServices().then(([coreStart, plugins]) => { + window.receivedStartServices = 'overlays' in coreStart; + }); core.application.register({ id: 'bar', diff --git a/test/plugin_functional/plugins/core_plugin_legacy/public/index.ts b/test/plugin_functional/plugins/core_plugin_legacy/public/index.ts index 6988ed82f34a7..51b5d2aaf3587 100644 --- a/test/plugin_functional/plugins/core_plugin_legacy/public/index.ts +++ b/test/plugin_functional/plugins/core_plugin_legacy/public/index.ts @@ -22,8 +22,8 @@ import { npSetup } from 'ui/new_platform'; npSetup.core.application.register({ id: 'core_legacy_compat', title: 'Core Legacy Compat', - async mount(...args) { + async mount(context, params) { const { renderApp } = await import('./application'); - return renderApp(...args); + return renderApp(context, params); }, }); diff --git a/test/plugin_functional/test_suites/core_plugins/ui_plugins.ts b/test/plugin_functional/test_suites/core_plugins/ui_plugins.ts index a971921ad3ed8..ff53583546487 100644 --- a/test/plugin_functional/test_suites/core_plugins/ui_plugins.ts +++ b/test/plugin_functional/test_suites/core_plugins/ui_plugins.ts @@ -36,28 +36,41 @@ export default function({ getService, getPageObjects }: PluginFunctionalProvider expect(corePluginB).to.equal(`Plugin A said: Hello from Plugin A!`); }); }); + describe('have injectedMetadata service provided', function describeIndexTests() { before(async () => { await PageObjects.common.navigateToApp('bar'); }); - it('should attach string to window.corePluginB', async () => { + it('should attach boolean to window.hasAccessToInjectedMetadata', async () => { const hasAccessToInjectedMetadata = await browser.execute( 'return window.hasAccessToInjectedMetadata' ); expect(hasAccessToInjectedMetadata).to.equal(true); }); }); + describe('have env data provided', function describeIndexTests() { before(async () => { await PageObjects.common.navigateToApp('bar'); }); - it('should attach pluginContext to window.corePluginB', async () => { + it('should attach pluginContext to window.env', async () => { const envData: any = await browser.execute('return window.env'); expect(envData.mode.dev).to.be(true); expect(envData.packageInfo.version).to.be.a('string'); }); }); + + describe('have access to start services via coreSetup.getStartServices', function describeIndexTests() { + before(async () => { + await PageObjects.common.navigateToApp('bar'); + }); + + it('should attach boolean to window.receivedStartServices', async () => { + const receivedStartServices = await browser.execute('return window.receivedStartServices'); + expect(receivedStartServices).to.equal(true); + }); + }); }); } From 31a6b5013dd4d825742908cc72e5c7af443a46c0 Mon Sep 17 00:00:00 2001 From: Tim Sullivan Date: Thu, 12 Dec 2019 12:58:11 -0700 Subject: [PATCH 58/79] [Reporting/Screenshots] add error for no shared items found on the page (#52022) * [Reporting/Screenshots] add error for no shared items container found on the page * wording adjustment --- .../common/lib/screenshots/get_element_position_data.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/x-pack/legacy/plugins/reporting/export_types/common/lib/screenshots/get_element_position_data.ts b/x-pack/legacy/plugins/reporting/export_types/common/lib/screenshots/get_element_position_data.ts index 927cf9ec7d801..ce51dc2317c79 100644 --- a/x-pack/legacy/plugins/reporting/export_types/common/lib/screenshots/get_element_position_data.ts +++ b/x-pack/legacy/plugins/reporting/export_types/common/lib/screenshots/get_element_position_data.ts @@ -47,5 +47,11 @@ export const getElementPositionAndAttributes = async ( args: [layout.selectors.screenshot, { title: 'data-title', description: 'data-description' }], }); + if (elementsPositionAndAttributes.length === 0) { + throw new Error( + `No shared items containers were found on the page! Reporting requires a container element with the '${layout.selectors.screenshot}' attribute on the page.` + ); + } + return elementsPositionAndAttributes; }; From 617c8d589abe5309735065aa85dc4e04017f5a9f Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Thu, 12 Dec 2019 13:17:30 -0700 Subject: [PATCH 59/79] [Metrics UI] Add AWS Metricsets to Inventory Models (#49983) * Adding initial code for EC2 * Removing obsolute files; Adding EC2; * Removing currentTimerange and replacing it with currentTime; Timerange will now be calcuated on the server * Fixing AWS.s3 with Metrics Explorer * Auto calculating timerange and interval based on metricset.period * Adding S3 metricset * Inital addition of RDS metrics * Adding SQS and fixing a few things * Fixing typescript error * Adding RDS; Adjusting fields for S3; adding new formatter * Return 60 seconds by detault * Fixing types * Removing i18n * Fixing tests * Fixing translations * Fixes from merge * Removing IDX from code not covered by #52354 * fixing tests * Adding controls for crossliking; consolidating display name * remove obsolete import * Adding drop_last_bucket_support to TSVB models * Changing type * Fixing value per type * remvoing obsolete translation * Removing duplicate lines * Removing icons from switcher * Reducing boilerplate in Toolbar Items * Changing file name --- .../plugins/infra/common/ecs_allowed_list.ts | 6 + .../infra/common/graphql/shared/schema.gql.ts | 4 + .../plugins/infra/common/graphql/types.ts | 38 ++++ .../infra/common/http_api/metadata_api.ts | 11 +- .../common/inventory_models/aws_ec2/index.ts | 30 +++ .../inventory_models/aws_ec2/layout.tsx | 116 +++++++++++ .../inventory_models/aws_ec2/metrics/index.ts | 28 +++ .../aws_ec2/metrics/snapshot/cpu.ts | 27 +++ .../metrics/snapshot/disk_io_read_bytes.ts | 15 ++ .../metrics/snapshot/disk_io_write_bytes.ts | 15 ++ .../aws_ec2/metrics/snapshot/rx.ts | 15 ++ .../aws_ec2/metrics/snapshot/tx.ts | 15 ++ .../metrics/tsvb/aws_ec2_cpu_utilization.ts | 37 ++++ .../metrics/tsvb/aws_ec2_diskio_bytes.ts | 41 ++++ .../metrics/tsvb/aws_ec2_network_traffic.ts | 41 ++++ .../aws_ec2/toolbar_items.tsx | 33 ++++ .../common/inventory_models/aws_rds/index.ts | 35 ++++ .../inventory_models/aws_rds/layout.tsx | 180 ++++++++++++++++++ .../inventory_models/aws_rds/metrics/index.ts | 38 ++++ .../aws_rds/metrics/snapshot/cpu.ts | 27 +++ .../snapshot/rds_active_transactions.ts | 15 ++ .../metrics/snapshot/rds_connections.ts | 15 ++ .../aws_rds/metrics/snapshot/rds_latency.ts | 15 ++ .../metrics/snapshot/rds_queries_executed.ts | 15 ++ .../tsvb/aws_rds_active_transactions.ts | 36 ++++ .../metrics/tsvb/aws_rds_connections.ts | 25 +++ .../aws_rds/metrics/tsvb/aws_rds_cpu_total.ts | 37 ++++ .../aws_rds/metrics/tsvb/aws_rds_latency.ts | 68 +++++++ .../metrics/tsvb/aws_rds_queries_executed.ts | 24 +++ .../aws_rds/toolbar_items.tsx | 32 ++++ .../common/inventory_models/aws_s3/index.ts | 35 ++++ .../common/inventory_models/aws_s3/layout.tsx | 143 ++++++++++++++ .../inventory_models/aws_s3/metrics/index.ts | 38 ++++ .../aws_s3/metrics/snapshot/s3_bucket_size.ts | 15 ++ .../metrics/snapshot/s3_download_bytes.ts | 15 ++ .../metrics/snapshot/s3_number_of_objects.ts | 15 ++ .../metrics/snapshot/s3_total_requests.ts | 15 ++ .../metrics/snapshot/s3_upload_bytes.ts | 15 ++ .../aws_s3/metrics/tsvb/aws_s3_bucket_size.ts | 26 +++ .../metrics/tsvb/aws_s3_download_bytes.ts | 25 +++ .../metrics/tsvb/aws_s3_number_of_objects.ts | 26 +++ .../metrics/tsvb/aws_s3_total_requests.ts | 26 +++ .../metrics/tsvb/aws_s3_upload_bytes.ts | 26 +++ .../inventory_models/aws_s3/toolbar_items.tsx | 28 +++ .../common/inventory_models/aws_sqs/index.ts | 35 ++++ .../inventory_models/aws_sqs/layout.tsx | 143 ++++++++++++++ .../inventory_models/aws_sqs/metrics/index.ts | 38 ++++ .../metrics/snapshot/sqs_messages_delayed.ts | 15 ++ .../metrics/snapshot/sqs_messages_empty.ts | 15 ++ .../metrics/snapshot/sqs_messages_sent.ts | 15 ++ .../metrics/snapshot/sqs_messages_visible.ts | 15 ++ .../metrics/snapshot/sqs_oldest_message.ts | 15 ++ .../metrics/tsvb/aws_sqs_messages_delayed.ts | 26 +++ .../metrics/tsvb/aws_sqs_messages_empty.ts | 26 +++ .../metrics/tsvb/aws_sqs_messages_sent.ts | 26 +++ .../metrics/tsvb/aws_sqs_messages_visible.ts | 26 +++ .../metrics/tsvb/aws_sqs_oldest_message.ts | 26 +++ .../aws_sqs/toolbar_items.tsx | 28 +++ .../inventory_models/container/index.ts | 15 ++ .../container/metrics/index.ts | 1 + .../container/toolbar_items.tsx | 74 +++---- .../inventory_models/create_tsvb_model.ts | 24 +++ .../common/inventory_models/host/index.ts | 15 ++ .../inventory_models/host/metrics/index.ts | 1 + .../inventory_models/host/toolbar_items.tsx | 77 +++----- .../infra/common/inventory_models/index.ts | 41 +++- .../infra/common/inventory_models/layouts.ts | 8 + .../infra/common/inventory_models/metrics.ts | 8 + .../common/inventory_models/pod/index.ts | 15 ++ .../inventory_models/pod/metrics/index.ts | 1 + .../inventory_models/pod/toolbar_items.tsx | 60 ++---- .../metrics_and_groupby_toolbar_items.tsx | 52 +++++ .../inventory_models/shared/metrics/index.ts | 1 + .../infra/common/inventory_models/toolbars.ts | 8 + .../infra/common/inventory_models/types.ts | 52 +++++ .../public/components/inventory/layout.tsx | 7 +- .../inventory/toolbars/toolbar_wrapper.tsx | 128 +++++++++++++ .../components/nodes_overview/index.tsx | 47 ++++- .../components/nodes_overview/table.tsx | 13 +- .../components/waffle/group_of_groups.tsx | 6 +- .../components/waffle/group_of_nodes.tsx | 8 +- .../waffle/lib/field_to_display_name.ts | 42 +++- .../infra/public/components/waffle/map.tsx | 10 +- .../infra/public/components/waffle/node.tsx | 15 +- .../components/waffle/node_context_menu.tsx | 62 +++--- .../waffle/waffle_inventory_switcher.tsx | 105 ++++++---- .../waffle/waffle_metric_controls.tsx | 2 +- .../public/containers/waffle/use_snaphot.ts | 9 +- .../infra/public/graphql/introspection.json | 25 ++- .../plugins/infra/public/graphql/types.ts | 38 ++++ .../infrastructure/snapshot/page_content.tsx | 4 +- .../infra/public/pages/link_to/link_to.tsx | 7 +- .../pages/link_to/redirect_to_node_logs.tsx | 10 +- .../public/utils/formatters/high_precision.ts | 11 ++ .../infra/public/utils/formatters/index.ts | 2 + .../plugins/infra/server/graphql/types.ts | 38 ++++ .../metrics/kibana_metrics_adapter.ts | 13 +- .../plugins/infra/server/lib/constants.ts | 17 -- .../create_timerange_with_interval.ts | 59 ++++++ .../server/lib/snapshot/query_helpers.ts | 23 ++- .../server/lib/snapshot/response_helpers.ts | 17 +- .../infra/server/lib/snapshot/snapshot.ts | 43 +++-- .../infra/server/lib/snapshot/types.ts | 23 +++ .../routes/metadata/lib/get_id_field_name.ts | 18 -- .../metadata/lib/get_metric_metadata.ts | 13 +- .../routes/metadata/lib/get_node_info.ts | 18 +- .../routes/metadata/lib/get_pod_node_name.ts | 5 +- .../routes/metadata/lib/has_apm_data.ts | 9 +- .../infra/server/routes/snapshot/index.ts | 2 +- .../server/utils/calculate_metric_interval.ts | 12 +- .../translations/translations/ja-JP.json | 5 +- .../translations/translations/zh-CN.json | 3 - .../test/api_integration/apis/infra/waffle.ts | 18 +- 113 files changed, 2860 insertions(+), 411 deletions(-) create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/index.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/layout.tsx create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/index.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/cpu.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/disk_io_read_bytes.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/disk_io_write_bytes.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/rx.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/tx.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/tsvb/aws_ec2_cpu_utilization.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/tsvb/aws_ec2_diskio_bytes.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/tsvb/aws_ec2_network_traffic.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/toolbar_items.tsx create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/index.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/layout.tsx create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/index.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/cpu.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_active_transactions.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_connections.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_latency.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_queries_executed.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/tsvb/aws_rds_active_transactions.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/tsvb/aws_rds_connections.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/tsvb/aws_rds_cpu_total.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/tsvb/aws_rds_latency.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/tsvb/aws_rds_queries_executed.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/toolbar_items.tsx create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/index.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/layout.tsx create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/index.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_bucket_size.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_download_bytes.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_number_of_objects.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_total_requests.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_upload_bytes.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/tsvb/aws_s3_bucket_size.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/tsvb/aws_s3_download_bytes.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/tsvb/aws_s3_number_of_objects.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/tsvb/aws_s3_total_requests.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/tsvb/aws_s3_upload_bytes.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/toolbar_items.tsx create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/index.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/layout.tsx create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/index.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_delayed.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_empty.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_sent.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_visible.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_oldest_message.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/tsvb/aws_sqs_messages_delayed.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/tsvb/aws_sqs_messages_empty.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/tsvb/aws_sqs_messages_sent.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/tsvb/aws_sqs_messages_visible.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/tsvb/aws_sqs_oldest_message.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/toolbar_items.tsx create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/create_tsvb_model.ts create mode 100644 x-pack/legacy/plugins/infra/common/inventory_models/shared/compontents/metrics_and_groupby_toolbar_items.tsx create mode 100644 x-pack/legacy/plugins/infra/public/utils/formatters/high_precision.ts create mode 100644 x-pack/legacy/plugins/infra/server/lib/snapshot/create_timerange_with_interval.ts create mode 100644 x-pack/legacy/plugins/infra/server/lib/snapshot/types.ts delete mode 100644 x-pack/legacy/plugins/infra/server/routes/metadata/lib/get_id_field_name.ts diff --git a/x-pack/legacy/plugins/infra/common/ecs_allowed_list.ts b/x-pack/legacy/plugins/infra/common/ecs_allowed_list.ts index 37b037214bb02..1728cd1fa4b45 100644 --- a/x-pack/legacy/plugins/infra/common/ecs_allowed_list.ts +++ b/x-pack/legacy/plugins/infra/common/ecs_allowed_list.ts @@ -45,6 +45,8 @@ export const DOCKER_ALLOWED_LIST = [ 'docker.container.labels', ]; +export const AWS_S3_ALLOWED_LIST = ['aws.s3']; + export const getAllowedListForPrefix = (prefix: string) => { const firstPart = first(prefix.split(/\./)); const defaultAllowedList = prefix ? [...ECS_ALLOWED_LIST, prefix] : ECS_ALLOWED_LIST; @@ -55,6 +57,10 @@ export const getAllowedListForPrefix = (prefix: string) => { return [...defaultAllowedList, ...PROMETHEUS_ALLOWED_LIST]; case 'kubernetes': return [...defaultAllowedList, ...K8S_ALLOWED_LIST]; + case 'aws': + if (prefix === 'aws.s3_daily_storage') { + return [...defaultAllowedList, ...AWS_S3_ALLOWED_LIST]; + } default: return defaultAllowedList; } diff --git a/x-pack/legacy/plugins/infra/common/graphql/shared/schema.gql.ts b/x-pack/legacy/plugins/infra/common/graphql/shared/schema.gql.ts index fd86e605b8747..071313817eff3 100644 --- a/x-pack/legacy/plugins/infra/common/graphql/shared/schema.gql.ts +++ b/x-pack/legacy/plugins/infra/common/graphql/shared/schema.gql.ts @@ -30,5 +30,9 @@ export const sharedSchema = gql` pod container host + awsEC2 + awsS3 + awsRDS + awsSQS } `; diff --git a/x-pack/legacy/plugins/infra/common/graphql/types.ts b/x-pack/legacy/plugins/infra/common/graphql/types.ts index 273cbfc1d4f89..0520409800bce 100644 --- a/x-pack/legacy/plugins/infra/common/graphql/types.ts +++ b/x-pack/legacy/plugins/infra/common/graphql/types.ts @@ -552,6 +552,10 @@ export enum InfraNodeType { pod = 'pod', container = 'container', host = 'host', + awsEC2 = 'awsEC2', + awsS3 = 'awsS3', + awsRDS = 'awsRDS', + awsSQS = 'awsSQS', } export enum InfraSnapshotMetricType { @@ -562,6 +566,22 @@ export enum InfraSnapshotMetricType { tx = 'tx', rx = 'rx', logRate = 'logRate', + diskIOReadBytes = 'diskIOReadBytes', + diskIOWriteBytes = 'diskIOWriteBytes', + s3TotalRequests = 's3TotalRequests', + s3NumberOfObjects = 's3NumberOfObjects', + s3BucketSize = 's3BucketSize', + s3DownloadBytes = 's3DownloadBytes', + s3UploadBytes = 's3UploadBytes', + rdsConnections = 'rdsConnections', + rdsQueriesExecuted = 'rdsQueriesExecuted', + rdsActiveTransactions = 'rdsActiveTransactions', + rdsLatency = 'rdsLatency', + sqsMessagesVisible = 'sqsOldestMessage', + sqsMessagesDelayed = 'sqsMessagesDelayed', + sqsMessagesSent = 'sqsMessagesSent', + sqsMessagesEmpty = 'sqsMessagesEmpty', + sqsOldestMessage = 'sqsOldestMessage', } export enum InfraMetric { @@ -602,6 +622,24 @@ export enum InfraMetric { awsNetworkPackets = 'awsNetworkPackets', awsDiskioBytes = 'awsDiskioBytes', awsDiskioOps = 'awsDiskioOps', + awsEC2CpuUtilization = 'awsEC2CpuUtilization', + awsEC2DiskIOBytes = 'awsEC2DiskIOBytes', + awsEC2NetworkTraffic = 'awsEC2NetworkTraffic', + awsS3TotalRequests = 'awsS3TotalRequests', + awsS3NumberOfObjects = 'awsS3NumberOfObjects', + awsS3BucketSize = 'awsS3BucketSize', + awsS3DownloadBytes = 'awsS3DownloadBytes', + awsS3UploadBytes = 'awsS3UploadBytes', + awsRDSCpuTotal = 'awsRDSCpuTotal', + awsRDSConnections = 'awsRDSConnections', + awsRDSQueriesExecuted = 'awsRDSQueriesExecuted', + awsRDSActiveTransactions = 'awsRDSActiveTransactions', + awsRDSLatency = 'awsRDSLatency', + awsSQSMessagesVisible = 'awsSQSMessagesVisible', + awsSQSMessagesDelayed = 'awsSQSMessagesDelayed', + awsSQSMessagesSent = 'awsSQSMessagesSent', + awsSQSMessagesEmpty = 'awsSQSMessagesEmpty', + awsSQSOldestMessage = 'awsSQSOldestMessage', custom = 'custom', } diff --git a/x-pack/legacy/plugins/infra/common/http_api/metadata_api.ts b/x-pack/legacy/plugins/infra/common/http_api/metadata_api.ts index ace61e13193c8..7fc3c3e876f08 100644 --- a/x-pack/legacy/plugins/infra/common/http_api/metadata_api.ts +++ b/x-pack/legacy/plugins/infra/common/http_api/metadata_api.ts @@ -5,16 +5,11 @@ */ import * as rt from 'io-ts'; - -export const InfraMetadataNodeTypeRT = rt.keyof({ - host: null, - pod: null, - container: null, -}); +import { ItemTypeRT } from '../../common/inventory_models/types'; export const InfraMetadataRequestRT = rt.type({ nodeId: rt.string, - nodeType: InfraMetadataNodeTypeRT, + nodeType: ItemTypeRT, sourceId: rt.string, }); @@ -96,5 +91,3 @@ export type InfraMetadataMachine = rt.TypeOf; export type InfraMetadataHost = rt.TypeOf; export type InfraMetadataOS = rt.TypeOf; - -export type InfraMetadataNodeType = rt.TypeOf; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/index.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/index.ts new file mode 100644 index 0000000000000..ba4a6bb22c184 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/index.ts @@ -0,0 +1,30 @@ +/* + * 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 { metrics } from './metrics'; +import { InventoryModel } from '../types'; + +export const awsEC2: InventoryModel = { + id: 'awsEC2', + displayName: i18n.translate('xpack.infra.inventoryModels.awsEC2.displayName', { + defaultMessage: 'EC2 Instances', + }), + requiredModules: ['aws'], + crosslinkSupport: { + details: true, + logs: true, + apm: true, + uptime: true, + }, + metrics, + fields: { + id: 'cloud.instance.id', + name: 'cloud.instance.name', + ip: 'aws.ec2.instance.public.ip', + }, + requiredMetrics: ['awsEC2CpuUtilization', 'awsEC2NetworkTraffic', 'awsEC2DiskIOBytes'], +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/layout.tsx b/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/layout.tsx new file mode 100644 index 0000000000000..01009b478951a --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/layout.tsx @@ -0,0 +1,116 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { LayoutPropsWithTheme } from '../../../public/pages/metrics/types'; +import { Section } from '../../../public/pages/metrics/components/section'; +import { SubSection } from '../../../public/pages/metrics/components/sub_section'; +import { ChartSectionVis } from '../../../public/pages/metrics/components/chart_section_vis'; +import { withTheme } from '../../../../../common/eui_styled_components'; + +export const Layout = withTheme(({ metrics, theme }: LayoutPropsWithTheme) => ( + +
+ + + + + + + + + +
+
+)); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/index.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/index.ts new file mode 100644 index 0000000000000..18b7cca2048a5 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/index.ts @@ -0,0 +1,28 @@ +/* + * 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 { cpu } from './snapshot/cpu'; +import { rx } from './snapshot/rx'; +import { tx } from './snapshot/tx'; +import { diskIOReadBytes } from './snapshot/disk_io_read_bytes'; +import { diskIOWriteBytes } from './snapshot/disk_io_write_bytes'; + +import { awsEC2CpuUtilization } from './tsvb/aws_ec2_cpu_utilization'; +import { awsEC2NetworkTraffic } from './tsvb/aws_ec2_network_traffic'; +import { awsEC2DiskIOBytes } from './tsvb/aws_ec2_diskio_bytes'; + +import { InventoryMetrics } from '../../types'; + +export const metrics: InventoryMetrics = { + tsvb: { + awsEC2CpuUtilization, + awsEC2NetworkTraffic, + awsEC2DiskIOBytes, + }, + snapshot: { cpu, rx, tx, diskIOReadBytes, diskIOWriteBytes }, + defaultSnapshot: 'cpu', + defaultTimeRangeInSeconds: 14400, // 4 hours +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/cpu.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/cpu.ts new file mode 100644 index 0000000000000..483d9de784919 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/cpu.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { SnapshotModel } from '../../../types'; + +export const cpu: SnapshotModel = { + cpu_avg: { + avg: { + field: 'aws.ec2.cpu.total.pct', + }, + }, + cpu: { + bucket_script: { + buckets_path: { + cpu: 'cpu_avg', + }, + script: { + source: 'params.cpu / 100', + lang: 'painless', + }, + gap_policy: 'skip', + }, + }, +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/disk_io_read_bytes.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/disk_io_read_bytes.ts new file mode 100644 index 0000000000000..48e4a9eb59fad --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/disk_io_read_bytes.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 { SnapshotModel } from '../../../types'; + +export const diskIOReadBytes: SnapshotModel = { + diskIOReadBytes: { + avg: { + field: 'aws.ec2.diskio.read.bytes_per_sec', + }, + }, +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/disk_io_write_bytes.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/disk_io_write_bytes.ts new file mode 100644 index 0000000000000..deadaa8c4a776 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/disk_io_write_bytes.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 { SnapshotModel } from '../../../types'; + +export const diskIOWriteBytes: SnapshotModel = { + diskIOWriteBytes: { + avg: { + field: 'aws.ec2.diskio.write.bytes_per_sec', + }, + }, +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/rx.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/rx.ts new file mode 100644 index 0000000000000..2b857ce9b338a --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/rx.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 { SnapshotModel } from '../../../types'; + +export const rx: SnapshotModel = { + rx: { + avg: { + field: 'aws.ec2.network.in.bytes_per_sec', + }, + }, +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/tx.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/tx.ts new file mode 100644 index 0000000000000..63c9da8ea1888 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/tx.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 { SnapshotModel } from '../../../types'; + +export const tx: SnapshotModel = { + tx: { + avg: { + field: 'aws.ec2.network.in.bytes_per_sec', + }, + }, +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/tsvb/aws_ec2_cpu_utilization.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/tsvb/aws_ec2_cpu_utilization.ts new file mode 100644 index 0000000000000..a7a06ef1cfc1d --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/tsvb/aws_ec2_cpu_utilization.ts @@ -0,0 +1,37 @@ +/* + * 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 { createTSVBModel } from '../../../create_tsvb_model'; + +export const awsEC2CpuUtilization = createTSVBModel( + 'awsEC2CpuUtilization', + ['aws.ec2'], + [ + { + id: 'total', + split_mode: 'everything', + metrics: [ + { + field: 'aws.ec2.cpu.total.pct', + id: 'avg-cpu', + type: 'avg', + }, + { + id: 'convert-to-percent', + script: 'params.avg / 100', + type: 'calculation', + variables: [ + { + field: 'avg-cpu', + id: 'var-avg', + name: 'avg', + }, + ], + }, + ], + }, + ] +); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/tsvb/aws_ec2_diskio_bytes.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/tsvb/aws_ec2_diskio_bytes.ts new file mode 100644 index 0000000000000..35d165936211a --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/tsvb/aws_ec2_diskio_bytes.ts @@ -0,0 +1,41 @@ +/* + * 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 { createTSVBModel } from '../../../create_tsvb_model'; +export const awsEC2DiskIOBytes = createTSVBModel( + 'awsEC2DiskIOBytes', + ['aws.ec2'], + [ + { + id: 'write', + split_mode: 'everything', + metrics: [ + { + field: 'aws.ec2.diskio.write.bytes_per_sec', + id: 'avg-write', + type: 'avg', + }, + ], + }, + { + id: 'read', + split_mode: 'everything', + metrics: [ + { + field: 'aws.ec2.diskio.read.bytes_per_sec', + id: 'avg-read', + type: 'avg', + }, + { + id: 'calculation-rate', + type: 'calculation', + variables: [{ id: 'rate-var', name: 'rate', field: 'avg-read' }], + script: 'params.rate * -1', + }, + ], + }, + ] +); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/tsvb/aws_ec2_network_traffic.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/tsvb/aws_ec2_network_traffic.ts new file mode 100644 index 0000000000000..ea4b41d0bcd68 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/metrics/tsvb/aws_ec2_network_traffic.ts @@ -0,0 +1,41 @@ +/* + * 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 { createTSVBModel } from '../../../create_tsvb_model'; +export const awsEC2NetworkTraffic = createTSVBModel( + 'awsEC2NetworkTraffic', + ['aws.ec2'], + [ + { + id: 'tx', + split_mode: 'everything', + metrics: [ + { + field: 'aws.ec2.network.out.bytes_per_sec', + id: 'avg-tx', + type: 'avg', + }, + ], + }, + { + id: 'rx', + split_mode: 'everything', + metrics: [ + { + field: 'aws.ec2.network.in.bytes_per_sec', + id: 'avg-rx', + type: 'avg', + }, + { + id: 'calculation-rate', + type: 'calculation', + variables: [{ id: 'rate-var', name: 'rate', field: 'avg-rx' }], + script: 'params.rate * -1', + }, + ], + }, + ] +); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/toolbar_items.tsx b/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/toolbar_items.tsx new file mode 100644 index 0000000000000..fc09f0761a522 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_ec2/toolbar_items.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 from 'react'; +import { ToolbarProps } from '../../../public/components/inventory/toolbars/toolbar'; +import { MetricsAndGroupByToolbarItems } from '../shared/compontents/metrics_and_groupby_toolbar_items'; +import { InfraSnapshotMetricType } from '../../graphql/types'; + +export const AwsEC2ToolbarItems = (props: ToolbarProps) => { + const metricTypes = [ + InfraSnapshotMetricType.cpu, + InfraSnapshotMetricType.rx, + InfraSnapshotMetricType.tx, + InfraSnapshotMetricType.diskIOReadBytes, + InfraSnapshotMetricType.diskIOWriteBytes, + ]; + const groupByFields = [ + 'cloud.availability_zone', + 'cloud.machine.type', + 'aws.ec2.instance.image.id', + 'aws.ec2.instance.state.name', + ]; + return ( + + ); +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/index.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/index.ts new file mode 100644 index 0000000000000..e81dee504b064 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/index.ts @@ -0,0 +1,35 @@ +/* + * 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 { metrics } from './metrics'; +import { InventoryModel } from '../types'; + +export const awsRDS: InventoryModel = { + id: 'awsRDS', + displayName: i18n.translate('xpack.infra.inventoryModels.awsRDS.displayName', { + defaultMessage: 'RDS Databases', + }), + requiredModules: ['aws'], + crosslinkSupport: { + details: true, + logs: true, + apm: false, + uptime: false, + }, + metrics, + fields: { + id: 'aws.rds.db_instance.arn', + name: 'aws.rds.db_instance.identifier', + }, + requiredMetrics: [ + 'awsRDSCpuTotal', + 'awsRDSConnections', + 'awsRDSQueriesExecuted', + 'awsRDSActiveTransactions', + 'awsRDSLatency', + ], +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/layout.tsx b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/layout.tsx new file mode 100644 index 0000000000000..5f1185666a35d --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/layout.tsx @@ -0,0 +1,180 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { LayoutPropsWithTheme } from '../../../public/pages/metrics/types'; +import { Section } from '../../../public/pages/metrics/components/section'; +import { SubSection } from '../../../public/pages/metrics/components/sub_section'; +import { ChartSectionVis } from '../../../public/pages/metrics/components/chart_section_vis'; +import { withTheme } from '../../../../../common/eui_styled_components'; + +export const Layout = withTheme(({ metrics, theme }: LayoutPropsWithTheme) => ( + +
+ + + + + + + + + + + + + + + +
+
+)); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/index.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/index.ts new file mode 100644 index 0000000000000..eaded5d8df223 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/index.ts @@ -0,0 +1,38 @@ +/* + * 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 { InventoryMetrics } from '../../types'; + +import { cpu } from './snapshot/cpu'; +import { rdsLatency } from './snapshot/rds_latency'; +import { rdsConnections } from './snapshot/rds_connections'; +import { rdsQueriesExecuted } from './snapshot/rds_queries_executed'; +import { rdsActiveTransactions } from './snapshot/rds_active_transactions'; + +import { awsRDSLatency } from './tsvb/aws_rds_latency'; +import { awsRDSConnections } from './tsvb/aws_rds_connections'; +import { awsRDSCpuTotal } from './tsvb/aws_rds_cpu_total'; +import { awsRDSQueriesExecuted } from './tsvb/aws_rds_queries_executed'; +import { awsRDSActiveTransactions } from './tsvb/aws_rds_active_transactions'; + +export const metrics: InventoryMetrics = { + tsvb: { + awsRDSLatency, + awsRDSConnections, + awsRDSCpuTotal, + awsRDSQueriesExecuted, + awsRDSActiveTransactions, + }, + snapshot: { + cpu, + rdsLatency, + rdsConnections, + rdsQueriesExecuted, + rdsActiveTransactions, + }, + defaultSnapshot: 'cpu', + defaultTimeRangeInSeconds: 14400, // 4 hours +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/cpu.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/cpu.ts new file mode 100644 index 0000000000000..e277b3b11958b --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/cpu.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { SnapshotModel } from '../../../types'; + +export const cpu: SnapshotModel = { + cpu_avg: { + avg: { + field: 'aws.rds.cpu.total.pct', + }, + }, + cpu: { + bucket_script: { + buckets_path: { + cpu: 'cpu_avg', + }, + script: { + source: 'params.cpu / 100', + lang: 'painless', + }, + gap_policy: 'skip', + }, + }, +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_active_transactions.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_active_transactions.ts new file mode 100644 index 0000000000000..be3dba100ba29 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_active_transactions.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 { SnapshotModel } from '../../../types'; + +export const rdsActiveTransactions: SnapshotModel = { + rdsActiveTransactions: { + avg: { + field: 'aws.rds.transactions.active', + }, + }, +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_connections.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_connections.ts new file mode 100644 index 0000000000000..c7855d5548eea --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_connections.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 { SnapshotModel } from '../../../types'; + +export const rdsConnections: SnapshotModel = { + rdsConnections: { + avg: { + field: 'aws.rds.database_connections', + }, + }, +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_latency.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_latency.ts new file mode 100644 index 0000000000000..2997b54d2f92e --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_latency.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 { SnapshotModel } from '../../../types'; + +export const rdsLatency: SnapshotModel = { + rdsLatency: { + avg: { + field: 'aws.rds.latency.dml', + }, + }, +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_queries_executed.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_queries_executed.ts new file mode 100644 index 0000000000000..18e6538fb1e1e --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_queries_executed.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 { SnapshotModel } from '../../../types'; + +export const rdsQueriesExecuted: SnapshotModel = { + rdsQueriesExecuted: { + avg: { + field: 'aws.rds.queries', + }, + }, +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/tsvb/aws_rds_active_transactions.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/tsvb/aws_rds_active_transactions.ts new file mode 100644 index 0000000000000..026cdeac40c36 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/tsvb/aws_rds_active_transactions.ts @@ -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 { createTSVBModel } from '../../../create_tsvb_model'; + +export const awsRDSActiveTransactions = createTSVBModel( + 'awsRDSActiveTransactions', + ['aws.rds'], + [ + { + id: 'active', + split_mode: 'everything', + metrics: [ + { + field: 'aws.rds.transactions.active', + id: 'avg', + type: 'avg', + }, + ], + }, + { + id: 'blocked', + split_mode: 'everything', + metrics: [ + { + field: 'aws.rds.transactions.blocked', + id: 'avg', + type: 'avg', + }, + ], + }, + ] +); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/tsvb/aws_rds_connections.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/tsvb/aws_rds_connections.ts new file mode 100644 index 0000000000000..145cc758e4a5b --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/tsvb/aws_rds_connections.ts @@ -0,0 +1,25 @@ +/* + * 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 { createTSVBModel } from '../../../create_tsvb_model'; + +export const awsRDSConnections = createTSVBModel( + 'awsRDSConnections', + ['aws.rds'], + [ + { + id: 'connections', + split_mode: 'everything', + metrics: [ + { + field: 'aws.rds.database_connections', + id: 'avg-conns', + type: 'avg', + }, + ], + }, + ] +); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/tsvb/aws_rds_cpu_total.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/tsvb/aws_rds_cpu_total.ts new file mode 100644 index 0000000000000..9a8eefc859bb0 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/tsvb/aws_rds_cpu_total.ts @@ -0,0 +1,37 @@ +/* + * 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 { createTSVBModel } from '../../../create_tsvb_model'; + +export const awsRDSCpuTotal = createTSVBModel( + 'awsRDSCpuTotal', + ['aws.rds'], + [ + { + id: 'cpu', + split_mode: 'everything', + metrics: [ + { + field: 'aws.rds.cpu.total.pct', + id: 'avg-cpu', + type: 'avg', + }, + { + id: 'convert-to-percent', + script: 'params.avg / 100', + type: 'calculation', + variables: [ + { + field: 'avg-cpu', + id: 'var-avg', + name: 'avg', + }, + ], + }, + ], + }, + ] +); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/tsvb/aws_rds_latency.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/tsvb/aws_rds_latency.ts new file mode 100644 index 0000000000000..80dffeeb717c6 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/tsvb/aws_rds_latency.ts @@ -0,0 +1,68 @@ +/* + * 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 { createTSVBModel } from '../../../create_tsvb_model'; + +export const awsRDSLatency = createTSVBModel( + 'awsRDSLatency', + ['aws.rds'], + [ + { + id: 'read', + split_mode: 'everything', + metrics: [ + { + field: 'aws.rds.latency.read', + id: 'avg', + type: 'avg', + }, + ], + }, + { + id: 'write', + split_mode: 'everything', + metrics: [ + { + field: 'aws.rds.latency.write', + id: 'avg', + type: 'avg', + }, + ], + }, + { + id: 'insert', + split_mode: 'everything', + metrics: [ + { + field: 'aws.rds.latency.insert', + id: 'avg', + type: 'avg', + }, + ], + }, + { + id: 'update', + split_mode: 'everything', + metrics: [ + { + field: 'aws.rds.latency.update', + id: 'avg', + type: 'avg', + }, + ], + }, + { + id: 'commit', + split_mode: 'everything', + metrics: [ + { + field: 'aws.rds.latency.commit', + id: 'avg', + type: 'avg', + }, + ], + }, + ] +); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/tsvb/aws_rds_queries_executed.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/tsvb/aws_rds_queries_executed.ts new file mode 100644 index 0000000000000..4dd1a1e89a21a --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/metrics/tsvb/aws_rds_queries_executed.ts @@ -0,0 +1,24 @@ +/* + * 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 { createTSVBModel } from '../../../create_tsvb_model'; +export const awsRDSQueriesExecuted = createTSVBModel( + 'awsRDSQueriesExecuted', + ['aws.rds'], + [ + { + id: 'queries', + split_mode: 'everything', + metrics: [ + { + field: 'aws.rds.queries', + id: 'avg-queries', + type: 'avg', + }, + ], + }, + ] +); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/toolbar_items.tsx b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/toolbar_items.tsx new file mode 100644 index 0000000000000..b60d6292c9c0f --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_rds/toolbar_items.tsx @@ -0,0 +1,32 @@ +/* + * 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 { ToolbarProps } from '../../../public/components/inventory/toolbars/toolbar'; +import { InfraSnapshotMetricType } from '../../../public/graphql/types'; +import { MetricsAndGroupByToolbarItems } from '../shared/compontents/metrics_and_groupby_toolbar_items'; + +export const AwsRDSToolbarItems = (props: ToolbarProps) => { + const metricTypes = [ + InfraSnapshotMetricType.cpu, + InfraSnapshotMetricType.rdsConnections, + InfraSnapshotMetricType.rdsQueriesExecuted, + InfraSnapshotMetricType.rdsActiveTransactions, + InfraSnapshotMetricType.rdsLatency, + ]; + const groupByFields = [ + 'cloud.availability_zone', + 'aws.rds.db_instance.class', + 'aws.rds.db_instance.status', + ]; + return ( + + ); +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/index.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/index.ts new file mode 100644 index 0000000000000..c5de4ed80a1cb --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/index.ts @@ -0,0 +1,35 @@ +/* + * 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 { metrics } from './metrics'; +import { InventoryModel } from '../types'; + +export const awsS3: InventoryModel = { + id: 'awsS3', + displayName: i18n.translate('xpack.infra.inventoryModels.awsS3.displayName', { + defaultMessage: 'S3 Buckets', + }), + requiredModules: ['aws'], + crosslinkSupport: { + details: true, + logs: true, + apm: false, + uptime: false, + }, + metrics, + fields: { + id: 'aws.s3.bucket.name', + name: 'aws.s3.bucket.name', + }, + requiredMetrics: [ + 'awsS3BucketSize', + 'awsS3NumberOfObjects', + 'awsS3TotalRequests', + 'awsS3DownloadBytes', + 'awsS3UploadBytes', + ], +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/layout.tsx b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/layout.tsx new file mode 100644 index 0000000000000..80089f15b04b2 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/layout.tsx @@ -0,0 +1,143 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { LayoutPropsWithTheme } from '../../../public/pages/metrics/types'; +import { Section } from '../../../public/pages/metrics/components/section'; +import { SubSection } from '../../../public/pages/metrics/components/sub_section'; +import { ChartSectionVis } from '../../../public/pages/metrics/components/chart_section_vis'; +import { withTheme } from '../../../../../common/eui_styled_components'; + +export const Layout = withTheme(({ metrics, theme }: LayoutPropsWithTheme) => ( + +
+ + + + + + + + + + + + + + + +
+
+)); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/index.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/index.ts new file mode 100644 index 0000000000000..5aa974c16feec --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/index.ts @@ -0,0 +1,38 @@ +/* + * 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 { InventoryMetrics } from '../../types'; + +import { awsS3BucketSize } from './tsvb/aws_s3_bucket_size'; +import { awsS3TotalRequests } from './tsvb/aws_s3_total_requests'; +import { awsS3NumberOfObjects } from './tsvb/aws_s3_number_of_objects'; +import { awsS3DownloadBytes } from './tsvb/aws_s3_download_bytes'; +import { awsS3UploadBytes } from './tsvb/aws_s3_upload_bytes'; + +import { s3BucketSize } from './snapshot/s3_bucket_size'; +import { s3TotalRequests } from './snapshot/s3_total_requests'; +import { s3NumberOfObjects } from './snapshot/s3_number_of_objects'; +import { s3DownloadBytes } from './snapshot/s3_download_bytes'; +import { s3UploadBytes } from './snapshot/s3_upload_bytes'; + +export const metrics: InventoryMetrics = { + tsvb: { + awsS3BucketSize, + awsS3TotalRequests, + awsS3NumberOfObjects, + awsS3DownloadBytes, + awsS3UploadBytes, + }, + snapshot: { + s3BucketSize, + s3NumberOfObjects, + s3TotalRequests, + s3UploadBytes, + s3DownloadBytes, + }, + defaultSnapshot: 's3BucketSize', + defaultTimeRangeInSeconds: 86400 * 7, // 7 days +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_bucket_size.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_bucket_size.ts new file mode 100644 index 0000000000000..a99753a39c97c --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_bucket_size.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 { SnapshotModel } from '../../../types'; + +export const s3BucketSize: SnapshotModel = { + s3BucketSize: { + max: { + field: 'aws.s3_daily_storage.bucket.size.bytes', + }, + }, +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_download_bytes.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_download_bytes.ts new file mode 100644 index 0000000000000..a0b23dadee37a --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_download_bytes.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 { SnapshotModel } from '../../../types'; + +export const s3DownloadBytes: SnapshotModel = { + s3DownloadBytes: { + max: { + field: 'aws.s3_request.downloaded.bytes', + }, + }, +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_number_of_objects.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_number_of_objects.ts new file mode 100644 index 0000000000000..29162a59db47a --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_number_of_objects.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 { SnapshotModel } from '../../../types'; + +export const s3NumberOfObjects: SnapshotModel = { + s3NumberOfObjects: { + max: { + field: 'aws.s3_daily_storage.number_of_objects', + }, + }, +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_total_requests.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_total_requests.ts new file mode 100644 index 0000000000000..bc57c6eb38234 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_total_requests.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 { SnapshotModel } from '../../../types'; + +export const s3TotalRequests: SnapshotModel = { + s3TotalRequests: { + max: { + field: 'aws.s3_request.requests.total', + }, + }, +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_upload_bytes.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_upload_bytes.ts new file mode 100644 index 0000000000000..977d73254c3cd --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_upload_bytes.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 { SnapshotModel } from '../../../types'; + +export const s3UploadBytes: SnapshotModel = { + s3UploadBytes: { + max: { + field: 'aws.s3_request.uploaded.bytes', + }, + }, +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/tsvb/aws_s3_bucket_size.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/tsvb/aws_s3_bucket_size.ts new file mode 100644 index 0000000000000..216f98b9e16b4 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/tsvb/aws_s3_bucket_size.ts @@ -0,0 +1,26 @@ +/* + * 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 { createTSVBModel } from '../../../create_tsvb_model'; + +export const awsS3BucketSize = createTSVBModel( + 'awsS3BucketSize', + ['aws.s3_daily_storage'], + [ + { + id: 'bytes', + split_mode: 'everything', + metrics: [ + { + field: 'aws.s3_daily_storage.bucket.size.bytes', + id: 'max-bytes', + type: 'max', + }, + ], + }, + ], + '>=86400s', + false +); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/tsvb/aws_s3_download_bytes.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/tsvb/aws_s3_download_bytes.ts new file mode 100644 index 0000000000000..15eb3130a5e23 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/tsvb/aws_s3_download_bytes.ts @@ -0,0 +1,25 @@ +/* + * 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 { createTSVBModel } from '../../../create_tsvb_model'; + +export const awsS3DownloadBytes = createTSVBModel( + 'awsS3DownloadBytes', + ['aws.s3_request'], + [ + { + id: 'bytes', + split_mode: 'everything', + metrics: [ + { + field: 'aws.s3_request.downloaded.bytes', + id: 'max-bytes', + type: 'max', + }, + ], + }, + ], + '>=300s' +); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/tsvb/aws_s3_number_of_objects.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/tsvb/aws_s3_number_of_objects.ts new file mode 100644 index 0000000000000..c108735bc0efd --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/tsvb/aws_s3_number_of_objects.ts @@ -0,0 +1,26 @@ +/* + * 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 { createTSVBModel } from '../../../create_tsvb_model'; + +export const awsS3NumberOfObjects = createTSVBModel( + 'awsS3NumberOfObjects', + ['aws.s3_daily_storage'], + [ + { + id: 'objects', + split_mode: 'everything', + metrics: [ + { + field: 'aws.s3_daily_storage.number_of_objects', + id: 'max-size', + type: 'max', + }, + ], + }, + ], + '>=86400s', + false +); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/tsvb/aws_s3_total_requests.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/tsvb/aws_s3_total_requests.ts new file mode 100644 index 0000000000000..311067fd96b47 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/tsvb/aws_s3_total_requests.ts @@ -0,0 +1,26 @@ +/* + * 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 { createTSVBModel } from '../../../create_tsvb_model'; + +export const awsS3TotalRequests = createTSVBModel( + 'awsS3TotalRequests', + ['aws.s3_request'], + [ + { + id: 'total', + split_mode: 'everything', + metrics: [ + { + field: 'aws.s3_request.requests.total', + id: 'max-size', + type: 'max', + }, + ], + }, + ], + '>=300s' +); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/tsvb/aws_s3_upload_bytes.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/tsvb/aws_s3_upload_bytes.ts new file mode 100644 index 0000000000000..ab66b47cfa781 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/metrics/tsvb/aws_s3_upload_bytes.ts @@ -0,0 +1,26 @@ +/* + * 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 { createTSVBModel } from '../../../create_tsvb_model'; + +export const awsS3UploadBytes = createTSVBModel( + 'awsS3UploadBytes', + ['aws.s3_request'], + [ + { + id: 'bytes', + split_mode: 'everything', + metrics: [ + { + field: 'aws.s3_request.uploaded.bytes', + id: 'max-bytes', + type: 'max', + }, + ], + }, + ], + '>=300s' +); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/toolbar_items.tsx b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/toolbar_items.tsx new file mode 100644 index 0000000000000..6764de237118a --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_s3/toolbar_items.tsx @@ -0,0 +1,28 @@ +/* + * 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 { ToolbarProps } from '../../../public/components/inventory/toolbars/toolbar'; +import { InfraSnapshotMetricType } from '../../../public/graphql/types'; +import { MetricsAndGroupByToolbarItems } from '../shared/compontents/metrics_and_groupby_toolbar_items'; + +export const AwsS3ToolbarItems = (props: ToolbarProps) => { + const metricTypes = [ + InfraSnapshotMetricType.s3BucketSize, + InfraSnapshotMetricType.s3NumberOfObjects, + InfraSnapshotMetricType.s3TotalRequests, + InfraSnapshotMetricType.s3DownloadBytes, + InfraSnapshotMetricType.s3UploadBytes, + ]; + const groupByFields = ['cloud.region']; + return ( + + ); +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/index.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/index.ts new file mode 100644 index 0000000000000..d7fb7c7a615b1 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/index.ts @@ -0,0 +1,35 @@ +/* + * 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 { metrics } from './metrics'; +import { InventoryModel } from '../types'; + +export const awsSQS: InventoryModel = { + id: 'awsSQS', + displayName: i18n.translate('xpack.infra.inventoryModels.awsSQS.displayName', { + defaultMessage: 'SQS Queues', + }), + requiredModules: ['aws'], + crosslinkSupport: { + details: true, + logs: true, + apm: false, + uptime: false, + }, + metrics, + fields: { + id: 'aws.sqs.queue.name', + name: 'aws.sqs.queue.name', + }, + requiredMetrics: [ + 'awsSQSMessagesVisible', + 'awsSQSMessagesDelayed', + 'awsSQSMessagesSent', + 'awsSQSMessagesEmpty', + 'awsSQSOldestMessage', + ], +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/layout.tsx b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/layout.tsx new file mode 100644 index 0000000000000..40cb0a64d83cc --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/layout.tsx @@ -0,0 +1,143 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { LayoutPropsWithTheme } from '../../../public/pages/metrics/types'; +import { Section } from '../../../public/pages/metrics/components/section'; +import { SubSection } from '../../../public/pages/metrics/components/sub_section'; +import { ChartSectionVis } from '../../../public/pages/metrics/components/chart_section_vis'; +import { withTheme } from '../../../../../common/eui_styled_components'; + +export const Layout = withTheme(({ metrics, theme }: LayoutPropsWithTheme) => ( + +
+ + + + + + + + + + + + + + + +
+
+)); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/index.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/index.ts new file mode 100644 index 0000000000000..7bc593cc22035 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/index.ts @@ -0,0 +1,38 @@ +/* + * 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 { InventoryMetrics } from '../../types'; + +import { sqsMessagesVisible } from './snapshot/sqs_messages_visible'; +import { sqsMessagesDelayed } from './snapshot/sqs_messages_delayed'; +import { sqsMessagesEmpty } from './snapshot/sqs_messages_empty'; +import { sqsMessagesSent } from './snapshot/sqs_messages_sent'; +import { sqsOldestMessage } from './snapshot/sqs_oldest_message'; + +import { awsSQSMessagesVisible } from './tsvb/aws_sqs_messages_visible'; +import { awsSQSMessagesDelayed } from './tsvb/aws_sqs_messages_delayed'; +import { awsSQSMessagesSent } from './tsvb/aws_sqs_messages_sent'; +import { awsSQSMessagesEmpty } from './tsvb/aws_sqs_messages_empty'; +import { awsSQSOldestMessage } from './tsvb/aws_sqs_oldest_message'; + +export const metrics: InventoryMetrics = { + tsvb: { + awsSQSMessagesVisible, + awsSQSMessagesDelayed, + awsSQSMessagesSent, + awsSQSMessagesEmpty, + awsSQSOldestMessage, + }, + snapshot: { + sqsMessagesVisible, + sqsMessagesDelayed, + sqsMessagesEmpty, + sqsMessagesSent, + sqsOldestMessage, + }, + defaultSnapshot: 'sqsMessagesVisible', + defaultTimeRangeInSeconds: 14400, // 4 hours +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_delayed.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_delayed.ts new file mode 100644 index 0000000000000..679f86671725e --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_delayed.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 { SnapshotModel } from '../../../types'; + +export const sqsMessagesDelayed: SnapshotModel = { + sqsMessagesDelayed: { + max: { + field: 'aws.sqs.messages.delayed', + }, + }, +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_empty.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_empty.ts new file mode 100644 index 0000000000000..d80a3f3451e1d --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_empty.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 { SnapshotModel } from '../../../types'; + +export const sqsMessagesEmpty: SnapshotModel = { + sqsMessagesEmpty: { + max: { + field: 'aws.sqs.messages.not_visible', + }, + }, +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_sent.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_sent.ts new file mode 100644 index 0000000000000..3d6934bf3da85 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_sent.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 { SnapshotModel } from '../../../types'; + +export const sqsMessagesSent: SnapshotModel = { + sqsMessagesSent: { + max: { + field: 'aws.sqs.messages.sent', + }, + }, +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_visible.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_visible.ts new file mode 100644 index 0000000000000..1a78c50cd7949 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_visible.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 { SnapshotModel } from '../../../types'; + +export const sqsMessagesVisible: SnapshotModel = { + sqsMessagesVisible: { + avg: { + field: 'aws.sqs.messages.visible', + }, + }, +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_oldest_message.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_oldest_message.ts new file mode 100644 index 0000000000000..ae780069c8ca1 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_oldest_message.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 { SnapshotModel } from '../../../types'; + +export const sqsOldestMessage: SnapshotModel = { + sqsOldestMessage: { + max: { + field: 'aws.sqs.oldest_message_age.sec', + }, + }, +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/tsvb/aws_sqs_messages_delayed.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/tsvb/aws_sqs_messages_delayed.ts new file mode 100644 index 0000000000000..469b9ddd33953 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/tsvb/aws_sqs_messages_delayed.ts @@ -0,0 +1,26 @@ +/* + * 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 { createTSVBModel } from '../../../create_tsvb_model'; + +export const awsSQSMessagesDelayed = createTSVBModel( + 'awsSQSMessagesDelayed', + ['aws.sqs'], + [ + { + id: 'delayed', + split_mode: 'everything', + metrics: [ + { + field: 'aws.sqs.messages.delayed', + id: 'avg-delayed', + type: 'avg', + }, + ], + }, + ], + '>=300s' +); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/tsvb/aws_sqs_messages_empty.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/tsvb/aws_sqs_messages_empty.ts new file mode 100644 index 0000000000000..54c9e503a8c8c --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/tsvb/aws_sqs_messages_empty.ts @@ -0,0 +1,26 @@ +/* + * 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 { createTSVBModel } from '../../../create_tsvb_model'; + +export const awsSQSMessagesEmpty = createTSVBModel( + 'awsSQSMessagesEmpty', + ['aws.sqs'], + [ + { + id: 'empty', + split_mode: 'everything', + metrics: [ + { + field: 'aws.sqs.messages.not_visible', + id: 'avg-empty', + type: 'avg', + }, + ], + }, + ], + '>=300s' +); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/tsvb/aws_sqs_messages_sent.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/tsvb/aws_sqs_messages_sent.ts new file mode 100644 index 0000000000000..98389ef22fbe8 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/tsvb/aws_sqs_messages_sent.ts @@ -0,0 +1,26 @@ +/* + * 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 { createTSVBModel } from '../../../create_tsvb_model'; + +export const awsSQSMessagesSent = createTSVBModel( + 'awsSQSMessagesSent', + ['aws.sqs'], + [ + { + id: 'sent', + split_mode: 'everything', + metrics: [ + { + field: 'aws.sqs.messages.sent', + id: 'avg-sent', + type: 'avg', + }, + ], + }, + ], + '>=300s' +); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/tsvb/aws_sqs_messages_visible.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/tsvb/aws_sqs_messages_visible.ts new file mode 100644 index 0000000000000..c96ab07e4ae75 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/tsvb/aws_sqs_messages_visible.ts @@ -0,0 +1,26 @@ +/* + * 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 { createTSVBModel } from '../../../create_tsvb_model'; + +export const awsSQSMessagesVisible = createTSVBModel( + 'awsSQSMessagesVisible', + ['aws.sqs'], + [ + { + id: 'visible', + split_mode: 'everything', + metrics: [ + { + field: 'aws.sqs.messages.visible', + id: 'avg-visible', + type: 'avg', + }, + ], + }, + ], + '>=300s' +); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/tsvb/aws_sqs_oldest_message.ts b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/tsvb/aws_sqs_oldest_message.ts new file mode 100644 index 0000000000000..812906386fb67 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/metrics/tsvb/aws_sqs_oldest_message.ts @@ -0,0 +1,26 @@ +/* + * 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 { createTSVBModel } from '../../../create_tsvb_model'; + +export const awsSQSOldestMessage = createTSVBModel( + 'awsSQSOldestMessage', + ['aws.sqs'], + [ + { + id: 'oldest', + split_mode: 'everything', + metrics: [ + { + field: 'aws.sqs.oldest_message_age.sec', + id: 'max-oldest', + type: 'max', + }, + ], + }, + ], + '>=300s' +); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/toolbar_items.tsx b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/toolbar_items.tsx new file mode 100644 index 0000000000000..89d372d6ac21c --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/aws_sqs/toolbar_items.tsx @@ -0,0 +1,28 @@ +/* + * 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 { ToolbarProps } from '../../../public/components/inventory/toolbars/toolbar'; +import { MetricsAndGroupByToolbarItems } from '../shared/compontents/metrics_and_groupby_toolbar_items'; +import { InfraSnapshotMetricType } from '../../graphql/types'; + +export const AwsSQSToolbarItems = (props: ToolbarProps) => { + const metricTypes = [ + InfraSnapshotMetricType.sqsMessagesVisible, + InfraSnapshotMetricType.sqsMessagesDelayed, + InfraSnapshotMetricType.sqsMessagesSent, + InfraSnapshotMetricType.sqsMessagesEmpty, + InfraSnapshotMetricType.sqsOldestMessage, + ]; + const groupByFields = ['cloud.region']; + return ( + + ); +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/container/index.ts b/x-pack/legacy/plugins/infra/common/inventory_models/container/index.ts index 54fe938528d19..af7b6058ff174 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/container/index.ts +++ b/x-pack/legacy/plugins/infra/common/inventory_models/container/index.ts @@ -4,12 +4,27 @@ * you may not use this file except in compliance with the Elastic License. */ +import { i18n } from '@kbn/i18n'; import { metrics } from './metrics'; import { InventoryModel } from '../types'; export const container: InventoryModel = { id: 'container', + displayName: i18n.translate('xpack.infra.inventoryModel.container.displayName', { + defaultMessage: 'Docker Containers', + }), requiredModules: ['docker'], + crosslinkSupport: { + details: true, + logs: true, + apm: true, + uptime: true, + }, + fields: { + id: 'container.id', + name: 'container.name', + ip: 'continaer.ip_address', + }, metrics, requiredMetrics: [ 'containerOverview', diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/container/metrics/index.ts b/x-pack/legacy/plugins/infra/common/inventory_models/container/metrics/index.ts index 9e0153c5d6ea6..73a10cbadb66d 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/container/metrics/index.ts +++ b/x-pack/legacy/plugins/infra/common/inventory_models/container/metrics/index.ts @@ -30,4 +30,5 @@ export const metrics: InventoryMetrics = { }, snapshot: { cpu, memory, rx, tx }, defaultSnapshot: 'cpu', + defaultTimeRangeInSeconds: 3600, // 1 hour }; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/container/toolbar_items.tsx b/x-pack/legacy/plugins/infra/common/inventory_models/container/toolbar_items.tsx index ddb3c0491f164..9ed2cbe6dea08 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/container/toolbar_items.tsx +++ b/x-pack/legacy/plugins/infra/common/inventory_models/container/toolbar_items.tsx @@ -4,61 +4,31 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useMemo } from 'react'; -import { EuiFlexItem } from '@elastic/eui'; +import React from 'react'; import { ToolbarProps } from '../../../public/components/inventory/toolbars/toolbar'; -import { WaffleMetricControls } from '../../../public/components/waffle/waffle_metric_controls'; -import { WaffleGroupByControls } from '../../../public/components/waffle/waffle_group_by_controls'; -import { InfraSnapshotMetricType } from '../../../public/graphql/types'; -import { - toMetricOpt, - toGroupByOpt, -} from '../../../public/components/inventory/toolbars/toolbar_wrapper'; +import { MetricsAndGroupByToolbarItems } from '../shared/compontents/metrics_and_groupby_toolbar_items'; +import { InfraSnapshotMetricType } from '../../graphql/types'; export const ContainerToolbarItems = (props: ToolbarProps) => { - const options = useMemo( - () => - [ - InfraSnapshotMetricType.cpu, - InfraSnapshotMetricType.memory, - InfraSnapshotMetricType.rx, - InfraSnapshotMetricType.tx, - ].map(toMetricOpt), - [] - ); - - const groupByOptions = useMemo( - () => - [ - 'host.name', - 'cloud.availability_zone', - 'cloud.machine.type', - 'cloud.project.id', - 'cloud.provider', - 'service.type', - ].map(toGroupByOpt), - [] - ); + const metricTypes = [ + InfraSnapshotMetricType.cpu, + InfraSnapshotMetricType.memory, + InfraSnapshotMetricType.rx, + InfraSnapshotMetricType.tx, + ]; + const groupByFields = [ + 'host.name', + 'cloud.availability_zone', + 'cloud.machine.type', + 'cloud.project.id', + 'cloud.provider', + 'service.type', + ]; return ( - <> - - - - - - - + ); }; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/create_tsvb_model.ts b/x-pack/legacy/plugins/infra/common/inventory_models/create_tsvb_model.ts new file mode 100644 index 0000000000000..7036b2236881f --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/create_tsvb_model.ts @@ -0,0 +1,24 @@ +/* + * 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 { TSVBMetricModelCreator, TSVBMetricModel, TSVBSeries, InventoryMetric } from './types'; + +export const createTSVBModel = ( + id: InventoryMetric, + requires: string[], + series: TSVBSeries[], + interval = '>=300s', + dropLastBucket = true +): TSVBMetricModelCreator => (timeField, indexPattern): TSVBMetricModel => ({ + id, + requires, + drop_last_bucket: dropLastBucket, + index_pattern: indexPattern, + interval, + time_field: timeField, + type: 'timeseries', + series, +}); diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/host/index.ts b/x-pack/legacy/plugins/infra/common/inventory_models/host/index.ts index 08056e650a32e..54d3267eef57a 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/host/index.ts +++ b/x-pack/legacy/plugins/infra/common/inventory_models/host/index.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { i18n } from '@kbn/i18n'; import { metrics } from './metrics'; import { InventoryModel } from '../types'; import { @@ -13,7 +14,21 @@ import { export const host: InventoryModel = { id: 'host', + displayName: i18n.translate('xpack.infra.inventoryModel.host.displayName', { + defaultMessage: 'Hosts', + }), requiredModules: ['system'], + crosslinkSupport: { + details: true, + logs: true, + apm: true, + uptime: true, + }, + fields: { + id: 'host.name', + name: 'host.name', + ip: 'host.ip', + }, metrics, requiredMetrics: [ 'hostSystemOverview', diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/host/metrics/index.ts b/x-pack/legacy/plugins/infra/common/inventory_models/host/metrics/index.ts index f4c0150309dd8..7f77f23e4fb95 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/host/metrics/index.ts +++ b/x-pack/legacy/plugins/infra/common/inventory_models/host/metrics/index.ts @@ -52,4 +52,5 @@ export const metrics: InventoryMetrics = { }, snapshot: { count, cpu, load, logRate, memory, rx, tx }, defaultSnapshot: 'cpu', + defaultTimeRangeInSeconds: 3600, // 1 hour }; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/host/toolbar_items.tsx b/x-pack/legacy/plugins/infra/common/inventory_models/host/toolbar_items.tsx index 8e1bb0dfb4816..f8df81a33a8ec 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/host/toolbar_items.tsx +++ b/x-pack/legacy/plugins/infra/common/inventory_models/host/toolbar_items.tsx @@ -4,63 +4,32 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useMemo } from 'react'; -import { EuiFlexItem } from '@elastic/eui'; +import React from 'react'; import { ToolbarProps } from '../../../public/components/inventory/toolbars/toolbar'; -import { WaffleMetricControls } from '../../../public/components/waffle/waffle_metric_controls'; -import { WaffleGroupByControls } from '../../../public/components/waffle/waffle_group_by_controls'; -import { InfraSnapshotMetricType } from '../../../public/graphql/types'; -import { - toGroupByOpt, - toMetricOpt, -} from '../../../public/components/inventory/toolbars/toolbar_wrapper'; +import { MetricsAndGroupByToolbarItems } from '../shared/compontents/metrics_and_groupby_toolbar_items'; +import { InfraSnapshotMetricType } from '../../graphql/types'; export const HostToolbarItems = (props: ToolbarProps) => { - const metricOptions = useMemo( - () => - [ - InfraSnapshotMetricType.cpu, - InfraSnapshotMetricType.memory, - InfraSnapshotMetricType.load, - InfraSnapshotMetricType.rx, - InfraSnapshotMetricType.tx, - InfraSnapshotMetricType.logRate, - ].map(toMetricOpt), - [] - ); - - const groupByOptions = useMemo( - () => - [ - 'cloud.availability_zone', - 'cloud.machine.type', - 'cloud.project.id', - 'cloud.provider', - 'service.type', - ].map(toGroupByOpt), - [] - ); - + const metricTypes = [ + InfraSnapshotMetricType.cpu, + InfraSnapshotMetricType.memory, + InfraSnapshotMetricType.load, + InfraSnapshotMetricType.rx, + InfraSnapshotMetricType.tx, + InfraSnapshotMetricType.logRate, + ]; + const groupByFields = [ + 'cloud.availability_zone', + 'cloud.machine.type', + 'cloud.project.id', + 'cloud.provider', + 'service.type', + ]; return ( - <> - - - - - - - + ); }; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/index.ts b/x-pack/legacy/plugins/infra/common/inventory_models/index.ts index 79aad7b2ccf6f..d9fd8fa465b7a 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/index.ts +++ b/x-pack/legacy/plugins/infra/common/inventory_models/index.ts @@ -7,11 +7,15 @@ import { i18n } from '@kbn/i18n'; import { host } from './host'; import { pod } from './pod'; +import { awsEC2 } from './aws_ec2'; +import { awsS3 } from './aws_s3'; +import { awsRDS } from './aws_rds'; +import { awsSQS } from './aws_sqs'; import { container } from './container'; import { InventoryItemType } from './types'; export { metrics } from './metrics'; -const inventoryModels = [host, pod, container]; +export const inventoryModels = [host, pod, container, awsEC2, awsS3, awsRDS, awsSQS]; export const findInventoryModel = (type: InventoryItemType) => { const model = inventoryModels.find(m => m.id === type); @@ -24,3 +28,38 @@ export const findInventoryModel = (type: InventoryItemType) => { } return model; }; + +interface InventoryFields { + message: string[]; + host: string; + pod: string; + container: string; + timestamp: string; + tiebreaker: string; +} + +const LEGACY_TYPES = ['host', 'pod', 'container']; + +const getFieldByType = (type: InventoryItemType, fields: InventoryFields) => { + switch (type) { + case 'pod': + return fields.pod; + case 'host': + return fields.host; + case 'container': + return fields.container; + } +}; + +export const findInventoryFields = (type: InventoryItemType, fields: InventoryFields) => { + const inventoryModel = findInventoryModel(type); + if (LEGACY_TYPES.includes(type)) { + const id = getFieldByType(type, fields) || inventoryModel.fields.id; + return { + ...inventoryModel.fields, + id, + }; + } else { + return inventoryModel.fields; + } +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/layouts.ts b/x-pack/legacy/plugins/infra/common/inventory_models/layouts.ts index 0c593bec1af3a..d9008753adf7b 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/layouts.ts +++ b/x-pack/legacy/plugins/infra/common/inventory_models/layouts.ts @@ -17,6 +17,10 @@ import { ReactNode, FunctionComponent } from 'react'; import { Layout as HostLayout } from './host/layout'; import { Layout as PodLayout } from './pod/layout'; import { Layout as ContainerLayout } from './container/layout'; +import { Layout as AwsEC2Layout } from './aws_ec2/layout'; +import { Layout as AwsS3Layout } from './aws_s3/layout'; +import { Layout as AwsRDSLayout } from './aws_rds/layout'; +import { Layout as AwsSQSLayout } from './aws_sqs/layout'; import { InventoryItemType } from './types'; import { LayoutProps } from '../../public/pages/metrics/types'; @@ -28,6 +32,10 @@ const layouts: Layouts = { host: HostLayout, pod: PodLayout, container: ContainerLayout, + awsEC2: AwsEC2Layout, + awsS3: AwsS3Layout, + awsRDS: AwsRDSLayout, + awsSQS: AwsSQSLayout, }; export const findLayout = (type: InventoryItemType) => { diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/metrics.ts b/x-pack/legacy/plugins/infra/common/inventory_models/metrics.ts index 78dc262b29bac..cadc059fc5aeb 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/metrics.ts +++ b/x-pack/legacy/plugins/infra/common/inventory_models/metrics.ts @@ -8,6 +8,10 @@ import { metrics as hostMetrics } from './host/metrics'; import { metrics as sharedMetrics } from './shared/metrics'; import { metrics as podMetrics } from './pod/metrics'; import { metrics as containerMetrics } from './container/metrics'; +import { metrics as awsEC2Metrics } from './aws_ec2/metrics'; +import { metrics as awsS3Metrics } from './aws_s3/metrics'; +import { metrics as awsRDSMetrics } from './aws_rds/metrics'; +import { metrics as awsSQSMetrics } from './aws_sqs/metrics'; export const metrics = { tsvb: { @@ -15,5 +19,9 @@ export const metrics = { ...sharedMetrics.tsvb, ...podMetrics.tsvb, ...containerMetrics.tsvb, + ...awsEC2Metrics.tsvb, + ...awsS3Metrics.tsvb, + ...awsRDSMetrics.tsvb, + ...awsSQSMetrics.tsvb, }, }; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/pod/index.ts b/x-pack/legacy/plugins/infra/common/inventory_models/pod/index.ts index 66ace03abac00..3efc5827b4f23 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/pod/index.ts +++ b/x-pack/legacy/plugins/infra/common/inventory_models/pod/index.ts @@ -4,13 +4,28 @@ * you may not use this file except in compliance with the Elastic License. */ +import { i18n } from '@kbn/i18n'; import { metrics } from './metrics'; import { InventoryModel } from '../types'; import { nginx as nginxRequiredMetrics } from '../shared/metrics/required_metrics'; export const pod: InventoryModel = { id: 'pod', + displayName: i18n.translate('xpack.infra.inventoryModel.pod.displayName', { + defaultMessage: 'Kubernetes Pods', + }), requiredModules: ['kubernetes'], + crosslinkSupport: { + details: true, + logs: true, + apm: true, + uptime: true, + }, + fields: { + id: 'kubernetes.pod.uid', + name: 'kubernetes.pod.name', + ip: 'kubernetes.pod.ip', + }, metrics, requiredMetrics: [ 'podOverview', diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/pod/metrics/index.ts b/x-pack/legacy/plugins/infra/common/inventory_models/pod/metrics/index.ts index 2aa7ac6b496af..b4420b5532cc6 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/pod/metrics/index.ts +++ b/x-pack/legacy/plugins/infra/common/inventory_models/pod/metrics/index.ts @@ -26,4 +26,5 @@ export const metrics: InventoryMetrics = { }, snapshot: { cpu, memory, rx, tx }, defaultSnapshot: 'cpu', + defaultTimeRangeInSeconds: 3600, // 1 hour }; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/pod/toolbar_items.tsx b/x-pack/legacy/plugins/infra/common/inventory_models/pod/toolbar_items.tsx index cc0676fc60ae4..9ef4a889dc589 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/pod/toolbar_items.tsx +++ b/x-pack/legacy/plugins/infra/common/inventory_models/pod/toolbar_items.tsx @@ -4,54 +4,24 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useMemo } from 'react'; -import { EuiFlexItem } from '@elastic/eui'; +import React from 'react'; import { ToolbarProps } from '../../../public/components/inventory/toolbars/toolbar'; -import { WaffleMetricControls } from '../../../public/components/waffle/waffle_metric_controls'; -import { WaffleGroupByControls } from '../../../public/components/waffle/waffle_group_by_controls'; -import { InfraSnapshotMetricType } from '../../../public/graphql/types'; -import { - toGroupByOpt, - toMetricOpt, -} from '../../../public/components/inventory/toolbars/toolbar_wrapper'; +import { MetricsAndGroupByToolbarItems } from '../shared/compontents/metrics_and_groupby_toolbar_items'; +import { InfraSnapshotMetricType } from '../../graphql/types'; export const PodToolbarItems = (props: ToolbarProps) => { - const options = useMemo( - () => - [ - InfraSnapshotMetricType.cpu, - InfraSnapshotMetricType.memory, - InfraSnapshotMetricType.rx, - InfraSnapshotMetricType.tx, - ].map(toMetricOpt), - [] - ); - - const groupByOptions = useMemo( - () => ['kubernetes.namespace', 'kubernetes.node.name', 'service.type'].map(toGroupByOpt), - [] - ); - + const metricTypes = [ + InfraSnapshotMetricType.cpu, + InfraSnapshotMetricType.memory, + InfraSnapshotMetricType.rx, + InfraSnapshotMetricType.tx, + ]; + const groupByFields = ['kubernetes.namespace', 'kubernetes.node.name', 'service.type']; return ( - <> - - - - - - - + ); }; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/shared/compontents/metrics_and_groupby_toolbar_items.tsx b/x-pack/legacy/plugins/infra/common/inventory_models/shared/compontents/metrics_and_groupby_toolbar_items.tsx new file mode 100644 index 0000000000000..c46ad5c6df952 --- /dev/null +++ b/x-pack/legacy/plugins/infra/common/inventory_models/shared/compontents/metrics_and_groupby_toolbar_items.tsx @@ -0,0 +1,52 @@ +/* + * 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, { useMemo } from 'react'; +import { EuiFlexItem } from '@elastic/eui'; +import { ToolbarProps } from '../../../../public/components/inventory/toolbars/toolbar'; +import { WaffleMetricControls } from '../../../../public/components/waffle/waffle_metric_controls'; +import { WaffleGroupByControls } from '../../../../public/components/waffle/waffle_group_by_controls'; +import { InfraSnapshotMetricType } from '../../../../public/graphql/types'; +import { + toGroupByOpt, + toMetricOpt, +} from '../../../../public/components/inventory/toolbars/toolbar_wrapper'; + +interface Props extends ToolbarProps { + metricTypes: InfraSnapshotMetricType[]; + groupByFields: string[]; +} + +export const MetricsAndGroupByToolbarItems = (props: Props) => { + const metricOptions = useMemo(() => props.metricTypes.map(toMetricOpt), [props.metricTypes]); + + const groupByOptions = useMemo(() => props.groupByFields.map(toGroupByOpt), [ + props.groupByFields, + ]); + + return ( + <> + + + + + + + + ); +}; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/shared/metrics/index.ts b/x-pack/legacy/plugins/infra/common/inventory_models/shared/metrics/index.ts index 6416aa08e8585..2bab5c5229c5b 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/shared/metrics/index.ts +++ b/x-pack/legacy/plugins/infra/common/inventory_models/shared/metrics/index.ts @@ -35,4 +35,5 @@ export const metrics: InventoryMetrics = { count, }, defaultSnapshot: 'count', + defaultTimeRangeInSeconds: 3600, }; diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/toolbars.ts b/x-pack/legacy/plugins/infra/common/inventory_models/toolbars.ts index dc3c409ac497e..05def078c7f2d 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/toolbars.ts +++ b/x-pack/legacy/plugins/infra/common/inventory_models/toolbars.ts @@ -11,6 +11,10 @@ import { HostToolbarItems } from './host/toolbar_items'; import { ContainerToolbarItems } from './container/toolbar_items'; import { PodToolbarItems } from './pod/toolbar_items'; import { ToolbarProps } from '../../public/components/inventory/toolbars/toolbar'; +import { AwsEC2ToolbarItems } from './aws_ec2/toolbar_items'; +import { AwsS3ToolbarItems } from './aws_s3/toolbar_items'; +import { AwsRDSToolbarItems } from './aws_rds/toolbar_items'; +import { AwsSQSToolbarItems } from './aws_sqs/toolbar_items'; interface Toolbars { [type: string]: ReactNode; @@ -20,6 +24,10 @@ const toolbars: Toolbars = { host: HostToolbarItems, container: ContainerToolbarItems, pod: PodToolbarItems, + awsEC2: AwsEC2ToolbarItems, + awsS3: AwsS3ToolbarItems, + awsRDS: AwsRDSToolbarItems, + awsSQS: AwsSQSToolbarItems, }; export const findToolbar = (type: InventoryItemType) => { diff --git a/x-pack/legacy/plugins/infra/common/inventory_models/types.ts b/x-pack/legacy/plugins/infra/common/inventory_models/types.ts index 93eaf214ad23e..e1cbdcb52ff27 100644 --- a/x-pack/legacy/plugins/infra/common/inventory_models/types.ts +++ b/x-pack/legacy/plugins/infra/common/inventory_models/types.ts @@ -30,6 +30,7 @@ export const InventoryFormatterTypeRT = rt.keyof({ bytes: null, number: null, percent: null, + highPercision: null, }); export type InventoryFormatterType = rt.TypeOf; export type InventoryItemType = rt.TypeOf; @@ -72,6 +73,24 @@ export const InventoryMetricRT = rt.keyof({ awsNetworkPackets: null, awsDiskioBytes: null, awsDiskioOps: null, + awsEC2CpuUtilization: null, + awsEC2NetworkTraffic: null, + awsEC2DiskIOBytes: null, + awsS3TotalRequests: null, + awsS3NumberOfObjects: null, + awsS3BucketSize: null, + awsS3DownloadBytes: null, + awsS3UploadBytes: null, + awsRDSCpuTotal: null, + awsRDSConnections: null, + awsRDSQueriesExecuted: null, + awsRDSActiveTransactions: null, + awsRDSLatency: null, + awsSQSMessagesVisible: null, + awsSQSMessagesDelayed: null, + awsSQSMessagesSent: null, + awsSQSMessagesEmpty: null, + awsSQSOldestMessage: null, custom: null, }); export type InventoryMetric = rt.TypeOf; @@ -162,6 +181,8 @@ export const TSVBSeriesRT = rt.intersection([ }), ]); +export type TSVBSeries = rt.TypeOf; + export const TSVBMetricModelRT = rt.intersection([ rt.type({ id: InventoryMetricRT, @@ -176,6 +197,7 @@ export const TSVBMetricModelRT = rt.intersection([ filter: rt.string, map_field_to: rt.string, id_type: rt.keyof({ cloud: null, node: null }), + drop_last_bucket: rt.boolean, }), ]); @@ -267,6 +289,22 @@ export const SnapshotMetricTypeRT = rt.keyof({ tx: null, rx: null, logRate: null, + diskIOReadBytes: null, + diskIOWriteBytes: null, + s3TotalRequests: null, + s3NumberOfObjects: null, + s3BucketSize: null, + s3DownloadBytes: null, + s3UploadBytes: null, + rdsConnections: null, + rdsQueriesExecuted: null, + rdsActiveTransactions: null, + rdsLatency: null, + sqsMessagesVisible: null, + sqsMessagesDelayed: null, + sqsMessagesSent: null, + sqsMessagesEmpty: null, + sqsOldestMessage: null, }); export type SnapshotMetricType = rt.TypeOf; @@ -275,11 +313,25 @@ export interface InventoryMetrics { tsvb: { [name: string]: TSVBMetricModelCreator }; snapshot: { [name: string]: SnapshotModel }; defaultSnapshot: SnapshotMetricType; + /** This is used by the inventory view to calculate the appropriate amount of time for the metrics detail page. Some metris like awsS3 require multiple days where others like host only need an hour.*/ + defaultTimeRangeInSeconds: number; } export interface InventoryModel { id: string; + displayName: string; requiredModules: string[]; + fields: { + id: string; + name: string; + ip?: string; + }; + crosslinkSupport: { + details: boolean; + logs: boolean; + apm: boolean; + uptime: boolean; + }; metrics: InventoryMetrics; requiredMetrics: InventoryMetric[]; } diff --git a/x-pack/legacy/plugins/infra/public/components/inventory/layout.tsx b/x-pack/legacy/plugins/infra/public/components/inventory/layout.tsx index 47858624fde0f..cb48c99963d17 100644 --- a/x-pack/legacy/plugins/infra/public/components/inventory/layout.tsx +++ b/x-pack/legacy/plugins/infra/public/components/inventory/layout.tsx @@ -8,7 +8,6 @@ import React from 'react'; import { InfraWaffleMapOptions, InfraWaffleMapBounds } from '../../lib/lib'; import { InfraNodeType, - InfraTimerangeInput, InfraSnapshotMetricInput, InfraSnapshotGroupbyInput, } from '../../graphql/types'; @@ -23,7 +22,7 @@ export interface LayoutProps { options: InfraWaffleMapOptions; nodeType: InfraNodeType; onDrilldown: (filter: KueryFilterQuery) => void; - timeRange: InfraTimerangeInput; + currentTime: number; onViewChange: (view: string) => void; view: string; boundsOverride: InfraWaffleMapBounds; @@ -42,7 +41,7 @@ export const Layout = (props: LayoutProps) => { props.groupBy, props.nodeType, props.sourceId, - props.timeRange + props.currentTime ); return ( <> @@ -55,7 +54,7 @@ export const Layout = (props: LayoutProps) => { loading={loading} reload={reload} onDrilldown={props.onDrilldown} - timeRange={props.timeRange} + currentTime={props.currentTime} onViewChange={props.onViewChange} view={props.view} autoBounds={props.autoBounds} diff --git a/x-pack/legacy/plugins/infra/public/components/inventory/toolbars/toolbar_wrapper.tsx b/x-pack/legacy/plugins/infra/public/components/inventory/toolbars/toolbar_wrapper.tsx index 7cb86f6e4d0ec..c4721fee4b746 100644 --- a/x-pack/legacy/plugins/infra/public/components/inventory/toolbars/toolbar_wrapper.tsx +++ b/x-pack/legacy/plugins/infra/public/components/inventory/toolbars/toolbar_wrapper.tsx @@ -81,6 +81,54 @@ const ToolbarTranslations = { Count: i18n.translate('xpack.infra.waffle.metricOptions.countText', { defaultMessage: 'Count', }), + DiskIOReadBytes: i18n.translate('xpack.infra.waffle.metricOptions.diskIOReadBytes', { + defaultMessage: 'Disk Reads', + }), + DiskIOWriteBytes: i18n.translate('xpack.infra.waffle.metricOptions.diskIOWriteBytes', { + defaultMessage: 'Disk Writes', + }), + s3BucketSize: i18n.translate('xpack.infra.waffle.metricOptions.s3BucketSize', { + defaultMessage: 'Bucket Size', + }), + s3TotalRequests: i18n.translate('xpack.infra.waffle.metricOptions.s3TotalRequests', { + defaultMessage: 'Total Requests', + }), + s3NumberOfObjects: i18n.translate('xpack.infra.waffle.metricOptions.s3NumberOfObjects', { + defaultMessage: 'Number of Objects', + }), + s3DownloadBytes: i18n.translate('xpack.infra.waffle.metricOptions.s3DownloadBytes', { + defaultMessage: 'Downloads (Bytes)', + }), + s3UploadBytes: i18n.translate('xpack.infra.waffle.metricOptions.s3UploadBytes', { + defaultMessage: 'Uploads (Bytes)', + }), + rdsConnections: i18n.translate('xpack.infra.waffle.metricOptions.rdsConnections', { + defaultMessage: 'Connections', + }), + rdsQueriesExecuted: i18n.translate('xpack.infra.waffle.metricOptions.rdsQueriesExecuted', { + defaultMessage: 'Queries Executed', + }), + rdsActiveTransactions: i18n.translate('xpack.infra.waffle.metricOptions.rdsActiveTransactions', { + defaultMessage: 'Active Transactions', + }), + rdsLatency: i18n.translate('xpack.infra.waffle.metricOptions.rdsLatency', { + defaultMessage: 'Latency', + }), + sqsMessagesVisible: i18n.translate('xpack.infra.waffle.metricOptions.sqsMessagesVisible', { + defaultMessage: 'Messages Available', + }), + sqsMessagesDelayed: i18n.translate('xpack.infra.waffle.metricOptions.sqsMessagesDelayed', { + defaultMessage: 'Messages Delayed', + }), + sqsMessagesSent: i18n.translate('xpack.infra.waffle.metricOptions.sqsMessagesSent', { + defaultMessage: 'Messages Added', + }), + sqsMessagesEmpty: i18n.translate('xpack.infra.waffle.metricOptions.sqsMessagesEmpty', { + defaultMessage: 'Messages Returned Empty', + }), + sqsOldestMessage: i18n.translate('xpack.infra.waffle.metricOptions.sqsOldestMessage', { + defaultMessage: 'Oldest Message', + }), }; export const toGroupByOpt = (field: string) => ({ @@ -126,5 +174,85 @@ export const toMetricOpt = (metric: InfraSnapshotMetricType) => { text: ToolbarTranslations.Count, value: InfraSnapshotMetricType.count, }; + case InfraSnapshotMetricType.diskIOReadBytes: + return { + text: ToolbarTranslations.DiskIOReadBytes, + value: InfraSnapshotMetricType.diskIOReadBytes, + }; + case InfraSnapshotMetricType.diskIOWriteBytes: + return { + text: ToolbarTranslations.DiskIOWriteBytes, + value: InfraSnapshotMetricType.diskIOWriteBytes, + }; + case InfraSnapshotMetricType.s3BucketSize: + return { + text: ToolbarTranslations.s3BucketSize, + value: InfraSnapshotMetricType.s3BucketSize, + }; + case InfraSnapshotMetricType.s3TotalRequests: + return { + text: ToolbarTranslations.s3TotalRequests, + value: InfraSnapshotMetricType.s3TotalRequests, + }; + case InfraSnapshotMetricType.s3NumberOfObjects: + return { + text: ToolbarTranslations.s3NumberOfObjects, + value: InfraSnapshotMetricType.s3NumberOfObjects, + }; + case InfraSnapshotMetricType.s3DownloadBytes: + return { + text: ToolbarTranslations.s3DownloadBytes, + value: InfraSnapshotMetricType.s3DownloadBytes, + }; + case InfraSnapshotMetricType.s3UploadBytes: + return { + text: ToolbarTranslations.s3UploadBytes, + value: InfraSnapshotMetricType.s3UploadBytes, + }; + case InfraSnapshotMetricType.rdsConnections: + return { + text: ToolbarTranslations.rdsConnections, + value: InfraSnapshotMetricType.rdsConnections, + }; + case InfraSnapshotMetricType.rdsQueriesExecuted: + return { + text: ToolbarTranslations.rdsQueriesExecuted, + value: InfraSnapshotMetricType.rdsQueriesExecuted, + }; + case InfraSnapshotMetricType.rdsActiveTransactions: + return { + text: ToolbarTranslations.rdsActiveTransactions, + value: InfraSnapshotMetricType.rdsActiveTransactions, + }; + case InfraSnapshotMetricType.rdsLatency: + return { + text: ToolbarTranslations.rdsLatency, + value: InfraSnapshotMetricType.rdsLatency, + }; + case InfraSnapshotMetricType.sqsMessagesVisible: + return { + text: ToolbarTranslations.sqsMessagesVisible, + value: InfraSnapshotMetricType.sqsMessagesVisible, + }; + case InfraSnapshotMetricType.sqsMessagesDelayed: + return { + text: ToolbarTranslations.sqsMessagesDelayed, + value: InfraSnapshotMetricType.sqsMessagesDelayed, + }; + case InfraSnapshotMetricType.sqsMessagesSent: + return { + text: ToolbarTranslations.sqsMessagesSent, + value: InfraSnapshotMetricType.sqsMessagesSent, + }; + case InfraSnapshotMetricType.sqsMessagesEmpty: + return { + text: ToolbarTranslations.sqsMessagesEmpty, + value: InfraSnapshotMetricType.sqsMessagesEmpty, + }; + case InfraSnapshotMetricType.sqsOldestMessage: + return { + text: ToolbarTranslations.sqsOldestMessage, + value: InfraSnapshotMetricType.sqsOldestMessage, + }; } }; diff --git a/x-pack/legacy/plugins/infra/public/components/nodes_overview/index.tsx b/x-pack/legacy/plugins/infra/public/components/nodes_overview/index.tsx index acddbee8db267..edf1b228b278a 100644 --- a/x-pack/legacy/plugins/infra/public/components/nodes_overview/index.tsx +++ b/x-pack/legacy/plugins/infra/public/components/nodes_overview/index.tsx @@ -11,12 +11,7 @@ import { get, max, min } from 'lodash'; import React from 'react'; import euiStyled from '../../../../../common/eui_styled_components'; -import { - InfraSnapshotMetricType, - InfraSnapshotNode, - InfraNodeType, - InfraTimerangeInput, -} from '../../graphql/types'; +import { InfraSnapshotMetricType, InfraSnapshotNode, InfraNodeType } from '../../graphql/types'; import { InfraFormatterType, InfraWaffleMapBounds, InfraWaffleMapOptions } from '../../lib/lib'; import { KueryFilterQuery } from '../../store/local/waffle_filter'; import { createFormatter } from '../../utils/formatters'; @@ -34,7 +29,7 @@ interface Props { loading: boolean; reload: () => void; onDrilldown: (filter: KueryFilterQuery) => void; - timeRange: InfraTimerangeInput; + currentTime: number; onViewChange: (view: string) => void; view: string; boundsOverride: InfraWaffleMapBounds; @@ -67,6 +62,38 @@ const METRIC_FORMATTERS: MetricFormatters = { formatter: InfraFormatterType.abbreviatedNumber, template: '{{value}}/s', }, + [InfraSnapshotMetricType.diskIOReadBytes]: { + formatter: InfraFormatterType.bytes, + template: '{{value}}/s', + }, + [InfraSnapshotMetricType.diskIOWriteBytes]: { + formatter: InfraFormatterType.bytes, + template: '{{value}}/s', + }, + [InfraSnapshotMetricType.s3BucketSize]: { + formatter: InfraFormatterType.bytes, + template: '{{value}}', + }, + [InfraSnapshotMetricType.s3TotalRequests]: { + formatter: InfraFormatterType.abbreviatedNumber, + template: '{{value}}', + }, + [InfraSnapshotMetricType.s3NumberOfObjects]: { + formatter: InfraFormatterType.abbreviatedNumber, + template: '{{value}}', + }, + [InfraSnapshotMetricType.s3UploadBytes]: { + formatter: InfraFormatterType.bytes, + template: '{{value}}', + }, + [InfraSnapshotMetricType.s3DownloadBytes]: { + formatter: InfraFormatterType.bytes, + template: '{{value}}', + }, + [InfraSnapshotMetricType.sqsOldestMessage]: { + formatter: InfraFormatterType.number, + template: '{{value}} seconds', + }, }; const calculateBoundsFromNodes = (nodes: InfraSnapshotNode[]): InfraWaffleMapBounds => { @@ -92,8 +119,8 @@ export const NodesOverview = class extends React.Component { nodeType, reload, view, + currentTime, options, - timeRange, } = this.props; if (loading) { return ( @@ -152,7 +179,7 @@ export const NodesOverview = class extends React.Component { nodes={nodes} options={options} formatter={this.formatter} - timeRange={timeRange} + currentTime={currentTime} onFilter={this.handleDrilldown} /> @@ -163,7 +190,7 @@ export const NodesOverview = class extends React.Component { nodes={nodes} options={options} formatter={this.formatter} - timeRange={timeRange} + currentTime={currentTime} onFilter={this.handleDrilldown} bounds={bounds} dataBounds={dataBounds} diff --git a/x-pack/legacy/plugins/infra/public/components/nodes_overview/table.tsx b/x-pack/legacy/plugins/infra/public/components/nodes_overview/table.tsx index 5b201d2be4333..b4abf962bd892 100644 --- a/x-pack/legacy/plugins/infra/public/components/nodes_overview/table.tsx +++ b/x-pack/legacy/plugins/infra/public/components/nodes_overview/table.tsx @@ -10,12 +10,7 @@ import { i18n } from '@kbn/i18n'; import { last } from 'lodash'; import React from 'react'; import { createWaffleMapNode } from '../../containers/waffle/nodes_to_wafflemap'; -import { - InfraSnapshotNode, - InfraSnapshotNodePath, - InfraTimerangeInput, - InfraNodeType, -} from '../../graphql/types'; +import { InfraSnapshotNode, InfraSnapshotNodePath, InfraNodeType } from '../../graphql/types'; import { InfraWaffleMapNode, InfraWaffleMapOptions } from '../../lib/lib'; import { fieldToName } from '../waffle/lib/field_to_display_name'; import { NodeContextMenu } from '../waffle/node_context_menu'; @@ -25,7 +20,7 @@ interface Props { nodeType: InfraNodeType; options: InfraWaffleMapOptions; formatter: (subject: string | number) => string; - timeRange: InfraTimerangeInput; + currentTime: number; onFilter: (filter: string) => void; } @@ -49,7 +44,7 @@ const getGroupPaths = (path: InfraSnapshotNodePath[]) => { export const TableView = class extends React.PureComponent { public readonly state: State = initialState; public render() { - const { nodes, options, formatter, timeRange, nodeType } = this.props; + const { nodes, options, formatter, currentTime, nodeType } = this.props; const columns = [ { field: 'name', @@ -68,7 +63,7 @@ export const TableView = class extends React.PureComponent { node={item.node} nodeType={nodeType} closePopover={this.closePopoverFor(uniqueID)} - timeRange={timeRange} + currentTime={currentTime} isPopoverOpen={this.state.isPopoverOpen.includes(uniqueID)} options={options} popoverPosition="rightCenter" diff --git a/x-pack/legacy/plugins/infra/public/components/waffle/group_of_groups.tsx b/x-pack/legacy/plugins/infra/public/components/waffle/group_of_groups.tsx index 3f456c3c8d406..7a229fbbe02ec 100644 --- a/x-pack/legacy/plugins/infra/public/components/waffle/group_of_groups.tsx +++ b/x-pack/legacy/plugins/infra/public/components/waffle/group_of_groups.tsx @@ -7,7 +7,7 @@ import React from 'react'; import euiStyled from '../../../../../common/eui_styled_components'; -import { InfraNodeType, InfraTimerangeInput } from '../../graphql/types'; +import { InfraNodeType } from '../../graphql/types'; import { InfraWaffleMapBounds, InfraWaffleMapGroupOfGroups, @@ -23,7 +23,7 @@ interface Props { formatter: (val: number) => string; bounds: InfraWaffleMapBounds; nodeType: InfraNodeType; - timeRange: InfraTimerangeInput; + currentTime: number; } export const GroupOfGroups: React.FC = props => { @@ -41,7 +41,7 @@ export const GroupOfGroups: React.FC = props => { formatter={props.formatter} bounds={props.bounds} nodeType={props.nodeType} - timeRange={props.timeRange} + currentTime={props.currentTime} /> ))} diff --git a/x-pack/legacy/plugins/infra/public/components/waffle/group_of_nodes.tsx b/x-pack/legacy/plugins/infra/public/components/waffle/group_of_nodes.tsx index bc7d31a301496..c40c68cbdbf28 100644 --- a/x-pack/legacy/plugins/infra/public/components/waffle/group_of_nodes.tsx +++ b/x-pack/legacy/plugins/infra/public/components/waffle/group_of_nodes.tsx @@ -7,7 +7,7 @@ import React from 'react'; import euiStyled from '../../../../../common/eui_styled_components'; -import { InfraNodeType, InfraTimerangeInput } from '../../graphql/types'; +import { InfraNodeType } from '../../graphql/types'; import { InfraWaffleMapBounds, InfraWaffleMapGroupOfNodes, @@ -24,7 +24,7 @@ interface Props { isChild: boolean; bounds: InfraWaffleMapBounds; nodeType: InfraNodeType; - timeRange: InfraTimerangeInput; + currentTime: number; } export const GroupOfNodes: React.FC = ({ @@ -35,7 +35,7 @@ export const GroupOfNodes: React.FC = ({ isChild = false, bounds, nodeType, - timeRange, + currentTime, }) => { const width = group.width > 200 ? group.width : 200; return ( @@ -51,7 +51,7 @@ export const GroupOfNodes: React.FC = ({ formatter={formatter} bounds={bounds} nodeType={nodeType} - timeRange={timeRange} + currentTime={currentTime} /> ))} diff --git a/x-pack/legacy/plugins/infra/public/components/waffle/lib/field_to_display_name.ts b/x-pack/legacy/plugins/infra/public/components/waffle/lib/field_to_display_name.ts index b34b2801a50f1..7160c8eaa8dde 100644 --- a/x-pack/legacy/plugins/infra/public/components/waffle/lib/field_to_display_name.ts +++ b/x-pack/legacy/plugins/infra/public/components/waffle/lib/field_to_display_name.ts @@ -10,6 +10,14 @@ interface Lookup { [id: string]: string; } +const availabilityZoneName = i18n.translate('xpack.infra.groupByDisplayNames.availabilityZone', { + defaultMessage: 'Availability zone', +}); + +const machineTypeName = i18n.translate('xpack.infra.groupByDisplayNames.machineType', { + defaultMessage: 'Machine type', +}); + export const fieldToName = (field: string) => { const LOOKUP: Lookup = { 'kubernetes.namespace': i18n.translate('xpack.infra.groupByDisplayNames.kubernetesNamespace', { @@ -21,12 +29,8 @@ export const fieldToName = (field: string) => { 'host.name': i18n.translate('xpack.infra.groupByDisplayNames.hostName', { defaultMessage: 'Host', }), - 'cloud.availability_zone': i18n.translate('xpack.infra.groupByDisplayNames.availabilityZone', { - defaultMessage: 'Availability zone', - }), - 'cloud.machine.type': i18n.translate('xpack.infra.groupByDisplayNames.machineType', { - defaultMessage: 'Machine type', - }), + 'cloud.availability_zone': availabilityZoneName, + 'cloud.machine.type': machineTypeName, 'cloud.project.id': i18n.translate('xpack.infra.groupByDisplayNames.projectID', { defaultMessage: 'Project ID', }), @@ -36,6 +40,32 @@ export const fieldToName = (field: string) => { 'service.type': i18n.translate('xpack.infra.groupByDisplayNames.serviceType', { defaultMessage: 'Service type', }), + 'aws.cloud.availability_zone': availabilityZoneName, + 'aws.cloud.machine.type': machineTypeName, + 'aws.tags': i18n.translate('xpack.infra.groupByDisplayNames.tags', { + defaultMessage: 'Tags', + }), + 'aws.ec2.instance.image.id': i18n.translate('xpack.infra.groupByDisplayNames.image', { + defaultMessage: 'Image', + }), + 'aws.ec2.instance.state.name': i18n.translate('xpack.infra.groupByDisplayNames.state.name', { + defaultMessage: 'State', + }), + 'cloud.region': i18n.translate('xpack.infra.groupByDisplayNames.cloud.region', { + defaultMessage: 'Region', + }), + 'aws.rds.db_instance.class': i18n.translate( + 'xpack.infra.groupByDisplayNames.rds.db_instance.class', + { + defaultMessage: 'Instance Class', + } + ), + 'aws.rds.db_instance.status': i18n.translate( + 'xpack.infra.groupByDisplayNames.rds.db_instance.status', + { + defaultMessage: 'Status', + } + ), }; return LOOKUP[field] || field; }; diff --git a/x-pack/legacy/plugins/infra/public/components/waffle/map.tsx b/x-pack/legacy/plugins/infra/public/components/waffle/map.tsx index ed7db4fe3dfe1..6c0209a60f1cd 100644 --- a/x-pack/legacy/plugins/infra/public/components/waffle/map.tsx +++ b/x-pack/legacy/plugins/infra/public/components/waffle/map.tsx @@ -11,7 +11,7 @@ import { isWaffleMapGroupWithGroups, isWaffleMapGroupWithNodes, } from '../../containers/waffle/type_guards'; -import { InfraSnapshotNode, InfraNodeType, InfraTimerangeInput } from '../../graphql/types'; +import { InfraSnapshotNode, InfraNodeType } from '../../graphql/types'; import { InfraWaffleMapBounds, InfraWaffleMapOptions } from '../../lib/lib'; import { AutoSizer } from '../auto_sizer'; import { GroupOfGroups } from './group_of_groups'; @@ -24,7 +24,7 @@ interface Props { nodeType: InfraNodeType; options: InfraWaffleMapOptions; formatter: (subject: string | number) => string; - timeRange: InfraTimerangeInput; + currentTime: number; onFilter: (filter: string) => void; bounds: InfraWaffleMapBounds; dataBounds: InfraWaffleMapBounds; @@ -33,7 +33,7 @@ interface Props { export const Map: React.FC = ({ nodes, options, - timeRange, + currentTime, onFilter, formatter, bounds, @@ -59,7 +59,7 @@ export const Map: React.FC = ({ formatter={formatter} bounds={bounds} nodeType={nodeType} - timeRange={timeRange} + currentTime={currentTime} /> ); } @@ -74,7 +74,7 @@ export const Map: React.FC = ({ isChild={false} bounds={bounds} nodeType={nodeType} - timeRange={timeRange} + currentTime={currentTime} /> ); } diff --git a/x-pack/legacy/plugins/infra/public/components/waffle/node.tsx b/x-pack/legacy/plugins/infra/public/components/waffle/node.tsx index 8f09a3fdca9cf..f0770064c3cf9 100644 --- a/x-pack/legacy/plugins/infra/public/components/waffle/node.tsx +++ b/x-pack/legacy/plugins/infra/public/components/waffle/node.tsx @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import moment from 'moment'; import { darken, readableColor } from 'polished'; import React from 'react'; @@ -12,7 +11,7 @@ import { i18n } from '@kbn/i18n'; import { ConditionalToolTip } from './conditional_tooltip'; import euiStyled from '../../../../../common/eui_styled_components'; -import { InfraTimerangeInput, InfraNodeType } from '../../graphql/types'; +import { InfraNodeType } from '../../graphql/types'; import { InfraWaffleMapBounds, InfraWaffleMapNode, InfraWaffleMapOptions } from '../../lib/lib'; import { colorFromValue } from './lib/color_from_value'; import { NodeContextMenu } from './node_context_menu'; @@ -30,13 +29,13 @@ interface Props { formatter: (val: number) => string; bounds: InfraWaffleMapBounds; nodeType: InfraNodeType; - timeRange: InfraTimerangeInput; + currentTime: number; } export const Node = class extends React.PureComponent { public readonly state: State = initialState; public render() { - const { nodeType, node, options, squareSize, bounds, formatter, timeRange } = this.props; + const { nodeType, node, options, squareSize, bounds, formatter, currentTime } = this.props; const { isPopoverOpen } = this.state; const { metric } = node; const valueMode = squareSize > 70; @@ -44,12 +43,6 @@ export const Node = class extends React.PureComponent { const rawValue = (metric && metric.value) || 0; const color = colorFromValue(options.legend, rawValue, bounds); const value = formatter(rawValue); - const newTimerange = { - ...timeRange, - from: moment(timeRange.to) - .subtract(1, 'hour') - .valueOf(), - }; const nodeAriaLabel = i18n.translate('xpack.infra.node.ariaLabel', { defaultMessage: '{nodeName}, click to open menu', values: { nodeName: node.name }, @@ -61,7 +54,7 @@ export const Node = class extends React.PureComponent { isPopoverOpen={isPopoverOpen} closePopover={this.closePopover} options={options} - timeRange={newTimerange} + currentTime={currentTime} popoverPosition="downCenter" > { + const inventoryModel = findInventoryModel(nodeType); // Due to the changing nature of the fields between APM and this UI, // We need to have some exceptions until 7.0 & ECS is finalized. Reference // #26620 for the details for these fields. // TODO: This is tech debt, remove it after 7.0 & ECS migration. - const APM_FIELDS = { - [InfraNodeType.host]: 'host.hostname', - [InfraNodeType.container]: 'container.id', - [InfraNodeType.pod]: 'kubernetes.pod.uid', - }; + const apmField = nodeType === InfraNodeType.host ? 'host.hostname' : inventoryModel.fields.id; const nodeLogsMenuItem = { name: i18n.translate('xpack.infra.nodeContextMenu.viewLogsName', { @@ -62,11 +59,12 @@ export const NodeContextMenu = injectUICapabilities( href: getNodeLogsUrl({ nodeType, nodeId: node.id, - time: timeRange.to, + time: currentTime, }), 'data-test-subj': 'viewLogsContextMenuItem', }; + const nodeDetailFrom = currentTime - inventoryModel.metrics.defaultTimeRangeInSeconds * 1000; const nodeDetailMenuItem = { name: i18n.translate('xpack.infra.nodeContextMenu.viewMetricsName', { defaultMessage: 'View metrics', @@ -74,45 +72,47 @@ export const NodeContextMenu = injectUICapabilities( href: getNodeDetailUrl({ nodeType, nodeId: node.id, - from: timeRange.from, - to: timeRange.to, + from: nodeDetailFrom, + to: currentTime, }), }; const apmTracesMenuItem = { name: i18n.translate('xpack.infra.nodeContextMenu.viewAPMTraces', { - defaultMessage: 'View {nodeType} APM traces', - values: { nodeType }, + defaultMessage: 'View APM traces', }), - href: `../app/apm#/traces?_g=()&kuery=${APM_FIELDS[nodeType]}:"${node.id}"`, + href: `../app/apm#/traces?_g=()&kuery=${apmField}:"${node.id}"`, 'data-test-subj': 'viewApmTracesContextMenuItem', }; const uptimeMenuItem = { name: i18n.translate('xpack.infra.nodeContextMenu.viewUptimeLink', { - defaultMessage: 'View {nodeType} in Uptime', - values: { nodeType }, + defaultMessage: 'View in Uptime', }), href: createUptimeLink(options, nodeType, node), }; - const showLogsLink = node.id && uiCapabilities.logs.show; - const showAPMTraceLink = uiCapabilities.apm && uiCapabilities.apm.show; + const showDetail = inventoryModel.crosslinkSupport.details; + const showLogsLink = + inventoryModel.crosslinkSupport.logs && node.id && uiCapabilities.logs.show; + const showAPMTraceLink = + inventoryModel.crosslinkSupport.apm && uiCapabilities.apm && uiCapabilities.apm.show; const showUptimeLink = - [InfraNodeType.pod, InfraNodeType.container].includes(nodeType) || node.ip; + inventoryModel.crosslinkSupport.uptime && + ([InfraNodeType.pod, InfraNodeType.container].includes(nodeType) || node.ip); - const panels: EuiContextMenuPanelDescriptor[] = [ - { - id: 0, - title: '', - items: [ - ...(showLogsLink ? [nodeLogsMenuItem] : []), - nodeDetailMenuItem, - ...(showAPMTraceLink ? [apmTracesMenuItem] : []), - ...(showUptimeLink ? [uptimeMenuItem] : []), - ], - }, + const items = [ + ...(showLogsLink ? [nodeLogsMenuItem] : []), + ...(showDetail ? [nodeDetailMenuItem] : []), + ...(showAPMTraceLink ? [apmTracesMenuItem] : []), + ...(showUptimeLink ? [uptimeMenuItem] : []), ]; + const panels: EuiContextMenuPanelDescriptor[] = [{ id: 0, title: '', items }]; + + // If there is nothing to show then we need to return the child as is + if (items.length === 0) { + return <>{children}; + } return ( void; } +const getDisplayNameForType = (type: InventoryItemType) => { + const inventoryModel = findInventoryModel(type); + return inventoryModel.displayName; +}; + export const WaffleInventorySwitcher: React.FC = ({ changeNodeType, changeGroupBy, @@ -48,44 +59,62 @@ export const WaffleInventorySwitcher: React.FC = ( const goToHost = useCallback(() => goToNodeType('host' as InfraNodeType), [goToNodeType]); const goToK8 = useCallback(() => goToNodeType('pod' as InfraNodeType), [goToNodeType]); const goToDocker = useCallback(() => goToNodeType('container' as InfraNodeType), [goToNodeType]); + const goToAwsEC2 = useCallback(() => goToNodeType('awsEC2' as InfraNodeType), [goToNodeType]); + const goToAwsS3 = useCallback(() => goToNodeType('awsS3' as InfraNodeType), [goToNodeType]); + const goToAwsRDS = useCallback(() => goToNodeType('awsRDS' as InfraNodeType), [goToNodeType]); + const goToAwsSQS = useCallback(() => goToNodeType('awsSQS' as InfraNodeType), [goToNodeType]); const panels = useMemo( - () => [ - { - id: 0, - items: [ - { - name: i18n.translate('xpack.infra.waffle.nodeTypeSwitcher.hostsLabel', { - defaultMessage: 'Hosts', - }), - icon: 'host', - onClick: goToHost, - }, - { - name: 'Kubernetes', - icon: 'kubernetes', - onClick: goToK8, - }, - { - name: 'Docker', - icon: 'docker', - onClick: goToDocker, - }, - ], - }, - ], - [goToDocker, goToHost, goToK8] + () => + [ + { + id: 'firstPanel', + items: [ + { + name: getDisplayNameForType('host'), + onClick: goToHost, + }, + { + name: getDisplayNameForType('pod'), + onClick: goToK8, + }, + { + name: getDisplayNameForType('container'), + onClick: goToDocker, + }, + { + name: 'AWS', + panel: 'awsPanel', + }, + ], + }, + { + id: 'awsPanel', + title: 'AWS', + items: [ + { + name: getDisplayNameForType('awsEC2'), + onClick: goToAwsEC2, + }, + { + name: getDisplayNameForType('awsS3'), + onClick: goToAwsS3, + }, + { + name: getDisplayNameForType('awsRDS'), + onClick: goToAwsRDS, + }, + { + name: getDisplayNameForType('awsSQS'), + onClick: goToAwsSQS, + }, + ], + }, + ] as EuiContextMenuPanelDescriptor[], + [goToAwsEC2, goToAwsRDS, goToAwsS3, goToAwsSQS, goToDocker, goToHost, goToK8] ); + const selectedText = useMemo(() => { - switch (nodeType) { - case InfraNodeType.host: - return i18n.translate('xpack.infra.waffle.nodeTypeSwitcher.hostsLabel', { - defaultMessage: 'Hosts', - }); - case InfraNodeType.pod: - return 'Kubernetes'; - case InfraNodeType.container: - return 'Docker'; - } + return getDisplayNameForType(nodeType); }, [nodeType]); return ( @@ -107,7 +136,7 @@ export const WaffleInventorySwitcher: React.FC = ( withTitle anchorPosition="downLeft" > - + ); diff --git a/x-pack/legacy/plugins/infra/public/components/waffle/waffle_metric_controls.tsx b/x-pack/legacy/plugins/infra/public/components/waffle/waffle_metric_controls.tsx index b0ea6f13f2bb6..d5ae6fcf7f7a2 100644 --- a/x-pack/legacy/plugins/infra/public/components/waffle/waffle_metric_controls.tsx +++ b/x-pack/legacy/plugins/infra/public/components/waffle/waffle_metric_controls.tsx @@ -44,7 +44,7 @@ export const WaffleMetricControls = class extends React.PureComponent o.value === metric.type); if (!currentLabel) { - return 'null'; + return null; } const panels: EuiContextMenuPanelDescriptor[] = [ { diff --git a/x-pack/legacy/plugins/infra/public/containers/waffle/use_snaphot.ts b/x-pack/legacy/plugins/infra/public/containers/waffle/use_snaphot.ts index 4c8d41afd36b5..63b91bd97776a 100644 --- a/x-pack/legacy/plugins/infra/public/containers/waffle/use_snaphot.ts +++ b/x-pack/legacy/plugins/infra/public/containers/waffle/use_snaphot.ts @@ -12,7 +12,6 @@ import { InfraNodeType, InfraSnapshotMetricInput, InfraSnapshotGroupbyInput, - InfraTimerangeInput, } from '../../graphql/types'; import { throwErrors, createPlainError } from '../../../common/runtime_types'; import { useHTTPRequest } from '../../hooks/use_http_request'; @@ -27,7 +26,7 @@ export function useSnapshot( groupBy: InfraSnapshotGroupbyInput[], nodeType: InfraNodeType, sourceId: string, - timerange: InfraTimerangeInput + currentTime: number ) { const decodeResponse = (response: any) => { return pipe( @@ -36,6 +35,12 @@ export function useSnapshot( ); }; + const timerange = { + interval: '1m', + to: currentTime, + from: currentTime - 360 * 1000, + }; + const { error, loading, response, makeRequest } = useHTTPRequest( '/api/metrics/snapshot', 'POST', diff --git a/x-pack/legacy/plugins/infra/public/graphql/introspection.json b/x-pack/legacy/plugins/infra/public/graphql/introspection.json index 64792d606f446..ae8d3dcdd5bec 100644 --- a/x-pack/legacy/plugins/infra/public/graphql/introspection.json +++ b/x-pack/legacy/plugins/infra/public/graphql/introspection.json @@ -2129,7 +2129,8 @@ "isDeprecated": false, "deprecationReason": null }, - { "name": "host", "description": "", "isDeprecated": false, "deprecationReason": null } + { "name": "host", "description": "", "isDeprecated": false, "deprecationReason": null }, + { "name": "awsEC2", "description": "", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, @@ -2191,7 +2192,9 @@ { "name": "memory", "description": "", "isDeprecated": false, "deprecationReason": null }, { "name": "tx", "description": "", "isDeprecated": false, "deprecationReason": null }, { "name": "rx", "description": "", "isDeprecated": false, "deprecationReason": null }, - { "name": "logRate", "description": "", "isDeprecated": false, "deprecationReason": null } + { "name": "logRate", "description": "", "isDeprecated": false, "deprecationReason": null }, + { "name": "diskIOReadBytes", "description": "", "isDeprecated": false, "deprecationReason": null }, + { "name": "diskIOWriteBytes", "description": "", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, @@ -2585,6 +2588,24 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "awsEC2CpuUtilization", + "description": "", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "awsEC2NetworkTraffic", + "description": "", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "awsEC2DiskIOBytes", + "description": "", + "isDeprecated": false, + "deprecationReason": null + }, { "name": "custom", "description": "", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null diff --git a/x-pack/legacy/plugins/infra/public/graphql/types.ts b/x-pack/legacy/plugins/infra/public/graphql/types.ts index 8d0e75523a8ed..3715f02bb252e 100644 --- a/x-pack/legacy/plugins/infra/public/graphql/types.ts +++ b/x-pack/legacy/plugins/infra/public/graphql/types.ts @@ -554,6 +554,10 @@ export enum InfraNodeType { pod = 'pod', container = 'container', host = 'host', + awsEC2 = 'awsEC2', + awsS3 = 'awsS3', + awsRDS = 'awsRDS', + awsSQS = 'awsSQS', } export enum InfraSnapshotMetricType { @@ -564,6 +568,22 @@ export enum InfraSnapshotMetricType { tx = 'tx', rx = 'rx', logRate = 'logRate', + diskIOReadBytes = 'diskIOReadBytes', + diskIOWriteBytes = 'diskIOWriteBytes', + s3TotalRequests = 's3TotalRequests', + s3NumberOfObjects = 's3NumberOfObjects', + s3BucketSize = 's3BucketSize', + s3DownloadBytes = 's3DownloadBytes', + s3UploadBytes = 's3UploadBytes', + rdsConnections = 'rdsConnections', + rdsQueriesExecuted = 'rdsQueriesExecuted', + rdsActiveTransactions = 'rdsActiveTransactions', + rdsLatency = 'rdsLatency', + sqsMessagesVisible = 'sqsMessagesVisible', + sqsMessagesDelayed = 'sqsMessagesDelayed', + sqsMessagesSent = 'sqsMessagesSent', + sqsMessagesEmpty = 'sqsMessagesEmpty', + sqsOldestMessage = 'sqsOldestMessage', } export enum InfraMetric { @@ -604,6 +624,24 @@ export enum InfraMetric { awsNetworkPackets = 'awsNetworkPackets', awsDiskioBytes = 'awsDiskioBytes', awsDiskioOps = 'awsDiskioOps', + awsEC2CpuUtilization = 'awsEC2CpuUtilization', + awsEC2DiskIOBytes = 'awsEC2DiskIOBytes', + awsEC2NetworkTraffic = 'awsEC2NetworkTraffic', + awsS3TotalRequests = 'awsS3TotalRequests', + awsS3NumberOfObjects = 'awsS3NumberOfObjects', + awsS3BucketSize = 'awsS3BucketSize', + awsS3DownloadBytes = 'awsS3DownloadBytes', + awsS3UploadBytes = 'awsS3UploadBytes', + awsRDSCpuTotal = 'awsRDSCpuTotal', + awsRDSConnections = 'awsRDSConnections', + awsRDSQueriesExecuted = 'awsRDSQueriesExecuted', + awsRDSActiveTransactions = 'awsRDSActiveTransactions', + awsRDSLatency = 'awsRDSLatency', + awsSQSMessagesVisible = 'awsSQSMessagesVisible', + awsSQSMessagesDelayed = 'awsSQSMessagesDelayed', + awsSQSMessagesSent = 'awsSQSMessagesSent', + awsSQSMessagesEmpty = 'awsSQSMessagesEmpty', + awsSQSOldestMessage = 'awsSQSOldestMessage', custom = 'custom', } diff --git a/x-pack/legacy/plugins/infra/public/pages/infrastructure/snapshot/page_content.tsx b/x-pack/legacy/plugins/infra/public/pages/infrastructure/snapshot/page_content.tsx index 04aa0a9188a57..85b551a448d0e 100644 --- a/x-pack/legacy/plugins/infra/public/pages/infrastructure/snapshot/page_content.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/infrastructure/snapshot/page_content.tsx @@ -21,7 +21,7 @@ export const SnapshotPageContent: React.FC = () => ( {({ filterQueryAsJson, applyFilterQuery }) => ( - {({ currentTimeRange, isAutoReloading }) => ( + {({ currentTime }) => ( {({ metric, @@ -33,12 +33,12 @@ export const SnapshotPageContent: React.FC = () => ( boundsOverride, }) => ( ; } +const ITEM_TYPES = inventoryModels.map(m => m.id).join('|'); + export const LinkToPage: React.FC = props => ( ; +const getFieldByNodeType = (nodeType: InfraNodeType, fields: SourceConfigurationFields.Fields) => { + const inventoryFields = findInventoryFields(nodeType, fields); + return inventoryFields.id; +}; + export const RedirectToNodeLogs = ({ match: { params: { nodeId, nodeType, sourceId = 'default' }, @@ -50,7 +56,7 @@ export const RedirectToNodeLogs = ({ return null; } - const nodeFilter = `${configuration.fields[nodeType]}: ${nodeId}`; + const nodeFilter = `${getFieldByNodeType(nodeType, configuration.fields)}: ${nodeId}`; const userFilter = getFilterFromLocation(location); const filter = userFilter ? `(${nodeFilter}) and (${userFilter})` : nodeFilter; diff --git a/x-pack/legacy/plugins/infra/public/utils/formatters/high_precision.ts b/x-pack/legacy/plugins/infra/public/utils/formatters/high_precision.ts new file mode 100644 index 0000000000000..391b19d2af91b --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/utils/formatters/high_precision.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 const formatHighPercision = (val: number) => { + return Number(val).toLocaleString('en', { + maximumFractionDigits: 5, + }); +}; diff --git a/x-pack/legacy/plugins/infra/public/utils/formatters/index.ts b/x-pack/legacy/plugins/infra/public/utils/formatters/index.ts index efb20e71a9ce4..3c60dba747825 100644 --- a/x-pack/legacy/plugins/infra/public/utils/formatters/index.ts +++ b/x-pack/legacy/plugins/infra/public/utils/formatters/index.ts @@ -10,6 +10,7 @@ import { createBytesFormatter } from './bytes'; import { formatNumber } from './number'; import { formatPercent } from './percent'; import { InventoryFormatterType } from '../../../common/inventory_models/types'; +import { formatHighPercision } from './high_precision'; export const FORMATTERS = { number: formatNumber, @@ -21,6 +22,7 @@ export const FORMATTERS = { // bytes in bits formatted string out bits: createBytesFormatter(InfraWaffleMapDataFormat.bitsDecimal), percent: formatPercent, + highPercision: formatHighPercision, }; export const createFormatter = (format: InventoryFormatterType, template: string = '{{value}}') => ( diff --git a/x-pack/legacy/plugins/infra/server/graphql/types.ts b/x-pack/legacy/plugins/infra/server/graphql/types.ts index 8f87979dbde2e..88ad5b2f58f23 100644 --- a/x-pack/legacy/plugins/infra/server/graphql/types.ts +++ b/x-pack/legacy/plugins/infra/server/graphql/types.ts @@ -580,6 +580,10 @@ export enum InfraNodeType { pod = 'pod', container = 'container', host = 'host', + awsEC2 = 'awsEC2', + awsS3 = 'awsS3', + awsRDS = 'awsRDS', + awsSQS = 'awsSQS' } export enum InfraSnapshotMetricType { @@ -590,6 +594,22 @@ export enum InfraSnapshotMetricType { tx = 'tx', rx = 'rx', logRate = 'logRate', + diskIOReadBytes = 'diskIOReadBytes', + diskIOWriteBytes = 'diskIOWriteBytes', + s3TotalRequests = 's3TotalRequests', + s3NumberOfObjects = 's3NumberOfObjects', + s3BucketSize = 's3BucketSize', + s3DownloadBytes = 's3DownloadBytes', + s3UploadBytes = 's3UploadBytes', + rdsConnections = 'rdsConnections', + rdsQueriesExecuted = 'rdsQueriesExecuted', + rdsActiveTransactions = 'rdsActiveTransactions', + rdsLatency = 'rdsLatency', + sqsMessagesVisible = 'sqsOldestMessage', + sqsMessagesDelayed = 'sqsMessagesDelayed', + sqsMessagesSent = 'sqsMessagesSent', + sqsMessagesEmpty = 'sqsMessagesEmpty', + sqsOldestMessage = 'sqsOldestMessage', } export enum InfraMetric { @@ -630,6 +650,24 @@ export enum InfraMetric { awsNetworkPackets = 'awsNetworkPackets', awsDiskioBytes = 'awsDiskioBytes', awsDiskioOps = 'awsDiskioOps', + awsEC2CpuUtilization = 'awsEC2CpuUtilization', + awsEC2DiskIOBytes = 'awsEC2DiskIOBytes', + awsEC2NetworkTraffic = 'awsEC2NetworkTraffic', + awsS3TotalRequests = 'awsS3TotalRequests', + awsS3NumberOfObjects = 'awsS3NumberOfObjects', + awsS3BucketSize = 'awsS3BucketSize', + awsS3DownloadBytes = 'awsS3DownloadBytes', + awsS3UploadBytes = 'awsS3UploadBytes', + awsRDSCpuTotal = 'awsRDSCpuTotal', + awsRDSConnections = 'awsRDSConnections', + awsRDSQueriesExecuted = 'awsRDSQueriesExecuted', + awsRDSActiveTransactions = 'awsRDSActiveTransactions', + awsRDSLatency = 'awsRDSLatency', + awsSQSMessagesVisible = 'awsSQSMessagesVisible', + awsSQSMessagesDelayed = 'awsSQSMessagesDelayed', + awsSQSMessagesSent = 'awsSQSMessagesSent', + awsSQSMessagesEmpty = 'awsSQSMessagesEmpty', + awsSQSOldestMessage = 'awsSQSOldestMessage', custom = 'custom', } diff --git a/x-pack/legacy/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts b/x-pack/legacy/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts index db3c516841cd4..c4146f5758d80 100644 --- a/x-pack/legacy/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts +++ b/x-pack/legacy/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts @@ -7,11 +7,11 @@ import { i18n } from '@kbn/i18n'; import { flatten, get } from 'lodash'; import { KibanaRequest, RequestHandlerContext } from 'src/core/server'; -import { InfraMetric, InfraMetricData, InfraNodeType } from '../../../graphql/types'; +import { InfraMetric, InfraMetricData } from '../../../graphql/types'; import { KibanaFramework } from '../framework/kibana_framework_adapter'; import { InfraMetricsAdapter, InfraMetricsRequestOptions } from './adapter_types'; import { checkValidNode } from './lib/check_valid_node'; -import { metrics } from '../../../../common/inventory_models'; +import { metrics, findInventoryFields } from '../../../../common/inventory_models'; import { TSVBMetricModelCreator } from '../../../../common/inventory_models/types'; import { calculateMetricInterval } from '../../../utils/calculate_metric_interval'; @@ -27,13 +27,10 @@ export class KibanaMetricsAdapter implements InfraMetricsAdapter { options: InfraMetricsRequestOptions, rawRequest: KibanaRequest // NP_TODO: Temporarily needed until metrics getVisData no longer needs full request ): Promise { - const fields = { - [InfraNodeType.host]: options.sourceConfiguration.fields.host, - [InfraNodeType.container]: options.sourceConfiguration.fields.container, - [InfraNodeType.pod]: options.sourceConfiguration.fields.pod, - }; const indexPattern = `${options.sourceConfiguration.metricAlias},${options.sourceConfiguration.logAlias}`; - const nodeField = fields[options.nodeType]; + const fields = findInventoryFields(options.nodeType, options.sourceConfiguration.fields); + const nodeField = fields.id; + const search = (searchOptions: object) => this.framework.callWithRequest<{}, Aggregation>(requestContext, 'search', searchOptions); diff --git a/x-pack/legacy/plugins/infra/server/lib/constants.ts b/x-pack/legacy/plugins/infra/server/lib/constants.ts index 4f2fa561da0c5..0765256c4160c 100644 --- a/x-pack/legacy/plugins/infra/server/lib/constants.ts +++ b/x-pack/legacy/plugins/infra/server/lib/constants.ts @@ -4,21 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -import { InfraNodeType } from '../graphql/types'; - -// Used for metadata and snapshots resolvers to find the field that contains -// a displayable name of a node. -// Intentionally not the same as xpack.infra.sources.default.fields.{host,container,pod}. -// TODO: consider moving this to source configuration too. -export const NAME_FIELDS = { - [InfraNodeType.host]: 'host.name', - [InfraNodeType.pod]: 'kubernetes.pod.name', - [InfraNodeType.container]: 'container.name', -}; -export const IP_FIELDS = { - [InfraNodeType.host]: 'host.ip', - [InfraNodeType.pod]: 'kubernetes.pod.ip', - [InfraNodeType.container]: 'container.ip_address', -}; - export const CLOUD_METRICS_MODULES = ['aws']; diff --git a/x-pack/legacy/plugins/infra/server/lib/snapshot/create_timerange_with_interval.ts b/x-pack/legacy/plugins/infra/server/lib/snapshot/create_timerange_with_interval.ts new file mode 100644 index 0000000000000..6c27e54a78bee --- /dev/null +++ b/x-pack/legacy/plugins/infra/server/lib/snapshot/create_timerange_with_interval.ts @@ -0,0 +1,59 @@ +/* + * 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 { uniq } from 'lodash'; +import { RequestHandlerContext } from 'kibana/server'; +import { InfraSnapshotRequestOptions } from './types'; +import { InfraTimerangeInput } from '../../../public/graphql/types'; +import { getMetricsAggregations } from './query_helpers'; +import { calculateMetricInterval } from '../../utils/calculate_metric_interval'; +import { SnapshotModel, SnapshotModelMetricAggRT } from '../../../common/inventory_models/types'; +import { KibanaFramework } from '../adapters/framework/kibana_framework_adapter'; + +export const createTimeRangeWithInterval = async ( + framework: KibanaFramework, + requestContext: RequestHandlerContext, + options: InfraSnapshotRequestOptions +): Promise => { + const aggregations = getMetricsAggregations(options); + const modules = aggregationsToModules(aggregations); + const interval = + (await calculateMetricInterval( + framework, + requestContext, + { + indexPattern: options.sourceConfiguration.metricAlias, + timestampField: options.sourceConfiguration.fields.timestamp, + timerange: { from: options.timerange.from, to: options.timerange.to }, + }, + modules, + options.nodeType + )) || 60000; + return { + interval: `${interval}s`, + from: options.timerange.to - interval * 5000, // We need at least 5 buckets worth of data + to: options.timerange.to, + }; +}; + +const aggregationsToModules = (aggregations: SnapshotModel): string[] => { + return uniq( + Object.values(aggregations) + .reduce((modules, agg) => { + if (SnapshotModelMetricAggRT.is(agg)) { + return modules.concat(Object.values(agg).map(a => a?.field)); + } + return modules; + }, [] as Array) + .filter(v => v) + .map(field => + field! + .split(/\./) + .slice(0, 2) + .join('.') + ) + ) as string[]; +}; diff --git a/x-pack/legacy/plugins/infra/server/lib/snapshot/query_helpers.ts b/x-pack/legacy/plugins/infra/server/lib/snapshot/query_helpers.ts index 6ebbe8775562c..44d32c7b915a8 100644 --- a/x-pack/legacy/plugins/infra/server/lib/snapshot/query_helpers.ts +++ b/x-pack/legacy/plugins/infra/server/lib/snapshot/query_helpers.ts @@ -4,11 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { get } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { findInventoryModel } from '../../../common/inventory_models/index'; -import { InfraSnapshotRequestOptions } from './snapshot'; -import { NAME_FIELDS } from '../constants'; +import { findInventoryModel, findInventoryFields } from '../../../common/inventory_models/index'; +import { InfraSnapshotRequestOptions } from './types'; import { getIntervalInSeconds } from '../../utils/get_interval_in_seconds'; import { SnapshotModelRT, SnapshotModel } from '../../../common/inventory_models/types'; @@ -21,28 +19,35 @@ interface GroupBySource { }; } +export const getFieldByNodeType = (options: InfraSnapshotRequestOptions) => { + const inventoryFields = findInventoryFields(options.nodeType, options.sourceConfiguration.fields); + return inventoryFields.id; +}; + export const getGroupedNodesSources = (options: InfraSnapshotRequestOptions) => { + const fields = findInventoryFields(options.nodeType, options.sourceConfiguration.fields); const sources: GroupBySource[] = options.groupBy.map(gb => { return { [`${gb.field}`]: { terms: { field: gb.field } } }; }); sources.push({ id: { - terms: { field: options.sourceConfiguration.fields[options.nodeType] }, + terms: { field: fields.id }, }, }); sources.push({ - name: { terms: { field: NAME_FIELDS[options.nodeType], missing_bucket: true } }, + name: { terms: { field: fields.name, missing_bucket: true } }, }); return sources; }; export const getMetricsSources = (options: InfraSnapshotRequestOptions) => { - return [{ id: { terms: { field: options.sourceConfiguration.fields[options.nodeType] } } }]; + const fields = findInventoryFields(options.nodeType, options.sourceConfiguration.fields); + return [{ id: { terms: { field: fields.id } } }]; }; export const getMetricsAggregations = (options: InfraSnapshotRequestOptions): SnapshotModel => { - const model = findInventoryModel(options.nodeType); - const aggregation = get(model, ['metrics', 'snapshot', options.metric.type]); + const inventoryModel = findInventoryModel(options.nodeType); + const aggregation = inventoryModel.metrics.snapshot?.[options.metric.type]; if (!SnapshotModelRT.is(aggregation)) { throw new Error( i18n.translate('xpack.infra.snapshot.missingSnapshotMetricError', { diff --git a/x-pack/legacy/plugins/infra/server/lib/snapshot/response_helpers.ts b/x-pack/legacy/plugins/infra/server/lib/snapshot/response_helpers.ts index 6b18d9489c100..d22f41ff152f7 100644 --- a/x-pack/legacy/plugins/infra/server/lib/snapshot/response_helpers.ts +++ b/x-pack/legacy/plugins/infra/server/lib/snapshot/response_helpers.ts @@ -14,8 +14,8 @@ import { InfraNodeType, } from '../../graphql/types'; import { getIntervalInSeconds } from '../../utils/get_interval_in_seconds'; -import { InfraSnapshotRequestOptions } from './snapshot'; -import { IP_FIELDS } from '../constants'; +import { InfraSnapshotRequestOptions } from './types'; +import { findInventoryModel } from '../../../common/inventory_models'; export interface InfraSnapshotNodeMetricsBucket { key: { id: string }; @@ -73,12 +73,13 @@ export const getIPFromBucket = ( nodeType: InfraNodeType, bucket: InfraSnapshotNodeGroupByBucket ): string | null => { - const ip = get( - bucket, - `ip.hits.hits[0]._source.${IP_FIELDS[nodeType]}`, - null - ); - + const inventoryModel = findInventoryModel(nodeType); + if (!inventoryModel.fields.ip) { + return null; + } + const ip = get(bucket, `ip.hits.hits[0]._source.${inventoryModel.fields.ip}`, null) as + | string[] + | null; if (Array.isArray(ip)) { return ip.find(isIPv4) || null; } else if (typeof ip === 'string') { diff --git a/x-pack/legacy/plugins/infra/server/lib/snapshot/snapshot.ts b/x-pack/legacy/plugins/infra/server/lib/snapshot/snapshot.ts index 95769414832cc..d1db0ef07b338 100644 --- a/x-pack/legacy/plugins/infra/server/lib/snapshot/snapshot.ts +++ b/x-pack/legacy/plugins/infra/server/lib/snapshot/snapshot.ts @@ -5,14 +5,7 @@ */ import { RequestHandlerContext } from 'src/core/server'; -import { - InfraSnapshotGroupbyInput, - InfraSnapshotMetricInput, - InfraSnapshotNode, - InfraTimerangeInput, - InfraNodeType, - InfraSourceConfiguration, -} from '../../graphql/types'; +import { InfraSnapshotNode } from '../../graphql/types'; import { InfraDatabaseSearchResponse } from '../adapters/framework'; import { KibanaFramework } from '../adapters/framework/kibana_framework_adapter'; import { InfraSources } from '../sources'; @@ -32,18 +25,11 @@ import { InfraSnapshotNodeGroupByBucket, InfraSnapshotNodeMetricsBucket, } from './response_helpers'; -import { IP_FIELDS } from '../constants'; import { getAllCompositeData } from '../../utils/get_all_composite_data'; import { createAfterKeyHandler } from '../../utils/create_afterkey_handler'; - -export interface InfraSnapshotRequestOptions { - nodeType: InfraNodeType; - sourceConfiguration: InfraSourceConfiguration; - timerange: InfraTimerangeInput; - groupBy: InfraSnapshotGroupbyInput[]; - metric: InfraSnapshotMetricInput; - filterQuery: JsonObject | undefined; -} +import { findInventoryModel } from '../../../common/inventory_models'; +import { InfraSnapshotRequestOptions } from './types'; +import { createTimeRangeWithInterval } from './create_timerange_with_interval'; export class InfraSnapshot { constructor(private readonly libs: { sources: InfraSources; framework: KibanaFramework }) {} @@ -56,8 +42,22 @@ export class InfraSnapshot { // in order to page through the results of their respective composite aggregations. // Both chains of requests are supposed to run in parallel, and their results be merged // when they have both been completed. - const groupedNodesPromise = requestGroupedNodes(requestContext, options, this.libs.framework); - const nodeMetricsPromise = requestNodeMetrics(requestContext, options, this.libs.framework); + const timeRangeWithIntervalApplied = await createTimeRangeWithInterval( + this.libs.framework, + requestContext, + options + ); + const optionsWithTimerange = { ...options, timerange: timeRangeWithIntervalApplied }; + const groupedNodesPromise = requestGroupedNodes( + requestContext, + optionsWithTimerange, + this.libs.framework + ); + const nodeMetricsPromise = requestNodeMetrics( + requestContext, + optionsWithTimerange, + this.libs.framework + ); const groupedNodeBuckets = await groupedNodesPromise; const nodeMetricBuckets = await nodeMetricsPromise; @@ -79,6 +79,7 @@ const requestGroupedNodes = async ( options: InfraSnapshotRequestOptions, framework: KibanaFramework ): Promise => { + const inventoryModel = findInventoryModel(options.nodeType); const query = { allowNoIndices: true, index: `${options.sourceConfiguration.logAlias},${options.sourceConfiguration.metricAlias}`, @@ -112,7 +113,7 @@ const requestGroupedNodes = async ( top_hits: { sort: [{ [options.sourceConfiguration.fields.timestamp]: { order: 'desc' } }], _source: { - includes: [IP_FIELDS[options.nodeType]], + includes: inventoryModel.fields.ip ? [inventoryModel.fields.ip] : [], }, size: 1, }, diff --git a/x-pack/legacy/plugins/infra/server/lib/snapshot/types.ts b/x-pack/legacy/plugins/infra/server/lib/snapshot/types.ts new file mode 100644 index 0000000000000..778f5045894a9 --- /dev/null +++ b/x-pack/legacy/plugins/infra/server/lib/snapshot/types.ts @@ -0,0 +1,23 @@ +/* + * 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 { JsonObject } from '../../../common/typed_json'; +import { + InfraNodeType, + InfraSourceConfiguration, + InfraTimerangeInput, + InfraSnapshotGroupbyInput, + InfraSnapshotMetricInput, +} from '../../../public/graphql/types'; + +export interface InfraSnapshotRequestOptions { + nodeType: InfraNodeType; + sourceConfiguration: InfraSourceConfiguration; + timerange: InfraTimerangeInput; + groupBy: InfraSnapshotGroupbyInput[]; + metric: InfraSnapshotMetricInput; + filterQuery: JsonObject | undefined; +} diff --git a/x-pack/legacy/plugins/infra/server/routes/metadata/lib/get_id_field_name.ts b/x-pack/legacy/plugins/infra/server/routes/metadata/lib/get_id_field_name.ts deleted file mode 100644 index 5f6bdd30fa2b8..0000000000000 --- a/x-pack/legacy/plugins/infra/server/routes/metadata/lib/get_id_field_name.ts +++ /dev/null @@ -1,18 +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 { InfraSourceConfiguration } from '../../../lib/sources'; - -export const getIdFieldName = (sourceConfiguration: InfraSourceConfiguration, nodeType: string) => { - switch (nodeType) { - case 'host': - return sourceConfiguration.fields.host; - case 'container': - return sourceConfiguration.fields.container; - default: - return sourceConfiguration.fields.pod; - } -}; diff --git a/x-pack/legacy/plugins/infra/server/routes/metadata/lib/get_metric_metadata.ts b/x-pack/legacy/plugins/infra/server/routes/metadata/lib/get_metric_metadata.ts index 3bd22062c26a0..191339565b813 100644 --- a/x-pack/legacy/plugins/infra/server/routes/metadata/lib/get_metric_metadata.ts +++ b/x-pack/legacy/plugins/infra/server/routes/metadata/lib/get_metric_metadata.ts @@ -12,8 +12,8 @@ import { } from '../../../lib/adapters/framework'; import { KibanaFramework } from '../../../lib/adapters/framework/kibana_framework_adapter'; import { InfraSourceConfiguration } from '../../../lib/sources'; -import { getIdFieldName } from './get_id_field_name'; -import { NAME_FIELDS } from '../../../lib/constants'; +import { findInventoryFields } from '../../../../common/inventory_models'; +import { InventoryItemType } from '../../../../common/inventory_models/types'; export interface InfraMetricsAdapterResponse { id: string; @@ -26,10 +26,9 @@ export const getMetricMetadata = async ( requestContext: RequestHandlerContext, sourceConfiguration: InfraSourceConfiguration, nodeId: string, - nodeType: 'host' | 'pod' | 'container' + nodeType: InventoryItemType ): Promise => { - const idFieldName = getIdFieldName(sourceConfiguration, nodeType); - + const fields = findInventoryFields(nodeType, sourceConfiguration.fields); const metricQuery = { allowNoIndices: true, ignoreUnavailable: true, @@ -40,7 +39,7 @@ export const getMetricMetadata = async ( must_not: [{ match: { 'event.dataset': 'aws.ec2' } }], filter: [ { - match: { [idFieldName]: nodeId }, + match: { [fields.id]: nodeId }, }, ], }, @@ -49,7 +48,7 @@ export const getMetricMetadata = async ( aggs: { nodeName: { terms: { - field: NAME_FIELDS[nodeType], + field: fields.name, size: 1, }, }, diff --git a/x-pack/legacy/plugins/infra/server/routes/metadata/lib/get_node_info.ts b/x-pack/legacy/plugins/infra/server/routes/metadata/lib/get_node_info.ts index 1567b6d1bd1ec..4ff0df30abedd 100644 --- a/x-pack/legacy/plugins/infra/server/routes/metadata/lib/get_node_info.ts +++ b/x-pack/legacy/plugins/infra/server/routes/metadata/lib/get_node_info.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { first } from 'lodash'; +import { first, set, startsWith } from 'lodash'; import { RequestHandlerContext } from 'src/core/server'; import { KibanaFramework } from '../../../lib/adapters/framework/kibana_framework_adapter'; import { InfraSourceConfiguration } from '../../../lib/sources'; @@ -12,14 +12,15 @@ import { InfraNodeType } from '../../../graphql/types'; import { InfraMetadataInfo } from '../../../../common/http_api/metadata_api'; import { getPodNodeName } from './get_pod_node_name'; import { CLOUD_METRICS_MODULES } from '../../../lib/constants'; -import { getIdFieldName } from './get_id_field_name'; +import { findInventoryFields } from '../../../../common/inventory_models'; +import { InventoryItemType } from '../../../../common/inventory_models/types'; export const getNodeInfo = async ( framework: KibanaFramework, requestContext: RequestHandlerContext, sourceConfiguration: InfraSourceConfiguration, nodeId: string, - nodeType: 'host' | 'pod' | 'container' + nodeType: InventoryItemType ): Promise => { // If the nodeType is a Kubernetes pod then we need to get the node info // from a host record instead of a pod. This is due to the fact that any host @@ -45,6 +46,7 @@ export const getNodeInfo = async ( } return {}; } + const fields = findInventoryFields(nodeType, sourceConfiguration.fields); const params = { allowNoIndices: true, ignoreUnavailable: true, @@ -55,12 +57,18 @@ export const getNodeInfo = async ( _source: ['host.*', 'cloud.*'], query: { bool: { - must_not: CLOUD_METRICS_MODULES.map(module => ({ match: { 'event.module': module } })), - filter: [{ match: { [getIdFieldName(sourceConfiguration, nodeType)]: nodeId } }], + filter: [{ match: { [fields.id]: nodeId } }], }, }, }, }; + if (!CLOUD_METRICS_MODULES.some(m => startsWith(nodeType, m))) { + set( + params, + 'body.query.bool.must_not', + CLOUD_METRICS_MODULES.map(module => ({ match: { 'event.module': module } })) + ); + } const response = await framework.callWithRequest<{ _source: InfraMetadataInfo }, {}>( requestContext, 'search', diff --git a/x-pack/legacy/plugins/infra/server/routes/metadata/lib/get_pod_node_name.ts b/x-pack/legacy/plugins/infra/server/routes/metadata/lib/get_pod_node_name.ts index 47ffc7f83b6bc..be6e29a794d09 100644 --- a/x-pack/legacy/plugins/infra/server/routes/metadata/lib/get_pod_node_name.ts +++ b/x-pack/legacy/plugins/infra/server/routes/metadata/lib/get_pod_node_name.ts @@ -8,7 +8,7 @@ import { first, get } from 'lodash'; import { RequestHandlerContext } from 'src/core/server'; import { KibanaFramework } from '../../../lib/adapters/framework/kibana_framework_adapter'; import { InfraSourceConfiguration } from '../../../lib/sources'; -import { getIdFieldName } from './get_id_field_name'; +import { findInventoryFields } from '../../../../common/inventory_models'; export const getPodNodeName = async ( framework: KibanaFramework, @@ -17,6 +17,7 @@ export const getPodNodeName = async ( nodeId: string, nodeType: 'host' | 'pod' | 'container' ): Promise => { + const fields = findInventoryFields(nodeType, sourceConfiguration.fields); const params = { allowNoIndices: true, ignoreUnavailable: true, @@ -28,7 +29,7 @@ export const getPodNodeName = async ( query: { bool: { filter: [ - { match: { [getIdFieldName(sourceConfiguration, nodeType)]: nodeId } }, + { match: { [fields.id]: nodeId } }, { exists: { field: `kubernetes.node.name` } }, ], }, diff --git a/x-pack/legacy/plugins/infra/server/routes/metadata/lib/has_apm_data.ts b/x-pack/legacy/plugins/infra/server/routes/metadata/lib/has_apm_data.ts index ab242804173c0..9ca0819d74d46 100644 --- a/x-pack/legacy/plugins/infra/server/routes/metadata/lib/has_apm_data.ts +++ b/x-pack/legacy/plugins/infra/server/routes/metadata/lib/has_apm_data.ts @@ -8,24 +8,25 @@ import { RequestHandlerContext } from 'src/core/server'; import { KibanaFramework } from '../../../lib/adapters/framework/kibana_framework_adapter'; import { InfraSourceConfiguration } from '../../../lib/sources'; -import { getIdFieldName } from './get_id_field_name'; +import { findInventoryFields } from '../../../../common/inventory_models'; +import { InventoryItemType } from '../../../../common/inventory_models/types'; export const hasAPMData = async ( framework: KibanaFramework, requestContext: RequestHandlerContext, sourceConfiguration: InfraSourceConfiguration, nodeId: string, - nodeType: 'host' | 'pod' | 'container' + nodeType: InventoryItemType ) => { const apmIndices = await framework.plugins.apm.getApmIndices( requestContext.core.savedObjects.client ); const apmIndex = apmIndices['apm_oss.transactionIndices'] || 'apm-*'; + const fields = findInventoryFields(nodeType, sourceConfiguration.fields); // There is a bug in APM ECS data where host.name is not set. // This will fixed with: https://github.com/elastic/apm-server/issues/2502 - const nodeFieldName = - nodeType === 'host' ? 'host.hostname' : getIdFieldName(sourceConfiguration, nodeType); + const nodeFieldName = nodeType === 'host' ? 'host.hostname' : fields.id; const params = { allowNoIndices: true, ignoreUnavailable: true, diff --git a/x-pack/legacy/plugins/infra/server/routes/snapshot/index.ts b/x-pack/legacy/plugins/infra/server/routes/snapshot/index.ts index 013a261d24831..ae707bae79b9e 100644 --- a/x-pack/legacy/plugins/infra/server/routes/snapshot/index.ts +++ b/x-pack/legacy/plugins/infra/server/routes/snapshot/index.ts @@ -9,12 +9,12 @@ import { pipe } from 'fp-ts/lib/pipeable'; import { fold } from 'fp-ts/lib/Either'; import { identity } from 'fp-ts/lib/function'; import { InfraBackendLibs } from '../../lib/infra_types'; -import { InfraSnapshotRequestOptions } from '../../lib/snapshot'; import { UsageCollector } from '../../usage/usage_collector'; import { parseFilterQuery } from '../../utils/serialized_query'; import { InfraNodeType, InfraSnapshotMetricInput } from '../../../public/graphql/types'; import { SnapshotRequestRT, SnapshotNodeResponseRT } from '../../../common/http_api/snapshot_api'; import { throwErrors } from '../../../common/runtime_types'; +import { InfraSnapshotRequestOptions } from '../../lib/snapshot/types'; const escapeHatch = schema.object({}, { allowUnknowns: true }); diff --git a/x-pack/legacy/plugins/infra/server/utils/calculate_metric_interval.ts b/x-pack/legacy/plugins/infra/server/utils/calculate_metric_interval.ts index 5eb5d424cdd73..6247c0f0298a0 100644 --- a/x-pack/legacy/plugins/infra/server/utils/calculate_metric_interval.ts +++ b/x-pack/legacy/plugins/infra/server/utils/calculate_metric_interval.ts @@ -5,6 +5,8 @@ */ import { RequestHandlerContext } from 'src/core/server'; +import { InfraNodeType } from '../graphql/types'; +import { findInventoryModel } from '../../common/inventory_models'; import { KibanaFramework } from '../lib/adapters/framework/kibana_framework_adapter'; interface Options { @@ -24,8 +26,14 @@ export const calculateMetricInterval = async ( framework: KibanaFramework, requestContext: RequestHandlerContext, options: Options, - modules: string[] + modules: string[], + nodeType?: InfraNodeType // TODO: check that this type still makes sense ) => { + let from = options.timerange.from; + if (nodeType) { + const inventoryModel = findInventoryModel(nodeType); + from = options.timerange.to - inventoryModel.metrics.defaultTimeRangeInSeconds * 1000; + } const query = { allowNoIndices: true, index: options.indexPattern, @@ -37,7 +45,7 @@ export const calculateMetricInterval = async ( { range: { [options.timestampField]: { - gte: options.timerange.from, + gte: from, lte: options.timerange.to, format: 'epoch_millis', }, diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 18bfbff786edc..d6e72583e4d2e 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -5997,10 +5997,8 @@ "xpack.infra.metricsExplorer.openInTSVB": "ビジュアライザーで開く", "xpack.infra.metricsExplorer.viewNodeDetail": "{name} のメトリックを表示", "xpack.infra.node.ariaLabel": "{nodeName}、クリックしてメニューを開きます", - "xpack.infra.nodeContextMenu.viewAPMTraces": "{nodeType} APM トレースを表示", "xpack.infra.nodeContextMenu.viewLogsName": "ログを表示", "xpack.infra.nodeContextMenu.viewMetricsName": "メトリックを表示", - "xpack.infra.nodeContextMenu.viewUptimeLink": "アップタイムで {nodeType} を表示", "xpack.infra.nodesToWaffleMap.groupsWithGroups.allName": "すべて", "xpack.infra.nodesToWaffleMap.groupsWithNodes.allName": "すべて", "xpack.infra.notFoundPage.noContentFoundErrorTitle": "コンテンツがありません", @@ -6058,7 +6056,6 @@ "xpack.infra.waffle.metricOptions.outboundTrafficText": "送信トラフィック", "xpack.infra.waffle.noDataDescription": "期間またはフィルターを調整してみてください。", "xpack.infra.waffle.noDataTitle": "表示するデータがありません。", - "xpack.infra.waffle.nodeTypeSwitcher.hostsLabel": "すべてのホスト", "xpack.infra.waffle.selectTwoGroupingsTitle": "最大 2 つのグループ分けを選択してください", "xpack.infra.waffle.unableToSelectGroupErrorMessage": "{nodeType} のオプションでグループを選択できません", "xpack.infra.waffle.unableToSelectMetricErrorTitle": "メトリックのオプションまたは値を選択できません", @@ -12727,4 +12724,4 @@ "xpack.licensing.welcomeBanner.licenseIsExpiredDescription.updateYourLicenseLinkText": "ライセンスを更新", "xpack.licensing.welcomeBanner.licenseIsExpiredTitle": "ご使用の {licenseType} ライセンスは期限切れです" } -} \ No newline at end of file +} diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 7f55866c17a17..0f0a45ea19417 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -5999,10 +5999,8 @@ "xpack.infra.metricsExplorer.openInTSVB": "在 Visualize 中打开", "xpack.infra.metricsExplorer.viewNodeDetail": "查看 {name} 的指标", "xpack.infra.node.ariaLabel": "{nodeName},单击打开菜单", - "xpack.infra.nodeContextMenu.viewAPMTraces": "查看 {nodeType} APM 跟踪", "xpack.infra.nodeContextMenu.viewLogsName": "查看日志", "xpack.infra.nodeContextMenu.viewMetricsName": "查看指标", - "xpack.infra.nodeContextMenu.viewUptimeLink": "在 Uptime 中查看 {nodeType}", "xpack.infra.nodesToWaffleMap.groupsWithGroups.allName": "全部", "xpack.infra.nodesToWaffleMap.groupsWithNodes.allName": "全部", "xpack.infra.notFoundPage.noContentFoundErrorTitle": "未找到任何内容", @@ -6060,7 +6058,6 @@ "xpack.infra.waffle.metricOptions.outboundTrafficText": "出站流量", "xpack.infra.waffle.noDataDescription": "尝试调整您的时间或筛选。", "xpack.infra.waffle.noDataTitle": "没有可显示的数据。", - "xpack.infra.waffle.nodeTypeSwitcher.hostsLabel": "主机", "xpack.infra.waffle.selectTwoGroupingsTitle": "选择最多两个分组", "xpack.infra.waffle.unableToSelectGroupErrorMessage": "无法选择 {nodeType} 的分组依据选项", "xpack.infra.waffle.unableToSelectMetricErrorTitle": "无法选择指标选项或指标值。", diff --git a/x-pack/test/api_integration/apis/infra/waffle.ts b/x-pack/test/api_integration/apis/infra/waffle.ts index 41bdb08932999..1f79ad4eee4e5 100644 --- a/x-pack/test/api_integration/apis/infra/waffle.ts +++ b/x-pack/test/api_integration/apis/infra/waffle.ts @@ -189,9 +189,9 @@ export default function({ getService }: FtrProviderContext) { expect(firstNode).to.have.property('metric'); expect(firstNode.metric).to.eql({ name: 'cpu', - value: 0.003666666666666667, - avg: 0.00809090909090909, - max: 0.057833333333333334, + value: 0.009285714285714286, + max: 0.009285714285714286, + avg: 0.0015476190476190477, }); } }); @@ -279,9 +279,9 @@ export default function({ getService }: FtrProviderContext) { expect(firstNode).to.have.property('metric'); expect(firstNode.metric).to.eql({ name: 'cpu', - value: 0.003666666666666667, - avg: 0.00809090909090909, - max: 0.057833333333333334, + value: 0.009285714285714286, + max: 0.009285714285714286, + avg: 0.0015476190476190477, }); const secondNode = nodes[1]; expect(secondNode).to.have.property('path'); @@ -291,9 +291,9 @@ export default function({ getService }: FtrProviderContext) { expect(secondNode).to.have.property('metric'); expect(secondNode.metric).to.eql({ name: 'cpu', - value: 0.003666666666666667, - avg: 0.00809090909090909, - max: 0.057833333333333334, + value: 0.009285714285714286, + max: 0.009285714285714286, + avg: 0.0015476190476190477, }); } }); From f3813556ec6e0c249f0a94c96dd126b68fc6d317 Mon Sep 17 00:00:00 2001 From: Chris Davies Date: Thu, 12 Dec 2019 15:35:37 -0500 Subject: [PATCH 60/79] [Lens] Modify merge tables to use the same logic as auto date (#52931) --- .../editor_frame_plugin/merge_tables.test.ts | 35 +++++++++++++++++++ .../editor_frame_plugin/merge_tables.ts | 12 +++---- .../public/indexpattern_plugin/auto_date.ts | 26 ++++++++++++-- 3 files changed, 62 insertions(+), 11 deletions(-) diff --git a/x-pack/legacy/plugins/lens/public/editor_frame_plugin/merge_tables.test.ts b/x-pack/legacy/plugins/lens/public/editor_frame_plugin/merge_tables.test.ts index 6f0af07265516..8f124c25542c7 100644 --- a/x-pack/legacy/plugins/lens/public/editor_frame_plugin/merge_tables.test.ts +++ b/x-pack/legacy/plugins/lens/public/editor_frame_plugin/merge_tables.test.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import moment from 'moment'; import { mergeTables } from './merge_tables'; import { KibanaDatatable } from 'src/plugins/expressions/public'; @@ -69,4 +70,38 @@ describe('lens_merge_tables', () => { } `); }); + + it('should handle this week now/w', () => { + const { dateRange } = mergeTables.fn( + { + type: 'kibana_context', + timeRange: { + from: 'now/w', + to: 'now/w', + }, + }, + { layerIds: ['first', 'second'], tables: [] }, + {} + ); + + expect( + moment + .duration( + moment() + .startOf('week') + .diff(dateRange!.fromDate) + ) + .asDays() + ).toEqual(0); + + expect( + moment + .duration( + moment() + .endOf('week') + .diff(dateRange!.toDate) + ) + .asDays() + ).toEqual(0); + }); }); diff --git a/x-pack/legacy/plugins/lens/public/editor_frame_plugin/merge_tables.ts b/x-pack/legacy/plugins/lens/public/editor_frame_plugin/merge_tables.ts index 5f47898b4f632..dc03be894a87c 100644 --- a/x-pack/legacy/plugins/lens/public/editor_frame_plugin/merge_tables.ts +++ b/x-pack/legacy/plugins/lens/public/editor_frame_plugin/merge_tables.ts @@ -5,9 +5,9 @@ */ import { i18n } from '@kbn/i18n'; -import dateMath from '@elastic/datemath'; import { ExpressionFunction, KibanaContext, KibanaDatatable } from 'src/plugins/expressions/public'; import { LensMultiTable } from '../types'; +import { toAbsoluteDates } from '../indexpattern_plugin/auto_date'; interface MergeTables { layerIds: string[]; @@ -58,15 +58,11 @@ function getDateRange(ctx?: KibanaContext | null) { return; } - const fromDate = dateMath.parse(ctx.timeRange.from); - const toDate = dateMath.parse(ctx.timeRange.to); + const dateRange = toAbsoluteDates({ fromDate: ctx.timeRange.from, toDate: ctx.timeRange.to }); - if (!fromDate || !toDate) { + if (!dateRange) { return; } - return { - fromDate: fromDate.toDate(), - toDate: toDate.toDate(), - }; + return dateRange; } diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/auto_date.ts b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/auto_date.ts index dec0adba98103..b62585f5da09a 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/auto_date.ts +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/auto_date.ts @@ -16,16 +16,36 @@ interface LensAutoDateProps { aggConfigs: string; } -export function autoIntervalFromDateRange(dateRange?: DateRange, defaultValue: string = '1h') { +export function toAbsoluteDates(dateRange?: DateRange) { if (!dateRange) { + return; + } + + const fromDate = dateMath.parse(dateRange.fromDate); + const toDate = dateMath.parse(dateRange.toDate, { roundUp: true }); + + if (!fromDate || !toDate) { + return; + } + + return { + fromDate: fromDate.toDate(), + toDate: toDate.toDate(), + }; +} + +export function autoIntervalFromDateRange(dateRange?: DateRange, defaultValue: string = '1h') { + const dates = toAbsoluteDates(dateRange); + if (!dates) { return defaultValue; } const buckets = new TimeBuckets(); + buckets.setInterval('auto'); buckets.setBounds({ - min: dateMath.parse(dateRange.fromDate), - max: dateMath.parse(dateRange.toDate, { roundUp: true }), + min: dates.fromDate, + max: dates.toDate, }); return buckets.getInterval().expression; From 98c54e8d512339b94418e1af955e4882b7c7cd04 Mon Sep 17 00:00:00 2001 From: Frank Hassanabad Date: Thu, 12 Dec 2019 13:41:13 -0700 Subject: [PATCH 61/79] [SIEM][Detection Engine] Adds a tags service and optimizes alert_id lookups ## Summary * Adds a tags services for use by UI's that want to get a list of all the unique tags that are on all of the rules just like an aggregation * Removes the horribly inefficient `alert_id` look up that was a full alert scan and instead uses an internal structure that it augments to the tags for fast `alert_id` look ups. * Adds unit tests for the tags and internal structure tags * Updates other unit tests Usage for the UI: ```sh GET /api/detection_engine/tags ``` or shell script: ```sh ./get_tags.sh ``` Returns: ```sh [ "tag_1", "tag_2" ] ``` Testing: Ensure that the internal structure does not leak when doing any of these script/API calls * ./get_tags.sh * ./post_rule.sh ./rules/queries/query_with_tags.json * ./update_rule.sh ./rules/queries/query_with_tags.json * ./delete_rule.sh * ./find_rules.sh * ./find_rule_by_filter.sh "alert.attributes.enabled:%20true" * ./find_rule_by_filter.sh "alert.attributes.tags:tag_1" Caveat: You can do filter searches against tags that have the double underscore such as: ```sh ./find_rule_by_filter.sh "alert.attributes.tags:%20__*" ``` But that shouldn't be a big problem and more than likely no one will be naming something with double underscores. ### Checklist Use ~~strikethroughs~~ to remove checklist items you don't feel are applicable to this PR. ~~- [ ] This was checked for cross-browser compatibility, [including a check against IE11](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility)~~ ~~- [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/master/packages/kbn-i18n/README.md)~~ ~~- [ ] [Documentation](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#writing-documentation) was added for features that require explanation or tutorials~~ - [x] [Unit or functional tests](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility) were updated or added to match the most common scenarios ~~- [ ] This was checked for [keyboard-only and screenreader accessibility](https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Accessibility_testing_checklist)~~ ### For maintainers ~~- [ ] This was checked for breaking API changes and was [labeled appropriately](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#release-notes-process)~~ - [x] This includes a feature addition or change that requires a release note and was [labeled appropriately](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#release-notes-process) --- .../legacy/plugins/siem/common/constants.ts | 8 + .../plugins/siem/server/kibana.index.ts | 3 + .../routes/__mocks__/request_responses.ts | 3 +- .../routes/rules/utils.test.ts | 66 ++++ .../detection_engine/routes/rules/utils.ts | 7 +- .../routes/tags/read_tags_route.ts | 46 +++ .../rules/add_rule_id_to_tags.test.ts | 35 ++ .../rules/add_rule_id_to_tags.ts | 15 + .../detection_engine/rules/create_rules.ts | 3 +- .../detection_engine/rules/read_rules.test.ts | 146 +------ .../lib/detection_engine/rules/read_rules.ts | 84 ++-- .../lib/detection_engine/rules/types.ts | 9 - .../detection_engine/rules/update_rules.ts | 3 +- .../rules/update_tags.test.ts | 35 ++ .../lib/detection_engine/rules/update_tags.ts | 16 + .../lib/detection_engine/scripts/get_tags.sh | 15 + .../detection_engine/scripts/post_x_rules.sh | 1 + .../detection_engine/tags/read_tags.test.ts | 364 ++++++++++++++++++ .../lib/detection_engine/tags/read_tags.ts | 80 ++++ 19 files changed, 727 insertions(+), 212 deletions(-) create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/tags/read_tags_route.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/add_rule_id_to_tags.test.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/add_rule_id_to_tags.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_tags.test.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_tags.ts create mode 100755 x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/get_tags.sh create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/tags/read_tags.test.ts create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/tags/read_tags.ts diff --git a/x-pack/legacy/plugins/siem/common/constants.ts b/x-pack/legacy/plugins/siem/common/constants.ts index f08a6e66c3400..7b5015c34de14 100644 --- a/x-pack/legacy/plugins/siem/common/constants.ts +++ b/x-pack/legacy/plugins/siem/common/constants.ts @@ -40,6 +40,13 @@ export const DEFAULT_TIMEPICKER_QUICK_RANGES = 'timepicker:quickRanges'; */ export const SIGNALS_ID = `${APP_ID}.signals`; +/** + * Special internal structure for tags for signals. This is used + * to filter out tags that have internal structures within them. + */ +export const INTERNAL_IDENTIFIER = '__internal'; +export const INTERNAL_RULE_ID_KEY = `${INTERNAL_IDENTIFIER}_rule_id`; + /** * Detection engine routes */ @@ -47,6 +54,7 @@ export const DETECTION_ENGINE_URL = '/api/detection_engine'; export const DETECTION_ENGINE_RULES_URL = `${DETECTION_ENGINE_URL}/rules`; export const DETECTION_ENGINE_PRIVILEGES_URL = `${DETECTION_ENGINE_URL}/privileges`; export const DETECTION_ENGINE_INDEX_URL = `${DETECTION_ENGINE_URL}/index`; +export const DETECTION_ENGINE_TAGS_URL = `${DETECTION_ENGINE_URL}/tags`; /** * Default signals index key for kibana.dev.yml diff --git a/x-pack/legacy/plugins/siem/server/kibana.index.ts b/x-pack/legacy/plugins/siem/server/kibana.index.ts index 219c59dbf11a3..e90e6366dd9ec 100644 --- a/x-pack/legacy/plugins/siem/server/kibana.index.ts +++ b/x-pack/legacy/plugins/siem/server/kibana.index.ts @@ -19,6 +19,7 @@ import { querySignalsRoute } from './lib/detection_engine/routes/signals/query_s import { ServerFacade } from './types'; import { deleteIndexRoute } from './lib/detection_engine/routes/index/delete_index_route'; import { isAlertExecutor } from './lib/detection_engine/signals/types'; +import { readTagsRoute } from './lib/detection_engine/routes/tags/read_tags_route'; import { readPrivilegesRoute } from './lib/detection_engine/routes/privileges/read_privileges_route'; const APP_ID = 'siem'; @@ -54,6 +55,8 @@ export const initServerWithKibana = (context: PluginInitializerContext, __legacy readIndexRoute(__legacy); deleteIndexRoute(__legacy); + // Detection Engine tags routes that have the REST endpoints of /api/detection_engine/tags + readTagsRoute(__legacy); // Privileges API to get the generic user privileges readPrivilegesRoute(__legacy); }; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts index cb24b0d0c89b1..d9dd7bb1ff7d0 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -12,6 +12,7 @@ import { DETECTION_ENGINE_SIGNALS_STATUS_URL, DETECTION_ENGINE_PRIVILEGES_URL, DETECTION_ENGINE_QUERY_SIGNALS_URL, + INTERNAL_RULE_ID_KEY, } from '../../../../../common/constants'; import { RuleAlertType } from '../../rules/types'; import { RuleAlertParamsRest } from '../../types'; @@ -171,7 +172,7 @@ export const createActionResult = (): ActionResult => ({ export const getResult = (): RuleAlertType => ({ id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', name: 'Detect Root/Admin Users', - tags: [], + tags: [`${INTERNAL_RULE_ID_KEY}:rule-1`], alertTypeId: 'siem.signals', params: { description: 'Detecting root and admin users', diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts index d4e129f543ccf..a2312ce25e72a 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.test.ts @@ -11,8 +11,10 @@ import { getIdError, transformFindAlertsOrError, transformOrError, + transformTags, } from './utils'; import { getResult } from '../__mocks__/request_responses'; +import { INTERNAL_IDENTIFIER } from '../../../../../common/constants'; describe('utils', () => { describe('transformAlertToRule', () => { @@ -335,6 +337,53 @@ describe('utils', () => { type: 'query', }); }); + + test('should work with tags but filter out any internal tags', () => { + const fullRule = getResult(); + fullRule.tags = ['tag 1', 'tag 2', `${INTERNAL_IDENTIFIER}_some_other_value`]; + const rule = transformAlertToRule(fullRule); + expect(rule).toEqual({ + created_by: 'elastic', + description: 'Detecting root and admin users', + enabled: true, + false_positives: [], + from: 'now-6m', + id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', + immutable: false, + index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], + interval: '5m', + risk_score: 50, + rule_id: 'rule-1', + language: 'kuery', + max_signals: 100, + name: 'Detect Root/Admin Users', + output_index: '.siem-signals', + query: 'user.name: root or user.name: admin', + references: ['http://www.example.com', 'https://ww.example.com'], + severity: 'high', + updated_by: 'elastic', + tags: ['tag 1', 'tag 2'], + threats: [ + { + framework: 'MITRE ATT&CK', + tactic: { + id: 'TA0040', + name: 'impact', + reference: 'https://attack.mitre.org/tactics/TA0040/', + }, + techniques: [ + { + id: 'T1499', + name: 'endpoint denial of service', + reference: 'https://attack.mitre.org/techniques/T1499/', + }, + ], + }, + ], + to: 'now', + type: 'query', + }); + }); }); describe('getIdError', () => { @@ -493,4 +542,21 @@ describe('utils', () => { expect((output as Boom).message).toEqual('Internal error transforming'); }); }); + + describe('transformTags', () => { + test('it returns tags that have no internal structures', () => { + expect(transformTags(['tag 1', 'tag 2'])).toEqual(['tag 1', 'tag 2']); + }); + + test('it returns empty tags given empty tags', () => { + expect(transformTags([])).toEqual([]); + }); + + test('it returns tags with internal tags stripped out', () => { + expect(transformTags(['tag 1', `${INTERNAL_IDENTIFIER}_some_value`, 'tag 2'])).toEqual([ + 'tag 1', + 'tag 2', + ]); + }); + }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts index c9ae3abdfdc6b..ff06b63a034b8 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts @@ -6,6 +6,7 @@ import Boom from 'boom'; import { pickBy } from 'lodash/fp'; +import { INTERNAL_IDENTIFIER } from '../../../../../common/constants'; import { RuleAlertType, isAlertType, isAlertTypes } from '../../rules/types'; import { OutputRuleAlertRest } from '../../types'; @@ -25,6 +26,10 @@ export const getIdError = ({ } }; +export const transformTags = (tags: string[]): string[] => { + return tags.filter(tag => !tag.startsWith(INTERNAL_IDENTIFIER)); +}; + // Transforms the data but will remove any null or undefined it encounters and not include // those on the export export const transformAlertToRule = (alert: RuleAlertType): Partial => { @@ -51,7 +56,7 @@ export const transformAlertToRule = (alert: RuleAlertType): Partial { + server.route(createReadTagsRoute); +}; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/add_rule_id_to_tags.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/add_rule_id_to_tags.test.ts new file mode 100644 index 0000000000000..5a92c8ef42ed7 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/add_rule_id_to_tags.test.ts @@ -0,0 +1,35 @@ +/* + * 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 { addRuleIdToTags } from './add_rule_id_to_tags'; +import { INTERNAL_RULE_ID_KEY } from '../../../../common/constants'; + +describe('add_rule_id_to_tags', () => { + test('it should add a rule id as an internal structure to a single tag', () => { + const tags = addRuleIdToTags(['tag 1'], 'rule-1'); + expect(tags).toEqual(['tag 1', `${INTERNAL_RULE_ID_KEY}:rule-1`]); + }); + + test('it should add a rule id as an internal structure to two tags', () => { + const tags = addRuleIdToTags(['tag 1', 'tag 2'], 'rule-1'); + expect(tags).toEqual(['tag 1', 'tag 2', `${INTERNAL_RULE_ID_KEY}:rule-1`]); + }); + + test('it should add a rule id as an internal structure with empty tags', () => { + const tags = addRuleIdToTags([], 'rule-1'); + expect(tags).toEqual([`${INTERNAL_RULE_ID_KEY}:rule-1`]); + }); + + test('it should add not add an internal structure if rule id is undefined', () => { + const tags = addRuleIdToTags(['tag 1'], undefined); + expect(tags).toEqual(['tag 1']); + }); + + test('it should add not add an internal structure if rule id is null', () => { + const tags = addRuleIdToTags(['tag 1'], null); + expect(tags).toEqual(['tag 1']); + }); +}); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/add_rule_id_to_tags.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/add_rule_id_to_tags.ts new file mode 100644 index 0000000000000..1cf97881d514b --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/add_rule_id_to_tags.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 { INTERNAL_RULE_ID_KEY } from '../../../../common/constants'; + +export const addRuleIdToTags = (tags: string[], ruleId: string | null | undefined): string[] => { + if (ruleId == null) { + return tags; + } else { + return [...tags, `${INTERNAL_RULE_ID_KEY}:${ruleId}`]; + } +}; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts index 4cbf3756f58ac..c4c31190e1e83 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/create_rules.ts @@ -6,6 +6,7 @@ import { SIGNALS_ID } from '../../../../common/constants'; import { RuleParams } from './types'; +import { addRuleIdToTags } from './add_rule_id_to_tags'; export const createRules = async ({ alertsClient, @@ -37,7 +38,7 @@ export const createRules = async ({ return alertsClient.create({ data: { name, - tags, + tags: addRuleIdToTags(tags, ruleId), alertTypeId: SIGNALS_ID, params: { description, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/read_rules.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/read_rules.test.ts index b3d7ab1322775..6ba0aa95bdd7b 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/read_rules.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/read_rules.test.ts @@ -5,14 +5,9 @@ */ import { alertsClientMock } from '../../../../../alerting/server/alerts_client.mock'; -import { readRules, readRuleByRuleId, findRuleInArrayByRuleId } from './read_rules'; +import { readRules } from './read_rules'; import { AlertsClient } from '../../../../../alerting'; -import { - getResult, - getFindResultWithSingleHit, - getFindResultWithMultiHits, -} from '../routes/__mocks__/request_responses'; -import { SIGNALS_ID } from '../../../../common/constants'; +import { getResult, getFindResultWithSingleHit } from '../routes/__mocks__/request_responses'; describe('read_rules', () => { describe('readRules', () => { @@ -98,141 +93,4 @@ describe('read_rules', () => { expect(rule).toEqual(null); }); }); - - describe('readRuleByRuleId', () => { - test('should return a single value if the rule id matches', async () => { - const alertsClient = alertsClientMock.create(); - alertsClient.get.mockResolvedValue(getResult()); - alertsClient.find.mockResolvedValue(getFindResultWithSingleHit()); - - const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; - const rule = await readRuleByRuleId({ - alertsClient: unsafeCast, - ruleId: 'rule-1', - }); - expect(rule).toEqual(getResult()); - }); - - test('should not return a single value if the rule id does not match', async () => { - const alertsClient = alertsClientMock.create(); - alertsClient.get.mockResolvedValue(getResult()); - alertsClient.find.mockResolvedValue(getFindResultWithSingleHit()); - - const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; - const rule = await readRuleByRuleId({ - alertsClient: unsafeCast, - ruleId: 'rule-that-should-not-match-anything', - }); - expect(rule).toEqual(null); - }); - - test('should return a single value of rule-1 with multiple values', async () => { - const result1 = getResult(); - result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; - result1.params.ruleId = 'rule-1'; - - const result2 = getResult(); - result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d'; - result2.params.ruleId = 'rule-2'; - - const alertsClient = alertsClientMock.create(); - alertsClient.get.mockResolvedValue(getResult()); - alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1, result2])); - - const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; - const rule = await readRuleByRuleId({ - alertsClient: unsafeCast, - ruleId: 'rule-1', - }); - expect(rule).toEqual(result1); - }); - - test('should return a single value of rule-2 with multiple values', async () => { - const result1 = getResult(); - result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; - result1.params.ruleId = 'rule-1'; - - const result2 = getResult(); - result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d'; - result2.params.ruleId = 'rule-2'; - - const alertsClient = alertsClientMock.create(); - alertsClient.get.mockResolvedValue(getResult()); - alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1, result2])); - - const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; - const rule = await readRuleByRuleId({ - alertsClient: unsafeCast, - ruleId: 'rule-2', - }); - expect(rule).toEqual(result2); - }); - - test('should return null for a made up value with multiple values', async () => { - const result1 = getResult(); - result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; - result1.params.ruleId = 'rule-1'; - - const result2 = getResult(); - result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d'; - result2.params.ruleId = 'rule-2'; - - const alertsClient = alertsClientMock.create(); - alertsClient.get.mockResolvedValue(getResult()); - alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1, result2])); - - const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; - const rule = await readRuleByRuleId({ - alertsClient: unsafeCast, - ruleId: 'rule-that-should-not-match-anything', - }); - expect(rule).toEqual(null); - }); - }); - - describe('findRuleInArrayByRuleId', () => { - test('returns null if the objects are not of a signal rule type', () => { - const rule = findRuleInArrayByRuleId( - [ - { alertTypeId: 'made up 1', params: { ruleId: '123' } }, - { alertTypeId: 'made up 2', params: { ruleId: '456' } }, - ], - '123' - ); - expect(rule).toEqual(null); - }); - - test('returns correct type if the objects are of a signal rule type', () => { - const rule = findRuleInArrayByRuleId( - [ - { alertTypeId: SIGNALS_ID, params: { ruleId: '123' } }, - { alertTypeId: 'made up 2', params: { ruleId: '456' } }, - ], - '123' - ); - expect(rule).toEqual({ alertTypeId: 'siem.signals', params: { ruleId: '123' } }); - }); - - test('returns second correct type if the objects are of a signal rule type', () => { - const rule = findRuleInArrayByRuleId( - [ - { alertTypeId: SIGNALS_ID, params: { ruleId: '123' } }, - { alertTypeId: SIGNALS_ID, params: { ruleId: '456' } }, - ], - '456' - ); - expect(rule).toEqual({ alertTypeId: 'siem.signals', params: { ruleId: '456' } }); - }); - - test('returns null with correct types but data does not exist', () => { - const rule = findRuleInArrayByRuleId( - [ - { alertTypeId: SIGNALS_ID, params: { ruleId: '123' } }, - { alertTypeId: SIGNALS_ID, params: { ruleId: '456' } }, - ], - '892' - ); - expect(rule).toEqual(null); - }); - }); }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/read_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/read_rules.ts index 5c33526329016..9c83ae924486d 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/read_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/read_rules.ts @@ -4,66 +4,31 @@ * you may not use this file except in compliance with the Elastic License. */ +import { INTERNAL_RULE_ID_KEY } from '../../../../common/constants'; import { findRules } from './find_rules'; -import { RuleAlertType, isAlertTypeArray, ReadRuleParams, ReadRuleByRuleId } from './types'; +import { RuleAlertType, ReadRuleParams, isAlertType } from './types'; -export const findRuleInArrayByRuleId = ( - objects: object[], - ruleId: string -): RuleAlertType | null => { - if (isAlertTypeArray(objects)) { - const rules: RuleAlertType[] = objects; - const rule: RuleAlertType[] = rules.filter(datum => { - return datum.params.ruleId === ruleId; - }); - if (rule.length !== 0) { - return rule[0]; - } else { - return null; - } - } else { - return null; - } -}; - -// This an extremely slow and inefficient way of getting a rule by its id. -// I have to manually query every single record since the rule Params are -// not indexed and I cannot push in my own _id when I create an alert at the moment. -// TODO: Once we can directly push in the _id, then we should no longer need this way. -// TODO: This is meant to be _very_ temporary. -export const readRuleByRuleId = async ({ +/** + * This reads the rules through a cascade try of what is fastest to what is slowest. + * @param id - This is the fastest. This is the auto-generated id through the parameter id. + * and the id will either be found through `alertsClient.get({ id })` or it will not + * be returned as a not-found or a thrown error that is not 404. + * @param ruleId - This is a close second to being fast as long as it can find the rule_id from + * a filter query against the tags using `alert.attributes.tags: "__internal:${ruleId}"]` + */ +export const readRules = async ({ alertsClient, + id, ruleId, -}: ReadRuleByRuleId): Promise => { - const firstRules = await findRules({ alertsClient, page: 1 }); - const firstRule = findRuleInArrayByRuleId(firstRules.data, ruleId); - if (firstRule != null) { - return firstRule; - } else { - const totalPages = Math.ceil(firstRules.total / firstRules.perPage); - return Array(totalPages) - .fill({}) - .map((_, page) => { - // page index never starts at zero. It always has to be 1 or greater - return findRules({ alertsClient, page: page + 1 }); - }) - .reduce>(async (accum, findRule) => { - const rules = await findRule; - const rule = findRuleInArrayByRuleId(rules.data, ruleId); - if (rule != null) { - return rule; - } else { - return accum; - } - }, Promise.resolve(null)); - } -}; - -export const readRules = async ({ alertsClient, id, ruleId }: ReadRuleParams) => { +}: ReadRuleParams): Promise => { if (id != null) { try { - const output = await alertsClient.get({ id }); - return output; + const rule = await alertsClient.get({ id }); + if (isAlertType(rule)) { + return rule; + } else { + return null; + } } catch (err) { if (err.output.statusCode === 404) { return null; @@ -73,7 +38,16 @@ export const readRules = async ({ alertsClient, id, ruleId }: ReadRuleParams) => } } } else if (ruleId != null) { - return readRuleByRuleId({ alertsClient, ruleId }); + const ruleFromFind = await findRules({ + alertsClient, + filter: `alert.attributes.tags: "${INTERNAL_RULE_ID_KEY}:${ruleId}"`, + page: 1, + }); + if (ruleFromFind.data.length === 0 || !isAlertType(ruleFromFind.data[0])) { + return null; + } else { + return ruleFromFind.data[0]; + } } else { // should never get here, and yet here we are. return null; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/types.ts index 5c0fa76b52620..caeec68c504e6 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/types.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/types.ts @@ -84,11 +84,6 @@ export interface ReadRuleParams { ruleId?: string | undefined | null; } -export interface ReadRuleByRuleId { - alertsClient: AlertsClient; - ruleId: string; -} - export const isAlertTypes = (obj: unknown[]): obj is RuleAlertType[] => { return obj.every(rule => isAlertType(rule)); }; @@ -96,7 +91,3 @@ export const isAlertTypes = (obj: unknown[]): obj is RuleAlertType[] => { export const isAlertType = (obj: unknown): obj is RuleAlertType => { return get('alertTypeId', obj) === SIGNALS_ID; }; - -export const isAlertTypeArray = (objArray: unknown[]): objArray is RuleAlertType[] => { - return objArray.length === 0 || isAlertType(objArray[0]); -}; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts index 2eaa05ae2fa6a..b37e9f6cb8538 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_rules.ts @@ -8,6 +8,7 @@ import { defaults } from 'lodash/fp'; import { AlertAction } from '../../../../../alerting/server/types'; import { readRules } from './read_rules'; import { UpdateRuleParams } from './types'; +import { updateTags } from './update_tags'; export const calculateInterval = ( interval: string | undefined, @@ -114,7 +115,7 @@ export const updateRules = async ({ return alertsClient.update({ id: rule.id, data: { - tags: tags != null ? tags : [], + tags: updateTags(rule.tags, tags), name: calculateName({ updatedName: name, originalName: rule.name }), interval: calculateInterval(interval, rule.interval), actions, diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_tags.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_tags.test.ts new file mode 100644 index 0000000000000..cca937d73bd74 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_tags.test.ts @@ -0,0 +1,35 @@ +/* + * 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 { updateTags } from './update_tags'; +import { INTERNAL_IDENTIFIER } from '../../../../common/constants'; + +describe('update_tags', () => { + test('it should copy internal structures but not any other tags when updating', () => { + const tags = updateTags(['tag 2', `${INTERNAL_IDENTIFIER}_some_value`, 'tag 3'], ['tag 1']); + expect(tags).toEqual([`${INTERNAL_IDENTIFIER}_some_value`, 'tag 1']); + }); + + test('it should copy internal structures but not any other tags if given an update of empty tags', () => { + const tags = updateTags(['tag 2', `${INTERNAL_IDENTIFIER}_some_value`, 'tag 3'], []); + expect(tags).toEqual([`${INTERNAL_IDENTIFIER}_some_value`]); + }); + + test('it should work like a normal update if there are no internal structures', () => { + const tags = updateTags(['tag 2', 'tag 3'], ['tag 1']); + expect(tags).toEqual(['tag 1']); + }); + + test('it should not perform an update if the nextTags are undefined', () => { + const tags = updateTags(['tag 2', `${INTERNAL_IDENTIFIER}_some_value`, 'tag 3'], undefined); + expect(tags).toEqual(['tag 2', `${INTERNAL_IDENTIFIER}_some_value`, 'tag 3']); + }); + + test('it should not perform an update if the nextTags are null', () => { + const tags = updateTags(['tag 2', `${INTERNAL_IDENTIFIER}_some_value`, 'tag 3'], null); + expect(tags).toEqual(['tag 2', `${INTERNAL_IDENTIFIER}_some_value`, 'tag 3']); + }); +}); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_tags.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_tags.ts new file mode 100644 index 0000000000000..cf1424ea31600 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/update_tags.ts @@ -0,0 +1,16 @@ +/* + * 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 { INTERNAL_IDENTIFIER } from '../../../../common/constants'; + +export const updateTags = (prevTags: string[], nextTags: string[] | undefined | null): string[] => { + if (nextTags == null) { + return prevTags; + } else { + const allInternalStructures = prevTags.filter(tag => tag.startsWith(INTERNAL_IDENTIFIER)); + return [...allInternalStructures, ...nextTags]; + } +}; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/get_tags.sh b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/get_tags.sh new file mode 100755 index 0000000000000..2458c6aeba248 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/get_tags.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +# +# 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. +# + +set -e +./check_env_variables.sh + +# Example: ./get_tags.sh +curl -s -k \ + -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ + -X GET ${KIBANA_URL}${SPACE_URL}/api/detection_engine/tags | jq . diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/post_x_rules.sh b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/post_x_rules.sh index 53e7bb504746d..0dd4d85ea9da8 100755 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/post_x_rules.sh +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/post_x_rules.sh @@ -32,6 +32,7 @@ do { \"type\": \"query\", \"from\": \"now-6m\", \"to\": \"now\", + \"enabled\": \"false\", \"query\": \"user.name: root or user.name: admin\", \"language\": \"kuery\" }" \ diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/tags/read_tags.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/tags/read_tags.test.ts new file mode 100644 index 0000000000000..2d562672a4a63 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/tags/read_tags.test.ts @@ -0,0 +1,364 @@ +/* + * 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 { alertsClientMock } from '../../../../../alerting/server/alerts_client.mock'; +import { AlertsClient } from '../../../../../alerting'; +import { getResult, getFindResultWithMultiHits } from '../routes/__mocks__/request_responses'; +import { INTERNAL_RULE_ID_KEY, INTERNAL_IDENTIFIER } from '../../../../common/constants'; +import { readRawTags, readTags, convertTagsToSet, convertToTags, isTags } from './read_tags'; + +describe('read_tags', () => { + afterEach(() => { + jest.resetAllMocks(); + }); + + describe('readRawTags', () => { + test('it should return the intersection of tags to where none are repeating', async () => { + const result1 = getResult(); + result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + result1.params.ruleId = 'rule-1'; + result1.tags = ['tag 1', 'tag 2', 'tag 3']; + + const result2 = getResult(); + result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + result2.params.ruleId = 'rule-2'; + result2.tags = ['tag 1', 'tag 2', 'tag 3', 'tag 4']; + + const alertsClient = alertsClientMock.create(); + alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1, result2])); + + const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; + const tags = await readRawTags({ + alertsClient: unsafeCast, + }); + expect(tags).toEqual(['tag 1', 'tag 2', 'tag 3', 'tag 4']); + }); + + test('it should return the intersection of tags to where some are repeating values', async () => { + const result1 = getResult(); + result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + result1.params.ruleId = 'rule-1'; + result1.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3']; + + const result2 = getResult(); + result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + result2.params.ruleId = 'rule-2'; + result2.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3', 'tag 4']; + + const alertsClient = alertsClientMock.create(); + alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1, result2])); + + const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; + const tags = await readRawTags({ + alertsClient: unsafeCast, + }); + expect(tags).toEqual(['tag 1', 'tag 2', 'tag 3', 'tag 4']); + }); + + test('it should work with no tags defined between two results', async () => { + const result1 = getResult(); + result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + result1.params.ruleId = 'rule-1'; + result1.tags = []; + + const result2 = getResult(); + result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + result2.params.ruleId = 'rule-2'; + result2.tags = []; + + const alertsClient = alertsClientMock.create(); + alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1, result2])); + + const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; + const tags = await readRawTags({ + alertsClient: unsafeCast, + }); + expect(tags).toEqual([]); + }); + + test('it should work with a single tag which has repeating values in it', async () => { + const result1 = getResult(); + result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + result1.params.ruleId = 'rule-1'; + result1.tags = ['tag 1', 'tag 1', 'tag 1', 'tag 2']; + + const alertsClient = alertsClientMock.create(); + alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1])); + + const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; + const tags = await readRawTags({ + alertsClient: unsafeCast, + }); + expect(tags).toEqual(['tag 1', 'tag 2']); + }); + + test('it should work with a single tag which has empty tags', async () => { + const result1 = getResult(); + result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + result1.params.ruleId = 'rule-1'; + result1.tags = []; + + const alertsClient = alertsClientMock.create(); + alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1])); + + const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; + const tags = await readRawTags({ + alertsClient: unsafeCast, + }); + expect(tags).toEqual([]); + }); + }); + + describe('readTags', () => { + test('it should return the intersection of tags to where none are repeating', async () => { + const result1 = getResult(); + result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + result1.params.ruleId = 'rule-1'; + result1.tags = ['tag 1', 'tag 2', 'tag 3']; + + const result2 = getResult(); + result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + result2.params.ruleId = 'rule-2'; + result2.tags = ['tag 1', 'tag 2', 'tag 3', 'tag 4']; + + const alertsClient = alertsClientMock.create(); + alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1, result2])); + + const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; + const tags = await readTags({ + alertsClient: unsafeCast, + }); + expect(tags).toEqual(['tag 1', 'tag 2', 'tag 3', 'tag 4']); + }); + + test('it should return the intersection of tags to where some are repeating values', async () => { + const result1 = getResult(); + result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + result1.params.ruleId = 'rule-1'; + result1.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3']; + + const result2 = getResult(); + result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + result2.params.ruleId = 'rule-2'; + result2.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3', 'tag 4']; + + const alertsClient = alertsClientMock.create(); + alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1, result2])); + + const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; + const tags = await readTags({ + alertsClient: unsafeCast, + }); + expect(tags).toEqual(['tag 1', 'tag 2', 'tag 3', 'tag 4']); + }); + + test('it should work with no tags defined between two results', async () => { + const result1 = getResult(); + result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + result1.params.ruleId = 'rule-1'; + result1.tags = []; + + const result2 = getResult(); + result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + result2.params.ruleId = 'rule-2'; + result2.tags = []; + + const alertsClient = alertsClientMock.create(); + alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1, result2])); + + const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; + const tags = await readTags({ + alertsClient: unsafeCast, + }); + expect(tags).toEqual([]); + }); + + test('it should work with a single tag which has repeating values in it', async () => { + const result1 = getResult(); + result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + result1.params.ruleId = 'rule-1'; + result1.tags = ['tag 1', 'tag 1', 'tag 1', 'tag 2']; + + const alertsClient = alertsClientMock.create(); + alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1])); + + const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; + const tags = await readTags({ + alertsClient: unsafeCast, + }); + expect(tags).toEqual(['tag 1', 'tag 2']); + }); + + test('it should work with a single tag which has empty tags', async () => { + const result1 = getResult(); + result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + result1.params.ruleId = 'rule-1'; + result1.tags = []; + + const alertsClient = alertsClientMock.create(); + alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1])); + + const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; + const tags = await readTags({ + alertsClient: unsafeCast, + }); + expect(tags).toEqual([]); + }); + + test('it should filter out any __internal tags for things such as alert_id', async () => { + const result1 = getResult(); + result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + result1.params.ruleId = 'rule-1'; + result1.tags = [ + `${INTERNAL_IDENTIFIER}_some_value`, + `${INTERNAL_RULE_ID_KEY}_some_value`, + 'tag 1', + ]; + + const alertsClient = alertsClientMock.create(); + alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1])); + + const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; + const tags = await readTags({ + alertsClient: unsafeCast, + }); + expect(tags).toEqual(['tag 1']); + }); + + test('it should filter out any __internal tags with two different results', async () => { + const result1 = getResult(); + result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + result1.params.ruleId = 'rule-1'; + result1.tags = [ + `${INTERNAL_IDENTIFIER}_some_value`, + `${INTERNAL_RULE_ID_KEY}_some_value`, + 'tag 1', + 'tag 2', + 'tag 3', + 'tag 4', + 'tag 5', + ]; + + const result2 = getResult(); + result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + result2.params.ruleId = 'rule-2'; + result2.tags = [ + `${INTERNAL_IDENTIFIER}_some_value`, + `${INTERNAL_RULE_ID_KEY}_some_value`, + 'tag 1', + 'tag 2', + 'tag 3', + 'tag 4', + ]; + + const alertsClient = alertsClientMock.create(); + alertsClient.find.mockResolvedValue(getFindResultWithMultiHits([result1])); + + const unsafeCast: AlertsClient = (alertsClient as unknown) as AlertsClient; + const tags = await readTags({ + alertsClient: unsafeCast, + }); + expect(tags).toEqual(['tag 1', 'tag 2', 'tag 3', 'tag 4', 'tag 5']); + }); + }); + + describe('convertTagsToSet', () => { + test('it should convert the intersection of two tag systems without duplicates', () => { + const result1 = getResult(); + result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + result1.params.ruleId = 'rule-1'; + result1.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3']; + + const result2 = getResult(); + result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + result2.params.ruleId = 'rule-2'; + result2.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3', 'tag 4']; + + const findResult = getFindResultWithMultiHits([result1, result2]); + const set = convertTagsToSet(findResult.data); + expect(Array.from(set)).toEqual(['tag 1', 'tag 2', 'tag 3', 'tag 4']); + }); + + test('it should with with an empty array', () => { + const set = convertTagsToSet([]); + expect(Array.from(set)).toEqual([]); + }); + }); + + describe('convertToTags', () => { + test('it should convert the two tag systems together with duplicates', () => { + const result1 = getResult(); + result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + result1.params.ruleId = 'rule-1'; + result1.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3']; + + const result2 = getResult(); + result2.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + result2.params.ruleId = 'rule-2'; + result2.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3', 'tag 4']; + + const findResult = getFindResultWithMultiHits([result1, result2]); + const tags = convertToTags(findResult.data); + expect(tags).toEqual([ + 'tag 1', + 'tag 2', + 'tag 2', + 'tag 3', + 'tag 1', + 'tag 2', + 'tag 2', + 'tag 3', + 'tag 4', + ]); + }); + + test('it should filter out anything that is not a tag', () => { + const result1 = getResult(); + result1.id = '4baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + result1.params.ruleId = 'rule-1'; + result1.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3']; + + const result2 = getResult(); + result2.id = '99979e67-19a7-455f-b452-8eded6135716'; + result2.params.ruleId = 'rule-2'; + delete result2.tags; + + const result3 = getResult(); + result3.id = '5baa53f8-96da-44ee-ad58-41bccb7f9f3d'; + result3.params.ruleId = 'rule-2'; + result3.tags = ['tag 1', 'tag 2', 'tag 2', 'tag 3', 'tag 4']; + + const findResult = getFindResultWithMultiHits([result1, result2, result3]); + const tags = convertToTags(findResult.data); + expect(tags).toEqual([ + 'tag 1', + 'tag 2', + 'tag 2', + 'tag 3', + 'tag 1', + 'tag 2', + 'tag 2', + 'tag 3', + 'tag 4', + ]); + }); + + test('it should with with an empty array', () => { + const tags = convertToTags([]); + expect(tags).toEqual([]); + }); + }); + + describe('isTags', () => { + test('it should return true if the object has a tags on it', () => { + expect(isTags({ tags: [] })).toBe(true); + }); + + test('it should return false if the object does not have a tags on it', () => { + expect(isTags({})).toBe(false); + }); + }); +}); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/tags/read_tags.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/tags/read_tags.ts new file mode 100644 index 0000000000000..0f973d816917f --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/tags/read_tags.ts @@ -0,0 +1,80 @@ +/* + * 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 { has } from 'lodash/fp'; +import { INTERNAL_IDENTIFIER } from '../../../../common/constants'; +import { AlertsClient } from '../../../../../alerting'; +import { findRules } from '../rules/find_rules'; + +const DEFAULT_PER_PAGE: number = 1000; + +export interface TagType { + id: string; + tags: string[]; +} + +export const isTags = (obj: object): obj is TagType => { + return has('tags', obj); +}; + +export const convertToTags = (tagObjects: object[]): string[] => { + const tags = tagObjects.reduce((accum, tagObj) => { + if (isTags(tagObj)) { + return [...accum, ...tagObj.tags]; + } else { + return accum; + } + }, []); + return tags; +}; + +export const convertTagsToSet = (tagObjects: object[]): Set => { + return new Set(convertToTags(tagObjects)); +}; + +// Note: This is doing an in-memory aggregation of the tags by calling each of the alerting +// records in batches of this const setting and uses the fields to try to get the least +// amount of data per record back. If saved objects at some point supports aggregations +// then this should be replaced with a an aggregation call. +// Ref: https://www.elastic.co/guide/en/kibana/master/saved-objects-api.html +export const readTags = async ({ + alertsClient, + perPage = DEFAULT_PER_PAGE, +}: { + alertsClient: AlertsClient; + perPage?: number; +}): Promise => { + const tags = await readRawTags({ alertsClient, perPage }); + return tags.filter(tag => !tag.startsWith(INTERNAL_IDENTIFIER)); +}; + +export const readRawTags = async ({ + alertsClient, + perPage = DEFAULT_PER_PAGE, +}: { + alertsClient: AlertsClient; + perPage?: number; +}): Promise => { + const firstTags = await findRules({ alertsClient, fields: ['tags'], perPage, page: 1 }); + const firstSet = convertTagsToSet(firstTags.data); + const totalPages = Math.ceil(firstTags.total / firstTags.perPage); + if (totalPages <= 1) { + return Array.from(firstSet); + } else { + const returnTags = await Array(totalPages - 1) + .fill({}) + .map((_, page) => { + // page index starts at 2 as we already got the first page and we have more pages to go + return findRules({ alertsClient, fields: ['tags'], perPage, page: page + 2 }); + }) + .reduce>>(async (accum, nextTagPage) => { + const tagArray = convertToTags((await nextTagPage).data); + return new Set([...(await accum), ...tagArray]); + }, Promise.resolve(firstSet)); + + return Array.from(returnTags); + } +}; From 7e822c5df5931afea7d462b25b1dff123770254a Mon Sep 17 00:00:00 2001 From: Spencer Date: Thu, 12 Dec 2019 14:24:59 -0700 Subject: [PATCH 62/79] [renovate] disable rebaseConflictedPrs (#52932) --- renovate.json5 | 1 + src/dev/renovate/config.ts | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/renovate.json5 b/renovate.json5 index e4cb02604f50b..49474b28e7908 100644 --- a/renovate.json5 +++ b/renovate.json5 @@ -954,5 +954,6 @@ enabled: false, }, rebaseStalePrs: false, + rebaseConflictedPrs: false, semanticCommits: false, } diff --git a/src/dev/renovate/config.ts b/src/dev/renovate/config.ts index 6acbbaa4d5255..61feb4e47f022 100644 --- a/src/dev/renovate/config.ts +++ b/src/dev/renovate/config.ts @@ -123,6 +123,11 @@ export const RENOVATE_CONFIG = { */ rebaseStalePrs: false, + /** + * Disable automatic rebase on conflicts with the base branch + */ + rebaseConflictedPrs: false, + /** * Disable semantic commit formating */ From 4765ed0fa183ee88f89f61d88cc56d083ed84049 Mon Sep 17 00:00:00 2001 From: Bhavya RM Date: Thu, 12 Dec 2019 17:20:55 -0500 Subject: [PATCH 63/79] A11y base tests (#51893) a11y base tests --- .../editor/legacy/console_editor/editor.tsx | 3 + test/accessibility/apps/console.ts | 40 +++++++++++++ test/accessibility/apps/dashboard.ts | 57 +++++++++++++++++++ test/accessibility/apps/home.ts | 12 +++- test/accessibility/apps/management.ts | 8 +++ test/accessibility/apps/visualize.ts | 45 +++++++++++++++ test/accessibility/config.ts | 3 + x-pack/test/accessibility/config.ts | 2 - 8 files changed, 167 insertions(+), 3 deletions(-) create mode 100644 test/accessibility/apps/console.ts create mode 100644 test/accessibility/apps/dashboard.ts create mode 100644 test/accessibility/apps/visualize.ts diff --git a/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.tsx b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.tsx index a52c15c20c902..40b9cc4640eef 100644 --- a/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.tsx +++ b/src/legacy/core_plugins/console/public/np_ready/application/containers/editor/legacy/console_editor/editor.tsx @@ -211,6 +211,9 @@ function EditorUI() {